From 8bf9cd853fdeb722ee0a5c1a2e79a0bece390981 Mon Sep 17 00:00:00 2001 From: Fynn Date: Tue, 28 Jul 2015 19:16:16 -0300 Subject: [PATCH] FreeBSD support Former-commit-id: ff5dba816571945e8c0837f3ef52485da5fd7314 [formerly 2f23f618fd8f01331b593ab4e064138047fe7c77] Former-commit-id: 1ec5e7440481e307be5e131ac0a416fd7d2fea9f --- .gitignore | 37 + .gitmodules | 3 + .mailmap | 61 + .travis.yml | 33 + AUTHORS | 24 + COPYING | 619 + COPYING.LESSER | 165 + Godeps/Godeps.json | 127 + Godeps/Readme | 5 + Godeps/_workspace/.gitignore | 2 + .../code.google.com/p/go-uuid/uuid/LICENSE | 27 + .../src/code.google.com/p/go-uuid/uuid/dce.go | 84 + .../src/code.google.com/p/go-uuid/uuid/doc.go | 8 + .../code.google.com/p/go-uuid/uuid/hash.go | 53 + .../code.google.com/p/go-uuid/uuid/node.go | 101 + .../code.google.com/p/go-uuid/uuid/time.go | 132 + .../code.google.com/p/go-uuid/uuid/util.go | 43 + .../code.google.com/p/go-uuid/uuid/uuid.go | 163 + .../p/go-uuid/uuid/uuid_test.go | 390 + .../p/go-uuid/uuid/version1.go | 41 + .../p/go-uuid/uuid/version4.go | 25 + .../github.com/codegangsta/cli/.travis.yml | 6 + .../src/github.com/codegangsta/cli/LICENSE | 21 + .../src/github.com/codegangsta/cli/README.md | 298 + .../src/github.com/codegangsta/cli/app.go | 321 + .../github.com/codegangsta/cli/app_test.go | 622 + .../cli/autocomplete/bash_autocomplete | 13 + .../cli/autocomplete/zsh_autocomplete | 5 + .../src/github.com/codegangsta/cli/cli.go | 19 + .../github.com/codegangsta/cli/cli_test.go | 100 + .../src/github.com/codegangsta/cli/command.go | 177 + .../codegangsta/cli/command_test.go | 49 + .../src/github.com/codegangsta/cli/context.go | 344 + .../codegangsta/cli/context_test.go | 111 + .../src/github.com/codegangsta/cli/flag.go | 454 + .../github.com/codegangsta/cli/flag_test.go | 742 + .../src/github.com/codegangsta/cli/help.go | 215 + .../codegangsta/cli/helpers_test.go | 19 + .../github.com/davecgh/go-spew/spew/common.go | 450 + .../davecgh/go-spew/spew/common_test.go | 298 + .../github.com/davecgh/go-spew/spew/config.go | 294 + .../github.com/davecgh/go-spew/spew/doc.go | 202 + .../github.com/davecgh/go-spew/spew/dump.go | 506 + .../davecgh/go-spew/spew/dump_test.go | 1021 + .../davecgh/go-spew/spew/dumpcgo_test.go | 97 + .../davecgh/go-spew/spew/dumpnocgo_test.go | 26 + .../davecgh/go-spew/spew/example_test.go | 230 + .../github.com/davecgh/go-spew/spew/format.go | 419 + .../davecgh/go-spew/spew/format_test.go | 1535 + .../davecgh/go-spew/spew/internal_test.go | 156 + .../github.com/davecgh/go-spew/spew/spew.go | 148 + .../davecgh/go-spew/spew/spew_test.go | 308 + .../davecgh/go-spew/spew/testdata/dumpcgo.go | 82 + .../src/github.com/ethereum/ethash/.gitignore | 12 + .../github.com/ethereum/ethash/.travis.yml | 23 + .../github.com/ethereum/ethash/CMakeLists.txt | 14 + .../github.com/ethereum/ethash/MANIFEST.in | 17 + .../src/github.com/ethereum/ethash/Makefile | 6 + .../src/github.com/ethereum/ethash/README.md | 22 + .../github.com/ethereum/ethash/Vagrantfile | 7 + .../github.com/ethereum/ethash/appveyor.yml | 43 + .../cmake/modules/CMakeParseArguments.cmake | 161 + .../ethash/cmake/modules/FindCryptoPP.cmake | 108 + .../ethash/cmake/modules/FindOpenCL.cmake | 148 + .../FindPackageHandleStandardArgs.cmake | 382 + .../cmake/modules/FindPackageMessage.cmake | 57 + .../ethereum/ethash/cryptopp/CMakeLists.txt | 13 + .../src/github.com/ethereum/ethash/ethash.go | 376 + .../github.com/ethereum/ethash/ethash_test.go | 204 + .../src/github.com/ethereum/ethash/ethashc.go | 35 + .../src/github.com/ethereum/ethash/js/LICENSE | 22 + .../github.com/ethereum/ethash/js/ethash.js | 190 + .../github.com/ethereum/ethash/js/keccak.js | 404 + .../ethereum/ethash/js/makekeccak.js | 201 + .../src/github.com/ethereum/ethash/js/test.js | 53 + .../src/github.com/ethereum/ethash/js/util.js | 100 + .../src/github.com/ethereum/ethash/setup.py | 47 + .../ethash/src/benchmark/CMakeLists.txt | 58 + .../ethash/src/benchmark/benchmark.cpp | 278 + .../ethash/src/libethash/CMakeLists.txt | 44 + .../ethereum/ethash/src/libethash/compiler.h | 33 + .../ethash/src/libethash/data_sizes.h | 812 + .../ethereum/ethash/src/libethash/endian.h | 75 + .../ethereum/ethash/src/libethash/ethash.h | 147 + .../ethereum/ethash/src/libethash/fnv.h | 39 + .../ethereum/ethash/src/libethash/internal.c | 507 + .../ethereum/ethash/src/libethash/internal.h | 179 + .../ethereum/ethash/src/libethash/io.c | 119 + .../ethereum/ethash/src/libethash/io.h | 202 + .../ethereum/ethash/src/libethash/io_posix.c | 111 + .../ethereum/ethash/src/libethash/io_win32.c | 100 + .../ethereum/ethash/src/libethash/mmap.h | 47 + .../ethash/src/libethash/mmap_win32.c | 84 + .../ethereum/ethash/src/libethash/sha3.c | 151 + .../ethereum/ethash/src/libethash/sha3.h | 31 + .../ethash/src/libethash/sha3_cryptopp.cpp | 37 + .../ethash/src/libethash/sha3_cryptopp.h | 18 + .../ethereum/ethash/src/libethash/util.h | 47 + .../ethash/src/libethash/util_win32.c | 38 + .../ethereum/ethash/src/python/core.c | 267 + .../ethereum/ethash/test/c/CMakeLists.txt | 66 + .../ethereum/ethash/test/c/test.cpp | 669 + .../github.com/ethereum/ethash/test/c/test.sh | 32 + .../ethereum/ethash/test/python/.gitignore | 1 + .../ethash/test/python/requirements.txt | 3 + .../ethereum/ethash/test/python/test.sh | 30 + .../ethash/test/python/test_pyethash.py | 105 + .../github.com/ethereum/ethash/test/test.sh | 32 + .../src/github.com/gizak/termui/.gitignore | 24 + .../src/github.com/gizak/termui/.travis.yml | 6 + .../src/github.com/gizak/termui/LICENSE | 22 + .../src/github.com/gizak/termui/README.md | 159 + .../src/github.com/gizak/termui/bar.go | 135 + .../src/github.com/gizak/termui/block.go | 142 + .../src/github.com/gizak/termui/block_test.go | 46 + .../src/github.com/gizak/termui/box.go | 117 + .../src/github.com/gizak/termui/box_others.go | 14 + .../github.com/gizak/termui/box_windows.go | 14 + .../src/github.com/gizak/termui/canvas.go | 74 + .../github.com/gizak/termui/canvas_test.go | 55 + .../src/github.com/gizak/termui/chart.go | 336 + .../github.com/gizak/termui/chart_others.go | 11 + .../github.com/gizak/termui/chart_windows.go | 11 + .../src/github.com/gizak/termui/doc.go | 27 + .../src/github.com/gizak/termui/events.go | 219 + .../github.com/gizak/termui/events_test.go | 28 + .../gizak/termui/example/barchart.go | 35 + .../gizak/termui/example/barchart.png | Bin 0 -> 15386 bytes .../gizak/termui/example/dashboard.gif | Bin 0 -> 453764 bytes .../gizak/termui/example/dashboard.go | 148 + .../github.com/gizak/termui/example/gauge.go | 62 + .../github.com/gizak/termui/example/gauge.png | Bin 0 -> 32431 bytes .../github.com/gizak/termui/example/grid.gif | Bin 0 -> 800288 bytes .../github.com/gizak/termui/example/grid.go | 134 + .../gizak/termui/example/linechart.go | 68 + .../gizak/termui/example/linechart.png | Bin 0 -> 139361 bytes .../github.com/gizak/termui/example/list.go | 41 + .../github.com/gizak/termui/example/list.png | Bin 0 -> 37227 bytes .../gizak/termui/example/mbarchart.go | 50 + .../gizak/termui/example/mbarchart.png | Bin 0 -> 20075 bytes .../github.com/gizak/termui/example/par.go | 48 + .../github.com/gizak/termui/example/par.png | Bin 0 -> 65773 bytes .../gizak/termui/example/sparklines.go | 65 + .../gizak/termui/example/sparklines.png | Bin 0 -> 43431 bytes .../github.com/gizak/termui/example/theme.go | 143 + .../gizak/termui/example/themedefault.png | Bin 0 -> 105508 bytes .../gizak/termui/example/themehelloworld.png | Bin 0 -> 90111 bytes .../src/github.com/gizak/termui/gauge.go | 113 + .../src/github.com/gizak/termui/grid.go | 279 + .../src/github.com/gizak/termui/grid_test.go | 98 + .../src/github.com/gizak/termui/helper.go | 66 + .../github.com/gizak/termui/helper_test.go | 58 + .../src/github.com/gizak/termui/list.go | 104 + .../src/github.com/gizak/termui/mbar.go | 233 + .../src/github.com/gizak/termui/p.go | 71 + .../src/github.com/gizak/termui/point.go | 28 + .../src/github.com/gizak/termui/render.go | 60 + .../src/github.com/gizak/termui/sparkline.go | 156 + .../src/github.com/gizak/termui/theme.go | 84 + .../hashicorp/golang-lru/.gitignore | 23 + .../github.com/hashicorp/golang-lru/LICENSE | 362 + .../github.com/hashicorp/golang-lru/README.md | 25 + .../github.com/hashicorp/golang-lru/lru.go | 175 + .../hashicorp/golang-lru/lru_test.go | 127 + .../src/github.com/huin/goupnp/LICENSE | 23 + .../src/github.com/huin/goupnp/README.md | 14 + .../example_httpu_serving.go | 20 + .../example_internetgateway1.go | 67 + .../dcps/internetgateway1/internetgateway1.go | 3957 ++ .../dcps/internetgateway2/internetgateway2.go | 5271 ++ .../src/github.com/huin/goupnp/device.go | 184 + .../github.com/huin/goupnp/example/example.go | 6 + .../huin/goupnp/example/example_test.go | 62 + .../huin/goupnp/gotasks/specgen_task.go | 539 + .../src/github.com/huin/goupnp/goupnp.go | 115 + .../src/github.com/huin/goupnp/httpu/httpu.go | 117 + .../src/github.com/huin/goupnp/httpu/serve.go | 108 + .../src/github.com/huin/goupnp/scpd/scpd.go | 167 + .../github.com/huin/goupnp/service_client.go | 56 + .../src/github.com/huin/goupnp/soap/soap.go | 157 + .../github.com/huin/goupnp/soap/soap_test.go | 85 + .../src/github.com/huin/goupnp/soap/types.go | 508 + .../github.com/huin/goupnp/soap/types_test.go | 481 + .../github.com/huin/goupnp/ssdp/registry.go | 202 + .../src/github.com/huin/goupnp/ssdp/ssdp.go | 83 + .../src/github.com/jackpal/go-nat-pmp/LICENSE | 13 + .../github.com/jackpal/go-nat-pmp/README.md | 48 + .../github.com/jackpal/go-nat-pmp/natpmp.go | 184 + .../src/github.com/kardianos/osext/LICENSE | 27 + .../src/github.com/kardianos/osext/README.md | 14 + .../src/github.com/kardianos/osext/osext.go | 27 + .../github.com/kardianos/osext/osext_plan9.go | 20 + .../kardianos/osext/osext_procfs.go | 28 + .../kardianos/osext/osext_sysctl.go | 79 + .../github.com/kardianos/osext/osext_test.go | 79 + .../kardianos/osext/osext_windows.go | 34 + .../github.com/mattn/go-colorable/README.md | 42 + .../mattn/go-colorable/colorable_others.go | 16 + .../mattn/go-colorable/colorable_windows.go | 594 + .../src/github.com/mattn/go-isatty/README.md | 37 + .../src/github.com/mattn/go-isatty/doc.go | 2 + .../github.com/mattn/go-isatty/isatty_bsd.go | 17 + .../mattn/go-isatty/isatty_linux.go | 17 + .../mattn/go-isatty/isatty_windows.go | 18 + .../github.com/mattn/go-runewidth/.travis.yml | 9 + .../github.com/mattn/go-runewidth/README.mkd | 25 + .../mattn/go-runewidth/runewidth.go | 404 + .../mattn/go-runewidth/runewidth_js.go | 8 + .../mattn/go-runewidth/runewidth_posix.go | 69 + .../mattn/go-runewidth/runewidth_test.go | 134 + .../mattn/go-runewidth/runewidth_windows.go | 24 + .../src/github.com/nsf/termbox-go/AUTHORS | 4 + .../src/github.com/nsf/termbox-go/LICENSE | 19 + .../src/github.com/nsf/termbox-go/README.md | 21 + .../src/github.com/nsf/termbox-go/api.go | 451 + .../github.com/nsf/termbox-go/api_common.go | 183 + .../github.com/nsf/termbox-go/api_windows.go | 235 + .../nsf/termbox-go/collect_terminfo.py | 110 + .../src/github.com/nsf/termbox-go/syscalls.go | 39 + .../nsf/termbox-go/syscalls_darwin_386.go | 39 + .../nsf/termbox-go/syscalls_darwin_amd64.go | 40 + .../nsf/termbox-go/syscalls_freebsd.go | 39 + .../nsf/termbox-go/syscalls_linux.go | 33 + .../nsf/termbox-go/syscalls_netbsd.go | 39 + .../nsf/termbox-go/syscalls_openbsd.go | 39 + .../nsf/termbox-go/syscalls_windows.go | 61 + .../src/github.com/nsf/termbox-go/termbox.go | 407 + .../nsf/termbox-go/termbox_common.go | 59 + .../nsf/termbox-go/termbox_windows.go | 813 + .../src/github.com/nsf/termbox-go/terminfo.go | 219 + .../nsf/termbox-go/terminfo_builtin.go | 64 + .../src/github.com/peterh/liner/COPYING | 21 + .../src/github.com/peterh/liner/README.md | 95 + .../src/github.com/peterh/liner/bsdinput.go | 39 + .../src/github.com/peterh/liner/common.go | 219 + .../github.com/peterh/liner/fallbackinput.go | 57 + .../src/github.com/peterh/liner/input.go | 359 + .../github.com/peterh/liner/input_darwin.go | 39 + .../github.com/peterh/liner/input_linux.go | 26 + .../src/github.com/peterh/liner/input_test.go | 61 + .../github.com/peterh/liner/input_windows.go | 313 + .../src/github.com/peterh/liner/line.go | 864 + .../src/github.com/peterh/liner/line_test.go | 90 + .../src/github.com/peterh/liner/output.go | 63 + .../github.com/peterh/liner/output_windows.go | 54 + .../github.com/peterh/liner/prefix_test.go | 37 + .../src/github.com/peterh/liner/race_test.go | 44 + .../src/github.com/peterh/liner/signal.go | 12 + .../github.com/peterh/liner/signal_legacy.go | 11 + .../src/github.com/peterh/liner/unixmode.go | 37 + .../src/github.com/peterh/liner/width.go | 47 + .../src/github.com/peterh/liner/width_test.go | 87 + .../github.com/rcrowley/go-metrics/.gitignore | 9 + .../github.com/rcrowley/go-metrics/LICENSE | 29 + .../github.com/rcrowley/go-metrics/README.md | 104 + .../cmd/metrics-bench/metrics-bench.go | 20 + .../cmd/metrics-example/metrics-example.go | 154 + .../go-metrics/cmd/never-read/never-read.go | 22 + .../github.com/rcrowley/go-metrics/counter.go | 112 + .../rcrowley/go-metrics/counter_test.go | 77 + .../github.com/rcrowley/go-metrics/debug.go | 76 + .../rcrowley/go-metrics/debug_test.go | 48 + .../github.com/rcrowley/go-metrics/ewma.go | 118 + .../rcrowley/go-metrics/ewma_test.go | 225 + .../github.com/rcrowley/go-metrics/gauge.go | 84 + .../rcrowley/go-metrics/gauge_float64.go | 91 + .../rcrowley/go-metrics/gauge_float64_test.go | 38 + .../rcrowley/go-metrics/gauge_test.go | 37 + .../rcrowley/go-metrics/graphite.go | 111 + .../rcrowley/go-metrics/graphite_test.go | 22 + .../rcrowley/go-metrics/healthcheck.go | 61 + .../rcrowley/go-metrics/histogram.go | 202 + .../rcrowley/go-metrics/histogram_test.go | 95 + .../rcrowley/go-metrics/influxdb/influxdb.go | 114 + .../github.com/rcrowley/go-metrics/json.go | 83 + .../rcrowley/go-metrics/json_test.go | 28 + .../rcrowley/go-metrics/librato/client.go | 102 + .../rcrowley/go-metrics/librato/librato.go | 230 + .../src/github.com/rcrowley/go-metrics/log.go | 70 + .../github.com/rcrowley/go-metrics/memory.md | 285 + .../github.com/rcrowley/go-metrics/meter.go | 233 + .../rcrowley/go-metrics/meter_test.go | 60 + .../github.com/rcrowley/go-metrics/metrics.go | 13 + .../rcrowley/go-metrics/metrics_test.go | 107 + .../rcrowley/go-metrics/opentsdb.go | 119 + .../rcrowley/go-metrics/opentsdb_test.go | 22 + .../rcrowley/go-metrics/registry.go | 180 + .../rcrowley/go-metrics/registry_test.go | 118 + .../github.com/rcrowley/go-metrics/runtime.go | 200 + .../rcrowley/go-metrics/runtime_cgo.go | 10 + .../rcrowley/go-metrics/runtime_no_cgo.go | 7 + .../rcrowley/go-metrics/runtime_test.go | 78 + .../github.com/rcrowley/go-metrics/sample.go | 609 + .../rcrowley/go-metrics/sample_test.go | 363 + .../rcrowley/go-metrics/stathat/stathat.go | 69 + .../github.com/rcrowley/go-metrics/syslog.go | 78 + .../github.com/rcrowley/go-metrics/timer.go | 311 + .../rcrowley/go-metrics/timer_test.go | 81 + .../github.com/rcrowley/go-metrics/writer.go | 100 + .../rcrowley/go-metrics/writer_test.go | 22 + .../github.com/robertkrimen/otto/.gitignore | 5 + .../robertkrimen/otto/DESIGN.markdown | 1 + .../src/github.com/robertkrimen/otto/LICENSE | 7 + .../src/github.com/robertkrimen/otto/Makefile | 63 + .../robertkrimen/otto/README.markdown | 825 + .../robertkrimen/otto/array_test.go | 716 + .../robertkrimen/otto/ast/README.markdown | 1068 + .../github.com/robertkrimen/otto/ast/node.go | 498 + .../github.com/robertkrimen/otto/bug_test.go | 617 + .../github.com/robertkrimen/otto/builtin.go | 353 + .../robertkrimen/otto/builtin_array.go | 672 + .../robertkrimen/otto/builtin_boolean.go | 28 + .../robertkrimen/otto/builtin_date.go | 615 + .../robertkrimen/otto/builtin_error.go | 126 + .../robertkrimen/otto/builtin_function.go | 129 + .../robertkrimen/otto/builtin_json.go | 299 + .../robertkrimen/otto/builtin_math.go | 145 + .../robertkrimen/otto/builtin_number.go | 93 + .../robertkrimen/otto/builtin_object.go | 289 + .../robertkrimen/otto/builtin_regexp.go | 65 + .../robertkrimen/otto/builtin_string.go | 500 + .../robertkrimen/otto/builtin_test.go | 136 + .../src/github.com/robertkrimen/otto/clone.go | 155 + .../src/github.com/robertkrimen/otto/cmpl.go | 24 + .../robertkrimen/otto/cmpl_evaluate.go | 96 + .../otto/cmpl_evaluate_expression.go | 456 + .../otto/cmpl_evaluate_statement.go | 421 + .../robertkrimen/otto/cmpl_parse.go | 650 + .../github.com/robertkrimen/otto/cmpl_test.go | 54 + .../github.com/robertkrimen/otto/console.go | 51 + .../github.com/robertkrimen/otto/date_test.go | 481 + .../src/github.com/robertkrimen/otto/dbg.go | 9 + .../github.com/robertkrimen/otto/dbg/dbg.go | 387 + .../robertkrimen/otto/documentation_test.go | 95 + .../src/github.com/robertkrimen/otto/error.go | 245 + .../robertkrimen/otto/error_test.go | 192 + .../github.com/robertkrimen/otto/evaluate.go | 318 + .../robertkrimen/otto/file/README.markdown | 110 + .../github.com/robertkrimen/otto/file/file.go | 135 + .../robertkrimen/otto/function_test.go | 280 + .../github.com/robertkrimen/otto/global.go | 221 + .../robertkrimen/otto/global_test.go | 355 + .../src/github.com/robertkrimen/otto/inline | 1086 + .../github.com/robertkrimen/otto/inline.go | 6649 +++ .../github.com/robertkrimen/otto/json_test.go | 183 + .../github.com/robertkrimen/otto/math_test.go | 303 + .../robertkrimen/otto/number_test.go | 165 + .../github.com/robertkrimen/otto/object.go | 156 + .../robertkrimen/otto/object_class.go | 493 + .../robertkrimen/otto/object_test.go | 639 + .../src/github.com/robertkrimen/otto/otto.go | 578 + .../robertkrimen/otto/otto/Makefile | 5 + .../github.com/robertkrimen/otto/otto/main.go | 48 + .../src/github.com/robertkrimen/otto/otto_.go | 178 + .../robertkrimen/otto/otto_error_test.go | 48 + .../github.com/robertkrimen/otto/otto_test.go | 1379 + .../robertkrimen/otto/panic_test.go | 40 + .../robertkrimen/otto/parser/Makefile | 4 + .../robertkrimen/otto/parser/README.markdown | 190 + .../robertkrimen/otto/parser/dbg.go | 9 + .../robertkrimen/otto/parser/error.go | 175 + .../robertkrimen/otto/parser/expression.go | 815 + .../robertkrimen/otto/parser/lexer.go | 819 + .../robertkrimen/otto/parser/lexer_test.go | 380 + .../robertkrimen/otto/parser/marshal_test.go | 930 + .../robertkrimen/otto/parser/parser.go | 273 + .../robertkrimen/otto/parser/parser_test.go | 1004 + .../robertkrimen/otto/parser/regexp.go | 358 + .../robertkrimen/otto/parser/regexp_test.go | 149 + .../robertkrimen/otto/parser/scope.go | 44 + .../robertkrimen/otto/parser/statement.go | 663 + .../robertkrimen/otto/parser_test.go | 42 + .../github.com/robertkrimen/otto/property.go | 220 + .../robertkrimen/otto/reflect_test.go | 483 + .../robertkrimen/otto/regexp_test.go | 290 + .../otto/registry/README.markdown | 51 + .../robertkrimen/otto/registry/registry.go | 47 + .../github.com/robertkrimen/otto/result.go | 30 + .../github.com/robertkrimen/otto/runtime.go | 331 + .../robertkrimen/otto/runtime_test.go | 778 + .../src/github.com/robertkrimen/otto/scope.go | 34 + .../github.com/robertkrimen/otto/script.go | 122 + .../robertkrimen/otto/script_test.go | 78 + .../src/github.com/robertkrimen/otto/stash.go | 275 + .../robertkrimen/otto/string_test.go | 365 + .../robertkrimen/otto/terst/terst.go | 669 + .../robertkrimen/otto/test/Makefile | 26 + .../robertkrimen/otto/test/tester.go | 196 + .../robertkrimen/otto/testing_test.go | 135 + .../robertkrimen/otto/token/Makefile | 2 + .../robertkrimen/otto/token/README.markdown | 171 + .../robertkrimen/otto/token/token.go | 116 + .../robertkrimen/otto/token/token_const.go | 349 + .../robertkrimen/otto/token/tokenfmt | 222 + .../robertkrimen/otto/type_arguments.go | 106 + .../robertkrimen/otto/type_array.go | 109 + .../robertkrimen/otto/type_boolean.go | 13 + .../github.com/robertkrimen/otto/type_date.go | 299 + .../robertkrimen/otto/type_error.go | 13 + .../robertkrimen/otto/type_function.go | 262 + .../robertkrimen/otto/type_go_array.go | 134 + .../robertkrimen/otto/type_go_map.go | 87 + .../robertkrimen/otto/type_go_slice.go | 118 + .../robertkrimen/otto/type_go_struct.go | 146 + .../robertkrimen/otto/type_number.go | 5 + .../robertkrimen/otto/type_reference.go | 103 + .../robertkrimen/otto/type_regexp.go | 146 + .../robertkrimen/otto/type_string.go | 112 + .../robertkrimen/otto/underscore/Makefile | 11 + .../otto/underscore/README.markdown | 53 + .../robertkrimen/otto/underscore/source.go | 3462 ++ .../robertkrimen/otto/underscore/testify | 84 + .../otto/underscore/underscore.go | 49 + .../otto/underscore_arrays_test.go | 344 + .../otto/underscore_chaining_test.go | 95 + .../otto/underscore_collections_test.go | 698 + .../otto/underscore_functions_test.go | 208 + .../otto/underscore_objects_test.go | 826 + .../robertkrimen/otto/underscore_test.go | 165 + .../otto/underscore_utility_test.go | 419 + .../src/github.com/robertkrimen/otto/value.go | 989 + .../robertkrimen/otto/value_boolean.go | 40 + .../robertkrimen/otto/value_number.go | 324 + .../robertkrimen/otto/value_primitive.go | 23 + .../robertkrimen/otto/value_string.go | 103 + .../robertkrimen/otto/value_test.go | 281 + .../src/github.com/rs/cors/.travis.yml | 4 + .../_workspace/src/github.com/rs/cors/LICENSE | 19 + .../src/github.com/rs/cors/README.md | 84 + .../src/github.com/rs/cors/bench_test.go | 37 + .../_workspace/src/github.com/rs/cors/cors.go | 308 + .../src/github.com/rs/cors/cors_test.go | 288 + .../rs/cors/examples/alice/server.go | 24 + .../rs/cors/examples/default/server.go | 18 + .../rs/cors/examples/goji/server.go | 22 + .../rs/cors/examples/martini/server.go | 23 + .../rs/cors/examples/negroni/server.go | 26 + .../rs/cors/examples/nethttp/server.go | 20 + .../rs/cors/examples/openbar/server.go | 22 + .../src/github.com/rs/cors/utils.go | 27 + .../src/github.com/rs/cors/utils_test.go | 28 + .../syndtr/goleveldb/leveldb/batch.go | 252 + .../syndtr/goleveldb/leveldb/batch_test.go | 120 + .../syndtr/goleveldb/leveldb/bench2_test.go | 58 + .../syndtr/goleveldb/leveldb/bench_test.go | 464 + .../goleveldb/leveldb/cache/bench2_test.go | 30 + .../syndtr/goleveldb/leveldb/cache/cache.go | 676 + .../goleveldb/leveldb/cache/cache_test.go | 554 + .../syndtr/goleveldb/leveldb/cache/lru.go | 195 + .../syndtr/goleveldb/leveldb/comparer.go | 75 + .../leveldb/comparer/bytes_comparer.go | 51 + .../goleveldb/leveldb/comparer/comparer.go | 57 + .../syndtr/goleveldb/leveldb/corrupt_test.go | 500 + .../github.com/syndtr/goleveldb/leveldb/db.go | 945 + .../syndtr/goleveldb/leveldb/db_compaction.go | 835 + .../syndtr/goleveldb/leveldb/db_iter.go | 350 + .../syndtr/goleveldb/leveldb/db_snapshot.go | 183 + .../syndtr/goleveldb/leveldb/db_state.go | 211 + .../syndtr/goleveldb/leveldb/db_test.go | 2665 + .../syndtr/goleveldb/leveldb/db_util.go | 100 + .../syndtr/goleveldb/leveldb/db_write.go | 311 + .../syndtr/goleveldb/leveldb/doc.go | 90 + .../syndtr/goleveldb/leveldb/errors.go | 18 + .../syndtr/goleveldb/leveldb/errors/errors.go | 76 + .../syndtr/goleveldb/leveldb/external_test.go | 58 + .../syndtr/goleveldb/leveldb/filter.go | 31 + .../syndtr/goleveldb/leveldb/filter/bloom.go | 116 + .../goleveldb/leveldb/filter/bloom_test.go | 142 + .../syndtr/goleveldb/leveldb/filter/filter.go | 60 + .../goleveldb/leveldb/iterator/array_iter.go | 184 + .../leveldb/iterator/array_iter_test.go | 30 + .../leveldb/iterator/indexed_iter.go | 242 + .../leveldb/iterator/indexed_iter_test.go | 83 + .../syndtr/goleveldb/leveldb/iterator/iter.go | 131 + .../leveldb/iterator/iter_suite_test.go | 11 + .../goleveldb/leveldb/iterator/merged_iter.go | 304 + .../leveldb/iterator/merged_iter_test.go | 60 + .../goleveldb/leveldb/journal/journal.go | 520 + .../goleveldb/leveldb/journal/journal_test.go | 818 + .../syndtr/goleveldb/leveldb/key.go | 142 + .../syndtr/goleveldb/leveldb/key_test.go | 133 + .../goleveldb/leveldb/leveldb_suite_test.go | 11 + .../goleveldb/leveldb/memdb/bench_test.go | 75 + .../syndtr/goleveldb/leveldb/memdb/memdb.go | 468 + .../leveldb/memdb/memdb_suite_test.go | 11 + .../goleveldb/leveldb/memdb/memdb_test.go | 135 + .../syndtr/goleveldb/leveldb/opt/options.go | 639 + .../syndtr/goleveldb/leveldb/options.go | 92 + .../syndtr/goleveldb/leveldb/session.go | 455 + .../goleveldb/leveldb/session_record.go | 313 + .../goleveldb/leveldb/session_record_test.go | 64 + .../syndtr/goleveldb/leveldb/session_util.go | 249 + .../goleveldb/leveldb/storage/file_storage.go | 534 + .../leveldb/storage/file_storage_plan9.go | 52 + .../leveldb/storage/file_storage_solaris.go | 68 + .../leveldb/storage/file_storage_test.go | 142 + .../leveldb/storage/file_storage_unix.go | 63 + .../leveldb/storage/file_storage_windows.go | 69 + .../goleveldb/leveldb/storage/mem_storage.go | 203 + .../leveldb/storage/mem_storage_test.go | 66 + .../goleveldb/leveldb/storage/storage.go | 157 + .../syndtr/goleveldb/leveldb/storage_test.go | 539 + .../syndtr/goleveldb/leveldb/table.go | 521 + .../goleveldb/leveldb/table/block_test.go | 139 + .../syndtr/goleveldb/leveldb/table/reader.go | 1107 + .../syndtr/goleveldb/leveldb/table/table.go | 177 + .../leveldb/table/table_suite_test.go | 11 + .../goleveldb/leveldb/table/table_test.go | 122 + .../syndtr/goleveldb/leveldb/table/writer.go | 379 + .../syndtr/goleveldb/leveldb/testutil/db.go | 222 + .../goleveldb/leveldb/testutil/ginkgo.go | 21 + .../syndtr/goleveldb/leveldb/testutil/iter.go | 327 + .../syndtr/goleveldb/leveldb/testutil/kv.go | 352 + .../goleveldb/leveldb/testutil/kvtest.go | 187 + .../goleveldb/leveldb/testutil/storage.go | 586 + .../syndtr/goleveldb/leveldb/testutil/util.go | 171 + .../syndtr/goleveldb/leveldb/testutil_test.go | 63 + .../syndtr/goleveldb/leveldb/util.go | 91 + .../syndtr/goleveldb/leveldb/util/buffer.go | 293 + .../goleveldb/leveldb/util/buffer_pool.go | 238 + .../goleveldb/leveldb/util/buffer_test.go | 369 + .../syndtr/goleveldb/leveldb/util/crc32.go | 30 + .../syndtr/goleveldb/leveldb/util/hash.go | 48 + .../syndtr/goleveldb/leveldb/util/pool.go | 21 + .../goleveldb/leveldb/util/pool_legacy.go | 33 + .../syndtr/goleveldb/leveldb/util/range.go | 32 + .../syndtr/goleveldb/leveldb/util/util.go | 73 + .../syndtr/goleveldb/leveldb/version.go | 457 + .../syndtr/gosnappy/snappy/decode.go | 292 + .../syndtr/gosnappy/snappy/encode.go | 258 + .../syndtr/gosnappy/snappy/snappy.go | 68 + .../syndtr/gosnappy/snappy/snappy_test.go | 364 + .../src/golang.org/x/crypto/pbkdf2/pbkdf2.go | 77 + .../golang.org/x/crypto/pbkdf2/pbkdf2_test.go | 157 + .../x/crypto/ripemd160/ripemd160.go | 120 + .../x/crypto/ripemd160/ripemd160_test.go | 64 + .../x/crypto/ripemd160/ripemd160block.go | 161 + .../src/golang.org/x/crypto/scrypt/scrypt.go | 243 + .../golang.org/x/crypto/scrypt/scrypt_test.go | 160 + .../src/golang.org/x/net/html/atom/atom.go | 78 + .../golang.org/x/net/html/atom/atom_test.go | 109 + .../src/golang.org/x/net/html/atom/gen.go | 648 + .../src/golang.org/x/net/html/atom/table.go | 713 + .../golang.org/x/net/html/atom/table_test.go | 351 + .../golang.org/x/net/html/charset/charset.go | 244 + .../x/net/html/charset/charset_test.go | 236 + .../src/golang.org/x/net/html/charset/gen.go | 111 + .../golang.org/x/net/html/charset/table.go | 235 + .../html/charset/testdata/HTTP-charset.html | 48 + .../charset/testdata/HTTP-vs-UTF-8-BOM.html | 48 + .../testdata/HTTP-vs-meta-charset.html | 49 + .../testdata/HTTP-vs-meta-content.html | 49 + .../testdata/No-encoding-declaration.html | 47 + .../x/net/html/charset/testdata/README | 9 + .../html/charset/testdata/UTF-16BE-BOM.html | Bin 0 -> 2670 bytes .../html/charset/testdata/UTF-16LE-BOM.html | Bin 0 -> 2682 bytes .../testdata/UTF-8-BOM-vs-meta-charset.html | 49 + .../testdata/UTF-8-BOM-vs-meta-content.html | 48 + .../testdata/meta-charset-attribute.html | 48 + .../testdata/meta-content-attribute.html | 48 + .../src/golang.org/x/net/html/const.go | 102 + .../src/golang.org/x/net/html/doc.go | 106 + .../src/golang.org/x/net/html/doctype.go | 156 + .../src/golang.org/x/net/html/entity.go | 2253 + .../src/golang.org/x/net/html/entity_test.go | 29 + .../src/golang.org/x/net/html/escape.go | 258 + .../src/golang.org/x/net/html/escape_test.go | 97 + .../src/golang.org/x/net/html/example_test.go | 40 + .../src/golang.org/x/net/html/foreign.go | 226 + .../src/golang.org/x/net/html/node.go | 193 + .../src/golang.org/x/net/html/node_test.go | 146 + .../src/golang.org/x/net/html/parse.go | 2094 + .../src/golang.org/x/net/html/parse_test.go | 388 + .../src/golang.org/x/net/html/render.go | 271 + .../src/golang.org/x/net/html/render_test.go | 156 + .../golang.org/x/net/html/testdata/go1.html | 2237 + .../x/net/html/testdata/webkit/README | 28 + .../x/net/html/testdata/webkit/adoption01.dat | 194 + .../x/net/html/testdata/webkit/adoption02.dat | 31 + .../x/net/html/testdata/webkit/comments01.dat | 135 + .../x/net/html/testdata/webkit/doctype01.dat | 370 + .../x/net/html/testdata/webkit/entities01.dat | 603 + .../x/net/html/testdata/webkit/entities02.dat | 249 + .../html/testdata/webkit/html5test-com.dat | 246 + .../x/net/html/testdata/webkit/inbody01.dat | 43 + .../x/net/html/testdata/webkit/isindex.dat | 40 + ...pending-spec-changes-plain-text-unsafe.dat | Bin 0 -> 115 bytes .../testdata/webkit/pending-spec-changes.dat | 52 + .../testdata/webkit/plain-text-unsafe.dat | Bin 0 -> 4166 bytes .../net/html/testdata/webkit/scriptdata01.dat | 308 + .../testdata/webkit/scripted/adoption01.dat | 15 + .../testdata/webkit/scripted/webkit01.dat | 28 + .../x/net/html/testdata/webkit/tables01.dat | 212 + .../x/net/html/testdata/webkit/tests1.dat | 1952 + .../x/net/html/testdata/webkit/tests10.dat | 799 + .../x/net/html/testdata/webkit/tests11.dat | 482 + .../x/net/html/testdata/webkit/tests12.dat | 62 + .../x/net/html/testdata/webkit/tests14.dat | 74 + .../x/net/html/testdata/webkit/tests15.dat | 208 + .../x/net/html/testdata/webkit/tests16.dat | 2299 + .../x/net/html/testdata/webkit/tests17.dat | 153 + .../x/net/html/testdata/webkit/tests18.dat | 269 + .../x/net/html/testdata/webkit/tests19.dat | 1237 + .../x/net/html/testdata/webkit/tests2.dat | 763 + .../x/net/html/testdata/webkit/tests20.dat | 455 + .../x/net/html/testdata/webkit/tests21.dat | 221 + .../x/net/html/testdata/webkit/tests22.dat | 157 + .../x/net/html/testdata/webkit/tests23.dat | 155 + .../x/net/html/testdata/webkit/tests24.dat | 79 + .../x/net/html/testdata/webkit/tests25.dat | 219 + .../x/net/html/testdata/webkit/tests26.dat | 313 + .../x/net/html/testdata/webkit/tests3.dat | 305 + .../x/net/html/testdata/webkit/tests4.dat | 59 + .../x/net/html/testdata/webkit/tests5.dat | 191 + .../x/net/html/testdata/webkit/tests6.dat | 663 + .../x/net/html/testdata/webkit/tests7.dat | 390 + .../x/net/html/testdata/webkit/tests8.dat | 148 + .../x/net/html/testdata/webkit/tests9.dat | 457 + .../testdata/webkit/tests_innerHTML_1.dat | 741 + .../x/net/html/testdata/webkit/tricky01.dat | 261 + .../x/net/html/testdata/webkit/webkit01.dat | 610 + .../x/net/html/testdata/webkit/webkit02.dat | 159 + .../src/golang.org/x/net/html/token.go | 1219 + .../src/golang.org/x/net/html/token_test.go | 748 + .../x/text/encoding/charmap/charmap.go | 209 + .../x/text/encoding/charmap/maketables.go | 415 + .../x/text/encoding/charmap/tables.go | 5116 ++ .../golang.org/x/text/encoding/encoding.go | 179 + .../x/text/encoding/encoding_test.go | 1033 + .../x/text/encoding/example_test.go | 40 + .../x/text/encoding/htmlindex/htmlindex.go | 45 + .../x/text/encoding/ianaindex/example_test.go | 26 + .../x/text/encoding/ianaindex/ianaindex.go | 64 + .../text/encoding/internal/identifier/gen.go | 137 + .../internal/identifier/identifier.go | 80 + .../text/encoding/internal/identifier/mib.go | 1621 + .../x/text/encoding/internal/internal.go | 60 + .../x/text/encoding/japanese/all.go | 12 + .../x/text/encoding/japanese/eucjp.go | 210 + .../x/text/encoding/japanese/iso2022jp.go | 273 + .../x/text/encoding/japanese/maketables.go | 161 + .../x/text/encoding/japanese/shiftjis.go | 188 + .../x/text/encoding/japanese/tables.go | 26971 ++++++++++ .../x/text/encoding/korean/euckr.go | 177 + .../x/text/encoding/korean/maketables.go | 143 + .../x/text/encoding/korean/tables.go | 34152 ++++++++++++ .../x/text/encoding/simplifiedchinese/all.go | 12 + .../x/text/encoding/simplifiedchinese/gbk.go | 280 + .../encoding/simplifiedchinese/hzgb2312.go | 228 + .../encoding/simplifiedchinese/maketables.go | 161 + .../text/encoding/simplifiedchinese/tables.go | 43999 ++++++++++++++++ .../encoding/testdata/candide-gb18030.txt | 510 + .../encoding/testdata/candide-utf-16le.txt | Bin 0 -> 51932 bytes .../text/encoding/testdata/candide-utf-8.txt | 510 + .../testdata/candide-windows-1252.txt | 510 + .../encoding/testdata/rashomon-euc-jp.txt | 178 + .../testdata/rashomon-iso-2022-jp.txt | 178 + .../encoding/testdata/rashomon-shift-jis.txt | 178 + .../text/encoding/testdata/rashomon-utf-8.txt | 178 + ...nzi-bingfa-gb-levels-1-and-2-hz-gb2312.txt | 107 + .../sunzi-bingfa-gb-levels-1-and-2-utf-8.txt | 107 + .../testdata/sunzi-bingfa-simplified-gbk.txt | 107 + .../sunzi-bingfa-simplified-utf-8.txt | 107 + .../sunzi-bingfa-traditional-big5.txt | 106 + .../sunzi-bingfa-traditional-utf-8.txt | 106 + .../testdata/unsu-joh-eun-nal-euc-kr.txt | 175 + .../testdata/unsu-joh-eun-nal-utf-8.txt | 175 + .../text/encoding/traditionalchinese/big5.go | 198 + .../encoding/traditionalchinese/maketables.go | 140 + .../encoding/traditionalchinese/tables.go | 37142 +++++++++++++ .../x/text/encoding/unicode/override.go | 82 + .../x/text/encoding/unicode/unicode.go | 327 + .../x/text/transform/examples_test.go | 37 + .../golang.org/x/text/transform/transform.go | 616 + .../x/text/transform/transform_test.go | 1082 + .../src/gopkg.in/check.v1/.gitignore | 4 + .../_workspace/src/gopkg.in/check.v1/LICENSE | 25 + .../src/gopkg.in/check.v1/README.md | 20 + Godeps/_workspace/src/gopkg.in/check.v1/TODO | 2 + .../src/gopkg.in/check.v1/benchmark.go | 163 + .../src/gopkg.in/check.v1/benchmark_test.go | 91 + .../src/gopkg.in/check.v1/bootstrap_test.go | 82 + .../_workspace/src/gopkg.in/check.v1/check.go | 945 + .../src/gopkg.in/check.v1/check_test.go | 207 + .../src/gopkg.in/check.v1/checkers.go | 458 + .../src/gopkg.in/check.v1/checkers_test.go | 272 + .../src/gopkg.in/check.v1/export_test.go | 9 + .../src/gopkg.in/check.v1/fixture_test.go | 484 + .../src/gopkg.in/check.v1/foundation_test.go | 335 + .../src/gopkg.in/check.v1/helpers.go | 231 + .../src/gopkg.in/check.v1/helpers_test.go | 519 + .../src/gopkg.in/check.v1/printer.go | 168 + .../src/gopkg.in/check.v1/printer_test.go | 104 + .../_workspace/src/gopkg.in/check.v1/run.go | 175 + .../src/gopkg.in/check.v1/run_test.go | 419 + .../src/gopkg.in/fatih/set.v0/.travis.yml | 3 + .../src/gopkg.in/fatih/set.v0/LICENSE.md | 20 + .../src/gopkg.in/fatih/set.v0/README.md | 245 + .../src/gopkg.in/fatih/set.v0/set.go | 121 + .../src/gopkg.in/fatih/set.v0/set_nots.go | 195 + .../gopkg.in/fatih/set.v0/set_nots_test.go | 282 + .../src/gopkg.in/fatih/set.v0/set_test.go | 188 + .../src/gopkg.in/fatih/set.v0/set_ts.go | 200 + .../src/gopkg.in/fatih/set.v0/set_ts_test.go | 321 + .../collections/prque/example_test.go | 44 + .../cookiejar.v2/collections/prque/prque.go | 66 + .../collections/prque/prque_test.go | 130 + .../cookiejar.v2/collections/prque/sstack.go | 91 + .../collections/prque/sstack_test.go | 100 + Makefile | 28 + README.md | 78 + _data/invalid1 | Bin 0 -> 36072 bytes _data/valid1 | Bin 0 -> 18036 bytes _data/valid2 | Bin 0 -> 6125 bytes _data/valid3 | Bin 0 -> 14712 bytes _data/valid4 | Bin 0 -> 12496 bytes accounts/abi/abi.go | 171 + accounts/abi/abi_test.go | 346 + accounts/abi/doc.go | 26 + accounts/abi/numbers.go | 122 + accounts/abi/numbers_test.go | 88 + accounts/abi/type.go | 206 + accounts/account_manager.go | 235 + accounts/accounts_test.go | 149 + build/env.sh | 32 + build/ldflags.sh | 13 + build/test-global-coverage.sh | 26 + build/update-license.go | 356 + cmd/bootnode/main.go | 92 + cmd/disasm/main.go | 51 + cmd/ethtest/.bowerrc | 5 + cmd/ethtest/.editorconfig | 12 + cmd/ethtest/.gitignore | 18 + cmd/ethtest/.jshintrc | 50 + cmd/ethtest/.npmignore | 9 + cmd/ethtest/.travis.yml | 11 + cmd/ethtest/main.go | 214 + cmd/evm/code.txt | 1 + cmd/evm/input.txt | 1 + cmd/evm/main.go | 219 + cmd/geth/blocktestcmd.go | 136 + cmd/geth/chaincmd.go | 199 + cmd/geth/info_test.json | 1 + cmd/geth/js.go | 480 + cmd/geth/js_test.go | 517 + cmd/geth/main.go | 720 + cmd/geth/monitorcmd.go | 352 + cmd/rlpdump/main.go | 143 + cmd/utils/cmd.go | 264 + cmd/utils/customflags.go | 148 + cmd/utils/customflags_test.go | 44 + cmd/utils/flags.go | 543 + cmd/utils/legalese.go | 41 + common/.gitignore | 12 + common/.travis.yml | 3 + common/README.md | 139 + common/big.go | 153 + common/big_test.go | 89 + common/bytes.go | 284 + common/bytes_test.go | 216 + common/compiler/solidity.go | 212 + common/compiler/solidity_test.go | 113 + common/db.go | 26 + common/debug.go | 36 + common/docserver/docserver.go | 115 + common/docserver/docserver_test.go | 70 + common/list.go | 97 + common/main_test.go | 25 + common/math/dist.go | 96 + common/math/dist_test.go | 82 + common/natspec/natspec.go | 260 + common/natspec/natspec_e2e_test.go | 340 + common/natspec/natspec_e2e_test.go.orig | 253 + common/natspec/natspec_js.go | 4060 ++ common/natspec/natspec_test.go | 158 + common/number/int.go | 197 + common/number/uint_test.go | 108 + common/package.go | 139 + common/path.go | 129 + common/path_test.go | 52 + common/registrar/contracts.go | 163 + common/registrar/ethreg/ethreg.go | 48 + common/registrar/registrar.go | 408 + common/registrar/registrar_test.go | 112 + common/rlp.go | 292 + common/rlp_test.go | 176 + common/size.go | 89 + common/size_test.go | 59 + common/test_utils.go | 53 + common/types.go | 128 + common/types_template.go | 64 + common/types_test.go | 31 + common/value.go | 428 + common/value_test.go | 86 + compression/rle/read_write.go | 101 + compression/rle/read_write_test.go | 134 + core/.gitignore | 12 + core/asm.go | 66 + core/bad_block.go | 72 + core/bench_test.go | 179 + core/block_cache.go | 120 + core/block_cache_test.go | 76 + core/block_processor.go | 418 + core/block_processor_test.go | 88 + core/blocks.go | 27 + core/canary.go | 51 + core/chain_makers.go | 204 + core/chain_makers_test.go | 97 + core/chain_manager.go | 806 + core/chain_manager_test.go | 517 + core/chain_util.go | 154 + core/error.go | 178 + core/events.go | 71 + core/execution.go | 117 + core/fees.go | 23 + core/filter.go | 210 + core/filter_test.go | 17 + core/genesis.go | 161 + core/helper_test.go | 96 + core/manager.go | 35 + core/state/dump.go | 78 + core/state/errors.go | 39 + core/state/log.go | 66 + core/state/main_test.go | 25 + core/state/managed_state.go | 142 + core/state/managed_state_test.go | 126 + core/state/state_object.go | 374 + core/state/state_test.go | 119 + core/state/statedb.go | 385 + core/state_transition.go | 266 + core/transaction_pool.go | 457 + core/transaction_pool_test.go | 221 + core/transaction_util.go | 161 + core/types/block.go | 428 + core/types/block_test.go | 65 + core/types/bloom9.go | 79 + core/types/bloom9_test.go | 47 + core/types/common.go | 56 + core/types/derive_sha.go | 40 + core/types/receipt.go | 115 + core/types/transaction.go | 300 + core/types/transaction_test.go | 119 + core/vm/analysis.go | 63 + core/vm/asm.go | 61 + core/vm/common.go | 105 + core/vm/context.go | 119 + core/vm/contracts.go | 118 + core/vm/disasm.go | 37 + core/vm/environment.go | 84 + core/vm/errors.go | 44 + core/vm/gas.go | 142 + core/vm/logger.go | 67 + core/vm/memory.go | 96 + core/vm/opcodes.go | 486 + core/vm/stack.go | 87 + core/vm/virtual_machine.go | 22 + core/vm/vm.go | 835 + core/vm/vm_jit.go | 388 + core/vm/vm_jit_fake.go | 26 + core/vm_env.go | 97 + crypto/crypto.go | 339 + crypto/crypto_test.go | 96 + crypto/curve.go | 397 + crypto/ecies/.gitignore | 24 + crypto/ecies/LICENSE | 28 + crypto/ecies/README | 94 + crypto/ecies/asn1.go | 585 + crypto/ecies/ecies.go | 364 + crypto/ecies/ecies_test.go | 518 + crypto/ecies/params.go | 210 + crypto/encrypt_decrypt_test.go | 56 + crypto/key.go | 145 + crypto/key_store_passphrase.go | 286 + crypto/key_store_plain.go | 211 + crypto/key_store_test.go | 225 + crypto/keypair.go | 66 + crypto/mnemonic.go | 76 + crypto/mnemonic_test.go | 90 + crypto/mnemonic_words.go | 1646 + crypto/randentropy/rand_entropy.go | 52 + crypto/secp256k1/.gitignore | 24 + crypto/secp256k1/README.md | 25 + crypto/secp256k1/notes.go | 208 + crypto/secp256k1/secp256.go | 266 + crypto/secp256k1/secp256_test.go | 254 + crypto/secp256k1/secp256k1/.travis.yml | 32 + crypto/secp256k1/secp256k1/COPYING | 19 + crypto/secp256k1/secp256k1/Makefile.am | 77 + crypto/secp256k1/secp256k1/README.md | 61 + crypto/secp256k1/secp256k1/TODO | 3 + crypto/secp256k1/secp256k1/autogen.sh | 3 + .../secp256k1/build-aux/m4/bitcoin_secp.m4 | 61 + crypto/secp256k1/secp256k1/configure.ac | 330 + .../secp256k1/secp256k1/include/secp256k1.h | 295 + crypto/secp256k1/secp256k1/libsecp256k1.pc.in | 13 + crypto/secp256k1/secp256k1/obj/.gitignore | 0 crypto/secp256k1/secp256k1/src/bench.h | 56 + .../secp256k1/secp256k1/src/bench_internal.c | 318 + .../secp256k1/secp256k1/src/bench_recover.c | 49 + crypto/secp256k1/secp256k1/src/bench_sign.c | 48 + crypto/secp256k1/secp256k1/src/bench_verify.c | 55 + crypto/secp256k1/secp256k1/src/ecdsa.h | 23 + crypto/secp256k1/secp256k1/src/ecdsa_impl.h | 263 + crypto/secp256k1/secp256k1/src/eckey.h | 24 + crypto/secp256k1/secp256k1/src/eckey_impl.h | 202 + crypto/secp256k1/secp256k1/src/ecmult.h | 19 + crypto/secp256k1/secp256k1/src/ecmult_gen.h | 19 + .../secp256k1/secp256k1/src/ecmult_gen_impl.h | 128 + crypto/secp256k1/secp256k1/src/ecmult_impl.h | 302 + crypto/secp256k1/secp256k1/src/field.h | 116 + crypto/secp256k1/secp256k1/src/field_10x26.h | 47 + .../secp256k1/src/field_10x26_impl.h | 1116 + crypto/secp256k1/secp256k1/src/field_5x52.h | 47 + .../secp256k1/src/field_5x52_asm_impl.h | 502 + .../secp256k1/secp256k1/src/field_5x52_impl.h | 439 + .../secp256k1/src/field_5x52_int128_impl.h | 277 + crypto/secp256k1/secp256k1/src/field_impl.h | 263 + crypto/secp256k1/secp256k1/src/group.h | 118 + crypto/secp256k1/secp256k1/src/group_impl.h | 434 + crypto/secp256k1/secp256k1/src/hash.h | 41 + crypto/secp256k1/secp256k1/src/hash_impl.h | 293 + .../src/java/org/bitcoin/NativeSecp256k1.java | 60 + .../src/java/org_bitcoin_NativeSecp256k1.c | 23 + .../src/java/org_bitcoin_NativeSecp256k1.h | 21 + crypto/secp256k1/secp256k1/src/num.h | 68 + crypto/secp256k1/secp256k1/src/num_gmp.h | 20 + crypto/secp256k1/secp256k1/src/num_gmp_impl.h | 260 + crypto/secp256k1/secp256k1/src/num_impl.h | 24 + crypto/secp256k1/secp256k1/src/scalar.h | 93 + crypto/secp256k1/secp256k1/src/scalar_4x64.h | 19 + .../secp256k1/src/scalar_4x64_impl.h | 920 + crypto/secp256k1/secp256k1/src/scalar_8x32.h | 19 + .../secp256k1/src/scalar_8x32_impl.h | 681 + crypto/secp256k1/secp256k1/src/scalar_impl.h | 327 + crypto/secp256k1/secp256k1/src/secp256k1.c | 372 + crypto/secp256k1/secp256k1/src/testrand.h | 28 + .../secp256k1/secp256k1/src/testrand_impl.h | 60 + crypto/secp256k1/secp256k1/src/tests.c | 1917 + crypto/secp256k1/secp256k1/src/util.h | 104 + crypto/sha3/keccakf.go | 434 + crypto/sha3/sha3.go | 237 + .../cb61d5a9c4896fb9658090b597ef0e7be6f7b67e | 1 + crypto/tests/v1_test_vector.json | 28 + crypto/tests/v3_test_vector.json | 49 + docker/Dockerfile | 31 + docker/supervisord.conf | 23 + errs/errors.go | 110 + errs/errors_test.go | 62 + eth/backend.go | 736 + eth/downloader/downloader.go | 1216 + eth/downloader/downloader_test.go | 896 + eth/downloader/events.go | 21 + eth/downloader/peer.go | 267 + eth/downloader/queue.go | 376 + eth/fetcher/fetcher.go | 487 + eth/fetcher/fetcher_test.go | 503 + eth/fetcher/metrics.go | 32 + eth/gasprice.go | 203 + eth/handler.go | 513 + eth/metrics.go | 44 + eth/peer.go | 350 + eth/protocol.go | 123 + eth/protocol_test.go | 257 + eth/sync.go | 168 + ethdb/.gitignore | 12 + ethdb/README.md | 11 + ethdb/database.go | 271 + ethdb/database_test.go | 34 + ethdb/memory_database.go | 89 + event/event.go | 199 + event/event_test.go | 192 + event/example_test.go | 58 + event/filter/eth_filter.go | 127 + event/filter/filter.go | 95 + event/filter/filter_test.go | 55 + event/filter/generic_filter.go | 48 + generators/defaults.go | 81 + jsre/bignumber_js.go | 22 + jsre/ethereum_js.go | 6227 +++ jsre/jsre.go | 301 + jsre/jsre_test.go | 128 + jsre/pp_js.go | 137 + logger/example_test.go | 37 + logger/glog/LICENSE | 191 + logger/glog/README | 44 + logger/glog/glog.go | 1195 + logger/glog/glog_file.go | 128 + logger/glog/glog_test.go | 415 + logger/log.go | 65 + logger/loggers.go | 149 + logger/loggers_test.go | 192 + logger/logsystem.go | 76 + logger/sys.go | 142 + logger/types.go | 381 + logger/verbosity.go | 28 + metrics/disk.go | 25 + metrics/disk_linux.go | 71 + metrics/disk_nop.go | 26 + metrics/metrics.go | 112 + miner/agent.go | 123 + miner/miner.go | 161 + miner/remote_agent.go | 136 + miner/worker.go | 615 + p2p/dial.go | 294 + p2p/dial_test.go | 498 + p2p/discover/database.go | 353 + p2p/discover/database_test.go | 409 + p2p/discover/node.go | 320 + p2p/discover/node_test.go | 257 + p2p/discover/table.go | 548 + p2p/discover/table_test.go | 615 + p2p/discover/udp.go | 575 + p2p/discover/udp_test.go | 378 + p2p/message.go | 273 + p2p/message_test.go | 151 + p2p/metrics.go | 65 + p2p/nat/nat.go | 249 + p2p/nat/nat_test.go | 64 + p2p/nat/natpmp.go | 131 + p2p/nat/natupnp.go | 168 + p2p/nat/natupnp_test.go | 239 + p2p/peer.go | 361 + p2p/peer_error.go | 113 + p2p/peer_test.go | 309 + p2p/protocol.go | 68 + p2p/rlpx.go | 627 + p2p/rlpx_test.go | 374 + p2p/server.go | 672 + p2p/server_test.go | 438 + params/protocol_params.go | 72 + pow/block.go | 37 + pow/dagger/dagger.go | 176 + pow/dagger/dagger_test.go | 35 + pow/ezp/pow.go | 115 + pow/pow.go | 24 + rlp/decode.go | 980 + rlp/decode_test.go | 724 + rlp/doc.go | 33 + rlp/encode.go | 636 + rlp/encode_test.go | 304 + rlp/encoder_example_test.go | 54 + rlp/typecache.go | 120 + rpc/api/admin.go | 476 + rpc/api/admin_args.go | 490 + rpc/api/admin_js.go | 153 + rpc/api/api.go | 26 + rpc/api/api_test.go | 170 + rpc/api/args.go | 74 + rpc/api/args_test.go | 2651 + rpc/api/db.go | 144 + rpc/api/db_args.go | 126 + rpc/api/db_js.go | 29 + rpc/api/debug.go | 289 + rpc/api/debug_args.go | 87 + rpc/api/debug_js.go | 71 + rpc/api/eth.go | 639 + rpc/api/eth_args.go | 1054 + rpc/api/eth_js.go | 48 + rpc/api/mergedapi.go | 86 + rpc/api/miner.go | 181 + rpc/api/miner_args.go | 142 + rpc/api/miner_js.go | 83 + rpc/api/net.go | 100 + rpc/api/net_js.go | 39 + rpc/api/parsing.go | 516 + rpc/api/personal.go | 142 + rpc/api/personal_args.go | 108 + rpc/api/personal_js.go | 46 + rpc/api/shh.go | 195 + rpc/api/shh_args.go | 174 + rpc/api/ssh_js.go | 34 + rpc/api/txpool.go | 92 + rpc/api/txpool_js.go | 33 + rpc/api/utils.go | 204 + rpc/api/web3.go | 99 + rpc/api/web3_args.go | 45 + rpc/codec/codec.go | 63 + rpc/codec/json.go | 142 + rpc/codec/json_test.go | 157 + rpc/comms/comms.go | 147 + rpc/comms/http.go | 206 + rpc/comms/http_net.go | 182 + rpc/comms/inproc.go | 82 + rpc/comms/ipc.go | 118 + rpc/comms/ipc_unix.go | 79 + rpc/comms/ipc_windows.go | 699 + rpc/jeth.go | 107 + rpc/shared/errors.go | 112 + rpc/shared/types.go | 107 + rpc/shared/utils.go | 43 + rpc/xeth.go | 69 + tests/block_test.go | 112 + tests/block_test_util.go | 564 + tests/files/.gitignore | 5 + tests/files/ABITests/basic_abi_tests.json | 40 + tests/files/BasicTests/blockgenesistest.json | 20 + tests/files/BasicTests/crypto.json | 16 + tests/files/BasicTests/genesishashestest.json | 5 + tests/files/BasicTests/hexencodetest.json | 62 + tests/files/BasicTests/keyaddrtest.json | 22 + tests/files/BasicTests/rlptest.json | 146 + tests/files/BasicTests/txtest.json | 24 + .../RandomTests/bl201507071825GO.json | 61 + .../BlockchainTests/bcBlockGasLimitTest.json | 318 + .../files/BlockchainTests/bcBruncleTest.json | 265 + .../BlockchainTests/bcForkBlockTest.json | 321 + .../BlockchainTests/bcGasPricerTest.json | 1117 + .../BlockchainTests/bcInvalidHeaderTest.json | 1123 + .../BlockchainTests/bcInvalidRLPTest.json | 6077 +++ .../files/BlockchainTests/bcRPC_API_Test.json | 1259 + .../bcTotalDifficultyTest.json | 3240 ++ .../bcUncleHeaderValiditiy.json | 1748 + tests/files/BlockchainTests/bcUncleTest.json | 4547 ++ .../BlockchainTests/bcValidBlockTest.json | 1271 + .../bcWalletTest.json.REMOVED.git-id | 1 + .../GenesisTests/basic_genesis_tests.json | 67 + tests/files/KeyStoreTests/basic_tests.json | 97 + tests/files/PoWTests/ethash_tests.json | 24 + tests/files/README.md | 26 + .../RLPTests/RandomRLPTests/example.json | 6 + tests/files/RLPTests/invalidRLPTest.json | 11 + tests/files/RLPTests/rlptest.json | 146 + .../RandomTests/st201503121803PYTHON.json | 71 + .../RandomTests/st201503121806PYTHON.json | 71 + .../RandomTests/st201503121848GO.json | 72 + .../RandomTests/st201503121849GO.json | 71 + .../RandomTests/st201503121850GO.json | 72 + .../RandomTests/st201503121851GO.json | 71 + .../RandomTests/st201503121953GO.json | 71 + .../RandomTests/st201503122023GO.json | 71 + .../RandomTests/st201503122023PYTHON.json | 71 + .../RandomTests/st201503122027GO.json | 72 + .../RandomTests/st201503122054GO.json | 72 + .../RandomTests/st201503122055GO.json | 72 + .../RandomTests/st201503122115CPPJIT.json | 71 + .../RandomTests/st201503122115GO.json | 71 + .../RandomTests/st201503122123GO.json | 72 + .../RandomTests/st201503122124GO.json | 72 + .../RandomTests/st201503122128PYTHON.json | 71 + .../RandomTests/st201503122140GO.json | 72 + .../RandomTests/st201503122159GO.json | 72 + .../RandomTests/st201503122204GO.json | 72 + .../RandomTests/st201503122212GO.json | 72 + .../RandomTests/st201503122231GO.json | 72 + .../RandomTests/st201503122238GO.json | 72 + .../RandomTests/st201503122252GO.json | 72 + .../RandomTests/st201503122316GO.json | 72 + .../RandomTests/st201503122324GO.json | 72 + .../RandomTests/st201503122358GO.json | 71 + .../RandomTests/st201503130002GO.json | 71 + .../RandomTests/st201503130005GO.json | 72 + .../RandomTests/st201503130007GO.json | 72 + .../RandomTests/st201503130010GO.json | 72 + .../RandomTests/st201503130023PYTHON.json | 71 + .../RandomTests/st201503130059GO.json | 72 + .../RandomTests/st201503130101GO.json | 71 + .../RandomTests/st201503130109GO.json | 72 + .../RandomTests/st201503130117GO.json | 72 + .../RandomTests/st201503130122GO.json | 72 + .../RandomTests/st201503130156GO.json | 72 + .../RandomTests/st201503130156PYTHON.json | 71 + .../RandomTests/st201503130207GO.json | 72 + .../RandomTests/st201503130219CPPJIT.json | 71 + .../RandomTests/st201503130219GO.json | 71 + .../RandomTests/st201503130243GO.json | 72 + .../RandomTests/st201503130246GO.json | 72 + .../RandomTests/st201503130321GO.json | 72 + .../RandomTests/st201503130322GO.json | 72 + .../RandomTests/st201503130332GO.json | 72 + .../RandomTests/st201503130359GO.json | 72 + .../RandomTests/st201503130405GO.json | 80 + .../RandomTests/st201503130408GO.json | 82 + .../RandomTests/st201503130411GO.json | 72 + .../RandomTests/st201503130431GO.json | 72 + .../RandomTests/st201503130437GO.json | 72 + .../RandomTests/st201503130450GO.json | 72 + .../RandomTests/st201503130512CPPJIT.json | 71 + .../RandomTests/st201503130512GO.json | 71 + .../RandomTests/st201503130615GO.json | 72 + .../RandomTests/st201503130705GO.json | 72 + .../RandomTests/st201503130733CPPJIT.json | 71 + .../RandomTests/st201503130733GO.json | 71 + .../RandomTests/st201503130747GO.json | 72 + .../RandomTests/st201503130751GO.json | 72 + .../RandomTests/st201503130752PYTHON.json | 71 + .../RandomTests/st201503130757PYTHON.json | 72 + .../RandomTests/st201503131658GO.json | 72 + .../RandomTests/st201503131739GO.json | 71 + .../RandomTests/st201503131755CPPJIT.json | 71 + .../RandomTests/st201503131755GO.json | 71 + .../RandomTests/st201503132001CPPJIT.json | 71 + .../RandomTests/st201503132127PYTHON.json | 71 + .../RandomTests/st201503132201CPPJIT.json | 71 + .../RandomTests/st201503132201GO.json | 71 + .../RandomTests/st201503132202PYTHON.json | 71 + .../RandomTests/st201503140002PYTHON.json | 71 + .../RandomTests/st201503140240PYTHON.json | 71 + .../RandomTests/st201503140522PYTHON.json | 71 + .../RandomTests/st201503140756PYTHON.json | 72 + .../RandomTests/st201503141144PYTHON.json | 71 + .../RandomTests/st201503141510PYTHON.json | 71 + .../RandomTests/st201503150427PYTHON.json | 71 + .../RandomTests/st201503150716PYTHON.json | 71 + .../RandomTests/st201503151450PYTHON.json | 71 + .../RandomTests/st201503151516PYTHON.json | 71 + .../RandomTests/st201503151753PYTHON.json | 71 + .../RandomTests/st201503152057PYTHON.json | 71 + .../RandomTests/st201503152241PYTHON.json | 71 + .../RandomTests/st201503160014PYTHON.json | 72 + .../RandomTests/st201503160733PYTHON.json | 71 + .../RandomTests/st201503170051PYTHON.json | 71 + .../RandomTests/st201503170433PYTHON.json | 71 + .../RandomTests/st201503170523PYTHON.json | 71 + .../RandomTests/st201503171108PYTHON.json | 72 + .../RandomTests/st201503181223GO.json | 72 + .../RandomTests/st201503181225GO.json | 72 + .../RandomTests/st201503181226CPPJIT.json | 72 + .../RandomTests/st201503181227CPPJIT.json | 78 + .../st201503181227GO.json.REMOVED.git-id | 1 + .../RandomTests/st201503181229GO.json | 72 + .../st201503181230CPPJIT.json.REMOVED.git-id | 1 + .../RandomTests/st201503181230GO.json | 72 + .../RandomTests/st201503181231GO.json | 73 + .../RandomTests/st201503181232CPPJIT.json | 72 + .../RandomTests/st201503181232GO.json | 72 + .../RandomTests/st201503181233GO.json | 72 + .../RandomTests/st201503181234CPPJIT.json | 72 + .../RandomTests/st201503181234GO.json | 72 + .../RandomTests/st201503181235CPPJIT.json | 72 + .../RandomTests/st201503181235GO.json | 73 + .../RandomTests/st201503181236GO.json | 72 + .../RandomTests/st201503181237GO.json | 72 + .../RandomTests/st201503181239GO.json | 72 + .../RandomTests/st201503181241CPPJIT.json | 71 + .../RandomTests/st201503181241GO.json | 72 + .../RandomTests/st201503181243GO.json | 72 + .../RandomTests/st201503181244GO.json | 72 + .../st201503181245CPPJIT.json.REMOVED.git-id | 1 + .../RandomTests/st201503181245GO.json | 72 + .../RandomTests/st201503181246CPPJIT.json | 71 + .../RandomTests/st201503181246GO.json | 72 + .../RandomTests/st201503181247GO.json | 72 + .../RandomTests/st201503181248GO.json | 72 + .../RandomTests/st201503181249GO.json | 72 + .../RandomTests/st201503181250CPPJIT.json | 71 + .../RandomTests/st201503181250GO.json | 72 + .../RandomTests/st201503181251GO.json | 73 + .../RandomTests/st201503181252CPPJIT.json | 71 + .../RandomTests/st201503181253GO.json | 72 + .../RandomTests/st201503181255CPPJIT.json | 72 + .../RandomTests/st201503181255GO.json | 72 + .../RandomTests/st201503181257GO.json | 72 + .../RandomTests/st201503181258CPPJIT.json | 71 + .../RandomTests/st201503181258GO.json | 81 + .../RandomTests/st201503181301CPPJIT.json | 73 + .../RandomTests/st201503181301GO.json | 72 + .../RandomTests/st201503181303GO.json | 72 + .../RandomTests/st201503181304GO.json | 72 + .../RandomTests/st201503181305GO.json | 72 + .../RandomTests/st201503181306GO.json | 72 + .../RandomTests/st201503181307CPPJIT.json | 73 + .../RandomTests/st201503181307GO.json | 72 + .../RandomTests/st201503181308GO.json | 72 + .../RandomTests/st201503181309GO.json | 72 + .../RandomTests/st201503181310GO.json | 72 + .../RandomTests/st201503181311GO.json | 72 + .../RandomTests/st201503181313GO.json | 72 + .../RandomTests/st201503181314GO.json | 72 + .../RandomTests/st201503181315CPPJIT.json | 73 + .../RandomTests/st201503181315GO.json | 72 + .../RandomTests/st201503181316CPPJIT.json | 72 + .../st201503181316PYTHON.json.REMOVED.git-id | 1 + .../RandomTests/st201503181317GO.json | 72 + .../RandomTests/st201503181318CPPJIT.json | 71 + .../RandomTests/st201503181318GO.json | 72 + .../RandomTests/st201503181319GO.json | 72 + .../RandomTests/st201503181319PYTHON.json | 88 + .../RandomTests/st201503181322GO.json | 72 + .../RandomTests/st201503181323CPPJIT.json | 71 + .../RandomTests/st201503181323GO.json | 72 + .../RandomTests/st201503181324GO.json | 72 + .../RandomTests/st201503181325GO.json | 72 + .../st201503181326CPPJIT.json.REMOVED.git-id | 1 + .../RandomTests/st201503181326GO.json | 73 + .../RandomTests/st201503181327GO.json | 72 + .../RandomTests/st201503181329CPPJIT.json | 72 + .../RandomTests/st201503181329GO.json | 72 + .../RandomTests/st201503181330GO.json | 72 + .../RandomTests/st201503181332GO.json | 72 + .../RandomTests/st201503181333GO.json | 72 + .../RandomTests/st201503181334GO.json | 72 + .../RandomTests/st201503181336CPPJIT.json | 72 + .../RandomTests/st201503181337GO.json | 72 + .../RandomTests/st201503181338GO.json | 72 + .../RandomTests/st201503181339CPPJIT.json | 71 + .../RandomTests/st201503181339GO.json | 72 + .../RandomTests/st201503181340GO.json | 72 + .../RandomTests/st201503181341CPPJIT.json | 71 + .../RandomTests/st201503181342CPPJIT.json | 72 + .../RandomTests/st201503181342GO.json | 72 + .../RandomTests/st201503181345GO.json | 72 + .../RandomTests/st201503181346GO.json | 72 + .../RandomTests/st201503181347CPPJIT.json | 72 + .../RandomTests/st201503181347GO.json | 72 + .../st201503181347PYTHON.json.REMOVED.git-id | 1 + .../RandomTests/st201503181350CPPJIT.json | 71 + .../RandomTests/st201503181352GO.json | 72 + .../RandomTests/st201503181353GO.json | 72 + .../RandomTests/st201503181354CPPJIT.json | 71 + .../RandomTests/st201503181354GO.json | 72 + .../RandomTests/st201503181355GO.json | 72 + .../RandomTests/st201503181356CPPJIT.json | 73 + .../RandomTests/st201503181357CPPJIT.json | 72 + .../RandomTests/st201503181358CPPJIT.json | 71 + .../RandomTests/st201503181358GO.json | 72 + .../RandomTests/st201503181359GO.json | 72 + .../RandomTests/st201503181402CPPJIT.json | 73 + .../RandomTests/st201503181403GO.json | 72 + .../RandomTests/st201503181406CPPJIT.json | 72 + .../RandomTests/st201503181406GO.json | 73 + .../RandomTests/st201503181410GO.json | 73 + .../RandomTests/st201503181412CPPJIT.json | 72 + .../RandomTests/st201503181413GO.json | 72 + .../RandomTests/st201503181415GO.json | 72 + .../RandomTests/st201503181416GO.json | 72 + .../RandomTests/st201503181417CPPJIT.json | 78 + .../RandomTests/st201503181417GO.json | 72 + .../RandomTests/st201503181418CPPJIT.json | 79 + .../RandomTests/st201503181422GO.json | 72 + .../RandomTests/st201503181423CPPJIT.json | 81 + .../RandomTests/st201503181424GO.json | 72 + .../RandomTests/st201503181426CPPJIT.json | 72 + .../RandomTests/st201503181426GO.json | 72 + .../RandomTests/st201503181428GO.json | 72 + .../RandomTests/st201503181430CPPJIT.json | 73 + .../RandomTests/st201503181435GO.json | 72 + .../RandomTests/st201503181436GO.json | 72 + .../RandomTests/st201503181437CPPJIT.json | 72 + .../RandomTests/st201503181437GO.json | 72 + .../RandomTests/st201503181438CPPJIT.json | 81 + .../RandomTests/st201503181438GO.json | 72 + .../RandomTests/st201503181439CPPJIT.json | 71 + .../RandomTests/st201503181439GO.json | 71 + .../RandomTests/st201503181439PYTHON.json | 71 + .../RandomTests/st201503181440GO.json | 72 + .../RandomTests/st201503181441GO.json | 72 + .../RandomTests/st201503181442GO.json | 72 + .../RandomTests/st201503181445CPPJIT.json | 72 + .../RandomTests/st201503181446GO.json | 72 + .../RandomTests/st201503181447GO.json | 72 + .../RandomTests/st201503181450GO.json | 72 + .../RandomTests/st201503181451CPPJIT.json | 71 + .../RandomTests/st201503181453GO.json | 72 + .../RandomTests/st201503181455GO.json | 73 + .../RandomTests/st201503181456CPPJIT.json | 72 + .../RandomTests/st201503181457GO.json | 72 + .../RandomTests/st201503181458GO.json | 72 + .../RandomTests/st201503181459GO.json | 72 + .../RandomTests/st201503181500GO.json | 72 + .../RandomTests/st201503181501GO.json | 72 + .../RandomTests/st201503181503GO.json | 72 + .../RandomTests/st201503181504GO.json | 72 + .../RandomTests/st201503181505GO.json | 72 + .../RandomTests/st201503181506CPPJIT.json | 72 + .../RandomTests/st201503181507GO.json | 72 + .../RandomTests/st201503181509CPPJIT.json | 72 + .../RandomTests/st201503181509GO.json | 72 + .../RandomTests/st201503181510GO.json | 72 + .../RandomTests/st201503181511GO.json | 72 + .../RandomTests/st201503181512GO.json | 72 + .../RandomTests/st201503181513CPPJIT.json | 71 + .../RandomTests/st201503181513GO.json | 72 + .../RandomTests/st201503181514CPPJIT.json | 72 + .../RandomTests/st201503181514GO.json | 72 + .../RandomTests/st201503181517CPPJIT.json | 72 + .../RandomTests/st201503181517GO.json | 72 + .../RandomTests/st201503181519CPPJIT.json | 71 + .../RandomTests/st201503181519GO.json | 73 + .../RandomTests/st201503181520CPPJIT.json | 72 + .../RandomTests/st201503181520GO.json | 73 + .../RandomTests/st201503181521GO.json | 72 + .../RandomTests/st201503181522GO.json | 72 + .../RandomTests/st201503181524CPPJIT.json | 73 + .../RandomTests/st201503181524GO.json | 72 + .../RandomTests/st201503181526GO.json | 72 + .../RandomTests/st201503181527GO.json | 72 + .../RandomTests/st201503181528CPPJIT.json | 71 + .../RandomTests/st201503181528GO.json | 71 + .../RandomTests/st201503181528PYTHON.json | 71 + .../RandomTests/st201503181529GO.json | 72 + .../RandomTests/st201503181531CPPJIT.json | 73 + .../RandomTests/st201503181533GO.json | 72 + .../RandomTests/st201503181534CPPJIT.json | 72 + .../RandomTests/st201503181534GO.json | 72 + .../RandomTests/st201503181536CPPJIT.json | 72 + .../RandomTests/st201503181536GO.json | 72 + .../RandomTests/st201503181537GO.json | 72 + .../RandomTests/st201503181538GO.json | 72 + .../RandomTests/st201503181539GO.json | 72 + .../RandomTests/st201503181540CPPJIT.json | 78 + .../RandomTests/st201503181540PYTHON.json | 78 + .../RandomTests/st201503181543GO.json | 72 + .../RandomTests/st201503181544CPPJIT.json | 72 + .../RandomTests/st201503181544GO.json | 72 + .../RandomTests/st201503181547GO.json | 72 + .../RandomTests/st201503181548CPPJIT.json | 71 + .../RandomTests/st201503181548GO.json | 72 + .../RandomTests/st201503181551GO.json | 72 + .../RandomTests/st201503181552CPPJIT.json | 72 + .../RandomTests/st201503181553GO.json | 72 + .../RandomTests/st201503181555CPPJIT.json | 71 + .../RandomTests/st201503181555GO.json | 72 + .../RandomTests/st201503181557GO.json | 72 + .../RandomTests/st201503181559GO.json | 72 + .../RandomTests/st201503181601CPPJIT.json | 71 + .../RandomTests/st201503181601GO.json | 72 + .../RandomTests/st201503181602GO.json | 72 + .../RandomTests/st201503181603GO.json | 72 + .../RandomTests/st201503181604GO.json | 72 + .../RandomTests/st201503181605GO.json | 72 + .../RandomTests/st201503181606GO.json | 72 + .../RandomTests/st201503181607GO.json | 72 + .../RandomTests/st201503181608CPPJIT.json | 71 + .../RandomTests/st201503181608GO.json | 72 + .../RandomTests/st201503181609GO.json | 72 + .../RandomTests/st201503181610CPPJIT.json | 72 + .../RandomTests/st201503181610GO.json | 72 + .../RandomTests/st201503181611CPPJIT.json | 72 + .../RandomTests/st201503181611GO.json | 73 + .../RandomTests/st201503181612GO.json | 72 + .../RandomTests/st201503181614CPPJIT.json | 71 + .../RandomTests/st201503181614GO.json | 72 + .../RandomTests/st201503181616CPPJIT.json | 72 + .../RandomTests/st201503181616GO.json | 72 + .../RandomTests/st201503181617GO.json | 72 + .../RandomTests/st201503181618GO.json | 72 + .../RandomTests/st201503181619GO.json | 72 + .../RandomTests/st201503181620CPPJIT.json | 72 + .../RandomTests/st201503181620GO.json | 72 + .../RandomTests/st201503181621GO.json | 72 + .../RandomTests/st201503181625GO.json | 72 + .../RandomTests/st201503181626CPPJIT.json | 71 + .../RandomTests/st201503181626GO.json | 73 + .../RandomTests/st201503181627GO.json | 72 + .../RandomTests/st201503181628GO.json | 72 + .../RandomTests/st201503181629GO.json | 72 + .../RandomTests/st201503181630CPPJIT.json | 79 + .../RandomTests/st201503181630GO.json | 72 + .../RandomTests/st201503181630PYTHON.json | 79 + .../RandomTests/st201503181632GO.json | 72 + .../RandomTests/st201503181634CPPJIT.json | 72 + .../RandomTests/st201503181635GO.json | 72 + .../RandomTests/st201503181636GO.json | 72 + .../RandomTests/st201503181638GO.json | 72 + .../RandomTests/st201503181639CPPJIT.json | 72 + .../RandomTests/st201503181641GO.json | 72 + .../RandomTests/st201503181645GO.json | 72 + .../RandomTests/st201503181646GO.json | 72 + .../RandomTests/st201503181647CPPJIT.json | 72 + .../RandomTests/st201503181649CPPJIT.json | 72 + .../RandomTests/st201503181650GO.json | 72 + .../RandomTests/st201503181652CPPJIT.json | 71 + .../RandomTests/st201503181653GO.json | 72 + .../RandomTests/st201503181654GO.json | 72 + .../RandomTests/st201503181655CPPJIT.json | 71 + .../RandomTests/st201503181655GO.json | 72 + .../RandomTests/st201503181656CPPJIT.json | 72 + .../RandomTests/st201503181656GO.json | 72 + .../RandomTests/st201503181657GO.json | 72 + .../RandomTests/st201503181658GO.json | 72 + .../RandomTests/st201503181700GO.json | 73 + .../RandomTests/st201503181702GO.json | 72 + .../RandomTests/st201503181703CPPJIT.json | 80 + .../RandomTests/st201503181703GO.json | 72 + .../RandomTests/st201503181704GO.json | 72 + .../RandomTests/st201503181706GO.json | 72 + .../RandomTests/st201503181709GO.json | 72 + .../RandomTests/st201503181711CPPJIT.json | 72 + .../RandomTests/st201503181711GO.json | 72 + .../RandomTests/st201503181713CPPJIT.json | 72 + .../RandomTests/st201503181713GO.json | 72 + .../RandomTests/st201503181714GO.json | 72 + .../RandomTests/st201503181715CPPJIT.json | 71 + .../RandomTests/st201503181715GO.json | 72 + .../RandomTests/st201503181716GO.json | 72 + .../RandomTests/st201503181717GO.json | 72 + .../RandomTests/st201503181720CPPJIT.json | 71 + .../RandomTests/st201503181722GO.json | 72 + .../RandomTests/st201503181723CPPJIT.json | 71 + .../RandomTests/st201503181723GO.json | 72 + .../RandomTests/st201503181724CPPJIT.json | 72 + .../RandomTests/st201503181724GO.json | 72 + .../RandomTests/st201503181725GO.json | 72 + .../RandomTests/st201503181728GO.json | 72 + .../RandomTests/st201503181729GO.json | 72 + .../RandomTests/st201503181730GO.json | 73 + .../RandomTests/st201503181731CPPJIT.json | 71 + .../RandomTests/st201503181732GO.json | 72 + .../RandomTests/st201503181734CPPJIT.json | 72 + .../RandomTests/st201503181734GO.json | 72 + .../RandomTests/st201503181735GO.json | 72 + .../RandomTests/st201503181737CPPJIT.json | 72 + .../RandomTests/st201503181737GO.json | 72 + .../RandomTests/st201503181738CPPJIT.json | 72 + .../RandomTests/st201503181738GO.json | 72 + .../RandomTests/st201503181739GO.json | 72 + .../RandomTests/st201503181740CPPJIT.json | 73 + .../RandomTests/st201503181740GO.json | 72 + .../RandomTests/st201503181742CPPJIT.json | 72 + .../RandomTests/st201503181743GO.json | 72 + .../RandomTests/st201503181744GO.json | 73 + .../RandomTests/st201503181745CPPJIT.json | 72 + .../RandomTests/st201503181746GO.json | 72 + .../RandomTests/st201503181747GO.json | 72 + .../RandomTests/st201503181748GO.json | 72 + .../RandomTests/st201503181749GO.json | 72 + .../RandomTests/st201503181750CPPJIT.json | 71 + .../RandomTests/st201503181750GO.json | 72 + .../RandomTests/st201503181752GO.json | 72 + .../RandomTests/st201503181753CPPJIT.json | 72 + .../RandomTests/st201503181754CPPJIT.json | 71 + .../RandomTests/st201503181754GO.json | 72 + .../RandomTests/st201503181755CPPJIT.json | 71 + .../RandomTests/st201503181755GO.json | 72 + .../RandomTests/st201503181756GO.json | 72 + .../RandomTests/st201503181757CPPJIT.json | 79 + .../RandomTests/st201503181757GO.json | 72 + .../RandomTests/st201503181759GO.json | 73 + .../RandomTests/st201503181800GO.json | 72 + .../RandomTests/st201503181801GO.json | 72 + .../RandomTests/st201503181802GO.json | 72 + .../RandomTests/st201503181803CPPJIT.json | 71 + .../RandomTests/st201503181803GO.json | 72 + .../RandomTests/st201503181804GO.json | 72 + .../RandomTests/st201503181806GO.json | 72 + .../RandomTests/st201503181808GO.json | 72 + .../RandomTests/st201503181809CPPJIT.json | 72 + .../RandomTests/st201503181812CPPJIT.json | 72 + .../RandomTests/st201503181812GO.json | 72 + .../RandomTests/st201503181814CPPJIT.json | 73 + .../RandomTests/st201503181815GO.json | 72 + .../RandomTests/st201503181816CPPJIT.json | 73 + .../RandomTests/st201503181817CPPJIT.json | 71 + .../RandomTests/st201503181819GO.json | 72 + .../RandomTests/st201503181821GO.json | 72 + .../RandomTests/st201503181822GO.json | 72 + .../RandomTests/st201503181823GO.json | 72 + .../RandomTests/st201503181824GO.json | 72 + .../RandomTests/st201503181825GO.json | 72 + .../RandomTests/st201503181829GO.json | 72 + .../RandomTests/st201503181830CPPJIT.json | 72 + .../RandomTests/st201503181833GO.json | 73 + .../RandomTests/st201503181834CPPJIT.json | 72 + .../RandomTests/st201503181834GO.json | 72 + .../RandomTests/st201503181837GO.json | 72 + .../RandomTests/st201503181840GO.json | 72 + .../RandomTests/st201503181842GO.json | 72 + .../RandomTests/st201503181843GO.json | 72 + .../RandomTests/st201503181844GO.json | 72 + .../RandomTests/st201503181845GO.json | 72 + .../RandomTests/st201503181846GO.json | 73 + .../RandomTests/st201503181847GO.json | 72 + .../RandomTests/st201503181848GO.json | 72 + .../RandomTests/st201503181849GO.json | 73 + .../RandomTests/st201503181850GO.json | 72 + .../RandomTests/st201503181851CPPJIT.json | 72 + .../RandomTests/st201503181851GO.json | 72 + .../RandomTests/st201503181852CPPJIT.json | 71 + .../RandomTests/st201503181854GO.json | 72 + .../RandomTests/st201503181855CPPJIT.json | 71 + .../RandomTests/st201503181857PYTHON.json | 71 + .../RandomTests/st201503181859GO.json | 72 + .../RandomTests/st201503181900GO.json | 72 + .../RandomTests/st201503181903GO.json | 72 + .../RandomTests/st201503181904GO.json | 72 + .../RandomTests/st201503181906GO.json | 72 + .../RandomTests/st201503181907GO.json | 72 + .../RandomTests/st201503181910GO.json | 72 + .../RandomTests/st201503181915GO.json | 72 + .../st201503181919CPPJIT.json.REMOVED.git-id | 1 + .../st201503181919PYTHON.json.REMOVED.git-id | 1 + .../RandomTests/st201503181920GO.json | 72 + .../RandomTests/st201503181922GO.json | 72 + .../RandomTests/st201503181926GO.json | 72 + .../RandomTests/st201503181929GO.json | 72 + .../st201503181931CPPJIT.json.REMOVED.git-id | 1 + .../RandomTests/st201503181931GO.json | 72 + .../st201503181931PYTHON.json.REMOVED.git-id | 1 + .../RandomTests/st201503191646GO.json | 72 + .../RandomTests/st201503200837JS.json | 64 + .../RandomTests/st201503200838JS.json | 64 + .../RandomTests/st201503200841JS.json | 64 + .../RandomTests/st201503200848JS.json | 64 + .../RandomTests/st201503240609JS.json | 71 + .../RandomTests/st201503302200JS.json | 71 + .../RandomTests/st201503302202JS.json | 71 + .../RandomTests/st201503302206JS.json | 71 + .../RandomTests/st201503302208JS.json | 71 + .../RandomTests/st201503302210JS.json | 71 + .../RandomTests/st201503302211JS.json | 71 + .../RandomTests/st201504011535GO.json | 71 + .../RandomTests/st201504011536GO.json | 71 + .../RandomTests/st201504011547GO.json | 71 + .../RandomTests/st201504011916JS.json | 72 + .../RandomTests/st201504012130JS.json | 71 + .../RandomTests/st201504012259JS.json | 72 + .../RandomTests/st201504012359JS.json | 72 + .../RandomTests/st201504020305JS.json | 71 + .../RandomTests/st201504020400JS.json | 71 + .../RandomTests/st201504020428JS.json | 71 + .../RandomTests/st201504020431JS.json | 71 + .../RandomTests/st201504020444JS.json | 71 + .../RandomTests/st201504020538JS.json | 72 + .../RandomTests/st201504020639JS.json | 78 + .../RandomTests/st201504020836JS.json | 71 + .../RandomTests/st201504020910JS.json | 71 + .../RandomTests/st201504021057JS.json | 71 + .../RandomTests/st201504021104JS.json | 71 + .../st201504021237CPPJIT.json.REMOVED.git-id | 1 + .../st201504021237GO.json.REMOVED.git-id | 1 + .../st201504021237JS.json.REMOVED.git-id | 1 + .../st201504021237PYTHON.json.REMOVED.git-id | 1 + .../RandomTests/st201504021949JS.json | 71 + .../RandomTests/st201504022003CPPJIT.json | 71 + .../RandomTests/st201504022124JS.json | 71 + .../RandomTests/st201504030138JS.json | 71 + .../RandomTests/st201504030646JS.json | 71 + .../RandomTests/st201504030709JS.json | 71 + .../RandomTests/st201504031133JS.json | 71 + .../RandomTests/st201504031446JS.json | 72 + .../RandomTests/st201504031841JS.json | 71 + .../RandomTests/st201504041605JS.json | 71 + .../RandomTests/st201504042052JS.json | 72 + .../RandomTests/st201504042226CPPJIT.json | 73 + .../RandomTests/st201504042355CPPJIT.json | 71 + .../RandomTests/st201504050059JS.json | 71 + .../RandomTests/st201504050733JS.json | 71 + .../RandomTests/st201504051540JS.json | 71 + .../RandomTests/st201504051944CPPJIT.json | 71 + .../RandomTests/st201504052008CPPJIT.json | 71 + .../RandomTests/st201504052014GO.json | 71 + .../RandomTests/st201504052031CPPJIT.json | 72 + .../RandomTests/st201504060057CPPJIT.json | 72 + .../RandomTests/st201504060418CPPJIT.json | 72 + .../RandomTests/st201504061106CPPJIT.json | 71 + .../RandomTests/st201504061134CPPJIT.json | 71 + .../RandomTests/st201504062033CPPJIT.json | 71 + .../RandomTests/st201504062046CPPJIT.json | 71 + .../RandomTests/st201504062314CPPJIT.json | 72 + .../RandomTests/st201504070746JS.json | 71 + .../RandomTests/st201504070816CPPJIT.json | 71 + .../RandomTests/st201504070836CPPJIT.json | 71 + .../RandomTests/st201504070839CPPJIT.json | 71 + .../RandomTests/st201504071041CPPJIT.json | 71 + .../RandomTests/st201504071056CPPJIT.json | 71 + .../RandomTests/st201504071621CPPJIT.json | 71 + .../RandomTests/st201504071653CPPJIT.json | 71 + .../RandomTests/st201504071750CPPJIT.json | 71 + .../RandomTests/st201504071905CPPJIT.json | 71 + .../RandomTests/st201504080454CPPJIT.json | 71 + .../RandomTests/st201504080457CPPJIT.json | 71 + .../RandomTests/st201504080650CPPJIT.json | 71 + .../RandomTests/st201504080840CPPJIT.json | 71 + .../RandomTests/st201504080948CPPJIT.json | 71 + .../RandomTests/st201504081100CPPJIT.json | 71 + .../RandomTests/st201504081134CPPJIT.json | 71 + .../RandomTests/st201504081138CPPJIT.json | 71 + .../RandomTests/st201504081611CPPJIT.json | 71 + .../RandomTests/st201504081841JAVA.json | 71 + .../RandomTests/st201504081842JAVA.json | 71 + .../RandomTests/st201504081843JAVA.json | 71 + .../RandomTests/st201504081928CPPJIT.json | 71 + .../RandomTests/st201504081953JAVA.json | 71 + .../RandomTests/st201504081954JAVA.json | 71 + .../RandomTests/st201504081955JAVA.json | 71 + .../RandomTests/st201504081956JAVA.json | 71 + .../RandomTests/st201504081957JAVA.json | 71 + .../RandomTests/st201504082000JAVA.json | 71 + .../RandomTests/st201504082001JAVA.json | 71 + .../RandomTests/st201504082002JAVA.json | 71 + .../RandomTests/st201504090553CPPJIT.json | 71 + .../RandomTests/st201504090657CPPJIT.json | 72 + .../RandomTests/st201504091403CPPJIT.json | 71 + .../RandomTests/st201504091641CPPJIT.json | 71 + .../RandomTests/st201504092303CPPJIT.json | 71 + .../RandomTests/st201504100125CPPJIT.json | 71 + .../RandomTests/st201504100215CPPJIT.json | 71 + .../RandomTests/st201504100226PYTHON.json | 86 + .../RandomTests/st201504100308CPPJIT.json | 71 + .../RandomTests/st201504100337CPPJIT.json | 71 + .../RandomTests/st201504100341CPPJIT.json | 71 + .../RandomTests/st201504101009CPPJIT.json | 71 + .../RandomTests/st201504101150CPPJIT.json | 71 + .../RandomTests/st201504101223CPPJIT.json | 71 + .../RandomTests/st201504101338CPPJIT.json | 71 + .../RandomTests/st201504101754PYTHON.json | 71 + .../RandomTests/st201504111554CPPJIT.json | 71 + .../RandomTests/st201504130653JS.json | 71 + .../RandomTests/st201504131821CPPJIT.json | 71 + .../RandomTests/st201504140229CPPJIT.json | 71 + .../RandomTests/st201504140236CPPJIT.json | 71 + .../RandomTests/st201504140359CPPJIT.json | 71 + .../RandomTests/st201504140750CPPJIT.json | 71 + .../RandomTests/st201504140818CPPJIT.json | 71 + .../RandomTests/st201504140900CPPJIT.json | 71 + .../RandomTests/st201504150854CPPJIT.json | 72 + .../RandomTests/st201504151057CPPJIT.json | 71 + .../RandomTests/st201504202124CPPJIT.json | 71 + .../RandomTests/st201504210245CPPJIT.json | 71 + .../RandomTests/st201504210957CPPJIT.json | 71 + .../RandomTests/st201504211739CPPJIT.json | 71 + .../RandomTests/st201504212038CPPJIT.json | 71 + .../RandomTests/st201504230729CPPJIT.json | 71 + .../RandomTests/st201504231639CPPJIT.json | 71 + .../RandomTests/st201504231710CPPJIT.json | 72 + .../RandomTests/st201504231742CPPJIT.json | 71 + .../RandomTests/st201504232350CPPJIT.json | 71 + .../RandomTests/st201504240140CPPJIT.json | 71 + .../RandomTests/st201504240220CPPJIT.json | 72 + .../RandomTests/st201504240351CPPJIT.json | 71 + .../RandomTests/st201504240817CPPJIT.json | 71 + .../RandomTests/st201504241118CPPJIT.json | 71 + .../RandomTests/st201505021810CPPJIT.json | 71 + .../RandomTests/st201505050557JS.json | 72 + .../RandomTests/st201505050929GO.json | 73 + .../RandomTests/st201505050942PYTHON.json | 72 + .../RandomTests/st201505051004PYTHON.json | 72 + .../RandomTests/st201505051016PYTHON.json | 72 + .../RandomTests/st201505051114GO.json | 72 + .../RandomTests/st201505051238GO.json | 73 + .../RandomTests/st201505051249GO.json | 72 + .../RandomTests/st201505051558PYTHON.json | 72 + .../RandomTests/st201505051611PYTHON.json | 72 + .../RandomTests/st201505051648JS.json | 72 + .../RandomTests/st201505051710GO.json | 72 + .../RandomTests/st201505052013GO.json | 73 + .../RandomTests/st201505052102JS.json | 72 + .../RandomTests/st201505052235GO.json | 72 + .../RandomTests/st201505052238JS.json | 72 + .../RandomTests/st201505052242PYTHON.json | 72 + .../RandomTests/st201505052343PYTHON.json | 72 + .../RandomTests/st201505060120GO.json | 72 + .../RandomTests/st201505060121GO.json | 73 + .../RandomTests/st201505060136PYTHON.json | 72 + .../RandomTests/st201505060646JS.json | 72 + .../RandomTests/st201505252314CPPJIT.json | 81 + .../RandomTests/st201505272131CPPJIT.json | 71 + .../RandomTests/st201506040034GO.json | 80 + .../RandomTests/st201506040157GO.json | 81 + .../RandomTests/st201506052130GO.json | 78 + .../RandomTests/st201506060929GO.json | 81 + .../RandomTests/st201506061255GO.json | 78 + .../RandomTests/st201506062331GO.json | 80 + .../RandomTests/st201506070548GO.json | 81 + .../RandomTests/st201506071050GO.json | 80 + .../RandomTests/st201506071624GO.json | 80 + .../RandomTests/st201506071819GO.json | 83 + .../RandomTests/st201506072007GO.json | 78 + .../RandomTests/st201506080556GO.json | 81 + .../RandomTests/st201506080721GO.json | 79 + .../RandomTests/st201506091836GO.json | 71 + .../RandomTests/st201506092032GO.json | 71 + .../RandomTests/st201506101359JS.json | 71 + .../RandomTests/st201507030359GO.json | 78 + tests/files/StateTests/stBlockHashTest.json | 255 + .../StateTests/stCallCreateCallCodeTest.json | 2769 + tests/files/StateTests/stExample.json | 65 + tests/files/StateTests/stInitCodeTest.json | 1101 + tests/files/StateTests/stLogTests.json | 3833 ++ .../files/StateTests/stMemoryStressTest.json | 382 + tests/files/StateTests/stMemoryTest.json | 4091 ++ .../StateTests/stPreCompiledContracts.json | 5784 ++ .../StateTests/stQuadraticComplexityTest.json | 8064 +++ tests/files/StateTests/stRecursiveCreate.json | 8403 +++ tests/files/StateTests/stRefundTest.json | 1197 + tests/files/StateTests/stSolidityTest.json | 1105 + tests/files/StateTests/stSpecialTest.json | 925 + ...stSystemOperationsTest.json.REMOVED.git-id | 1 + tests/files/StateTests/stTransactionTest.json | 2411 + tests/files/StateTests/stWalletTest.json | 3170 ++ tests/files/TODO | 21 + .../RandomTests/tr201506052141PYTHON.json | 5 + .../tt10mbDataField.json.REMOVED.git-id | 1 + .../TransactionTests/ttTransactionTest.json | 429 + .../ttWrongRLPTransaction.json | 277 + .../hex_encoded_securetrie_test.json | 44 + tests/files/TrieTests/trieanyorder.json | 54 + .../TrieTests/trieanyorder_secureTrie.json | 54 + tests/files/TrieTests/trietest.json | 86 + .../files/TrieTests/trietest_secureTrie.json | 86 + tests/files/TrieTests/trietestnextprev.json | 19 + .../RandomTests/201503102037PYTHON.json | 46 + .../RandomTests/201503102148PYTHON.json | 46 + .../RandomTests/201503102300PYTHON.json | 46 + .../RandomTests/201503102320PYTHON.json | 31 + .../RandomTests/201503110050PYTHON.json | 46 + .../RandomTests/201503110206PYTHON.json | 31 + .../RandomTests/201503110219PYTHON.json | 31 + .../RandomTests/201503110226PYTHON_DUP6.json | 46 + .../201503110346PYTHON_PUSH24.json | 46 + .../RandomTests/201503110526PYTHON.json | 31 + .../RandomTests/201503111844PYTHON.json | 46 + .../RandomTests/201503112218PYTHON.json | 31 + .../RandomTests/201503120317PYTHON.json | 31 + .../RandomTests/201503120525PYTHON.json | 31 + .../RandomTests/201503120547PYTHON.json | 31 + .../RandomTests/201503120909PYTHON.json | 31 + .../files/VMTests/RandomTests/randomTest.json | 46 + tests/files/VMTests/vmArithmeticTest.json | 8924 ++++ .../VMTests/vmBitwiseLogicOperationTest.json | 2682 + tests/files/VMTests/vmBlockInfoTest.json | 523 + .../VMTests/vmEnvironmentalInfoTest.json | 2462 + .../VMTests/vmIOandFlowOperationsTest.json | 4906 ++ .../VMTests/vmInputLimits.json.REMOVED.git-id | 1 + .../vmInputLimitsLight.json.REMOVED.git-id | 1 + tests/files/VMTests/vmLogTest.json | 2190 + tests/files/VMTests/vmPerformanceTest.json | 251 + tests/files/VMTests/vmPushDupSwapTest.json | 3234 ++ tests/files/VMTests/vmSha3Test.json | 716 + .../files/VMTests/vmSystemOperationsTest.json | 1771 + tests/files/VMTests/vmtests.json | 133 + tests/files/ansible/README.md | 5 + tests/files/ansible/Vagrantfile | 78 + tests/files/ansible/ec2-setup.yml | 9 + tests/files/ansible/ec2-terminate.yml | 10 + tests/files/ansible/ec2.ini | 95 + tests/files/ansible/ec2.py | 727 + tests/files/ansible/host-config.yml | 10 + .../ansible/roles/common/handlers/main.yml | 4 + .../files/ansible/roles/common/tasks/main.yml | 13 + .../ansible/roles/docker/handlers/main.yml | 4 + .../files/ansible/roles/docker/tasks/main.yml | 40 + tests/files/ansible/roles/ec2/tasks/setup.yml | 32 + .../ansible/roles/ec2/tasks/terminate.yml | 8 + tests/files/ansible/roles/ec2/vars/main.yml | 17 + .../ansible/roles/testrunner/tasks/main.yml | 34 + tests/files/ansible/site.yml | 3 + .../test-files/create-docker-images.sh | 7 + .../ansible/test-files/docker-cpp/Dockerfile | 32 + .../test-files/docker-cppjit/Dockerfile | 46 + .../ansible/test-files/docker-go/Dockerfile | 47 + .../test-files/docker-python/Dockerfile | 23 + tests/files/ansible/test-files/testrunner.sh | 57 + tests/files/ansible/testrunner-config.yml | 12 + tests/files/index.js | 25 + tests/files/package.json | 26 + tests/init.go | 116 + tests/rlp_test.go | 36 + tests/rlp_test_util.go | 188 + tests/state_test.go | 150 + tests/state_test_util.go | 199 + tests/transaction_test.go | 43 + tests/transaction_test_util.go | 221 + tests/util.go | 276 + tests/vm_test.go | 123 + tests/vm_test_util.go | 186 + trie/cache.go | 80 + trie/encoding.go | 92 + trie/encoding_test.go | 75 + trie/fullnode.go | 94 + trie/hashnode.go | 46 + trie/iterator.go | 140 + trie/iterator_test.go | 49 + trie/node.go | 61 + trie/secure_trie.go | 61 + trie/shortnode.go | 57 + trie/slice.go | 69 + trie/trie.go | 390 + trie/trie_test.go | 354 + trie/valuenode.go | 42 + whisper/doc.go | 32 + whisper/envelope.go | 147 + whisper/envelope_test.go | 158 + whisper/filter.go | 132 + whisper/filter_test.go | 215 + whisper/main.go | 106 + whisper/message.go | 156 + whisper/message_test.go | 158 + whisper/peer.go | 175 + whisper/peer_test.go | 258 + whisper/topic.go | 140 + whisper/topic_test.go | 215 + whisper/whisper.go | 354 + whisper/whisper_test.go | 201 + xeth/frontend.go | 44 + xeth/state.go | 52 + xeth/types.go | 240 + xeth/whisper.go | 121 + xeth/whisper_filter.go | 100 + xeth/whisper_message.go | 53 + xeth/xeth.go | 1022 + 1891 files changed, 549645 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 .mailmap create mode 100644 .travis.yml create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 COPYING.LESSER create mode 100644 Godeps/Godeps.json create mode 100644 Godeps/Readme create mode 100644 Godeps/_workspace/.gitignore create mode 100644 Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/LICENSE create mode 100644 Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/dce.go create mode 100644 Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/doc.go create mode 100644 Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/hash.go create mode 100644 Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/node.go create mode 100644 Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/time.go create mode 100644 Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/util.go create mode 100644 Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid.go create mode 100644 Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid_test.go create mode 100644 Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version1.go create mode 100644 Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version4.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/README.md create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/app.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/cli.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/command.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/context.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/flag.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/help.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common_test.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/config.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/doc.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump_test.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpcgo_test.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpnocgo_test.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/example_test.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format_test.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/internal_test.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew_test.go create mode 100644 Godeps/_workspace/src/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/.gitignore create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/.travis.yml create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/CMakeLists.txt create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/MANIFEST.in create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/Makefile create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/README.md create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/Vagrantfile create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/appveyor.yml create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/CMakeParseArguments.cmake create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindCryptoPP.cmake create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindOpenCL.cmake create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageHandleStandardArgs.cmake create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageMessage.cmake create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/cryptopp/CMakeLists.txt create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/ethash_test.go create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/ethashc.go create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/LICENSE create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/ethash.js create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/keccak.js create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/makekeccak.js create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/test.js create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/util.js create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/setup.py create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/CMakeLists.txt create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/benchmark.cpp create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/CMakeLists.txt create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/compiler.h create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/endian.h create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/fnv.h create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.c create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.h create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_posix.c create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_win32.c create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/mmap.h create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/mmap_win32.c create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.c create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.h create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.cpp create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.h create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util.h create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util_win32.c create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/c/CMakeLists.txt create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.sh create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/python/.gitignore create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/python/requirements.txt create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test.sh create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test_pyethash.py create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/test.sh create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/.gitignore create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/.travis.yml create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/LICENSE create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/README.md create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/bar.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/block.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/block_test.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/box.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/box_others.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/box_windows.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/canvas.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/canvas_test.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/chart.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/chart_others.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/chart_windows.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/doc.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/events.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/events_test.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/barchart.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/barchart.png create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.gif create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/gauge.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/gauge.png create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/grid.gif create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/grid.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/linechart.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/linechart.png create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/list.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/list.png create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.png create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/par.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/par.png create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.png create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/theme.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/themedefault.png create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/example/themehelloworld.png create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/gauge.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/grid.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/grid_test.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/helper.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/helper_test.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/list.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/mbar.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/p.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/point.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/render.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/sparkline.go create mode 100644 Godeps/_workspace/src/github.com/gizak/termui/theme.go create mode 100644 Godeps/_workspace/src/github.com/hashicorp/golang-lru/.gitignore create mode 100644 Godeps/_workspace/src/github.com/hashicorp/golang-lru/LICENSE create mode 100644 Godeps/_workspace/src/github.com/hashicorp/golang-lru/README.md create mode 100644 Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru.go create mode 100644 Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru_test.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/LICENSE create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/README.md create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_httpu_serving/example_httpu_serving.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_internetgateway1/example_internetgateway1.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway1/internetgateway1.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway2/internetgateway2.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/device.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/example/example.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/example/example_test.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/gotasks/specgen_task.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/goupnp.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/httpu/httpu.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/httpu/serve.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/scpd/scpd.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/service_client.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/soap/soap.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/soap/soap_test.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/soap/types.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/soap/types_test.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/ssdp/registry.go create mode 100644 Godeps/_workspace/src/github.com/huin/goupnp/ssdp/ssdp.go create mode 100644 Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/LICENSE create mode 100644 Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/README.md create mode 100644 Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go create mode 100644 Godeps/_workspace/src/github.com/kardianos/osext/LICENSE create mode 100644 Godeps/_workspace/src/github.com/kardianos/osext/README.md create mode 100644 Godeps/_workspace/src/github.com/kardianos/osext/osext.go create mode 100644 Godeps/_workspace/src/github.com/kardianos/osext/osext_plan9.go create mode 100644 Godeps/_workspace/src/github.com/kardianos/osext/osext_procfs.go create mode 100644 Godeps/_workspace/src/github.com/kardianos/osext/osext_sysctl.go create mode 100644 Godeps/_workspace/src/github.com/kardianos/osext/osext_test.go create mode 100644 Godeps/_workspace/src/github.com/kardianos/osext/osext_windows.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-colorable/README.md create mode 100644 Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-isatty/README.md create mode 100644 Godeps/_workspace/src/github.com/mattn/go-isatty/doc.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_bsd.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_linux.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_windows.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-runewidth/.travis.yml create mode 100644 Godeps/_workspace/src/github.com/mattn/go-runewidth/README.mkd create mode 100644 Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_js.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_posix.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_test.go create mode 100644 Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_windows.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/AUTHORS create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/LICENSE create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/README.md create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/api.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/api_common.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/collect_terminfo.py create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_386.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_amd64.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_freebsd.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_linux.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_netbsd.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_openbsd.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_windows.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_common.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo.go create mode 100644 Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo_builtin.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/COPYING create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/README.md create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/bsdinput.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/common.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/fallbackinput.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/input.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/input_darwin.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/input_linux.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/input_test.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/input_windows.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/line.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/line_test.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/output.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/output_windows.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/race_test.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/signal.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/signal_legacy.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/unixmode.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/width.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/width_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/.gitignore create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/LICENSE create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/README.md create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/cmd/metrics-bench/metrics-bench.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/cmd/metrics-example/metrics-example.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/cmd/never-read/never-read.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/counter.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/counter_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/debug.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/debug_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_float64.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_float64_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/healthcheck.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/histogram.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/histogram_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/influxdb/influxdb.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/json.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/json_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/librato/client.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/librato/librato.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/log.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/memory.md create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/meter.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/meter_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/metrics.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/metrics_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/opentsdb.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/opentsdb_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_cgo.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_no_cgo.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/sample.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/sample_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/stathat/stathat.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/syslog.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/timer.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/timer_test.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/writer.go create mode 100644 Godeps/_workspace/src/github.com/rcrowley/go-metrics/writer_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/.gitignore create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/DESIGN.markdown create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/LICENSE create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/Makefile create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/README.markdown create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/array_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/ast/README.markdown create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/ast/node.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/bug_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/builtin.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_array.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_boolean.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_date.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_error.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_function.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_json.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_math.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_number.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_object.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_regexp.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_string.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/clone.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_expression.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_parse.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/console.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/date_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/dbg.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/dbg/dbg.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/documentation_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/error.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/error_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/evaluate.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/file/README.markdown create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/file/file.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/function_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/global.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/global_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/inline create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/inline.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/json_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/math_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/number_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/object.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/object_class.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/object_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/otto/Makefile create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/otto/main.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/otto_.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/otto_error_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/otto_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/panic_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/Makefile create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/README.markdown create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/dbg.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/error.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/marshal_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/regexp.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/regexp_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/scope.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser/statement.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/parser_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/property.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/reflect_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/regexp_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/registry/README.markdown create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/registry/registry.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/result.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/runtime_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/scope.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/script.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/script_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/stash.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/string_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/terst/terst.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/test/Makefile create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/test/tester.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/testing_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/token/Makefile create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/token/README.markdown create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/token/token.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/token/token_const.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/token/tokenfmt create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_arguments.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_array.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_boolean.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_date.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_error.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_function.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_array.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_map.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_slice.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_struct.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_number.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_reference.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_regexp.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/type_string.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/Makefile create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/README.markdown create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/source.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/testify create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/underscore.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_arrays_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_chaining_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_collections_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_functions_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_objects_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_utility_test.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/value.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/value_boolean.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/value_number.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/value_primitive.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/value_string.go create mode 100644 Godeps/_workspace/src/github.com/robertkrimen/otto/value_test.go create mode 100644 Godeps/_workspace/src/github.com/rs/cors/.travis.yml create mode 100644 Godeps/_workspace/src/github.com/rs/cors/LICENSE create mode 100644 Godeps/_workspace/src/github.com/rs/cors/README.md create mode 100644 Godeps/_workspace/src/github.com/rs/cors/bench_test.go create mode 100644 Godeps/_workspace/src/github.com/rs/cors/cors.go create mode 100644 Godeps/_workspace/src/github.com/rs/cors/cors_test.go create mode 100644 Godeps/_workspace/src/github.com/rs/cors/examples/alice/server.go create mode 100644 Godeps/_workspace/src/github.com/rs/cors/examples/default/server.go create mode 100644 Godeps/_workspace/src/github.com/rs/cors/examples/goji/server.go create mode 100644 Godeps/_workspace/src/github.com/rs/cors/examples/martini/server.go create mode 100644 Godeps/_workspace/src/github.com/rs/cors/examples/negroni/server.go create mode 100644 Godeps/_workspace/src/github.com/rs/cors/examples/nethttp/server.go create mode 100644 Godeps/_workspace/src/github.com/rs/cors/examples/openbar/server.go create mode 100644 Godeps/_workspace/src/github.com/rs/cors/utils.go create mode 100644 Godeps/_workspace/src/github.com/rs/cors/utils_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench2_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/bench2_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/lru.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer/bytes_comparer.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer/comparer.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/corrupt_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_compaction.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_iter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_snapshot.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_state.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_util.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_write.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/doc.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors/errors.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/external_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/filter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter_suite_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/leveldb_suite_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/bench_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_suite_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt/options.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/options.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_util.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/block_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_suite_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/db.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/ginkgo.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/iter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kv.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kvtest.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/storage.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/util.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_pool.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/crc32.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/hash.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/pool.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/pool_legacy.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/range.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/util.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/version.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/decode.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/encode.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/crypto/pbkdf2/pbkdf2.go create mode 100644 Godeps/_workspace/src/golang.org/x/crypto/pbkdf2/pbkdf2_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/crypto/ripemd160/ripemd160.go create mode 100644 Godeps/_workspace/src/golang.org/x/crypto/ripemd160/ripemd160_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/crypto/ripemd160/ripemd160block.go create mode 100644 Godeps/_workspace/src/golang.org/x/crypto/scrypt/scrypt.go create mode 100644 Godeps/_workspace/src/golang.org/x/crypto/scrypt/scrypt_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/atom/atom.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/atom/atom_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/atom/gen.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/atom/table.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/atom/table_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/charset.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/charset_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/gen.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/table.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/HTTP-charset.html create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/HTTP-vs-UTF-8-BOM.html create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-charset.html create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-content.html create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/No-encoding-declaration.html create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/README create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/UTF-16BE-BOM.html create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/UTF-16LE-BOM.html create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-charset.html create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-content.html create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/meta-charset-attribute.html create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/meta-content-attribute.html create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/const.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/doc.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/doctype.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/entity.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/entity_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/escape.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/escape_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/example_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/foreign.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/node.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/node_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/parse.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/parse_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/render.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/render_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/go1.html create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/README create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/adoption01.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/adoption02.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/comments01.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/doctype01.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/entities01.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/entities02.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/html5test-com.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/inbody01.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/isindex.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/pending-spec-changes.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/plain-text-unsafe.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/scriptdata01.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/scripted/adoption01.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/scripted/webkit01.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tables01.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests1.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests10.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests11.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests12.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests14.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests15.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests16.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests17.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests18.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests19.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests2.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests20.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests21.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests22.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests23.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests24.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests25.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests26.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests3.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests4.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests5.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests6.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests7.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests8.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests9.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests_innerHTML_1.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tricky01.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/webkit01.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/webkit02.dat create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/token.go create mode 100644 Godeps/_workspace/src/golang.org/x/net/html/token_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/charmap/charmap.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/charmap/maketables.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/charmap/tables.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/encoding.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/encoding_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/example_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/htmlindex/htmlindex.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/ianaindex/example_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/ianaindex/ianaindex.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/internal/identifier/gen.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/internal/identifier/identifier.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/internal/identifier/mib.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/internal/internal.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/japanese/all.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/japanese/eucjp.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/japanese/iso2022jp.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/japanese/maketables.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/japanese/shiftjis.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/japanese/tables.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/korean/euckr.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/korean/maketables.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/korean/tables.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/simplifiedchinese/all.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/simplifiedchinese/gbk.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/simplifiedchinese/hzgb2312.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/simplifiedchinese/maketables.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/simplifiedchinese/tables.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/candide-gb18030.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/candide-utf-16le.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/candide-utf-8.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/candide-windows-1252.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/rashomon-euc-jp.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/rashomon-iso-2022-jp.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/rashomon-shift-jis.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/rashomon-utf-8.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/sunzi-bingfa-gb-levels-1-and-2-hz-gb2312.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/sunzi-bingfa-gb-levels-1-and-2-utf-8.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/sunzi-bingfa-simplified-gbk.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/sunzi-bingfa-simplified-utf-8.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/sunzi-bingfa-traditional-big5.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/sunzi-bingfa-traditional-utf-8.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/unsu-joh-eun-nal-euc-kr.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/testdata/unsu-joh-eun-nal-utf-8.txt create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/traditionalchinese/big5.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/traditionalchinese/maketables.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/traditionalchinese/tables.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/unicode/override.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/encoding/unicode/unicode.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/transform/examples_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/transform/transform.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/transform/transform_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/.gitignore create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/LICENSE create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/README.md create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/TODO create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/benchmark.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/benchmark_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/bootstrap_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/check.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/check_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/checkers.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/checkers_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/export_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/fixture_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/foundation_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/helpers.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/helpers_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/printer.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/printer_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/run.go create mode 100644 Godeps/_workspace/src/gopkg.in/check.v1/run_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/fatih/set.v0/.travis.yml create mode 100644 Godeps/_workspace/src/gopkg.in/fatih/set.v0/LICENSE.md create mode 100644 Godeps/_workspace/src/gopkg.in/fatih/set.v0/README.md create mode 100644 Godeps/_workspace/src/gopkg.in/fatih/set.v0/set.go create mode 100644 Godeps/_workspace/src/gopkg.in/fatih/set.v0/set_nots.go create mode 100644 Godeps/_workspace/src/gopkg.in/fatih/set.v0/set_nots_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/fatih/set.v0/set_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/fatih/set.v0/set_ts.go create mode 100644 Godeps/_workspace/src/gopkg.in/fatih/set.v0/set_ts_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/karalabe/cookiejar.v2/collections/prque/example_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/karalabe/cookiejar.v2/collections/prque/prque.go create mode 100644 Godeps/_workspace/src/gopkg.in/karalabe/cookiejar.v2/collections/prque/prque_test.go create mode 100644 Godeps/_workspace/src/gopkg.in/karalabe/cookiejar.v2/collections/prque/sstack.go create mode 100644 Godeps/_workspace/src/gopkg.in/karalabe/cookiejar.v2/collections/prque/sstack_test.go create mode 100644 Makefile create mode 100644 README.md create mode 100755 _data/invalid1 create mode 100755 _data/valid1 create mode 100755 _data/valid2 create mode 100755 _data/valid3 create mode 100755 _data/valid4 create mode 100644 accounts/abi/abi.go create mode 100644 accounts/abi/abi_test.go create mode 100644 accounts/abi/doc.go create mode 100644 accounts/abi/numbers.go create mode 100644 accounts/abi/numbers_test.go create mode 100644 accounts/abi/type.go create mode 100644 accounts/account_manager.go create mode 100644 accounts/accounts_test.go create mode 100755 build/env.sh create mode 100755 build/ldflags.sh create mode 100755 build/test-global-coverage.sh create mode 100644 build/update-license.go create mode 100644 cmd/bootnode/main.go create mode 100644 cmd/disasm/main.go create mode 100644 cmd/ethtest/.bowerrc create mode 100644 cmd/ethtest/.editorconfig create mode 100644 cmd/ethtest/.gitignore create mode 100644 cmd/ethtest/.jshintrc create mode 100644 cmd/ethtest/.npmignore create mode 100644 cmd/ethtest/.travis.yml create mode 100644 cmd/ethtest/main.go create mode 100644 cmd/evm/code.txt create mode 100644 cmd/evm/input.txt create mode 100644 cmd/evm/main.go create mode 100644 cmd/geth/blocktestcmd.go create mode 100644 cmd/geth/chaincmd.go create mode 100644 cmd/geth/info_test.json create mode 100644 cmd/geth/js.go create mode 100644 cmd/geth/js_test.go create mode 100644 cmd/geth/main.go create mode 100644 cmd/geth/monitorcmd.go create mode 100644 cmd/rlpdump/main.go create mode 100644 cmd/utils/cmd.go create mode 100644 cmd/utils/customflags.go create mode 100644 cmd/utils/customflags_test.go create mode 100644 cmd/utils/flags.go create mode 100644 cmd/utils/legalese.go create mode 100644 common/.gitignore create mode 100644 common/.travis.yml create mode 100644 common/README.md create mode 100644 common/big.go create mode 100644 common/big_test.go create mode 100644 common/bytes.go create mode 100644 common/bytes_test.go create mode 100644 common/compiler/solidity.go create mode 100644 common/compiler/solidity_test.go create mode 100644 common/db.go create mode 100644 common/debug.go create mode 100644 common/docserver/docserver.go create mode 100644 common/docserver/docserver_test.go create mode 100644 common/list.go create mode 100644 common/main_test.go create mode 100644 common/math/dist.go create mode 100644 common/math/dist_test.go create mode 100644 common/natspec/natspec.go create mode 100644 common/natspec/natspec_e2e_test.go create mode 100644 common/natspec/natspec_e2e_test.go.orig create mode 100644 common/natspec/natspec_js.go create mode 100644 common/natspec/natspec_test.go create mode 100644 common/number/int.go create mode 100644 common/number/uint_test.go create mode 100644 common/package.go create mode 100644 common/path.go create mode 100644 common/path_test.go create mode 100644 common/registrar/contracts.go create mode 100644 common/registrar/ethreg/ethreg.go create mode 100644 common/registrar/registrar.go create mode 100644 common/registrar/registrar_test.go create mode 100644 common/rlp.go create mode 100644 common/rlp_test.go create mode 100644 common/size.go create mode 100644 common/size_test.go create mode 100644 common/test_utils.go create mode 100644 common/types.go create mode 100644 common/types_template.go create mode 100644 common/types_test.go create mode 100644 common/value.go create mode 100644 common/value_test.go create mode 100644 compression/rle/read_write.go create mode 100644 compression/rle/read_write_test.go create mode 100644 core/.gitignore create mode 100644 core/asm.go create mode 100644 core/bad_block.go create mode 100644 core/bench_test.go create mode 100644 core/block_cache.go create mode 100644 core/block_cache_test.go create mode 100644 core/block_processor.go create mode 100644 core/block_processor_test.go create mode 100644 core/blocks.go create mode 100644 core/canary.go create mode 100644 core/chain_makers.go create mode 100644 core/chain_makers_test.go create mode 100644 core/chain_manager.go create mode 100644 core/chain_manager_test.go create mode 100644 core/chain_util.go create mode 100644 core/error.go create mode 100644 core/events.go create mode 100644 core/execution.go create mode 100644 core/fees.go create mode 100644 core/filter.go create mode 100644 core/filter_test.go create mode 100644 core/genesis.go create mode 100644 core/helper_test.go create mode 100644 core/manager.go create mode 100644 core/state/dump.go create mode 100644 core/state/errors.go create mode 100644 core/state/log.go create mode 100644 core/state/main_test.go create mode 100644 core/state/managed_state.go create mode 100644 core/state/managed_state_test.go create mode 100644 core/state/state_object.go create mode 100644 core/state/state_test.go create mode 100644 core/state/statedb.go create mode 100644 core/state_transition.go create mode 100644 core/transaction_pool.go create mode 100644 core/transaction_pool_test.go create mode 100644 core/transaction_util.go create mode 100644 core/types/block.go create mode 100644 core/types/block_test.go create mode 100644 core/types/bloom9.go create mode 100644 core/types/bloom9_test.go create mode 100644 core/types/common.go create mode 100644 core/types/derive_sha.go create mode 100644 core/types/receipt.go create mode 100644 core/types/transaction.go create mode 100644 core/types/transaction_test.go create mode 100644 core/vm/analysis.go create mode 100644 core/vm/asm.go create mode 100644 core/vm/common.go create mode 100644 core/vm/context.go create mode 100644 core/vm/contracts.go create mode 100644 core/vm/disasm.go create mode 100644 core/vm/environment.go create mode 100644 core/vm/errors.go create mode 100644 core/vm/gas.go create mode 100644 core/vm/logger.go create mode 100644 core/vm/memory.go create mode 100644 core/vm/opcodes.go create mode 100644 core/vm/stack.go create mode 100644 core/vm/virtual_machine.go create mode 100644 core/vm/vm.go create mode 100644 core/vm/vm_jit.go create mode 100644 core/vm/vm_jit_fake.go create mode 100644 core/vm_env.go create mode 100644 crypto/crypto.go create mode 100644 crypto/crypto_test.go create mode 100644 crypto/curve.go create mode 100644 crypto/ecies/.gitignore create mode 100644 crypto/ecies/LICENSE create mode 100644 crypto/ecies/README create mode 100644 crypto/ecies/asn1.go create mode 100644 crypto/ecies/ecies.go create mode 100644 crypto/ecies/ecies_test.go create mode 100644 crypto/ecies/params.go create mode 100644 crypto/encrypt_decrypt_test.go create mode 100644 crypto/key.go create mode 100644 crypto/key_store_passphrase.go create mode 100644 crypto/key_store_plain.go create mode 100644 crypto/key_store_test.go create mode 100644 crypto/keypair.go create mode 100644 crypto/mnemonic.go create mode 100644 crypto/mnemonic_test.go create mode 100644 crypto/mnemonic_words.go create mode 100644 crypto/randentropy/rand_entropy.go create mode 100644 crypto/secp256k1/.gitignore create mode 100644 crypto/secp256k1/README.md create mode 100644 crypto/secp256k1/notes.go create mode 100644 crypto/secp256k1/secp256.go create mode 100644 crypto/secp256k1/secp256_test.go create mode 100644 crypto/secp256k1/secp256k1/.travis.yml create mode 100644 crypto/secp256k1/secp256k1/COPYING create mode 100644 crypto/secp256k1/secp256k1/Makefile.am create mode 100644 crypto/secp256k1/secp256k1/README.md create mode 100644 crypto/secp256k1/secp256k1/TODO create mode 100755 crypto/secp256k1/secp256k1/autogen.sh create mode 100644 crypto/secp256k1/secp256k1/build-aux/m4/bitcoin_secp.m4 create mode 100644 crypto/secp256k1/secp256k1/configure.ac create mode 100644 crypto/secp256k1/secp256k1/include/secp256k1.h create mode 100644 crypto/secp256k1/secp256k1/libsecp256k1.pc.in create mode 100644 crypto/secp256k1/secp256k1/obj/.gitignore create mode 100644 crypto/secp256k1/secp256k1/src/bench.h create mode 100644 crypto/secp256k1/secp256k1/src/bench_internal.c create mode 100644 crypto/secp256k1/secp256k1/src/bench_recover.c create mode 100644 crypto/secp256k1/secp256k1/src/bench_sign.c create mode 100644 crypto/secp256k1/secp256k1/src/bench_verify.c create mode 100644 crypto/secp256k1/secp256k1/src/ecdsa.h create mode 100644 crypto/secp256k1/secp256k1/src/ecdsa_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/eckey.h create mode 100644 crypto/secp256k1/secp256k1/src/eckey_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/ecmult.h create mode 100644 crypto/secp256k1/secp256k1/src/ecmult_gen.h create mode 100644 crypto/secp256k1/secp256k1/src/ecmult_gen_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/ecmult_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/field.h create mode 100644 crypto/secp256k1/secp256k1/src/field_10x26.h create mode 100644 crypto/secp256k1/secp256k1/src/field_10x26_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/field_5x52.h create mode 100644 crypto/secp256k1/secp256k1/src/field_5x52_asm_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/field_5x52_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/field_5x52_int128_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/field_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/group.h create mode 100644 crypto/secp256k1/secp256k1/src/group_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/hash.h create mode 100644 crypto/secp256k1/secp256k1/src/hash_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java create mode 100644 crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c create mode 100644 crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h create mode 100644 crypto/secp256k1/secp256k1/src/num.h create mode 100644 crypto/secp256k1/secp256k1/src/num_gmp.h create mode 100644 crypto/secp256k1/secp256k1/src/num_gmp_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/num_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/scalar.h create mode 100644 crypto/secp256k1/secp256k1/src/scalar_4x64.h create mode 100644 crypto/secp256k1/secp256k1/src/scalar_4x64_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/scalar_8x32.h create mode 100644 crypto/secp256k1/secp256k1/src/scalar_8x32_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/scalar_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/secp256k1.c create mode 100644 crypto/secp256k1/secp256k1/src/testrand.h create mode 100644 crypto/secp256k1/secp256k1/src/testrand_impl.h create mode 100644 crypto/secp256k1/secp256k1/src/tests.c create mode 100644 crypto/secp256k1/secp256k1/src/util.h create mode 100644 crypto/sha3/keccakf.go create mode 100644 crypto/sha3/sha3.go create mode 100644 crypto/tests/v1/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e create mode 100644 crypto/tests/v1_test_vector.json create mode 100644 crypto/tests/v3_test_vector.json create mode 100644 docker/Dockerfile create mode 100644 docker/supervisord.conf create mode 100644 errs/errors.go create mode 100644 errs/errors_test.go create mode 100644 eth/backend.go create mode 100644 eth/downloader/downloader.go create mode 100644 eth/downloader/downloader_test.go create mode 100644 eth/downloader/events.go create mode 100644 eth/downloader/peer.go create mode 100644 eth/downloader/queue.go create mode 100644 eth/fetcher/fetcher.go create mode 100644 eth/fetcher/fetcher_test.go create mode 100644 eth/fetcher/metrics.go create mode 100644 eth/gasprice.go create mode 100644 eth/handler.go create mode 100644 eth/metrics.go create mode 100644 eth/peer.go create mode 100644 eth/protocol.go create mode 100644 eth/protocol_test.go create mode 100644 eth/sync.go create mode 100644 ethdb/.gitignore create mode 100644 ethdb/README.md create mode 100644 ethdb/database.go create mode 100644 ethdb/database_test.go create mode 100644 ethdb/memory_database.go create mode 100644 event/event.go create mode 100644 event/event_test.go create mode 100644 event/example_test.go create mode 100644 event/filter/eth_filter.go create mode 100644 event/filter/filter.go create mode 100644 event/filter/filter_test.go create mode 100644 event/filter/generic_filter.go create mode 100644 generators/defaults.go create mode 100644 jsre/bignumber_js.go create mode 100644 jsre/ethereum_js.go create mode 100644 jsre/jsre.go create mode 100644 jsre/jsre_test.go create mode 100644 jsre/pp_js.go create mode 100644 logger/example_test.go create mode 100644 logger/glog/LICENSE create mode 100644 logger/glog/README create mode 100644 logger/glog/glog.go create mode 100644 logger/glog/glog_file.go create mode 100644 logger/glog/glog_test.go create mode 100644 logger/log.go create mode 100644 logger/loggers.go create mode 100644 logger/loggers_test.go create mode 100644 logger/logsystem.go create mode 100644 logger/sys.go create mode 100644 logger/types.go create mode 100644 logger/verbosity.go create mode 100644 metrics/disk.go create mode 100644 metrics/disk_linux.go create mode 100644 metrics/disk_nop.go create mode 100644 metrics/metrics.go create mode 100644 miner/agent.go create mode 100644 miner/miner.go create mode 100644 miner/remote_agent.go create mode 100644 miner/worker.go create mode 100644 p2p/dial.go create mode 100644 p2p/dial_test.go create mode 100644 p2p/discover/database.go create mode 100644 p2p/discover/database_test.go create mode 100644 p2p/discover/node.go create mode 100644 p2p/discover/node_test.go create mode 100644 p2p/discover/table.go create mode 100644 p2p/discover/table_test.go create mode 100644 p2p/discover/udp.go create mode 100644 p2p/discover/udp_test.go create mode 100644 p2p/message.go create mode 100644 p2p/message_test.go create mode 100644 p2p/metrics.go create mode 100644 p2p/nat/nat.go create mode 100644 p2p/nat/nat_test.go create mode 100644 p2p/nat/natpmp.go create mode 100644 p2p/nat/natupnp.go create mode 100644 p2p/nat/natupnp_test.go create mode 100644 p2p/peer.go create mode 100644 p2p/peer_error.go create mode 100644 p2p/peer_test.go create mode 100644 p2p/protocol.go create mode 100644 p2p/rlpx.go create mode 100644 p2p/rlpx_test.go create mode 100644 p2p/server.go create mode 100644 p2p/server_test.go create mode 100755 params/protocol_params.go create mode 100644 pow/block.go create mode 100644 pow/dagger/dagger.go create mode 100644 pow/dagger/dagger_test.go create mode 100644 pow/ezp/pow.go create mode 100644 pow/pow.go create mode 100644 rlp/decode.go create mode 100644 rlp/decode_test.go create mode 100644 rlp/doc.go create mode 100644 rlp/encode.go create mode 100644 rlp/encode_test.go create mode 100644 rlp/encoder_example_test.go create mode 100644 rlp/typecache.go create mode 100644 rpc/api/admin.go create mode 100644 rpc/api/admin_args.go create mode 100644 rpc/api/admin_js.go create mode 100644 rpc/api/api.go create mode 100644 rpc/api/api_test.go create mode 100644 rpc/api/args.go create mode 100644 rpc/api/args_test.go create mode 100644 rpc/api/db.go create mode 100644 rpc/api/db_args.go create mode 100644 rpc/api/db_js.go create mode 100644 rpc/api/debug.go create mode 100644 rpc/api/debug_args.go create mode 100644 rpc/api/debug_js.go create mode 100644 rpc/api/eth.go create mode 100644 rpc/api/eth_args.go create mode 100644 rpc/api/eth_js.go create mode 100644 rpc/api/mergedapi.go create mode 100644 rpc/api/miner.go create mode 100644 rpc/api/miner_args.go create mode 100644 rpc/api/miner_js.go create mode 100644 rpc/api/net.go create mode 100644 rpc/api/net_js.go create mode 100644 rpc/api/parsing.go create mode 100644 rpc/api/personal.go create mode 100644 rpc/api/personal_args.go create mode 100644 rpc/api/personal_js.go create mode 100644 rpc/api/shh.go create mode 100644 rpc/api/shh_args.go create mode 100644 rpc/api/ssh_js.go create mode 100644 rpc/api/txpool.go create mode 100644 rpc/api/txpool_js.go create mode 100644 rpc/api/utils.go create mode 100644 rpc/api/web3.go create mode 100644 rpc/api/web3_args.go create mode 100644 rpc/codec/codec.go create mode 100644 rpc/codec/json.go create mode 100644 rpc/codec/json_test.go create mode 100644 rpc/comms/comms.go create mode 100644 rpc/comms/http.go create mode 100644 rpc/comms/http_net.go create mode 100644 rpc/comms/inproc.go create mode 100644 rpc/comms/ipc.go create mode 100644 rpc/comms/ipc_unix.go create mode 100644 rpc/comms/ipc_windows.go create mode 100644 rpc/jeth.go create mode 100644 rpc/shared/errors.go create mode 100644 rpc/shared/types.go create mode 100644 rpc/shared/utils.go create mode 100644 rpc/xeth.go create mode 100644 tests/block_test.go create mode 100644 tests/block_test_util.go create mode 100644 tests/files/.gitignore create mode 100644 tests/files/ABITests/basic_abi_tests.json create mode 100644 tests/files/BasicTests/blockgenesistest.json create mode 100644 tests/files/BasicTests/crypto.json create mode 100644 tests/files/BasicTests/genesishashestest.json create mode 100644 tests/files/BasicTests/hexencodetest.json create mode 100644 tests/files/BasicTests/keyaddrtest.json create mode 100644 tests/files/BasicTests/rlptest.json create mode 100644 tests/files/BasicTests/txtest.json create mode 100644 tests/files/BlockchainTests/RandomTests/bl201507071825GO.json create mode 100644 tests/files/BlockchainTests/bcBlockGasLimitTest.json create mode 100644 tests/files/BlockchainTests/bcBruncleTest.json create mode 100644 tests/files/BlockchainTests/bcForkBlockTest.json create mode 100644 tests/files/BlockchainTests/bcGasPricerTest.json create mode 100644 tests/files/BlockchainTests/bcInvalidHeaderTest.json create mode 100644 tests/files/BlockchainTests/bcInvalidRLPTest.json create mode 100644 tests/files/BlockchainTests/bcRPC_API_Test.json create mode 100644 tests/files/BlockchainTests/bcTotalDifficultyTest.json create mode 100644 tests/files/BlockchainTests/bcUncleHeaderValiditiy.json create mode 100644 tests/files/BlockchainTests/bcUncleTest.json create mode 100644 tests/files/BlockchainTests/bcValidBlockTest.json create mode 100644 tests/files/BlockchainTests/bcWalletTest.json.REMOVED.git-id create mode 100644 tests/files/GenesisTests/basic_genesis_tests.json create mode 100644 tests/files/KeyStoreTests/basic_tests.json create mode 100644 tests/files/PoWTests/ethash_tests.json create mode 100644 tests/files/README.md create mode 100644 tests/files/RLPTests/RandomRLPTests/example.json create mode 100644 tests/files/RLPTests/invalidRLPTest.json create mode 100644 tests/files/RLPTests/rlptest.json create mode 100644 tests/files/StateTests/RandomTests/st201503121803PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503121806PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503121848GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503121849GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503121850GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503121851GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503121953GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122023GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122023PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503122027GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122054GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122055GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122115CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503122115GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122123GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122124GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122128PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503122140GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122159GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122204GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122212GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122231GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122238GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122252GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122316GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122324GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503122358GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130002GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130005GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130007GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130010GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130023PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503130059GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130101GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130109GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130117GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130122GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130156GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130156PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503130207GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130219CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503130219GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130243GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130246GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130321GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130322GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130332GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130359GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130405GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130408GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130411GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130431GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130437GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130450GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130512CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503130512GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130615GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130705GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130733CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503130733GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130747GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130751GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503130752PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503130757PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503131658GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503131739GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503131755CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503131755GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503132001CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503132127PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503132201CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503132201GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503132202PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503140002PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503140240PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503140522PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503140756PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503141144PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503141510PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503150427PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503150716PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503151450PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503151516PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503151753PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503152057PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503152241PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503160014PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503160733PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503170051PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503170433PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503170523PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503171108PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503181223GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181225GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181226CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181227CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181227GO.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201503181229GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181230CPPJIT.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201503181230GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181231GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181232CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181232GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181233GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181234CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181234GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181235CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181235GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181236GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181237GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181239GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181241CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181241GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181243GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181244GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181245CPPJIT.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201503181245GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181246CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181246GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181247GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181248GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181249GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181250CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181250GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181251GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181252CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181253GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181255CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181255GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181257GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181258CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181258GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181301CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181301GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181303GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181304GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181305GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181306GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181307CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181307GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181308GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181309GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181310GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181311GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181313GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181314GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181315CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181315GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181316CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181316PYTHON.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201503181317GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181318CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181318GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181319GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181319PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503181322GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181323CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181323GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181324GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181325GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181326CPPJIT.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201503181326GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181327GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181329CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181329GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181330GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181332GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181333GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181334GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181336CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181337GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181338GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181339CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181339GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181340GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181341CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181342CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181342GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181345GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181346GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181347CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181347GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181347PYTHON.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201503181350CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181352GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181353GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181354CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181354GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181355GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181356CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181357CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181358CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181358GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181359GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181402CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181403GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181406CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181406GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181410GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181412CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181413GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181415GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181416GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181417CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181417GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181418CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181422GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181423CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181424GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181426CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181426GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181428GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181430CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181435GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181436GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181437CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181437GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181438CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181438GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181439CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181439GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181439PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503181440GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181441GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181442GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181445CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181446GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181447GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181450GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181451CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181453GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181455GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181456CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181457GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181458GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181459GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181500GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181501GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181503GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181504GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181505GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181506CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181507GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181509CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181509GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181510GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181511GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181512GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181513CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181513GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181514CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181514GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181517CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181517GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181519CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181519GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181520CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181520GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181521GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181522GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181524CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181524GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181526GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181527GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181528CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181528GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181528PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503181529GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181531CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181533GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181534CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181534GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181536CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181536GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181537GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181538GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181539GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181540CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181540PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503181543GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181544CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181544GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181547GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181548CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181548GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181551GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181552CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181553GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181555CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181555GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181557GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181559GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181601CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181601GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181602GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181603GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181604GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181605GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181606GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181607GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181608CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181608GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181609GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181610CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181610GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181611CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181611GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181612GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181614CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181614GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181616CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181616GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181617GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181618GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181619GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181620CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181620GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181621GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181625GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181626CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181626GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181627GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181628GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181629GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181630CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181630GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181630PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503181632GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181634CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181635GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181636GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181638GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181639CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181641GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181645GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181646GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181647CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181649CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181650GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181652CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181653GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181654GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181655CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181655GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181656CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181656GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181657GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181658GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181700GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181702GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181703CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181703GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181704GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181706GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181709GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181711CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181711GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181713CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181713GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181714GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181715CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181715GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181716GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181717GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181720CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181722GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181723CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181723GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181724CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181724GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181725GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181728GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181729GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181730GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181731CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181732GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181734CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181734GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181735GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181737CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181737GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181738CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181738GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181739GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181740CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181740GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181742CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181743GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181744GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181745CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181746GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181747GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181748GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181749GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181750CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181750GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181752GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181753CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181754CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181754GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181755CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181755GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181756GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181757CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181757GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181759GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181800GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181801GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181802GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181803CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181803GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181804GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181806GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181808GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181809CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181812CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181812GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181814CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181815GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181816CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181817CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181819GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181821GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181822GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181823GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181824GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181825GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181829GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181830CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181833GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181834CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181834GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181837GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181840GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181842GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181843GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181844GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181845GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181846GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181847GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181848GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181849GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181850GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181851CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181851GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181852CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181854GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181855CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201503181857PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201503181859GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181900GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181903GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181904GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181906GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181907GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181910GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181915GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181919CPPJIT.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201503181919PYTHON.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201503181920GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181922GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181926GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181929GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181931CPPJIT.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201503181931GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503181931PYTHON.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201503191646GO.json create mode 100644 tests/files/StateTests/RandomTests/st201503200837JS.json create mode 100644 tests/files/StateTests/RandomTests/st201503200838JS.json create mode 100644 tests/files/StateTests/RandomTests/st201503200841JS.json create mode 100644 tests/files/StateTests/RandomTests/st201503200848JS.json create mode 100644 tests/files/StateTests/RandomTests/st201503240609JS.json create mode 100644 tests/files/StateTests/RandomTests/st201503302200JS.json create mode 100644 tests/files/StateTests/RandomTests/st201503302202JS.json create mode 100644 tests/files/StateTests/RandomTests/st201503302206JS.json create mode 100644 tests/files/StateTests/RandomTests/st201503302208JS.json create mode 100644 tests/files/StateTests/RandomTests/st201503302210JS.json create mode 100644 tests/files/StateTests/RandomTests/st201503302211JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504011535GO.json create mode 100644 tests/files/StateTests/RandomTests/st201504011536GO.json create mode 100644 tests/files/StateTests/RandomTests/st201504011547GO.json create mode 100644 tests/files/StateTests/RandomTests/st201504011916JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504012130JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504012259JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504012359JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504020305JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504020400JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504020428JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504020431JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504020444JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504020538JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504020639JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504020836JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504020910JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504021057JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504021104JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504021237CPPJIT.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201504021237GO.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201504021237JS.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201504021237PYTHON.json.REMOVED.git-id create mode 100644 tests/files/StateTests/RandomTests/st201504021949JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504022003CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504022124JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504030138JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504030646JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504030709JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504031133JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504031446JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504031841JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504041605JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504042052JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504042226CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504042355CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504050059JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504050733JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504051540JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504051944CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504052008CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504052014GO.json create mode 100644 tests/files/StateTests/RandomTests/st201504052031CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504060057CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504060418CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504061106CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504061134CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504062033CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504062046CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504062314CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504070746JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504070816CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504070836CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504070839CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504071041CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504071056CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504071621CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504071653CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504071750CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504071905CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504080454CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504080457CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504080650CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504080840CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504080948CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504081100CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504081134CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504081138CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504081611CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504081841JAVA.json create mode 100644 tests/files/StateTests/RandomTests/st201504081842JAVA.json create mode 100644 tests/files/StateTests/RandomTests/st201504081843JAVA.json create mode 100644 tests/files/StateTests/RandomTests/st201504081928CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504081953JAVA.json create mode 100644 tests/files/StateTests/RandomTests/st201504081954JAVA.json create mode 100644 tests/files/StateTests/RandomTests/st201504081955JAVA.json create mode 100644 tests/files/StateTests/RandomTests/st201504081956JAVA.json create mode 100644 tests/files/StateTests/RandomTests/st201504081957JAVA.json create mode 100644 tests/files/StateTests/RandomTests/st201504082000JAVA.json create mode 100644 tests/files/StateTests/RandomTests/st201504082001JAVA.json create mode 100644 tests/files/StateTests/RandomTests/st201504082002JAVA.json create mode 100644 tests/files/StateTests/RandomTests/st201504090553CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504090657CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504091403CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504091641CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504092303CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504100125CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504100215CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504100226PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201504100308CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504100337CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504100341CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504101009CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504101150CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504101223CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504101338CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504101754PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201504111554CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504130653JS.json create mode 100644 tests/files/StateTests/RandomTests/st201504131821CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504140229CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504140236CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504140359CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504140750CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504140818CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504140900CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504150854CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504151057CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504202124CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504210245CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504210957CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504211739CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504212038CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504230729CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504231639CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504231710CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504231742CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504232350CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504240140CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504240220CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504240351CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504240817CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201504241118CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201505021810CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201505050557JS.json create mode 100644 tests/files/StateTests/RandomTests/st201505050929GO.json create mode 100644 tests/files/StateTests/RandomTests/st201505050942PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201505051004PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201505051016PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201505051114GO.json create mode 100644 tests/files/StateTests/RandomTests/st201505051238GO.json create mode 100644 tests/files/StateTests/RandomTests/st201505051249GO.json create mode 100644 tests/files/StateTests/RandomTests/st201505051558PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201505051611PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201505051648JS.json create mode 100644 tests/files/StateTests/RandomTests/st201505051710GO.json create mode 100644 tests/files/StateTests/RandomTests/st201505052013GO.json create mode 100644 tests/files/StateTests/RandomTests/st201505052102JS.json create mode 100644 tests/files/StateTests/RandomTests/st201505052235GO.json create mode 100644 tests/files/StateTests/RandomTests/st201505052238JS.json create mode 100644 tests/files/StateTests/RandomTests/st201505052242PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201505052343PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201505060120GO.json create mode 100644 tests/files/StateTests/RandomTests/st201505060121GO.json create mode 100644 tests/files/StateTests/RandomTests/st201505060136PYTHON.json create mode 100644 tests/files/StateTests/RandomTests/st201505060646JS.json create mode 100644 tests/files/StateTests/RandomTests/st201505252314CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201505272131CPPJIT.json create mode 100644 tests/files/StateTests/RandomTests/st201506040034GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506040157GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506052130GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506060929GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506061255GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506062331GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506070548GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506071050GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506071624GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506071819GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506072007GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506080556GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506080721GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506091836GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506092032GO.json create mode 100644 tests/files/StateTests/RandomTests/st201506101359JS.json create mode 100644 tests/files/StateTests/RandomTests/st201507030359GO.json create mode 100644 tests/files/StateTests/stBlockHashTest.json create mode 100644 tests/files/StateTests/stCallCreateCallCodeTest.json create mode 100644 tests/files/StateTests/stExample.json create mode 100644 tests/files/StateTests/stInitCodeTest.json create mode 100644 tests/files/StateTests/stLogTests.json create mode 100644 tests/files/StateTests/stMemoryStressTest.json create mode 100644 tests/files/StateTests/stMemoryTest.json create mode 100644 tests/files/StateTests/stPreCompiledContracts.json create mode 100644 tests/files/StateTests/stQuadraticComplexityTest.json create mode 100644 tests/files/StateTests/stRecursiveCreate.json create mode 100644 tests/files/StateTests/stRefundTest.json create mode 100644 tests/files/StateTests/stSolidityTest.json create mode 100644 tests/files/StateTests/stSpecialTest.json create mode 100644 tests/files/StateTests/stSystemOperationsTest.json.REMOVED.git-id create mode 100644 tests/files/StateTests/stTransactionTest.json create mode 100644 tests/files/StateTests/stWalletTest.json create mode 100644 tests/files/TODO create mode 100644 tests/files/TransactionTests/RandomTests/tr201506052141PYTHON.json create mode 100644 tests/files/TransactionTests/tt10mbDataField.json.REMOVED.git-id create mode 100644 tests/files/TransactionTests/ttTransactionTest.json create mode 100644 tests/files/TransactionTests/ttWrongRLPTransaction.json create mode 100644 tests/files/TrieTests/hex_encoded_securetrie_test.json create mode 100644 tests/files/TrieTests/trieanyorder.json create mode 100644 tests/files/TrieTests/trieanyorder_secureTrie.json create mode 100644 tests/files/TrieTests/trietest.json create mode 100644 tests/files/TrieTests/trietest_secureTrie.json create mode 100644 tests/files/TrieTests/trietestnextprev.json create mode 100644 tests/files/VMTests/RandomTests/201503102037PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201503102148PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201503102300PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201503102320PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201503110050PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201503110206PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201503110219PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201503110226PYTHON_DUP6.json create mode 100644 tests/files/VMTests/RandomTests/201503110346PYTHON_PUSH24.json create mode 100644 tests/files/VMTests/RandomTests/201503110526PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201503111844PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201503112218PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201503120317PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201503120525PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201503120547PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201503120909PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/randomTest.json create mode 100644 tests/files/VMTests/vmArithmeticTest.json create mode 100644 tests/files/VMTests/vmBitwiseLogicOperationTest.json create mode 100644 tests/files/VMTests/vmBlockInfoTest.json create mode 100644 tests/files/VMTests/vmEnvironmentalInfoTest.json create mode 100644 tests/files/VMTests/vmIOandFlowOperationsTest.json create mode 100644 tests/files/VMTests/vmInputLimits.json.REMOVED.git-id create mode 100644 tests/files/VMTests/vmInputLimitsLight.json.REMOVED.git-id create mode 100644 tests/files/VMTests/vmLogTest.json create mode 100644 tests/files/VMTests/vmPerformanceTest.json create mode 100644 tests/files/VMTests/vmPushDupSwapTest.json create mode 100644 tests/files/VMTests/vmSha3Test.json create mode 100644 tests/files/VMTests/vmSystemOperationsTest.json create mode 100644 tests/files/VMTests/vmtests.json create mode 100644 tests/files/ansible/README.md create mode 100644 tests/files/ansible/Vagrantfile create mode 100644 tests/files/ansible/ec2-setup.yml create mode 100644 tests/files/ansible/ec2-terminate.yml create mode 100644 tests/files/ansible/ec2.ini create mode 100755 tests/files/ansible/ec2.py create mode 100644 tests/files/ansible/host-config.yml create mode 100644 tests/files/ansible/roles/common/handlers/main.yml create mode 100644 tests/files/ansible/roles/common/tasks/main.yml create mode 100644 tests/files/ansible/roles/docker/handlers/main.yml create mode 100644 tests/files/ansible/roles/docker/tasks/main.yml create mode 100644 tests/files/ansible/roles/ec2/tasks/setup.yml create mode 100644 tests/files/ansible/roles/ec2/tasks/terminate.yml create mode 100644 tests/files/ansible/roles/ec2/vars/main.yml create mode 100644 tests/files/ansible/roles/testrunner/tasks/main.yml create mode 100644 tests/files/ansible/site.yml create mode 100755 tests/files/ansible/test-files/create-docker-images.sh create mode 100644 tests/files/ansible/test-files/docker-cpp/Dockerfile create mode 100644 tests/files/ansible/test-files/docker-cppjit/Dockerfile create mode 100644 tests/files/ansible/test-files/docker-go/Dockerfile create mode 100644 tests/files/ansible/test-files/docker-python/Dockerfile create mode 100755 tests/files/ansible/test-files/testrunner.sh create mode 100644 tests/files/ansible/testrunner-config.yml create mode 100644 tests/files/index.js create mode 100644 tests/files/package.json create mode 100644 tests/init.go create mode 100644 tests/rlp_test.go create mode 100644 tests/rlp_test_util.go create mode 100644 tests/state_test.go create mode 100644 tests/state_test_util.go create mode 100644 tests/transaction_test.go create mode 100644 tests/transaction_test_util.go create mode 100644 tests/util.go create mode 100644 tests/vm_test.go create mode 100644 tests/vm_test_util.go create mode 100644 trie/cache.go create mode 100644 trie/encoding.go create mode 100644 trie/encoding_test.go create mode 100644 trie/fullnode.go create mode 100644 trie/hashnode.go create mode 100644 trie/iterator.go create mode 100644 trie/iterator_test.go create mode 100644 trie/node.go create mode 100644 trie/secure_trie.go create mode 100644 trie/shortnode.go create mode 100644 trie/slice.go create mode 100644 trie/trie.go create mode 100644 trie/trie_test.go create mode 100644 trie/valuenode.go create mode 100644 whisper/doc.go create mode 100644 whisper/envelope.go create mode 100644 whisper/envelope_test.go create mode 100644 whisper/filter.go create mode 100644 whisper/filter_test.go create mode 100644 whisper/main.go create mode 100644 whisper/message.go create mode 100644 whisper/message_test.go create mode 100644 whisper/peer.go create mode 100644 whisper/peer_test.go create mode 100644 whisper/topic.go create mode 100644 whisper/topic_test.go create mode 100644 whisper/whisper.go create mode 100644 whisper/whisper_test.go create mode 100644 xeth/frontend.go create mode 100644 xeth/state.go create mode 100644 xeth/types.go create mode 100644 xeth/whisper.go create mode 100644 xeth/whisper_filter.go create mode 100644 xeth/whisper_message.go create mode 100644 xeth/xeth.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..3b34d32c28 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +/tmp +*/**/*un~ +*/**/*.test +*un~ +.DS_Store +*/**/.DS_Store +.ethtest +*/**/*tx_database* +*/**/*dapps* +Godeps/_workspace/pkg +Godeps/_workspace/bin + +#* +.#* +*# +*~ +.project +.settings + +deploy/osx/Mist.app +deploy/osx/Mist\ Installer.dmg +cmd/mist/assets/ext/ethereum.js/ + +# used by the Makefile +/build/_workspace/ +/build/bin/ + +# travis +profile.tmp +profile.cov + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..219564eb7b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cmd/mist/assets/ext/ethereum.js"] + path = cmd/mist/assets/ext/ethereum.js + url = https://github.com/ethereum/web3.js diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000000..704d397486 --- /dev/null +++ b/.mailmap @@ -0,0 +1,61 @@ +Jeffrey Wilcke +Jeffrey Wilcke +Jeffrey Wilcke +Jeffrey Wilcke + +Viktor Trón + +Joseph Goulden + +Nick Savers + +Maran Hidskes + +Taylor Gerring +Taylor Gerring + +Bas van Kervel +Bas van Kervel +Bas van Kervel + +Sven Ehlert + +Vitalik Buterin + +Marian Oancea + +Christoph Jentzsch + +Heiko Hees + +Alex Leverington +Alex Leverington + +Zsolt Felföldi + +Gavin Wood + +Martin Becze +Martin Becze + +Dimitry Khokhlov + +Roman Mandeleil + +Alec Perseghin + +Alon Muroch + +Arkadiy Paronyan + +Jae Kwon + +Aaron Kumavis + +Nick Dodson + +Jason Carver +Jason Carver + +Joseph Chow +Joseph Chow ethers diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..2b3ff92f61 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,33 @@ +language: go +go: + - 1.4.2 +install: + # - go get code.google.com/p/go.tools/cmd/goimports + # - go get github.com/golang/lint/golint + # - go get golang.org/x/tools/cmd/vet + - go get golang.org/x/tools/cmd/cover github.com/mattn/goveralls +before_script: + # - gofmt -l -w . + # - goimports -l -w . + # - golint . + # - go vet ./... + # - go test -race ./... +script: + - make travis-test-with-coverage +after_success: + - if [ "$COVERALLS_TOKEN" ]; then goveralls -coverprofile=profile.cov -service=travis-ci -repotoken $COVERALLS_TOKEN; fi +env: + global: + - secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64=" +sudo: false +addons: + apt: + packages: + - libgmp3-dev +notifications: + webhooks: + urls: + - https://webhooks.gitter.im/e/e09ccdce1048c5e03445 + on_success: change + on_failure: always + on_start: false diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000..0c5b547d7a --- /dev/null +++ b/AUTHORS @@ -0,0 +1,24 @@ +# This is the official list of go-ethereum authors for copyright purposes. + +Alex Leverington +Alexandre Van de Sande +Bas van Kervel +Daniel A. Nagy +Ethan Buchman +Fabian Vogelsteller +Felix Lange +Gustav Simonsson +Jae Kwon +Jason Carver +Jeffrey Wilcke +Joseph Chow +Kobi Gurkan +Maran Hidskes +Marek Kotewicz +Matthew Wampler-Doty +Nick Dodson +Péter Szilágyi +Taylor Gerring +Viktor Trón +Vitalik Buterin +Zsolt Felföldi diff --git a/COPYING b/COPYING new file mode 100644 index 0000000000..8d66e87723 --- /dev/null +++ b/COPYING @@ -0,0 +1,619 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2014 The go-ethereum Authors. + 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. \ No newline at end of file diff --git a/COPYING.LESSER b/COPYING.LESSER new file mode 100644 index 0000000000..65c5ca88a6 --- /dev/null +++ b/COPYING.LESSER @@ -0,0 +1,165 @@ + GNU LESSER 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. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser 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 +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json new file mode 100644 index 0000000000..199914baa4 --- /dev/null +++ b/Godeps/Godeps.json @@ -0,0 +1,127 @@ +{ + "ImportPath": "github.com/ethereum/go-ethereum", + "GoVersion": "go1.4", + "Packages": [ + "./..." + ], + "Deps": [ + { + "ImportPath": "code.google.com/p/go-uuid/uuid", + "Comment": "null-12", + "Rev": "7dda39b2e7d5e265014674c5af696ba4186679e9" + }, + { + "ImportPath": "github.com/codegangsta/cli", + "Comment": "1.2.0-95-g9b2bd2b", + "Rev": "9b2bd2b3489748d4d0a204fa4eb2ee9e89e0ebc6" + }, + { + "ImportPath": "github.com/davecgh/go-spew/spew", + "Rev": "3e6e67c4dcea3ac2f25fd4731abc0e1deaf36216" + }, + { + "ImportPath": "github.com/ethereum/ethash", + "Comment": "v23.1-227-g8f6ccaa", + "Rev": "8f6ccaaef9b418553807a73a95cb5f49cd3ea39f" + }, + { + "ImportPath": "github.com/gizak/termui", + "Rev": "bab8dce01c193d82bc04888a0a9a7814d505f532" + }, + { + "ImportPath": "github.com/howeyc/fsnotify", + "Comment": "v0.9.0-11-g6b1ef89", + "Rev": "6b1ef893dc11e0447abda6da20a5203481878dda" + }, + { + "ImportPath": "github.com/huin/goupnp", + "Rev": "5cff77a69fb22f5f1774c4451ea2aab63d4d2f20" + }, + { + "ImportPath": "github.com/jackpal/go-nat-pmp", + "Rev": "a45aa3d54aef73b504e15eb71bea0e5565b5e6e1" + }, + { + "ImportPath": "github.com/kardianos/osext", + "Rev": "ccfcd0245381f0c94c68f50626665eed3c6b726a" + }, + { + "ImportPath": "github.com/mattn/go-colorable", + "Rev": "043ae16291351db8465272edf465c9f388161627" + }, + { + "ImportPath": "github.com/mattn/go-isatty", + "Rev": "fdbe02a1b44e75977b2690062b83cf507d70c013" + }, + { + "ImportPath": "github.com/mattn/go-runewidth", + "Comment": "travisish-33-g5890272", + "Rev": "5890272cd41c5103531cd7b79e428d99c9e97f76" + }, + { + "ImportPath": "github.com/nsf/termbox-go", + "Rev": "675ffd907b7401b8a709a5ef2249978af5616bb2" + }, + { + "ImportPath": "github.com/peterh/liner", + "Rev": "29f6a646557d83e2b6e9ba05c45fbea9c006dbe8" + }, + { + "ImportPath": "github.com/rcrowley/go-metrics", + "Rev": "a5cfc242a56ba7fa70b785f678d6214837bf93b9" + }, + { + "ImportPath": "github.com/robertkrimen/otto", + "Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba" + }, + { + "ImportPath": "github.com/rs/cors", + "Rev": "6e0c3cb65fc0fdb064c743d176a620e3ca446dfb" + }, + { + "ImportPath": "github.com/syndtr/goleveldb/leveldb", + "Rev": "4875955338b0a434238a31165cb87255ab6e9e4a" + }, + { + "ImportPath": "github.com/syndtr/gosnappy/snappy", + "Rev": "156a073208e131d7d2e212cb749feae7c339e846" + }, + { + "ImportPath": "golang.org/x/crypto/pbkdf2", + "Rev": "4ed45ec682102c643324fae5dff8dab085b6c300" + }, + { + "ImportPath": "golang.org/x/crypto/ripemd160", + "Rev": "4ed45ec682102c643324fae5dff8dab085b6c300" + }, + { + "ImportPath": "golang.org/x/crypto/scrypt", + "Rev": "4ed45ec682102c643324fae5dff8dab085b6c300" + }, + { + "ImportPath": "golang.org/x/net/html", + "Rev": "e0403b4e005737430c05a57aac078479844f919c" + }, + { + "ImportPath": "golang.org/x/text/encoding", + "Rev": "c93e7c9fff19fb9139b5ab04ce041833add0134e" + }, + { + "ImportPath": "golang.org/x/text/transform", + "Rev": "c93e7c9fff19fb9139b5ab04ce041833add0134e" + }, + { + "ImportPath": "gopkg.in/check.v1", + "Rev": "64131543e7896d5bcc6bd5a76287eb75ea96c673" + }, + { + "ImportPath": "gopkg.in/fatih/set.v0", + "Comment": "v0.1.0-3-g27c4092", + "Rev": "27c40922c40b43fe04554d8223a402af3ea333f3" + }, + { + "ImportPath": "gopkg.in/karalabe/cookiejar.v2/collections/prque", + "Rev": "8dcd6a7f4951f6ff3ee9cbb919a06d8925822e57" + } + ] +} diff --git a/Godeps/Readme b/Godeps/Readme new file mode 100644 index 0000000000..4cdaa53d56 --- /dev/null +++ b/Godeps/Readme @@ -0,0 +1,5 @@ +This directory tree is generated automatically by godep. + +Please do not edit. + +See https://github.com/tools/godep for more information. diff --git a/Godeps/_workspace/.gitignore b/Godeps/_workspace/.gitignore new file mode 100644 index 0000000000..f037d684ef --- /dev/null +++ b/Godeps/_workspace/.gitignore @@ -0,0 +1,2 @@ +/pkg +/bin diff --git a/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/LICENSE b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/LICENSE new file mode 100644 index 0000000000..ab6b011a10 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 Google Inc. 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/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/dce.go b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/dce.go new file mode 100644 index 0000000000..50a0f2d099 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/dce.go @@ -0,0 +1,84 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" + "fmt" + "os" +) + +// A Domain represents a Version 2 domain +type Domain byte + +// Domain constants for DCE Security (Version 2) UUIDs. +const ( + Person = Domain(0) + Group = Domain(1) + Org = Domain(2) +) + +// NewDCESecurity returns a DCE Security (Version 2) UUID. +// +// The domain should be one of Person, Group or Org. +// On a POSIX system the id should be the users UID for the Person +// domain and the users GID for the Group. The meaning of id for +// the domain Org or on non-POSIX systems is site defined. +// +// For a given domain/id pair the same token may be returned for up to +// 7 minutes and 10 seconds. +func NewDCESecurity(domain Domain, id uint32) UUID { + uuid := NewUUID() + if uuid != nil { + uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 + uuid[9] = byte(domain) + binary.BigEndian.PutUint32(uuid[0:], id) + } + return uuid +} + +// NewDCEPerson returns a DCE Security (Version 2) UUID in the person +// domain with the id returned by os.Getuid. +// +// NewDCEPerson(Person, uint32(os.Getuid())) +func NewDCEPerson() UUID { + return NewDCESecurity(Person, uint32(os.Getuid())) +} + +// NewDCEGroup returns a DCE Security (Version 2) UUID in the group +// domain with the id returned by os.Getgid. +// +// NewDCEGroup(Group, uint32(os.Getgid())) +func NewDCEGroup() UUID { + return NewDCESecurity(Group, uint32(os.Getgid())) +} + +// Domain returns the domain for a Version 2 UUID or false. +func (uuid UUID) Domain() (Domain, bool) { + if v, _ := uuid.Version(); v != 2 { + return 0, false + } + return Domain(uuid[9]), true +} + +// Id returns the id for a Version 2 UUID or false. +func (uuid UUID) Id() (uint32, bool) { + if v, _ := uuid.Version(); v != 2 { + return 0, false + } + return binary.BigEndian.Uint32(uuid[0:4]), true +} + +func (d Domain) String() string { + switch d { + case Person: + return "Person" + case Group: + return "Group" + case Org: + return "Org" + } + return fmt.Sprintf("Domain%d", int(d)) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/doc.go b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/doc.go new file mode 100644 index 0000000000..d8bd013e68 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/doc.go @@ -0,0 +1,8 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The uuid package generates and inspects UUIDs. +// +// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security Services. +package uuid diff --git a/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/hash.go b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/hash.go new file mode 100644 index 0000000000..cdd4192fd9 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/hash.go @@ -0,0 +1,53 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "crypto/md5" + "crypto/sha1" + "hash" +) + +// Well known Name Space IDs and UUIDs +var ( + NameSpace_DNS = Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + NameSpace_URL = Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8") + NameSpace_OID = Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8") + NameSpace_X500 = Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8") + NIL = Parse("00000000-0000-0000-0000-000000000000") +) + +// NewHash returns a new UUID dervied from the hash of space concatenated with +// data generated by h. The hash should be at least 16 byte in length. The +// first 16 bytes of the hash are used to form the UUID. The version of the +// UUID will be the lower 4 bits of version. NewHash is used to implement +// NewMD5 and NewSHA1. +func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { + h.Reset() + h.Write(space) + h.Write([]byte(data)) + s := h.Sum(nil) + uuid := make([]byte, 16) + copy(uuid, s) + uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) + uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant + return uuid +} + +// NewMD5 returns a new MD5 (Version 3) UUID based on the +// supplied name space and data. +// +// NewHash(md5.New(), space, data, 3) +func NewMD5(space UUID, data []byte) UUID { + return NewHash(md5.New(), space, data, 3) +} + +// NewSHA1 returns a new SHA1 (Version 5) UUID based on the +// supplied name space and data. +// +// NewHash(sha1.New(), space, data, 5) +func NewSHA1(space UUID, data []byte) UUID { + return NewHash(sha1.New(), space, data, 5) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/node.go b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/node.go new file mode 100644 index 0000000000..dd0a8ac189 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/node.go @@ -0,0 +1,101 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import "net" + +var ( + interfaces []net.Interface // cached list of interfaces + ifname string // name of interface being used + nodeID []byte // hardware for version 1 UUIDs +) + +// NodeInterface returns the name of the interface from which the NodeID was +// derived. The interface "user" is returned if the NodeID was set by +// SetNodeID. +func NodeInterface() string { + return ifname +} + +// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. +// If name is "" then the first usable interface found will be used or a random +// Node ID will be generated. If a named interface cannot be found then false +// is returned. +// +// SetNodeInterface never fails when name is "". +func SetNodeInterface(name string) bool { + if interfaces == nil { + var err error + interfaces, err = net.Interfaces() + if err != nil && name != "" { + return false + } + } + + for _, ifs := range interfaces { + if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { + if setNodeID(ifs.HardwareAddr) { + ifname = ifs.Name + return true + } + } + } + + // We found no interfaces with a valid hardware address. If name + // does not specify a specific interface generate a random Node ID + // (section 4.1.6) + if name == "" { + if nodeID == nil { + nodeID = make([]byte, 6) + } + randomBits(nodeID) + return true + } + return false +} + +// NodeID returns a slice of a copy of the current Node ID, setting the Node ID +// if not already set. +func NodeID() []byte { + if nodeID == nil { + SetNodeInterface("") + } + nid := make([]byte, 6) + copy(nid, nodeID) + return nid +} + +// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes +// of id are used. If id is less than 6 bytes then false is returned and the +// Node ID is not set. +func SetNodeID(id []byte) bool { + if setNodeID(id) { + ifname = "user" + return true + } + return false +} + +func setNodeID(id []byte) bool { + if len(id) < 6 { + return false + } + if nodeID == nil { + nodeID = make([]byte, 6) + } + copy(nodeID, id) + return true +} + +// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is +// not valid. The NodeID is only well defined for version 1 and 2 UUIDs. +func (uuid UUID) NodeID() []byte { + if len(uuid) != 16 { + return nil + } + node := make([]byte, 6) + copy(node, uuid[10:]) + return node +} diff --git a/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/time.go b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/time.go new file mode 100644 index 0000000000..b9369c200b --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/time.go @@ -0,0 +1,132 @@ +// Copyright 2014 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" + "sync" + "time" +) + +// A Time represents a time as the number of 100's of nanoseconds since 15 Oct +// 1582. +type Time int64 + +const ( + lillian = 2299160 // Julian day of 15 Oct 1582 + unix = 2440587 // Julian day of 1 Jan 1970 + epoch = unix - lillian // Days between epochs + g1582 = epoch * 86400 // seconds between epochs + g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs +) + +var ( + mu sync.Mutex + lasttime uint64 // last time we returned + clock_seq uint16 // clock sequence for this run + + timeNow = time.Now // for testing +) + +// UnixTime converts t the number of seconds and nanoseconds using the Unix +// epoch of 1 Jan 1970. +func (t Time) UnixTime() (sec, nsec int64) { + sec = int64(t - g1582ns100) + nsec = (sec % 10000000) * 100 + sec /= 10000000 + return sec, nsec +} + +// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and +// adjusts the clock sequence as needed. An error is returned if the current +// time cannot be determined. +func GetTime() (Time, error) { + defer mu.Unlock() + mu.Lock() + return getTime() +} + +func getTime() (Time, error) { + t := timeNow() + + // If we don't have a clock sequence already, set one. + if clock_seq == 0 { + setClockSequence(-1) + } + now := uint64(t.UnixNano()/100) + g1582ns100 + + // If time has gone backwards with this clock sequence then we + // increment the clock sequence + if now <= lasttime { + clock_seq = ((clock_seq + 1) & 0x3fff) | 0x8000 + } + lasttime = now + return Time(now), nil +} + +// ClockSequence returns the current clock sequence, generating one if not +// already set. The clock sequence is only used for Version 1 UUIDs. +// +// The uuid package does not use global static storage for the clock sequence or +// the last time a UUID was generated. Unless SetClockSequence a new random +// clock sequence is generated the first time a clock sequence is requested by +// ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated +// for +func ClockSequence() int { + defer mu.Unlock() + mu.Lock() + return clockSequence() +} + +func clockSequence() int { + if clock_seq == 0 { + setClockSequence(-1) + } + return int(clock_seq & 0x3fff) +} + +// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to +// -1 causes a new sequence to be generated. +func SetClockSequence(seq int) { + defer mu.Unlock() + mu.Lock() + setClockSequence(seq) +} + +func setClockSequence(seq int) { + if seq == -1 { + var b [2]byte + randomBits(b[:]) // clock sequence + seq = int(b[0])<<8 | int(b[1]) + } + old_seq := clock_seq + clock_seq = uint16(seq&0x3fff) | 0x8000 // Set our variant + if old_seq != clock_seq { + lasttime = 0 + } +} + +// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in +// uuid. It returns false if uuid is not valid. The time is only well defined +// for version 1 and 2 UUIDs. +func (uuid UUID) Time() (Time, bool) { + if len(uuid) != 16 { + return 0, false + } + time := int64(binary.BigEndian.Uint32(uuid[0:4])) + time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 + time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 + return Time(time), true +} + +// ClockSequence returns the clock sequence encoded in uuid. It returns false +// if uuid is not valid. The clock sequence is only well defined for version 1 +// and 2 UUIDs. +func (uuid UUID) ClockSequence() (int, bool) { + if len(uuid) != 16 { + return 0, false + } + return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff, true +} diff --git a/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/util.go b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/util.go new file mode 100644 index 0000000000..de40b102c4 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/util.go @@ -0,0 +1,43 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "io" +) + +// randomBits completely fills slice b with random data. +func randomBits(b []byte) { + if _, err := io.ReadFull(rander, b); err != nil { + panic(err.Error()) // rand should never fail + } +} + +// xvalues returns the value of a byte as a hexadecimal digit or 255. +var xvalues = []byte{ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +} + +// xtob converts the the first two hex bytes of x into a byte. +func xtob(x string) (byte, bool) { + b1 := xvalues[x[0]] + b2 := xvalues[x[1]] + return (b1 << 4) | b2, b1 != 255 && b2 != 255 +} diff --git a/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid.go b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid.go new file mode 100644 index 0000000000..2920fae632 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid.go @@ -0,0 +1,163 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "bytes" + "crypto/rand" + "fmt" + "io" + "strings" +) + +// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC +// 4122. +type UUID []byte + +// A Version represents a UUIDs version. +type Version byte + +// A Variant represents a UUIDs variant. +type Variant byte + +// Constants returned by Variant. +const ( + Invalid = Variant(iota) // Invalid UUID + RFC4122 // The variant specified in RFC4122 + Reserved // Reserved, NCS backward compatibility. + Microsoft // Reserved, Microsoft Corporation backward compatibility. + Future // Reserved for future definition. +) + +var rander = rand.Reader // random function + +// New returns a new random (version 4) UUID as a string. It is a convenience +// function for NewRandom().String(). +func New() string { + return NewRandom().String() +} + +// Parse decodes s into a UUID or returns nil. Both the UUID form of +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded. +func Parse(s string) UUID { + if len(s) == 36+9 { + if strings.ToLower(s[:9]) != "urn:uuid:" { + return nil + } + s = s[9:] + } else if len(s) != 36 { + return nil + } + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return nil + } + uuid := make([]byte, 16) + for i, x := range []int{ + 0, 2, 4, 6, + 9, 11, + 14, 16, + 19, 21, + 24, 26, 28, 30, 32, 34} { + if v, ok := xtob(s[x:]); !ok { + return nil + } else { + uuid[i] = v + } + } + return uuid +} + +// Equal returns true if uuid1 and uuid2 are equal. +func Equal(uuid1, uuid2 UUID) bool { + return bytes.Equal(uuid1, uuid2) +} + +// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// , or "" if uuid is invalid. +func (uuid UUID) String() string { + if uuid == nil || len(uuid) != 16 { + return "" + } + b := []byte(uuid) + return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", + b[:4], b[4:6], b[6:8], b[8:10], b[10:]) +} + +// URN returns the RFC 2141 URN form of uuid, +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. +func (uuid UUID) URN() string { + if uuid == nil || len(uuid) != 16 { + return "" + } + b := []byte(uuid) + return fmt.Sprintf("urn:uuid:%08x-%04x-%04x-%04x-%012x", + b[:4], b[4:6], b[6:8], b[8:10], b[10:]) +} + +// Variant returns the variant encoded in uuid. It returns Invalid if +// uuid is invalid. +func (uuid UUID) Variant() Variant { + if len(uuid) != 16 { + return Invalid + } + switch { + case (uuid[8] & 0xc0) == 0x80: + return RFC4122 + case (uuid[8] & 0xe0) == 0xc0: + return Microsoft + case (uuid[8] & 0xe0) == 0xe0: + return Future + default: + return Reserved + } + panic("unreachable") +} + +// Version returns the verison of uuid. It returns false if uuid is not +// valid. +func (uuid UUID) Version() (Version, bool) { + if len(uuid) != 16 { + return 0, false + } + return Version(uuid[6] >> 4), true +} + +func (v Version) String() string { + if v > 15 { + return fmt.Sprintf("BAD_VERSION_%d", v) + } + return fmt.Sprintf("VERSION_%d", v) +} + +func (v Variant) String() string { + switch v { + case RFC4122: + return "RFC4122" + case Reserved: + return "Reserved" + case Microsoft: + return "Microsoft" + case Future: + return "Future" + case Invalid: + return "Invalid" + } + return fmt.Sprintf("BadVariant%d", int(v)) +} + +// SetRand sets the random number generator to r, which implents io.Reader. +// If r.Read returns an error when the package requests random data then +// a panic will be issued. +// +// Calling SetRand with nil sets the random number generator to the default +// generator. +func SetRand(r io.Reader) { + if r == nil { + rander = rand.Reader + return + } + rander = r +} diff --git a/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid_test.go b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid_test.go new file mode 100644 index 0000000000..417ebeb26a --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid_test.go @@ -0,0 +1,390 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "bytes" + "fmt" + "os" + "strings" + "testing" + "time" +) + +type test struct { + in string + version Version + variant Variant + isuuid bool +} + +var tests = []test{ + {"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true}, + {"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true}, + {"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true}, + {"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true}, + {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, + {"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true}, + {"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true}, + {"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true}, + {"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true}, + {"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true}, + {"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true}, + {"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true}, + {"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true}, + {"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true}, + {"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true}, + {"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true}, + + {"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, + {"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, + {"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, + {"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true}, + {"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true}, + {"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true}, + {"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true}, + {"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true}, + {"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true}, + {"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true}, + {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, + {"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true}, + {"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true}, + {"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true}, + {"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true}, + {"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true}, + {"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true}, + {"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true}, + + {"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false}, + {"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false}, + {"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false}, + {"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false}, + {"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false}, + {"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false}, +} + +var constants = []struct { + c interface{} + name string +}{ + {Person, "Person"}, + {Group, "Group"}, + {Org, "Org"}, + {Invalid, "Invalid"}, + {RFC4122, "RFC4122"}, + {Reserved, "Reserved"}, + {Microsoft, "Microsoft"}, + {Future, "Future"}, + {Domain(17), "Domain17"}, + {Variant(42), "BadVariant42"}, +} + +func testTest(t *testing.T, in string, tt test) { + uuid := Parse(in) + if ok := (uuid != nil); ok != tt.isuuid { + t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid) + } + if uuid == nil { + return + } + + if v := uuid.Variant(); v != tt.variant { + t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant) + } + if v, _ := uuid.Version(); v != tt.version { + t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version) + } +} + +func TestUUID(t *testing.T) { + for _, tt := range tests { + testTest(t, tt.in, tt) + testTest(t, strings.ToUpper(tt.in), tt) + } +} + +func TestConstants(t *testing.T) { + for x, tt := range constants { + v, ok := tt.c.(fmt.Stringer) + if !ok { + t.Errorf("%x: %v: not a stringer", x, v) + } else if s := v.String(); s != tt.name { + v, _ := tt.c.(int) + t.Errorf("%x: Constant %T:%d gives %q, expected %q\n", x, tt.c, v, s, tt.name) + } + } +} + +func TestRandomUUID(t *testing.T) { + m := make(map[string]bool) + for x := 1; x < 32; x++ { + uuid := NewRandom() + s := uuid.String() + if m[s] { + t.Errorf("NewRandom returned duplicated UUID %s\n", s) + } + m[s] = true + if v, _ := uuid.Version(); v != 4 { + t.Errorf("Random UUID of version %s\n", v) + } + if uuid.Variant() != RFC4122 { + t.Errorf("Random UUID is variant %d\n", uuid.Variant()) + } + } +} + +func TestNew(t *testing.T) { + m := make(map[string]bool) + for x := 1; x < 32; x++ { + s := New() + if m[s] { + t.Errorf("New returned duplicated UUID %s\n", s) + } + m[s] = true + uuid := Parse(s) + if uuid == nil { + t.Errorf("New returned %q which does not decode\n", s) + continue + } + if v, _ := uuid.Version(); v != 4 { + t.Errorf("Random UUID of version %s\n", v) + } + if uuid.Variant() != RFC4122 { + t.Errorf("Random UUID is variant %d\n", uuid.Variant()) + } + } +} + +func clockSeq(t *testing.T, uuid UUID) int { + seq, ok := uuid.ClockSequence() + if !ok { + t.Fatalf("%s: invalid clock sequence\n", uuid) + } + return seq +} + +func TestClockSeq(t *testing.T) { + // Fake time.Now for this test to return a monotonically advancing time; restore it at end. + defer func(orig func() time.Time) { timeNow = orig }(timeNow) + monTime := time.Now() + timeNow = func() time.Time { + monTime = monTime.Add(1 * time.Second) + return monTime + } + + SetClockSequence(-1) + uuid1 := NewUUID() + uuid2 := NewUUID() + + if clockSeq(t, uuid1) != clockSeq(t, uuid2) { + t.Errorf("clock sequence %d != %d\n", clockSeq(t, uuid1), clockSeq(t, uuid2)) + } + + SetClockSequence(-1) + uuid2 = NewUUID() + + // Just on the very off chance we generated the same sequence + // two times we try again. + if clockSeq(t, uuid1) == clockSeq(t, uuid2) { + SetClockSequence(-1) + uuid2 = NewUUID() + } + if clockSeq(t, uuid1) == clockSeq(t, uuid2) { + t.Errorf("Duplicate clock sequence %d\n", clockSeq(t, uuid1)) + } + + SetClockSequence(0x1234) + uuid1 = NewUUID() + if seq := clockSeq(t, uuid1); seq != 0x1234 { + t.Errorf("%s: expected seq 0x1234 got 0x%04x\n", uuid1, seq) + } +} + +func TestCoding(t *testing.T) { + text := "7d444840-9dc0-11d1-b245-5ffdce74fad2" + urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2" + data := UUID{ + 0x7d, 0x44, 0x48, 0x40, + 0x9d, 0xc0, + 0x11, 0xd1, + 0xb2, 0x45, + 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, + } + if v := data.String(); v != text { + t.Errorf("%x: encoded to %s, expected %s\n", data, v, text) + } + if v := data.URN(); v != urn { + t.Errorf("%x: urn is %s, expected %s\n", data, v, urn) + } + + uuid := Parse(text) + if !Equal(uuid, data) { + t.Errorf("%s: decoded to %s, expected %s\n", text, uuid, data) + } +} + +func TestVersion1(t *testing.T) { + uuid1 := NewUUID() + uuid2 := NewUUID() + + if Equal(uuid1, uuid2) { + t.Errorf("%s:duplicate uuid\n", uuid1) + } + if v, _ := uuid1.Version(); v != 1 { + t.Errorf("%s: version %s expected 1\n", uuid1, v) + } + if v, _ := uuid2.Version(); v != 1 { + t.Errorf("%s: version %s expected 1\n", uuid2, v) + } + n1 := uuid1.NodeID() + n2 := uuid2.NodeID() + if !bytes.Equal(n1, n2) { + t.Errorf("Different nodes %x != %x\n", n1, n2) + } + t1, ok := uuid1.Time() + if !ok { + t.Errorf("%s: invalid time\n", uuid1) + } + t2, ok := uuid2.Time() + if !ok { + t.Errorf("%s: invalid time\n", uuid2) + } + q1, ok := uuid1.ClockSequence() + if !ok { + t.Errorf("%s: invalid clock sequence\n", uuid1) + } + q2, ok := uuid2.ClockSequence() + if !ok { + t.Errorf("%s: invalid clock sequence", uuid2) + } + + switch { + case t1 == t2 && q1 == q2: + t.Errorf("time stopped\n") + case t1 > t2 && q1 == q2: + t.Errorf("time reversed\n") + case t1 < t2 && q1 != q2: + t.Errorf("clock sequence chaned unexpectedly\n") + } +} + +func TestNodeAndTime(t *testing.T) { + // Time is February 5, 1998 12:30:23.136364800 AM GMT + + uuid := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2") + node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2} + + ts, ok := uuid.Time() + if ok { + c := time.Unix(ts.UnixTime()) + want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC) + if !c.Equal(want) { + t.Errorf("Got time %v, want %v", c, want) + } + } else { + t.Errorf("%s: bad time\n", uuid) + } + if !bytes.Equal(node, uuid.NodeID()) { + t.Errorf("Expected node %v got %v\n", node, uuid.NodeID()) + } +} + +func TestMD5(t *testing.T) { + uuid := NewMD5(NameSpace_DNS, []byte("python.org")).String() + want := "6fa459ea-ee8a-3ca4-894e-db77e160355e" + if uuid != want { + t.Errorf("MD5: got %q expected %q\n", uuid, want) + } +} + +func TestSHA1(t *testing.T) { + uuid := NewSHA1(NameSpace_DNS, []byte("python.org")).String() + want := "886313e1-3b8a-5372-9b90-0c9aee199e5d" + if uuid != want { + t.Errorf("SHA1: got %q expected %q\n", uuid, want) + } +} + +func TestNodeID(t *testing.T) { + nid := []byte{1, 2, 3, 4, 5, 6} + SetNodeInterface("") + s := NodeInterface() + if s == "" || s == "user" { + t.Errorf("NodeInterface %q after SetInteface\n", s) + } + node1 := NodeID() + if node1 == nil { + t.Errorf("NodeID nil after SetNodeInterface\n", s) + } + SetNodeID(nid) + s = NodeInterface() + if s != "user" { + t.Errorf("Expected NodeInterface %q got %q\n", "user", s) + } + node2 := NodeID() + if node2 == nil { + t.Errorf("NodeID nil after SetNodeID\n", s) + } + if bytes.Equal(node1, node2) { + t.Errorf("NodeID not changed after SetNodeID\n", s) + } else if !bytes.Equal(nid, node2) { + t.Errorf("NodeID is %x, expected %x\n", node2, nid) + } +} + +func testDCE(t *testing.T, name string, uuid UUID, domain Domain, id uint32) { + if uuid == nil { + t.Errorf("%s failed\n", name) + return + } + if v, _ := uuid.Version(); v != 2 { + t.Errorf("%s: %s: expected version 2, got %s\n", name, uuid, v) + return + } + if v, ok := uuid.Domain(); !ok || v != domain { + if !ok { + t.Errorf("%s: %d: Domain failed\n", name, uuid) + } else { + t.Errorf("%s: %s: expected domain %d, got %d\n", name, uuid, domain, v) + } + } + if v, ok := uuid.Id(); !ok || v != id { + if !ok { + t.Errorf("%s: %d: Id failed\n", name, uuid) + } else { + t.Errorf("%s: %s: expected id %d, got %d\n", name, uuid, id, v) + } + } +} + +func TestDCE(t *testing.T) { + testDCE(t, "NewDCESecurity", NewDCESecurity(42, 12345678), 42, 12345678) + testDCE(t, "NewDCEPerson", NewDCEPerson(), Person, uint32(os.Getuid())) + testDCE(t, "NewDCEGroup", NewDCEGroup(), Group, uint32(os.Getgid())) +} + +type badRand struct{} + +func (r badRand) Read(buf []byte) (int, error) { + for i, _ := range buf { + buf[i] = byte(i) + } + return len(buf), nil +} + +func TestBadRand(t *testing.T) { + SetRand(badRand{}) + uuid1 := New() + uuid2 := New() + if uuid1 != uuid2 { + t.Errorf("execpted duplicates, got %q and %q\n", uuid1, uuid2) + } + SetRand(nil) + uuid1 = New() + uuid2 = New() + if uuid1 == uuid2 { + t.Errorf("unexecpted duplicates, got %q\n", uuid1) + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version1.go b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version1.go new file mode 100644 index 0000000000..63580044b6 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version1.go @@ -0,0 +1,41 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" +) + +// NewUUID returns a Version 1 UUID based on the current NodeID and clock +// sequence, and the current time. If the NodeID has not been set by SetNodeID +// or SetNodeInterface then it will be set automatically. If the NodeID cannot +// be set NewUUID returns nil. If clock sequence has not been set by +// SetClockSequence then it will be set automatically. If GetTime fails to +// return the current NewUUID returns nil. +func NewUUID() UUID { + if nodeID == nil { + SetNodeInterface("") + } + + now, err := GetTime() + if err != nil { + return nil + } + + uuid := make([]byte, 16) + + time_low := uint32(now & 0xffffffff) + time_mid := uint16((now >> 32) & 0xffff) + time_hi := uint16((now >> 48) & 0x0fff) + time_hi |= 0x1000 // Version 1 + + binary.BigEndian.PutUint32(uuid[0:], time_low) + binary.BigEndian.PutUint16(uuid[4:], time_mid) + binary.BigEndian.PutUint16(uuid[6:], time_hi) + binary.BigEndian.PutUint16(uuid[8:], clock_seq) + copy(uuid[10:], nodeID) + + return uuid +} diff --git a/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version4.go b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version4.go new file mode 100644 index 0000000000..b3d4a368dd --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version4.go @@ -0,0 +1,25 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +// Random returns a Random (Version 4) UUID or panics. +// +// The strength of the UUIDs is based on the strength of the crypto/rand +// package. +// +// A note about uniqueness derived from from the UUID Wikipedia entry: +// +// Randomly generated UUIDs have 122 random bits. One's annual risk of being +// hit by a meteorite is estimated to be one chance in 17 billion, that +// means the probability is about 0.00000000006 (6 × 10−11), +// equivalent to the odds of creating a few tens of trillions of UUIDs in a +// year and having one duplicate. +func NewRandom() UUID { + uuid := make([]byte, 16) + randomBits([]byte(uuid)) + uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 + uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 + return uuid +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml b/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml new file mode 100644 index 0000000000..baf46abc6f --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml @@ -0,0 +1,6 @@ +language: go +go: 1.1 + +script: +- go vet ./... +- go test -v ./... diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE b/Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE new file mode 100644 index 0000000000..5515ccfb71 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE @@ -0,0 +1,21 @@ +Copyright (C) 2013 Jeremy Saenz +All Rights Reserved. + +MIT LICENSE + +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/Godeps/_workspace/src/github.com/codegangsta/cli/README.md b/Godeps/_workspace/src/github.com/codegangsta/cli/README.md new file mode 100644 index 0000000000..4b3ddb0a30 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/README.md @@ -0,0 +1,298 @@ +[![Build Status](https://travis-ci.org/codegangsta/cli.png?branch=master)](https://travis-ci.org/codegangsta/cli) + +# cli.go +cli.go is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way. + +You can view the API docs here: +http://godoc.org/github.com/codegangsta/cli + +## Overview +Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app. + +**This is where cli.go comes into play.** cli.go makes command line programming fun, organized, and expressive! + +## Installation +Make sure you have a working Go environment (go 1.1 is *required*). [See the install instructions](http://golang.org/doc/install.html). + +To install `cli.go`, simply run: +``` +$ go get github.com/codegangsta/cli +``` + +Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands can be easily used: +``` +export PATH=$PATH:$GOPATH/bin +``` + +## Getting Started +One of the philosophies behind cli.go is that an API should be playful and full of discovery. So a cli.go app can be as little as one line of code in `main()`. + +``` go +package main + +import ( + "os" + "github.com/codegangsta/cli" +) + +func main() { + cli.NewApp().Run(os.Args) +} +``` + +This app will run and show help text, but is not very useful. Let's give an action to execute and some help documentation: + +``` go +package main + +import ( + "os" + "github.com/codegangsta/cli" +) + +func main() { + app := cli.NewApp() + app.Name = "boom" + app.Usage = "make an explosive entrance" + app.Action = func(c *cli.Context) { + println("boom! I say!") + } + + app.Run(os.Args) +} +``` + +Running this already gives you a ton of functionality, plus support for things like subcommands and flags, which are covered below. + +## Example + +Being a programmer can be a lonely job. Thankfully by the power of automation that is not the case! Let's create a greeter app to fend off our demons of loneliness! + +Start by creating a directory named `greet`, and within it, add a file, `greet.go` with the following code in it: + +``` go +package main + +import ( + "os" + "github.com/codegangsta/cli" +) + +func main() { + app := cli.NewApp() + app.Name = "greet" + app.Usage = "fight the loneliness!" + app.Action = func(c *cli.Context) { + println("Hello friend!") + } + + app.Run(os.Args) +} +``` + +Install our command to the `$GOPATH/bin` directory: + +``` +$ go install +``` + +Finally run our new command: + +``` +$ greet +Hello friend! +``` + +cli.go also generates some bitchass help text: +``` +$ greet help +NAME: + greet - fight the loneliness! + +USAGE: + greet [global options] command [command options] [arguments...] + +VERSION: + 0.0.0 + +COMMANDS: + help, h Shows a list of commands or help for one command + +GLOBAL OPTIONS + --version Shows version information +``` + +### Arguments +You can lookup arguments by calling the `Args` function on `cli.Context`. + +``` go +... +app.Action = func(c *cli.Context) { + println("Hello", c.Args()[0]) +} +... +``` + +### Flags +Setting and querying flags is simple. +``` go +... +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + }, +} +app.Action = func(c *cli.Context) { + name := "someone" + if len(c.Args()) > 0 { + name = c.Args()[0] + } + if c.String("lang") == "spanish" { + println("Hola", name) + } else { + println("Hello", name) + } +} +... +``` + +#### Alternate Names + +You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g. + +``` go +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + }, +} +``` + +That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error. + +#### Values from the Environment + +You can also have the default value set from the environment via `EnvVar`. e.g. + +``` go +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + EnvVar: "APP_LANG", + }, +} +``` + +The `EnvVar` may also be given as a comma-delimited "cascade", where the first environment variable that resolves is used as the default. + +``` go +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG", + }, +} +``` + +### Subcommands + +Subcommands can be defined for a more git-like command line app. +```go +... +app.Commands = []cli.Command{ + { + Name: "add", + Aliases: []string{"a"}, + Usage: "add a task to the list", + Action: func(c *cli.Context) { + println("added task: ", c.Args().First()) + }, + }, + { + Name: "complete", + Aliases: []string{"c"}, + Usage: "complete a task on the list", + Action: func(c *cli.Context) { + println("completed task: ", c.Args().First()) + }, + }, + { + Name: "template", + Aliases: []string{"r"}, + Usage: "options for task templates", + Subcommands: []cli.Command{ + { + Name: "add", + Usage: "add a new template", + Action: func(c *cli.Context) { + println("new task template: ", c.Args().First()) + }, + }, + { + Name: "remove", + Usage: "remove an existing template", + Action: func(c *cli.Context) { + println("removed task template: ", c.Args().First()) + }, + }, + }, + }, +} +... +``` + +### Bash Completion + +You can enable completion commands by setting the `EnableBashCompletion` +flag on the `App` object. By default, this setting will only auto-complete to +show an app's subcommands, but you can write your own completion methods for +the App or its subcommands. +```go +... +var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"} +app := cli.NewApp() +app.EnableBashCompletion = true +app.Commands = []cli.Command{ + { + Name: "complete", + Aliases: []string{"c"}, + Usage: "complete a task on the list", + Action: func(c *cli.Context) { + println("completed task: ", c.Args().First()) + }, + BashComplete: func(c *cli.Context) { + // This will complete if no args are passed + if len(c.Args()) > 0 { + return + } + for _, t := range tasks { + fmt.Println(t) + } + }, + } +} +... +``` + +#### To Enable + +Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while +setting the `PROG` variable to the name of your program: + +`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete` + + +## Contribution Guidelines +Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch. + +If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together. + +If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out. diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/app.go b/Godeps/_workspace/src/github.com/codegangsta/cli/app.go new file mode 100644 index 0000000000..cd29005190 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/app.go @@ -0,0 +1,321 @@ +package cli + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "strings" + "text/tabwriter" + "text/template" + "time" +) + +// App is the main structure of a cli application. It is recomended that +// and app be created with the cli.NewApp() function +type App struct { + // The name of the program. Defaults to os.Args[0] + Name string + // Description of the program. + Usage string + // Version of the program + Version string + // List of commands to execute + Commands []Command + // List of flags to parse + Flags []Flag + // Boolean to enable bash completion commands + EnableBashCompletion bool + // Boolean to hide built-in help command + HideHelp bool + // Boolean to hide built-in version flag + HideVersion bool + // An action to execute when the bash-completion flag is set + BashComplete func(context *Context) + // An action to execute before any subcommands are run, but after the context is ready + // If a non-nil error is returned, no subcommands are run + Before func(context *Context) error + // An action to execute after any subcommands are run, but after the subcommand has finished + // It is run even if Action() panics + After func(context *Context) error + // The action to execute when no subcommands are specified + Action func(context *Context) + // Execute this function if the proper command cannot be found + CommandNotFound func(context *Context, command string) + // Compilation date + Compiled time.Time + // List of all authors who contributed + Authors []Author + // Name of Author (Note: Use App.Authors, this is deprecated) + Author string + // Email of Author (Note: Use App.Authors, this is deprecated) + Email string + // Writer writer to write output to + Writer io.Writer +} + +// Tries to find out when this binary was compiled. +// Returns the current time if it fails to find it. +func compileTime() time.Time { + info, err := os.Stat(os.Args[0]) + if err != nil { + return time.Now() + } + return info.ModTime() +} + +// Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action. +func NewApp() *App { + return &App{ + Name: os.Args[0], + Usage: "A new cli application", + Version: "0.0.0", + BashComplete: DefaultAppComplete, + Action: helpCommand.Action, + Compiled: compileTime(), + Writer: os.Stdout, + } +} + +// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination +func (a *App) Run(arguments []string) (err error) { + if a.Author != "" || a.Email != "" { + a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email}) + } + + if HelpPrinter == nil { + defer func() { + HelpPrinter = nil + }() + + HelpPrinter = func(templ string, data interface{}) { + funcMap := template.FuncMap{ + "join": strings.Join, + } + + w := tabwriter.NewWriter(a.Writer, 0, 8, 1, '\t', 0) + t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) + err := t.Execute(w, data) + if err != nil { + panic(err) + } + w.Flush() + } + } + + // append help to commands + if a.Command(helpCommand.Name) == nil && !a.HideHelp { + a.Commands = append(a.Commands, helpCommand) + if (HelpFlag != BoolFlag{}) { + a.appendFlag(HelpFlag) + } + } + + //append version/help flags + if a.EnableBashCompletion { + a.appendFlag(BashCompletionFlag) + } + + if !a.HideVersion { + a.appendFlag(VersionFlag) + } + + // parse flags + set := flagSet(a.Name, a.Flags) + set.SetOutput(ioutil.Discard) + err = set.Parse(arguments[1:]) + nerr := normalizeFlags(a.Flags, set) + if nerr != nil { + fmt.Fprintln(a.Writer, nerr) + context := NewContext(a, set, set) + ShowAppHelp(context) + fmt.Fprintln(a.Writer) + return nerr + } + context := NewContext(a, set, set) + + if err != nil { + fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n") + ShowAppHelp(context) + fmt.Fprintln(a.Writer) + return err + } + + if checkCompletions(context) { + return nil + } + + if checkHelp(context) { + return nil + } + + if checkVersion(context) { + return nil + } + + if a.After != nil { + defer func() { + // err is always nil here. + // There is a check to see if it is non-nil + // just few lines before. + err = a.After(context) + }() + } + + if a.Before != nil { + err := a.Before(context) + if err != nil { + return err + } + } + + args := context.Args() + if args.Present() { + name := args.First() + c := a.Command(name) + if c != nil { + return c.Run(context) + } + } + + // Run default Action + a.Action(context) + return nil +} + +// Another entry point to the cli app, takes care of passing arguments and error handling +func (a *App) RunAndExitOnError() { + if err := a.Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags +func (a *App) RunAsSubcommand(ctx *Context) (err error) { + // append help to commands + if len(a.Commands) > 0 { + if a.Command(helpCommand.Name) == nil && !a.HideHelp { + a.Commands = append(a.Commands, helpCommand) + if (HelpFlag != BoolFlag{}) { + a.appendFlag(HelpFlag) + } + } + } + + // append flags + if a.EnableBashCompletion { + a.appendFlag(BashCompletionFlag) + } + + // parse flags + set := flagSet(a.Name, a.Flags) + set.SetOutput(ioutil.Discard) + err = set.Parse(ctx.Args().Tail()) + nerr := normalizeFlags(a.Flags, set) + context := NewContext(a, set, ctx.globalSet) + + if nerr != nil { + fmt.Fprintln(a.Writer, nerr) + if len(a.Commands) > 0 { + ShowSubcommandHelp(context) + } else { + ShowCommandHelp(ctx, context.Args().First()) + } + fmt.Fprintln(a.Writer) + return nerr + } + + if err != nil { + fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n") + ShowSubcommandHelp(context) + return err + } + + if checkCompletions(context) { + return nil + } + + if len(a.Commands) > 0 { + if checkSubcommandHelp(context) { + return nil + } + } else { + if checkCommandHelp(ctx, context.Args().First()) { + return nil + } + } + + if a.After != nil { + defer func() { + // err is always nil here. + // There is a check to see if it is non-nil + // just few lines before. + err = a.After(context) + }() + } + + if a.Before != nil { + err := a.Before(context) + if err != nil { + return err + } + } + + args := context.Args() + if args.Present() { + name := args.First() + c := a.Command(name) + if c != nil { + return c.Run(context) + } + } + + // Run default Action + a.Action(context) + + return nil +} + +// Returns the named command on App. Returns nil if the command does not exist +func (a *App) Command(name string) *Command { + for _, c := range a.Commands { + if c.HasName(name) { + return &c + } + } + + return nil +} + +func (a *App) hasFlag(flag Flag) bool { + for _, f := range a.Flags { + if flag == f { + return true + } + } + + return false +} + +func (a *App) appendFlag(flag Flag) { + if !a.hasFlag(flag) { + a.Flags = append(a.Flags, flag) + } +} + +// Author represents someone who has contributed to a cli project. +type Author struct { + Name string // The Authors name + Email string // The Authors email +} + +// String makes Author comply to the Stringer interface, to allow an easy print in the templating process +func (a Author) String() string { + e := "" + if a.Email != "" { + e = "<" + a.Email + "> " + } + + return fmt.Sprintf("%v %v", a.Name, e) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go new file mode 100644 index 0000000000..4a40b89cd4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go @@ -0,0 +1,622 @@ +package cli_test + +import ( + "flag" + "fmt" + "os" + "testing" + + "github.com/codegangsta/cli" +) + +func ExampleApp() { + // set args for examples sake + os.Args = []string{"greet", "--name", "Jeremy"} + + app := cli.NewApp() + app.Name = "greet" + app.Flags = []cli.Flag{ + cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, + } + app.Action = func(c *cli.Context) { + fmt.Printf("Hello %v\n", c.String("name")) + } + app.Author = "Harrison" + app.Email = "harrison@lolwut.com" + app.Authors = []cli.Author{cli.Author{Name: "Oliver Allen", Email: "oliver@toyshop.com"}} + app.Run(os.Args) + // Output: + // Hello Jeremy +} + +func ExampleAppSubcommand() { + // set args for examples sake + os.Args = []string{"say", "hi", "english", "--name", "Jeremy"} + app := cli.NewApp() + app.Name = "say" + app.Commands = []cli.Command{ + { + Name: "hello", + Aliases: []string{"hi"}, + Usage: "use it to see a description", + Description: "This is how we describe hello the function", + Subcommands: []cli.Command{ + { + Name: "english", + Aliases: []string{"en"}, + Usage: "sends a greeting in english", + Description: "greets someone in english", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "name", + Value: "Bob", + Usage: "Name of the person to greet", + }, + }, + Action: func(c *cli.Context) { + fmt.Println("Hello,", c.String("name")) + }, + }, + }, + }, + } + + app.Run(os.Args) + // Output: + // Hello, Jeremy +} + +func ExampleAppHelp() { + // set args for examples sake + os.Args = []string{"greet", "h", "describeit"} + + app := cli.NewApp() + app.Name = "greet" + app.Flags = []cli.Flag{ + cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, + } + app.Commands = []cli.Command{ + { + Name: "describeit", + Aliases: []string{"d"}, + Usage: "use it to see a description", + Description: "This is how we describe describeit the function", + Action: func(c *cli.Context) { + fmt.Printf("i like to describe things") + }, + }, + } + app.Run(os.Args) + // Output: + // NAME: + // describeit - use it to see a description + // + // USAGE: + // command describeit [arguments...] + // + // DESCRIPTION: + // This is how we describe describeit the function +} + +func ExampleAppBashComplete() { + // set args for examples sake + os.Args = []string{"greet", "--generate-bash-completion"} + + app := cli.NewApp() + app.Name = "greet" + app.EnableBashCompletion = true + app.Commands = []cli.Command{ + { + Name: "describeit", + Aliases: []string{"d"}, + Usage: "use it to see a description", + Description: "This is how we describe describeit the function", + Action: func(c *cli.Context) { + fmt.Printf("i like to describe things") + }, + }, { + Name: "next", + Usage: "next example", + Description: "more stuff to see when generating bash completion", + Action: func(c *cli.Context) { + fmt.Printf("the next example") + }, + }, + } + + app.Run(os.Args) + // Output: + // describeit + // d + // next + // help + // h +} + +func TestApp_Run(t *testing.T) { + s := "" + + app := cli.NewApp() + app.Action = func(c *cli.Context) { + s = s + c.Args().First() + } + + err := app.Run([]string{"command", "foo"}) + expect(t, err, nil) + err = app.Run([]string{"command", "bar"}) + expect(t, err, nil) + expect(t, s, "foobar") +} + +var commandAppTests = []struct { + name string + expected bool +}{ + {"foobar", true}, + {"batbaz", true}, + {"b", true}, + {"f", true}, + {"bat", false}, + {"nothing", false}, +} + +func TestApp_Command(t *testing.T) { + app := cli.NewApp() + fooCommand := cli.Command{Name: "foobar", Aliases: []string{"f"}} + batCommand := cli.Command{Name: "batbaz", Aliases: []string{"b"}} + app.Commands = []cli.Command{ + fooCommand, + batCommand, + } + + for _, test := range commandAppTests { + expect(t, app.Command(test.name) != nil, test.expected) + } +} + +func TestApp_CommandWithArgBeforeFlags(t *testing.T) { + var parsedOption, firstArg string + + app := cli.NewApp() + command := cli.Command{ + Name: "cmd", + Flags: []cli.Flag{ + cli.StringFlag{Name: "option", Value: "", Usage: "some option"}, + }, + Action: func(c *cli.Context) { + parsedOption = c.String("option") + firstArg = c.Args().First() + }, + } + app.Commands = []cli.Command{command} + + app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"}) + + expect(t, parsedOption, "my-option") + expect(t, firstArg, "my-arg") +} + +func TestApp_RunAsSubcommandParseFlags(t *testing.T) { + var context *cli.Context + + a := cli.NewApp() + a.Commands = []cli.Command{ + { + Name: "foo", + Action: func(c *cli.Context) { + context = c + }, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + }, + }, + Before: func(_ *cli.Context) error { return nil }, + }, + } + a.Run([]string{"", "foo", "--lang", "spanish", "abcd"}) + + expect(t, context.Args().Get(0), "abcd") + expect(t, context.String("lang"), "spanish") +} + +func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) { + var parsedOption string + var args []string + + app := cli.NewApp() + command := cli.Command{ + Name: "cmd", + Flags: []cli.Flag{ + cli.StringFlag{Name: "option", Value: "", Usage: "some option"}, + }, + Action: func(c *cli.Context) { + parsedOption = c.String("option") + args = c.Args() + }, + } + app.Commands = []cli.Command{command} + + app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"}) + + expect(t, parsedOption, "my-option") + expect(t, args[0], "my-arg") + expect(t, args[1], "--") + expect(t, args[2], "--notARealFlag") +} + +func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) { + var args []string + + app := cli.NewApp() + command := cli.Command{ + Name: "cmd", + Action: func(c *cli.Context) { + args = c.Args() + }, + } + app.Commands = []cli.Command{command} + + app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"}) + + expect(t, args[0], "my-arg") + expect(t, args[1], "--") + expect(t, args[2], "notAFlagAtAll") +} + +func TestApp_Float64Flag(t *testing.T) { + var meters float64 + + app := cli.NewApp() + app.Flags = []cli.Flag{ + cli.Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"}, + } + app.Action = func(c *cli.Context) { + meters = c.Float64("height") + } + + app.Run([]string{"", "--height", "1.93"}) + expect(t, meters, 1.93) +} + +func TestApp_ParseSliceFlags(t *testing.T) { + var parsedOption, firstArg string + var parsedIntSlice []int + var parsedStringSlice []string + + app := cli.NewApp() + command := cli.Command{ + Name: "cmd", + Flags: []cli.Flag{ + cli.IntSliceFlag{Name: "p", Value: &cli.IntSlice{}, Usage: "set one or more ip addr"}, + cli.StringSliceFlag{Name: "ip", Value: &cli.StringSlice{}, Usage: "set one or more ports to open"}, + }, + Action: func(c *cli.Context) { + parsedIntSlice = c.IntSlice("p") + parsedStringSlice = c.StringSlice("ip") + parsedOption = c.String("option") + firstArg = c.Args().First() + }, + } + app.Commands = []cli.Command{command} + + app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"}) + + IntsEquals := func(a, b []int) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true + } + + StrsEquals := func(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true + } + var expectedIntSlice = []int{22, 80} + var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"} + + if !IntsEquals(parsedIntSlice, expectedIntSlice) { + t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice) + } + + if !StrsEquals(parsedStringSlice, expectedStringSlice) { + t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice) + } +} + +func TestApp_DefaultStdout(t *testing.T) { + app := cli.NewApp() + + if app.Writer != os.Stdout { + t.Error("Default output writer not set.") + } +} + +type mockWriter struct { + written []byte +} + +func (fw *mockWriter) Write(p []byte) (n int, err error) { + if fw.written == nil { + fw.written = p + } else { + fw.written = append(fw.written, p...) + } + + return len(p), nil +} + +func (fw *mockWriter) GetWritten() (b []byte) { + return fw.written +} + +func TestApp_SetStdout(t *testing.T) { + w := &mockWriter{} + + app := cli.NewApp() + app.Name = "test" + app.Writer = w + + err := app.Run([]string{"help"}) + + if err != nil { + t.Fatalf("Run error: %s", err) + } + + if len(w.written) == 0 { + t.Error("App did not write output to desired writer.") + } +} + +func TestApp_BeforeFunc(t *testing.T) { + beforeRun, subcommandRun := false, false + beforeError := fmt.Errorf("fail") + var err error + + app := cli.NewApp() + + app.Before = func(c *cli.Context) error { + beforeRun = true + s := c.String("opt") + if s == "fail" { + return beforeError + } + + return nil + } + + app.Commands = []cli.Command{ + cli.Command{ + Name: "sub", + Action: func(c *cli.Context) { + subcommandRun = true + }, + }, + } + + app.Flags = []cli.Flag{ + cli.StringFlag{Name: "opt"}, + } + + // run with the Before() func succeeding + err = app.Run([]string{"command", "--opt", "succeed", "sub"}) + + if err != nil { + t.Fatalf("Run error: %s", err) + } + + if beforeRun == false { + t.Errorf("Before() not executed when expected") + } + + if subcommandRun == false { + t.Errorf("Subcommand not executed when expected") + } + + // reset + beforeRun, subcommandRun = false, false + + // run with the Before() func failing + err = app.Run([]string{"command", "--opt", "fail", "sub"}) + + // should be the same error produced by the Before func + if err != beforeError { + t.Errorf("Run error expected, but not received") + } + + if beforeRun == false { + t.Errorf("Before() not executed when expected") + } + + if subcommandRun == true { + t.Errorf("Subcommand executed when NOT expected") + } + +} + +func TestApp_AfterFunc(t *testing.T) { + afterRun, subcommandRun := false, false + afterError := fmt.Errorf("fail") + var err error + + app := cli.NewApp() + + app.After = func(c *cli.Context) error { + afterRun = true + s := c.String("opt") + if s == "fail" { + return afterError + } + + return nil + } + + app.Commands = []cli.Command{ + cli.Command{ + Name: "sub", + Action: func(c *cli.Context) { + subcommandRun = true + }, + }, + } + + app.Flags = []cli.Flag{ + cli.StringFlag{Name: "opt"}, + } + + // run with the After() func succeeding + err = app.Run([]string{"command", "--opt", "succeed", "sub"}) + + if err != nil { + t.Fatalf("Run error: %s", err) + } + + if afterRun == false { + t.Errorf("After() not executed when expected") + } + + if subcommandRun == false { + t.Errorf("Subcommand not executed when expected") + } + + // reset + afterRun, subcommandRun = false, false + + // run with the Before() func failing + err = app.Run([]string{"command", "--opt", "fail", "sub"}) + + // should be the same error produced by the Before func + if err != afterError { + t.Errorf("Run error expected, but not received") + } + + if afterRun == false { + t.Errorf("After() not executed when expected") + } + + if subcommandRun == false { + t.Errorf("Subcommand not executed when expected") + } +} + +func TestAppNoHelpFlag(t *testing.T) { + oldFlag := cli.HelpFlag + defer func() { + cli.HelpFlag = oldFlag + }() + + cli.HelpFlag = cli.BoolFlag{} + + app := cli.NewApp() + err := app.Run([]string{"test", "-h"}) + + if err != flag.ErrHelp { + t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err) + } +} + +func TestAppHelpPrinter(t *testing.T) { + oldPrinter := cli.HelpPrinter + defer func() { + cli.HelpPrinter = oldPrinter + }() + + var wasCalled = false + cli.HelpPrinter = func(template string, data interface{}) { + wasCalled = true + } + + app := cli.NewApp() + app.Run([]string{"-h"}) + + if wasCalled == false { + t.Errorf("Help printer expected to be called, but was not") + } +} + +func TestAppVersionPrinter(t *testing.T) { + oldPrinter := cli.VersionPrinter + defer func() { + cli.VersionPrinter = oldPrinter + }() + + var wasCalled = false + cli.VersionPrinter = func(c *cli.Context) { + wasCalled = true + } + + app := cli.NewApp() + ctx := cli.NewContext(app, nil, nil) + cli.ShowVersion(ctx) + + if wasCalled == false { + t.Errorf("Version printer expected to be called, but was not") + } +} + +func TestAppCommandNotFound(t *testing.T) { + beforeRun, subcommandRun := false, false + app := cli.NewApp() + + app.CommandNotFound = func(c *cli.Context, command string) { + beforeRun = true + } + + app.Commands = []cli.Command{ + cli.Command{ + Name: "bar", + Action: func(c *cli.Context) { + subcommandRun = true + }, + }, + } + + app.Run([]string{"command", "foo"}) + + expect(t, beforeRun, true) + expect(t, subcommandRun, false) +} + +func TestGlobalFlagsInSubcommands(t *testing.T) { + subcommandRun := false + app := cli.NewApp() + + app.Flags = []cli.Flag{ + cli.BoolFlag{Name: "debug, d", Usage: "Enable debugging"}, + } + + app.Commands = []cli.Command{ + cli.Command{ + Name: "foo", + Subcommands: []cli.Command{ + { + Name: "bar", + Action: func(c *cli.Context) { + if c.GlobalBool("debug") { + subcommandRun = true + } + }, + }, + }, + }, + } + + app.Run([]string{"command", "-d", "foo", "bar"}) + + expect(t, subcommandRun, true) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete new file mode 100644 index 0000000000..9b55dd990c --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete @@ -0,0 +1,13 @@ +#! /bin/bash + +_cli_bash_autocomplete() { + local cur prev opts base + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion ) + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + } + + complete -F _cli_bash_autocomplete $PROG \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete new file mode 100644 index 0000000000..5430a18f95 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete @@ -0,0 +1,5 @@ +autoload -U compinit && compinit +autoload -U bashcompinit && bashcompinit + +script_dir=$(dirname $0) +source ${script_dir}/bash_autocomplete diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/cli.go b/Godeps/_workspace/src/github.com/codegangsta/cli/cli.go new file mode 100644 index 0000000000..b742545812 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/cli.go @@ -0,0 +1,19 @@ +// Package cli provides a minimal framework for creating and organizing command line +// Go applications. cli is designed to be easy to understand and write, the most simple +// cli application can be written as follows: +// func main() { +// cli.NewApp().Run(os.Args) +// } +// +// Of course this application does not do much, so let's make this an actual application: +// func main() { +// app := cli.NewApp() +// app.Name = "greet" +// app.Usage = "say a greeting" +// app.Action = func(c *cli.Context) { +// println("Greetings") +// } +// +// app.Run(os.Args) +// } +package cli diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go new file mode 100644 index 0000000000..8a8df9736c --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go @@ -0,0 +1,100 @@ +package cli_test + +import ( + "os" + + "github.com/codegangsta/cli" +) + +func Example() { + app := cli.NewApp() + app.Name = "todo" + app.Usage = "task list on the command line" + app.Commands = []cli.Command{ + { + Name: "add", + Aliases: []string{"a"}, + Usage: "add a task to the list", + Action: func(c *cli.Context) { + println("added task: ", c.Args().First()) + }, + }, + { + Name: "complete", + Aliases: []string{"c"}, + Usage: "complete a task on the list", + Action: func(c *cli.Context) { + println("completed task: ", c.Args().First()) + }, + }, + } + + app.Run(os.Args) +} + +func ExampleSubcommand() { + app := cli.NewApp() + app.Name = "say" + app.Commands = []cli.Command{ + { + Name: "hello", + Aliases: []string{"hi"}, + Usage: "use it to see a description", + Description: "This is how we describe hello the function", + Subcommands: []cli.Command{ + { + Name: "english", + Aliases: []string{"en"}, + Usage: "sends a greeting in english", + Description: "greets someone in english", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "name", + Value: "Bob", + Usage: "Name of the person to greet", + }, + }, + Action: func(c *cli.Context) { + println("Hello, ", c.String("name")) + }, + }, { + Name: "spanish", + Aliases: []string{"sp"}, + Usage: "sends a greeting in spanish", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "surname", + Value: "Jones", + Usage: "Surname of the person to greet", + }, + }, + Action: func(c *cli.Context) { + println("Hola, ", c.String("surname")) + }, + }, { + Name: "french", + Aliases: []string{"fr"}, + Usage: "sends a greeting in french", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "nickname", + Value: "Stevie", + Usage: "Nickname of the person to greet", + }, + }, + Action: func(c *cli.Context) { + println("Bonjour, ", c.String("nickname")) + }, + }, + }, + }, { + Name: "bye", + Usage: "says goodbye", + Action: func(c *cli.Context) { + println("bye") + }, + }, + } + + app.Run(os.Args) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/command.go b/Godeps/_workspace/src/github.com/codegangsta/cli/command.go new file mode 100644 index 0000000000..b61691c865 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/command.go @@ -0,0 +1,177 @@ +package cli + +import ( + "fmt" + "io/ioutil" + "strings" +) + +// Command is a subcommand for a cli.App. +type Command struct { + // The name of the command + Name string + // short name of the command. Typically one character (deprecated, use `Aliases`) + ShortName string + // A list of aliases for the command + Aliases []string + // A short description of the usage of this command + Usage string + // A longer explanation of how the command works + Description string + // The function to call when checking for bash command completions + BashComplete func(context *Context) + // An action to execute before any sub-subcommands are run, but after the context is ready + // If a non-nil error is returned, no sub-subcommands are run + Before func(context *Context) error + // An action to execute after any subcommands are run, but after the subcommand has finished + // It is run even if Action() panics + After func(context *Context) error + // The function to call when this command is invoked + Action func(context *Context) + // List of child commands + Subcommands []Command + // List of flags to parse + Flags []Flag + // Treat all flags as normal arguments if true + SkipFlagParsing bool + // Boolean to hide built-in help command + HideHelp bool +} + +// Invokes the command given the context, parses ctx.Args() to generate command-specific flags +func (c Command) Run(ctx *Context) error { + + if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil { + return c.startApp(ctx) + } + + if !c.HideHelp && (HelpFlag != BoolFlag{}) { + // append help to flags + c.Flags = append( + c.Flags, + HelpFlag, + ) + } + + if ctx.App.EnableBashCompletion { + c.Flags = append(c.Flags, BashCompletionFlag) + } + + set := flagSet(c.Name, c.Flags) + set.SetOutput(ioutil.Discard) + + firstFlagIndex := -1 + terminatorIndex := -1 + for index, arg := range ctx.Args() { + if arg == "--" { + terminatorIndex = index + break + } else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 { + firstFlagIndex = index + } + } + + var err error + if firstFlagIndex > -1 && !c.SkipFlagParsing { + args := ctx.Args() + regularArgs := make([]string, len(args[1:firstFlagIndex])) + copy(regularArgs, args[1:firstFlagIndex]) + + var flagArgs []string + if terminatorIndex > -1 { + flagArgs = args[firstFlagIndex:terminatorIndex] + regularArgs = append(regularArgs, args[terminatorIndex:]...) + } else { + flagArgs = args[firstFlagIndex:] + } + + err = set.Parse(append(flagArgs, regularArgs...)) + } else { + err = set.Parse(ctx.Args().Tail()) + } + + if err != nil { + fmt.Fprint(ctx.App.Writer, "Incorrect Usage.\n\n") + ShowCommandHelp(ctx, c.Name) + fmt.Fprintln(ctx.App.Writer) + return err + } + + nerr := normalizeFlags(c.Flags, set) + if nerr != nil { + fmt.Fprintln(ctx.App.Writer, nerr) + fmt.Fprintln(ctx.App.Writer) + ShowCommandHelp(ctx, c.Name) + fmt.Fprintln(ctx.App.Writer) + return nerr + } + context := NewContext(ctx.App, set, ctx.globalSet) + + if checkCommandCompletions(context, c.Name) { + return nil + } + + if checkCommandHelp(context, c.Name) { + return nil + } + context.Command = c + c.Action(context) + return nil +} + +func (c Command) Names() []string { + names := []string{c.Name} + + if c.ShortName != "" { + names = append(names, c.ShortName) + } + + return append(names, c.Aliases...) +} + +// Returns true if Command.Name or Command.ShortName matches given name +func (c Command) HasName(name string) bool { + for _, n := range c.Names() { + if n == name { + return true + } + } + return false +} + +func (c Command) startApp(ctx *Context) error { + app := NewApp() + + // set the name and usage + app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) + if c.Description != "" { + app.Usage = c.Description + } else { + app.Usage = c.Usage + } + + // set CommandNotFound + app.CommandNotFound = ctx.App.CommandNotFound + + // set the flags and commands + app.Commands = c.Subcommands + app.Flags = c.Flags + app.HideHelp = c.HideHelp + + // bash completion + app.EnableBashCompletion = ctx.App.EnableBashCompletion + if c.BashComplete != nil { + app.BashComplete = c.BashComplete + } + + // set the actions + app.Before = c.Before + app.After = c.After + if c.Action != nil { + app.Action = c.Action + } else { + app.Action = helpSubcommand.Action + } + + return app.RunAsSubcommand(ctx) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go new file mode 100644 index 0000000000..4125b0c1b1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go @@ -0,0 +1,49 @@ +package cli_test + +import ( + "flag" + "testing" + + "github.com/codegangsta/cli" +) + +func TestCommandDoNotIgnoreFlags(t *testing.T) { + app := cli.NewApp() + set := flag.NewFlagSet("test", 0) + test := []string{"blah", "blah", "-break"} + set.Parse(test) + + c := cli.NewContext(app, set, set) + + command := cli.Command{ + Name: "test-cmd", + Aliases: []string{"tc"}, + Usage: "this is for testing", + Description: "testing", + Action: func(_ *cli.Context) {}, + } + err := command.Run(c) + + expect(t, err.Error(), "flag provided but not defined: -break") +} + +func TestCommandIgnoreFlags(t *testing.T) { + app := cli.NewApp() + set := flag.NewFlagSet("test", 0) + test := []string{"blah", "blah"} + set.Parse(test) + + c := cli.NewContext(app, set, set) + + command := cli.Command{ + Name: "test-cmd", + Aliases: []string{"tc"}, + Usage: "this is for testing", + Description: "testing", + Action: func(_ *cli.Context) {}, + SkipFlagParsing: true, + } + err := command.Run(c) + + expect(t, err, nil) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/context.go b/Godeps/_workspace/src/github.com/codegangsta/cli/context.go new file mode 100644 index 0000000000..37221bdc29 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/context.go @@ -0,0 +1,344 @@ +package cli + +import ( + "errors" + "flag" + "strconv" + "strings" + "time" +) + +// Context is a type that is passed through to +// each Handler action in a cli application. Context +// can be used to retrieve context-specific Args and +// parsed command-line options. +type Context struct { + App *App + Command Command + flagSet *flag.FlagSet + globalSet *flag.FlagSet + setFlags map[string]bool + globalSetFlags map[string]bool +} + +// Creates a new context. For use in when invoking an App or Command action. +func NewContext(app *App, set *flag.FlagSet, globalSet *flag.FlagSet) *Context { + return &Context{App: app, flagSet: set, globalSet: globalSet} +} + +// Looks up the value of a local int flag, returns 0 if no int flag exists +func (c *Context) Int(name string) int { + return lookupInt(name, c.flagSet) +} + +// Looks up the value of a local time.Duration flag, returns 0 if no time.Duration flag exists +func (c *Context) Duration(name string) time.Duration { + return lookupDuration(name, c.flagSet) +} + +// Looks up the value of a local float64 flag, returns 0 if no float64 flag exists +func (c *Context) Float64(name string) float64 { + return lookupFloat64(name, c.flagSet) +} + +// Looks up the value of a local bool flag, returns false if no bool flag exists +func (c *Context) Bool(name string) bool { + return lookupBool(name, c.flagSet) +} + +// Looks up the value of a local boolT flag, returns false if no bool flag exists +func (c *Context) BoolT(name string) bool { + return lookupBoolT(name, c.flagSet) +} + +// Looks up the value of a local string flag, returns "" if no string flag exists +func (c *Context) String(name string) string { + return lookupString(name, c.flagSet) +} + +// Looks up the value of a local string slice flag, returns nil if no string slice flag exists +func (c *Context) StringSlice(name string) []string { + return lookupStringSlice(name, c.flagSet) +} + +// Looks up the value of a local int slice flag, returns nil if no int slice flag exists +func (c *Context) IntSlice(name string) []int { + return lookupIntSlice(name, c.flagSet) +} + +// Looks up the value of a local generic flag, returns nil if no generic flag exists +func (c *Context) Generic(name string) interface{} { + return lookupGeneric(name, c.flagSet) +} + +// Looks up the value of a global int flag, returns 0 if no int flag exists +func (c *Context) GlobalInt(name string) int { + return lookupInt(name, c.globalSet) +} + +// Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists +func (c *Context) GlobalDuration(name string) time.Duration { + return lookupDuration(name, c.globalSet) +} + +// Looks up the value of a global bool flag, returns false if no bool flag exists +func (c *Context) GlobalBool(name string) bool { + return lookupBool(name, c.globalSet) +} + +// Looks up the value of a global string flag, returns "" if no string flag exists +func (c *Context) GlobalString(name string) string { + return lookupString(name, c.globalSet) +} + +// Looks up the value of a global string slice flag, returns nil if no string slice flag exists +func (c *Context) GlobalStringSlice(name string) []string { + return lookupStringSlice(name, c.globalSet) +} + +// Looks up the value of a global int slice flag, returns nil if no int slice flag exists +func (c *Context) GlobalIntSlice(name string) []int { + return lookupIntSlice(name, c.globalSet) +} + +// Looks up the value of a global generic flag, returns nil if no generic flag exists +func (c *Context) GlobalGeneric(name string) interface{} { + return lookupGeneric(name, c.globalSet) +} + +// Returns the number of flags set +func (c *Context) NumFlags() int { + return c.flagSet.NFlag() +} + +// Determines if the flag was actually set +func (c *Context) IsSet(name string) bool { + if c.setFlags == nil { + c.setFlags = make(map[string]bool) + c.flagSet.Visit(func(f *flag.Flag) { + c.setFlags[f.Name] = true + }) + } + return c.setFlags[name] == true +} + +// Determines if the global flag was actually set +func (c *Context) GlobalIsSet(name string) bool { + if c.globalSetFlags == nil { + c.globalSetFlags = make(map[string]bool) + c.globalSet.Visit(func(f *flag.Flag) { + c.globalSetFlags[f.Name] = true + }) + } + return c.globalSetFlags[name] == true +} + +// Returns a slice of flag names used in this context. +func (c *Context) FlagNames() (names []string) { + for _, flag := range c.Command.Flags { + name := strings.Split(flag.getName(), ",")[0] + if name == "help" { + continue + } + names = append(names, name) + } + return +} + +// Returns a slice of global flag names used by the app. +func (c *Context) GlobalFlagNames() (names []string) { + for _, flag := range c.App.Flags { + name := strings.Split(flag.getName(), ",")[0] + if name == "help" || name == "version" { + continue + } + names = append(names, name) + } + return +} + +type Args []string + +// Returns the command line arguments associated with the context. +func (c *Context) Args() Args { + args := Args(c.flagSet.Args()) + return args +} + +// Returns the nth argument, or else a blank string +func (a Args) Get(n int) string { + if len(a) > n { + return a[n] + } + return "" +} + +// Returns the first argument, or else a blank string +func (a Args) First() string { + return a.Get(0) +} + +// Return the rest of the arguments (not the first one) +// or else an empty string slice +func (a Args) Tail() []string { + if len(a) >= 2 { + return []string(a)[1:] + } + return []string{} +} + +// Checks if there are any arguments present +func (a Args) Present() bool { + return len(a) != 0 +} + +// Swaps arguments at the given indexes +func (a Args) Swap(from, to int) error { + if from >= len(a) || to >= len(a) { + return errors.New("index out of range") + } + a[from], a[to] = a[to], a[from] + return nil +} + +func lookupInt(name string, set *flag.FlagSet) int { + f := set.Lookup(name) + if f != nil { + val, err := strconv.Atoi(f.Value.String()) + if err != nil { + return 0 + } + return val + } + + return 0 +} + +func lookupDuration(name string, set *flag.FlagSet) time.Duration { + f := set.Lookup(name) + if f != nil { + val, err := time.ParseDuration(f.Value.String()) + if err == nil { + return val + } + } + + return 0 +} + +func lookupFloat64(name string, set *flag.FlagSet) float64 { + f := set.Lookup(name) + if f != nil { + val, err := strconv.ParseFloat(f.Value.String(), 64) + if err != nil { + return 0 + } + return val + } + + return 0 +} + +func lookupString(name string, set *flag.FlagSet) string { + f := set.Lookup(name) + if f != nil { + return f.Value.String() + } + + return "" +} + +func lookupStringSlice(name string, set *flag.FlagSet) []string { + f := set.Lookup(name) + if f != nil { + return (f.Value.(*StringSlice)).Value() + + } + + return nil +} + +func lookupIntSlice(name string, set *flag.FlagSet) []int { + f := set.Lookup(name) + if f != nil { + return (f.Value.(*IntSlice)).Value() + + } + + return nil +} + +func lookupGeneric(name string, set *flag.FlagSet) interface{} { + f := set.Lookup(name) + if f != nil { + return f.Value + } + return nil +} + +func lookupBool(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + val, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return false + } + return val + } + + return false +} + +func lookupBoolT(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + val, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return true + } + return val + } + + return false +} + +func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { + switch ff.Value.(type) { + case *StringSlice: + default: + set.Set(name, ff.Value.String()) + } +} + +func normalizeFlags(flags []Flag, set *flag.FlagSet) error { + visited := make(map[string]bool) + set.Visit(func(f *flag.Flag) { + visited[f.Name] = true + }) + for _, f := range flags { + parts := strings.Split(f.getName(), ",") + if len(parts) == 1 { + continue + } + var ff *flag.Flag + for _, name := range parts { + name = strings.Trim(name, " ") + if visited[name] { + if ff != nil { + return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name) + } + ff = set.Lookup(name) + } + } + if ff == nil { + continue + } + for _, name := range parts { + name = strings.Trim(name, " ") + if !visited[name] { + copyFlag(name, ff, set) + } + } + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go new file mode 100644 index 0000000000..d4a1877f07 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go @@ -0,0 +1,111 @@ +package cli_test + +import ( + "flag" + "testing" + "time" + + "github.com/codegangsta/cli" +) + +func TestNewContext(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Int("myflag", 12, "doc") + globalSet := flag.NewFlagSet("test", 0) + globalSet.Int("myflag", 42, "doc") + command := cli.Command{Name: "mycommand"} + c := cli.NewContext(nil, set, globalSet) + c.Command = command + expect(t, c.Int("myflag"), 12) + expect(t, c.GlobalInt("myflag"), 42) + expect(t, c.Command.Name, "mycommand") +} + +func TestContext_Int(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Int("myflag", 12, "doc") + c := cli.NewContext(nil, set, set) + expect(t, c.Int("myflag"), 12) +} + +func TestContext_Duration(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Duration("myflag", time.Duration(12*time.Second), "doc") + c := cli.NewContext(nil, set, set) + expect(t, c.Duration("myflag"), time.Duration(12*time.Second)) +} + +func TestContext_String(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.String("myflag", "hello world", "doc") + c := cli.NewContext(nil, set, set) + expect(t, c.String("myflag"), "hello world") +} + +func TestContext_Bool(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + c := cli.NewContext(nil, set, set) + expect(t, c.Bool("myflag"), false) +} + +func TestContext_BoolT(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", true, "doc") + c := cli.NewContext(nil, set, set) + expect(t, c.BoolT("myflag"), true) +} + +func TestContext_Args(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + c := cli.NewContext(nil, set, set) + set.Parse([]string{"--myflag", "bat", "baz"}) + expect(t, len(c.Args()), 2) + expect(t, c.Bool("myflag"), true) +} + +func TestContext_IsSet(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + set.String("otherflag", "hello world", "doc") + globalSet := flag.NewFlagSet("test", 0) + globalSet.Bool("myflagGlobal", true, "doc") + c := cli.NewContext(nil, set, globalSet) + set.Parse([]string{"--myflag", "bat", "baz"}) + globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"}) + expect(t, c.IsSet("myflag"), true) + expect(t, c.IsSet("otherflag"), false) + expect(t, c.IsSet("bogusflag"), false) + expect(t, c.IsSet("myflagGlobal"), false) +} + +func TestContext_GlobalIsSet(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + set.String("otherflag", "hello world", "doc") + globalSet := flag.NewFlagSet("test", 0) + globalSet.Bool("myflagGlobal", true, "doc") + globalSet.Bool("myflagGlobalUnset", true, "doc") + c := cli.NewContext(nil, set, globalSet) + set.Parse([]string{"--myflag", "bat", "baz"}) + globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"}) + expect(t, c.GlobalIsSet("myflag"), false) + expect(t, c.GlobalIsSet("otherflag"), false) + expect(t, c.GlobalIsSet("bogusflag"), false) + expect(t, c.GlobalIsSet("myflagGlobal"), true) + expect(t, c.GlobalIsSet("myflagGlobalUnset"), false) + expect(t, c.GlobalIsSet("bogusGlobal"), false) +} + +func TestContext_NumFlags(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + set.String("otherflag", "hello world", "doc") + globalSet := flag.NewFlagSet("test", 0) + globalSet.Bool("myflagGlobal", true, "doc") + c := cli.NewContext(nil, set, globalSet) + set.Parse([]string{"--myflag", "--otherflag=foo"}) + globalSet.Parse([]string{"--myflagGlobal"}) + expect(t, c.NumFlags(), 2) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go b/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go new file mode 100644 index 0000000000..251158667b --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go @@ -0,0 +1,454 @@ +package cli + +import ( + "flag" + "fmt" + "os" + "strconv" + "strings" + "time" +) + +// This flag enables bash-completion for all commands and subcommands +var BashCompletionFlag = BoolFlag{ + Name: "generate-bash-completion", +} + +// This flag prints the version for the application +var VersionFlag = BoolFlag{ + Name: "version, v", + Usage: "print the version", +} + +// This flag prints the help for all commands and subcommands +// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand +// unless HideHelp is set to true) +var HelpFlag = BoolFlag{ + Name: "help, h", + Usage: "show help", +} + +// Flag is a common interface related to parsing flags in cli. +// For more advanced flag parsing techniques, it is recomended that +// this interface be implemented. +type Flag interface { + fmt.Stringer + // Apply Flag settings to the given flag set + Apply(*flag.FlagSet) + getName() string +} + +func flagSet(name string, flags []Flag) *flag.FlagSet { + set := flag.NewFlagSet(name, flag.ContinueOnError) + + for _, f := range flags { + f.Apply(set) + } + return set +} + +func eachName(longName string, fn func(string)) { + parts := strings.Split(longName, ",") + for _, name := range parts { + name = strings.Trim(name, " ") + fn(name) + } +} + +// Generic is a generic parseable type identified by a specific flag +type Generic interface { + Set(value string) error + String() string +} + +// GenericFlag is the flag type for types implementing Generic +type GenericFlag struct { + Name string + Value Generic + Usage string + EnvVar string +} + +// String returns the string representation of the generic flag to display the +// help text to the user (uses the String() method of the generic flag to show +// the value) +func (f GenericFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage)) +} + +// Apply takes the flagset and calls Set on the generic flag with the value +// provided by the user for parsing by the flag +func (f GenericFlag) Apply(set *flag.FlagSet) { + val := f.Value + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + val.Set(envVal) + break + } + } + } + + eachName(f.Name, func(name string) { + set.Var(f.Value, name, f.Usage) + }) +} + +func (f GenericFlag) getName() string { + return f.Name +} + +type StringSlice []string + +func (f *StringSlice) Set(value string) error { + *f = append(*f, value) + return nil +} + +func (f *StringSlice) String() string { + return fmt.Sprintf("%s", *f) +} + +func (f *StringSlice) Value() []string { + return *f +} + +type StringSliceFlag struct { + Name string + Value *StringSlice + Usage string + EnvVar string +} + +func (f StringSliceFlag) String() string { + firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") + pref := prefixFor(firstName) + return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) +} + +func (f StringSliceFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + newVal := &StringSlice{} + for _, s := range strings.Split(envVal, ",") { + s = strings.TrimSpace(s) + newVal.Set(s) + } + f.Value = newVal + break + } + } + } + + eachName(f.Name, func(name string) { + set.Var(f.Value, name, f.Usage) + }) +} + +func (f StringSliceFlag) getName() string { + return f.Name +} + +type IntSlice []int + +func (f *IntSlice) Set(value string) error { + + tmp, err := strconv.Atoi(value) + if err != nil { + return err + } else { + *f = append(*f, tmp) + } + return nil +} + +func (f *IntSlice) String() string { + return fmt.Sprintf("%d", *f) +} + +func (f *IntSlice) Value() []int { + return *f +} + +type IntSliceFlag struct { + Name string + Value *IntSlice + Usage string + EnvVar string +} + +func (f IntSliceFlag) String() string { + firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") + pref := prefixFor(firstName) + return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) +} + +func (f IntSliceFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + newVal := &IntSlice{} + for _, s := range strings.Split(envVal, ",") { + s = strings.TrimSpace(s) + err := newVal.Set(s) + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + } + } + f.Value = newVal + break + } + } + } + + eachName(f.Name, func(name string) { + set.Var(f.Value, name, f.Usage) + }) +} + +func (f IntSliceFlag) getName() string { + return f.Name +} + +type BoolFlag struct { + Name string + Usage string + EnvVar string +} + +func (f BoolFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)) +} + +func (f BoolFlag) Apply(set *flag.FlagSet) { + val := false + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValBool, err := strconv.ParseBool(envVal) + if err == nil { + val = envValBool + } + break + } + } + } + + eachName(f.Name, func(name string) { + set.Bool(name, val, f.Usage) + }) +} + +func (f BoolFlag) getName() string { + return f.Name +} + +type BoolTFlag struct { + Name string + Usage string + EnvVar string +} + +func (f BoolTFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)) +} + +func (f BoolTFlag) Apply(set *flag.FlagSet) { + val := true + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValBool, err := strconv.ParseBool(envVal) + if err == nil { + val = envValBool + break + } + } + } + } + + eachName(f.Name, func(name string) { + set.Bool(name, val, f.Usage) + }) +} + +func (f BoolTFlag) getName() string { + return f.Name +} + +type StringFlag struct { + Name string + Value string + Usage string + EnvVar string +} + +func (f StringFlag) String() string { + var fmtString string + fmtString = "%s %v\t%v" + + if len(f.Value) > 0 { + fmtString = "%s \"%v\"\t%v" + } else { + fmtString = "%s %v\t%v" + } + + return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage)) +} + +func (f StringFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + f.Value = envVal + break + } + } + } + + eachName(f.Name, func(name string) { + set.String(name, f.Value, f.Usage) + }) +} + +func (f StringFlag) getName() string { + return f.Name +} + +type IntFlag struct { + Name string + Value int + Usage string + EnvVar string +} + +func (f IntFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) +} + +func (f IntFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValInt, err := strconv.ParseInt(envVal, 0, 64) + if err == nil { + f.Value = int(envValInt) + break + } + } + } + } + + eachName(f.Name, func(name string) { + set.Int(name, f.Value, f.Usage) + }) +} + +func (f IntFlag) getName() string { + return f.Name +} + +type DurationFlag struct { + Name string + Value time.Duration + Usage string + EnvVar string +} + +func (f DurationFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) +} + +func (f DurationFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValDuration, err := time.ParseDuration(envVal) + if err == nil { + f.Value = envValDuration + break + } + } + } + } + + eachName(f.Name, func(name string) { + set.Duration(name, f.Value, f.Usage) + }) +} + +func (f DurationFlag) getName() string { + return f.Name +} + +type Float64Flag struct { + Name string + Value float64 + Usage string + EnvVar string +} + +func (f Float64Flag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) +} + +func (f Float64Flag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValFloat, err := strconv.ParseFloat(envVal, 10) + if err == nil { + f.Value = float64(envValFloat) + } + } + } + } + + eachName(f.Name, func(name string) { + set.Float64(name, f.Value, f.Usage) + }) +} + +func (f Float64Flag) getName() string { + return f.Name +} + +func prefixFor(name string) (prefix string) { + if len(name) == 1 { + prefix = "-" + } else { + prefix = "--" + } + + return +} + +func prefixedNames(fullName string) (prefixed string) { + parts := strings.Split(fullName, ",") + for i, name := range parts { + name = strings.Trim(name, " ") + prefixed += prefixFor(name) + name + if i < len(parts)-1 { + prefixed += ", " + } + } + return +} + +func withEnvHint(envVar, str string) string { + envText := "" + if envVar != "" { + envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $")) + } + return str + envText +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go new file mode 100644 index 0000000000..f0f096a2d5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go @@ -0,0 +1,742 @@ +package cli_test + +import ( + "fmt" + "os" + "reflect" + "strings" + "testing" + + "github.com/codegangsta/cli" +) + +var boolFlagTests = []struct { + name string + expected string +}{ + {"help", "--help\t"}, + {"h", "-h\t"}, +} + +func TestBoolFlagHelpOutput(t *testing.T) { + + for _, test := range boolFlagTests { + flag := cli.BoolFlag{Name: test.name} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +var stringFlagTests = []struct { + name string + value string + expected string +}{ + {"help", "", "--help \t"}, + {"h", "", "-h \t"}, + {"h", "", "-h \t"}, + {"test", "Something", "--test \"Something\"\t"}, +} + +func TestStringFlagHelpOutput(t *testing.T) { + + for _, test := range stringFlagTests { + flag := cli.StringFlag{Name: test.name, Value: test.value} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +func TestStringFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_FOO", "derp") + for _, test := range stringFlagTests { + flag := cli.StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_FOO]") { + t.Errorf("%s does not end with [$APP_FOO]", output) + } + } +} + +var stringSliceFlagTests = []struct { + name string + value *cli.StringSlice + expected string +}{ + {"help", func() *cli.StringSlice { + s := &cli.StringSlice{} + s.Set("") + return s + }(), "--help [--help option --help option]\t"}, + {"h", func() *cli.StringSlice { + s := &cli.StringSlice{} + s.Set("") + return s + }(), "-h [-h option -h option]\t"}, + {"h", func() *cli.StringSlice { + s := &cli.StringSlice{} + s.Set("") + return s + }(), "-h [-h option -h option]\t"}, + {"test", func() *cli.StringSlice { + s := &cli.StringSlice{} + s.Set("Something") + return s + }(), "--test [--test option --test option]\t"}, +} + +func TestStringSliceFlagHelpOutput(t *testing.T) { + + for _, test := range stringSliceFlagTests { + flag := cli.StringSliceFlag{Name: test.name, Value: test.value} + output := flag.String() + + if output != test.expected { + t.Errorf("%q does not match %q", output, test.expected) + } + } +} + +func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_QWWX", "11,4") + for _, test := range stringSliceFlagTests { + flag := cli.StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_QWWX]") { + t.Errorf("%q does not end with [$APP_QWWX]", output) + } + } +} + +var intFlagTests = []struct { + name string + expected string +}{ + {"help", "--help \"0\"\t"}, + {"h", "-h \"0\"\t"}, +} + +func TestIntFlagHelpOutput(t *testing.T) { + + for _, test := range intFlagTests { + flag := cli.IntFlag{Name: test.name} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +func TestIntFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_BAR", "2") + for _, test := range intFlagTests { + flag := cli.IntFlag{Name: test.name, EnvVar: "APP_BAR"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_BAR]") { + t.Errorf("%s does not end with [$APP_BAR]", output) + } + } +} + +var durationFlagTests = []struct { + name string + expected string +}{ + {"help", "--help \"0\"\t"}, + {"h", "-h \"0\"\t"}, +} + +func TestDurationFlagHelpOutput(t *testing.T) { + + for _, test := range durationFlagTests { + flag := cli.DurationFlag{Name: test.name} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_BAR", "2h3m6s") + for _, test := range durationFlagTests { + flag := cli.DurationFlag{Name: test.name, EnvVar: "APP_BAR"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_BAR]") { + t.Errorf("%s does not end with [$APP_BAR]", output) + } + } +} + +var intSliceFlagTests = []struct { + name string + value *cli.IntSlice + expected string +}{ + {"help", &cli.IntSlice{}, "--help [--help option --help option]\t"}, + {"h", &cli.IntSlice{}, "-h [-h option -h option]\t"}, + {"h", &cli.IntSlice{}, "-h [-h option -h option]\t"}, + {"test", func() *cli.IntSlice { + i := &cli.IntSlice{} + i.Set("9") + return i + }(), "--test [--test option --test option]\t"}, +} + +func TestIntSliceFlagHelpOutput(t *testing.T) { + + for _, test := range intSliceFlagTests { + flag := cli.IntSliceFlag{Name: test.name, Value: test.value} + output := flag.String() + + if output != test.expected { + t.Errorf("%q does not match %q", output, test.expected) + } + } +} + +func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_SMURF", "42,3") + for _, test := range intSliceFlagTests { + flag := cli.IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_SMURF]") { + t.Errorf("%q does not end with [$APP_SMURF]", output) + } + } +} + +var float64FlagTests = []struct { + name string + expected string +}{ + {"help", "--help \"0\"\t"}, + {"h", "-h \"0\"\t"}, +} + +func TestFloat64FlagHelpOutput(t *testing.T) { + + for _, test := range float64FlagTests { + flag := cli.Float64Flag{Name: test.name} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_BAZ", "99.4") + for _, test := range float64FlagTests { + flag := cli.Float64Flag{Name: test.name, EnvVar: "APP_BAZ"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_BAZ]") { + t.Errorf("%s does not end with [$APP_BAZ]", output) + } + } +} + +var genericFlagTests = []struct { + name string + value cli.Generic + expected string +}{ + {"test", &Parser{"abc", "def"}, "--test \"abc,def\"\ttest flag"}, + {"t", &Parser{"abc", "def"}, "-t \"abc,def\"\ttest flag"}, +} + +func TestGenericFlagHelpOutput(t *testing.T) { + + for _, test := range genericFlagTests { + flag := cli.GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"} + output := flag.String() + + if output != test.expected { + t.Errorf("%q does not match %q", output, test.expected) + } + } +} + +func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_ZAP", "3") + for _, test := range genericFlagTests { + flag := cli.GenericFlag{Name: test.name, EnvVar: "APP_ZAP"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_ZAP]") { + t.Errorf("%s does not end with [$APP_ZAP]", output) + } + } +} + +func TestParseMultiString(t *testing.T) { + (&cli.App{ + Flags: []cli.Flag{ + cli.StringFlag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.String("serve") != "10" { + t.Errorf("main name not set") + } + if ctx.String("s") != "10" { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run", "-s", "10"}) +} + +func TestParseMultiStringFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_COUNT", "20") + (&cli.App{ + Flags: []cli.Flag{ + cli.StringFlag{Name: "count, c", EnvVar: "APP_COUNT"}, + }, + Action: func(ctx *cli.Context) { + if ctx.String("count") != "20" { + t.Errorf("main name not set") + } + if ctx.String("c") != "20" { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiStringFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_COUNT", "20") + (&cli.App{ + Flags: []cli.Flag{ + cli.StringFlag{Name: "count, c", EnvVar: "COMPAT_COUNT,APP_COUNT"}, + }, + Action: func(ctx *cli.Context) { + if ctx.String("count") != "20" { + t.Errorf("main name not set") + } + if ctx.String("c") != "20" { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiStringSlice(t *testing.T) { + (&cli.App{ + Flags: []cli.Flag{ + cli.StringSliceFlag{Name: "serve, s", Value: &cli.StringSlice{}}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"10", "20"}) { + t.Errorf("main name not set") + } + if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"10", "20"}) { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run", "-s", "10", "-s", "20"}) +} + +func TestParseMultiStringSliceFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_INTERVALS", "20,30,40") + + (&cli.App{ + Flags: []cli.Flag{ + cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "APP_INTERVALS"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiStringSliceFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_INTERVALS", "20,30,40") + + (&cli.App{ + Flags: []cli.Flag{ + cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiInt(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.IntFlag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Int("serve") != 10 { + t.Errorf("main name not set") + } + if ctx.Int("s") != 10 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "-s", "10"}) +} + +func TestParseMultiIntFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_TIMEOUT_SECONDS", "10") + a := cli.App{ + Flags: []cli.Flag{ + cli.IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Int("timeout") != 10 { + t.Errorf("main name not set") + } + if ctx.Int("t") != 10 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiIntFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_TIMEOUT_SECONDS", "10") + a := cli.App{ + Flags: []cli.Flag{ + cli.IntFlag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Int("timeout") != 10 { + t.Errorf("main name not set") + } + if ctx.Int("t") != 10 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiIntSlice(t *testing.T) { + (&cli.App{ + Flags: []cli.Flag{ + cli.IntSliceFlag{Name: "serve, s", Value: &cli.IntSlice{}}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) { + t.Errorf("main name not set") + } + if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run", "-s", "10", "-s", "20"}) +} + +func TestParseMultiIntSliceFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_INTERVALS", "20,30,40") + + (&cli.App{ + Flags: []cli.Flag{ + cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "APP_INTERVALS"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiIntSliceFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_INTERVALS", "20,30,40") + + (&cli.App{ + Flags: []cli.Flag{ + cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiFloat64(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.Float64Flag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Float64("serve") != 10.2 { + t.Errorf("main name not set") + } + if ctx.Float64("s") != 10.2 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "-s", "10.2"}) +} + +func TestParseMultiFloat64FromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_TIMEOUT_SECONDS", "15.5") + a := cli.App{ + Flags: []cli.Flag{ + cli.Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Float64("timeout") != 15.5 { + t.Errorf("main name not set") + } + if ctx.Float64("t") != 15.5 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiFloat64FromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_TIMEOUT_SECONDS", "15.5") + a := cli.App{ + Flags: []cli.Flag{ + cli.Float64Flag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Float64("timeout") != 15.5 { + t.Errorf("main name not set") + } + if ctx.Float64("t") != 15.5 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiBool(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolFlag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Bool("serve") != true { + t.Errorf("main name not set") + } + if ctx.Bool("s") != true { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "--serve"}) +} + +func TestParseMultiBoolFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_DEBUG", "1") + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Bool("debug") != true { + t.Errorf("main name not set from env") + } + if ctx.Bool("d") != true { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiBoolFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_DEBUG", "1") + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Bool("debug") != true { + t.Errorf("main name not set from env") + } + if ctx.Bool("d") != true { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiBoolT(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolTFlag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.BoolT("serve") != true { + t.Errorf("main name not set") + } + if ctx.BoolT("s") != true { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "--serve"}) +} + +func TestParseMultiBoolTFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_DEBUG", "0") + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolTFlag{Name: "debug, d", EnvVar: "APP_DEBUG"}, + }, + Action: func(ctx *cli.Context) { + if ctx.BoolT("debug") != false { + t.Errorf("main name not set from env") + } + if ctx.BoolT("d") != false { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiBoolTFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_DEBUG", "0") + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolTFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"}, + }, + Action: func(ctx *cli.Context) { + if ctx.BoolT("debug") != false { + t.Errorf("main name not set from env") + } + if ctx.BoolT("d") != false { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +type Parser [2]string + +func (p *Parser) Set(value string) error { + parts := strings.Split(value, ",") + if len(parts) != 2 { + return fmt.Errorf("invalid format") + } + + (*p)[0] = parts[0] + (*p)[1] = parts[1] + + return nil +} + +func (p *Parser) String() string { + return fmt.Sprintf("%s,%s", p[0], p[1]) +} + +func TestParseGeneric(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.GenericFlag{Name: "serve, s", Value: &Parser{}}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) { + t.Errorf("main name not set") + } + if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "-s", "10,20"}) +} + +func TestParseGenericFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_SERVE", "20,30") + a := cli.App{ + Flags: []cli.Flag{ + cli.GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseGenericFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_FOO", "99,2000") + a := cli.App{ + Flags: []cli.Flag{ + cli.GenericFlag{Name: "foos", Value: &Parser{}, EnvVar: "COMPAT_FOO,APP_FOO"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) { + t.Errorf("value not set from env") + } + }, + } + a.Run([]string{"run"}) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/help.go b/Godeps/_workspace/src/github.com/codegangsta/cli/help.go new file mode 100644 index 0000000000..7c4f81be62 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/help.go @@ -0,0 +1,215 @@ +package cli + +import "fmt" + +// The text template for the Default help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var AppHelpTemplate = `NAME: + {{.Name}} - {{.Usage}} + +USAGE: + {{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...] + +VERSION: + {{.Version}} + +AUTHOR(S): + {{range .Authors}}{{ . }} + {{end}} +COMMANDS: + {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} + {{end}}{{if .Flags}} +GLOBAL OPTIONS: + {{range .Flags}}{{.}} + {{end}}{{end}} +` + +// The text template for the command help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var CommandHelpTemplate = `NAME: + {{.Name}} - {{.Usage}} + +USAGE: + command {{.Name}}{{if .Flags}} [command options]{{end}} [arguments...]{{if .Description}} + +DESCRIPTION: + {{.Description}}{{end}}{{if .Flags}} + +OPTIONS: + {{range .Flags}}{{.}} + {{end}}{{ end }} +` + +// The text template for the subcommand help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var SubcommandHelpTemplate = `NAME: + {{.Name}} - {{.Usage}} + +USAGE: + {{.Name}} command{{if .Flags}} [command options]{{end}} [arguments...] + +COMMANDS: + {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} + {{end}}{{if .Flags}} +OPTIONS: + {{range .Flags}}{{.}} + {{end}}{{end}} +` + +var helpCommand = Command{ + Name: "help", + Aliases: []string{"h"}, + Usage: "Shows a list of commands or help for one command", + Action: func(c *Context) { + args := c.Args() + if args.Present() { + ShowCommandHelp(c, args.First()) + } else { + ShowAppHelp(c) + } + }, +} + +var helpSubcommand = Command{ + Name: "help", + Aliases: []string{"h"}, + Usage: "Shows a list of commands or help for one command", + Action: func(c *Context) { + args := c.Args() + if args.Present() { + ShowCommandHelp(c, args.First()) + } else { + ShowSubcommandHelp(c) + } + }, +} + +// Prints help for the App +type helpPrinter func(templ string, data interface{}) + +var HelpPrinter helpPrinter = nil + +// Prints version for the App +var VersionPrinter = printVersion + +func ShowAppHelp(c *Context) { + HelpPrinter(AppHelpTemplate, c.App) +} + +// Prints the list of subcommands as the default app completion method +func DefaultAppComplete(c *Context) { + for _, command := range c.App.Commands { + for _, name := range command.Names() { + fmt.Fprintln(c.App.Writer, name) + } + } +} + +// Prints help for the given command +func ShowCommandHelp(c *Context, command string) { + // show the subcommand help for a command with subcommands + if command == "" { + HelpPrinter(SubcommandHelpTemplate, c.App) + return + } + + for _, c := range c.App.Commands { + if c.HasName(command) { + HelpPrinter(CommandHelpTemplate, c) + return + } + } + + if c.App.CommandNotFound != nil { + c.App.CommandNotFound(c, command) + } else { + fmt.Fprintf(c.App.Writer, "No help topic for '%v'\n", command) + } +} + +// Prints help for the given subcommand +func ShowSubcommandHelp(c *Context) { + ShowCommandHelp(c, c.Command.Name) +} + +// Prints the version number of the App +func ShowVersion(c *Context) { + VersionPrinter(c) +} + +func printVersion(c *Context) { + fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version) +} + +// Prints the lists of commands within a given context +func ShowCompletions(c *Context) { + a := c.App + if a != nil && a.BashComplete != nil { + a.BashComplete(c) + } +} + +// Prints the custom completions for a given command +func ShowCommandCompletions(ctx *Context, command string) { + c := ctx.App.Command(command) + if c != nil && c.BashComplete != nil { + c.BashComplete(ctx) + } +} + +func checkVersion(c *Context) bool { + if c.GlobalBool("version") { + ShowVersion(c) + return true + } + + return false +} + +func checkHelp(c *Context) bool { + if c.GlobalBool("h") || c.GlobalBool("help") { + ShowAppHelp(c) + return true + } + + return false +} + +func checkCommandHelp(c *Context, name string) bool { + if c.Bool("h") || c.Bool("help") { + ShowCommandHelp(c, name) + return true + } + + return false +} + +func checkSubcommandHelp(c *Context) bool { + if c.GlobalBool("h") || c.GlobalBool("help") { + ShowSubcommandHelp(c) + return true + } + + return false +} + +func checkCompletions(c *Context) bool { + if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion { + ShowCompletions(c) + return true + } + + return false +} + +func checkCommandCompletions(c *Context, name string) bool { + if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion { + ShowCommandCompletions(c, name) + return true + } + + return false +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go new file mode 100644 index 0000000000..cdc4feb2fc --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go @@ -0,0 +1,19 @@ +package cli_test + +import ( + "reflect" + "testing" +) + +/* Test Helpers */ +func expect(t *testing.T, a interface{}, b interface{}) { + if a != b { + t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} + +func refute(t *testing.T, a interface{}, b interface{}) { + if a == b { + t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common.go new file mode 100644 index 0000000000..8252cd3ee5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common.go @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "io" + "reflect" + "sort" + "strconv" + "unsafe" +) + +const ( + // ptrSize is the size of a pointer on the current arch. + ptrSize = unsafe.Sizeof((*byte)(nil)) +) + +var ( + // offsetPtr, offsetScalar, and offsetFlag are the offsets for the + // internal reflect.Value fields. These values are valid before golang + // commit ecccf07e7f9d which changed the format. The are also valid + // after commit 82f48826c6c7 which changed the format again to mirror + // the original format. Code in the init function updates these offsets + // as necessary. + offsetPtr = uintptr(ptrSize) + offsetScalar = uintptr(0) + offsetFlag = uintptr(ptrSize * 2) + + // flagKindWidth and flagKindShift indicate various bits that the + // reflect package uses internally to track kind information. + // + // flagRO indicates whether or not the value field of a reflect.Value is + // read-only. + // + // flagIndir indicates whether the value field of a reflect.Value is + // the actual data or a pointer to the data. + // + // These values are valid before golang commit 90a7c3c86944 which + // changed their positions. Code in the init function updates these + // flags as necessary. + flagKindWidth = uintptr(5) + flagKindShift = uintptr(flagKindWidth - 1) + flagRO = uintptr(1 << 0) + flagIndir = uintptr(1 << 1) +) + +func init() { + // Older versions of reflect.Value stored small integers directly in the + // ptr field (which is named val in the older versions). Versions + // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named + // scalar for this purpose which unfortunately came before the flag + // field, so the offset of the flag field is different for those + // versions. + // + // This code constructs a new reflect.Value from a known small integer + // and checks if the size of the reflect.Value struct indicates it has + // the scalar field. When it does, the offsets are updated accordingly. + vv := reflect.ValueOf(0xf00) + if unsafe.Sizeof(vv) == (ptrSize * 4) { + offsetScalar = ptrSize * 2 + offsetFlag = ptrSize * 3 + } + + // Commit 90a7c3c86944 changed the flag positions such that the low + // order bits are the kind. This code extracts the kind from the flags + // field and ensures it's the correct type. When it's not, the flag + // order has been changed to the newer format, so the flags are updated + // accordingly. + upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag) + upfv := *(*uintptr)(upf) + flagKindMask := uintptr((1<>flagKindShift != uintptr(reflect.Int) { + flagKindShift = 0 + flagRO = 1 << 5 + flagIndir = 1 << 6 + } +} + +// unsafeReflectValue converts the passed reflect.Value into a one that bypasses +// the typical safety restrictions preventing access to unaddressable and +// unexported data. It works by digging the raw pointer to the underlying +// value out of the protected value and generating a new unprotected (unsafe) +// reflect.Value to it. +// +// This allows us to check for implementations of the Stringer and error +// interfaces to be used for pretty printing ordinarily unaddressable and +// inaccessible values such as unexported struct fields. +func unsafeReflectValue(v reflect.Value) (rv reflect.Value) { + indirects := 1 + vt := v.Type() + upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr) + rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag)) + if rvf&flagIndir != 0 { + vt = reflect.PtrTo(v.Type()) + indirects++ + } else if offsetScalar != 0 { + // The value is in the scalar field when it's not one of the + // reference types. + switch vt.Kind() { + case reflect.Uintptr: + case reflect.Chan: + case reflect.Func: + case reflect.Map: + case reflect.Ptr: + case reflect.UnsafePointer: + default: + upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + + offsetScalar) + } + } + + pv := reflect.NewAt(vt, upv) + rv = pv + for i := 0; i < indirects; i++ { + rv = rv.Elem() + } + return rv +} + +// Some constants in the form of bytes to avoid string overhead. This mirrors +// the technique used in the fmt package. +var ( + panicBytes = []byte("(PANIC=") + plusBytes = []byte("+") + iBytes = []byte("i") + trueBytes = []byte("true") + falseBytes = []byte("false") + interfaceBytes = []byte("(interface {})") + commaNewlineBytes = []byte(",\n") + newlineBytes = []byte("\n") + openBraceBytes = []byte("{") + openBraceNewlineBytes = []byte("{\n") + closeBraceBytes = []byte("}") + asteriskBytes = []byte("*") + colonBytes = []byte(":") + colonSpaceBytes = []byte(": ") + openParenBytes = []byte("(") + closeParenBytes = []byte(")") + spaceBytes = []byte(" ") + pointerChainBytes = []byte("->") + nilAngleBytes = []byte("") + maxNewlineBytes = []byte("\n") + maxShortBytes = []byte("") + circularBytes = []byte("") + circularShortBytes = []byte("") + invalidAngleBytes = []byte("") + openBracketBytes = []byte("[") + closeBracketBytes = []byte("]") + percentBytes = []byte("%") + precisionBytes = []byte(".") + openAngleBytes = []byte("<") + closeAngleBytes = []byte(">") + openMapBytes = []byte("map[") + closeMapBytes = []byte("]") + lenEqualsBytes = []byte("len=") + capEqualsBytes = []byte("cap=") +) + +// hexDigits is used to map a decimal value to a hex digit. +var hexDigits = "0123456789abcdef" + +// catchPanic handles any panics that might occur during the handleMethods +// calls. +func catchPanic(w io.Writer, v reflect.Value) { + if err := recover(); err != nil { + w.Write(panicBytes) + fmt.Fprintf(w, "%v", err) + w.Write(closeParenBytes) + } +} + +// handleMethods attempts to call the Error and String methods on the underlying +// type the passed reflect.Value represents and outputes the result to Writer w. +// +// It handles panics in any called methods by catching and displaying the error +// as the formatted value. +func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { + // We need an interface to check if the type implements the error or + // Stringer interface. However, the reflect package won't give us an + // interface on certain things like unexported struct fields in order + // to enforce visibility rules. We use unsafe to bypass these restrictions + // since this package does not mutate the values. + if !v.CanInterface() { + v = unsafeReflectValue(v) + } + + // Choose whether or not to do error and Stringer interface lookups against + // the base type or a pointer to the base type depending on settings. + // Technically calling one of these methods with a pointer receiver can + // mutate the value, however, types which choose to satisify an error or + // Stringer interface with a pointer receiver should not be mutating their + // state inside these interface methods. + var viface interface{} + if !cs.DisablePointerMethods { + if !v.CanAddr() { + v = unsafeReflectValue(v) + } + viface = v.Addr().Interface() + } else { + if v.CanAddr() { + v = v.Addr() + } + viface = v.Interface() + } + + // Is it an error or Stringer? + switch iface := viface.(type) { + case error: + defer catchPanic(w, v) + if cs.ContinueOnMethod { + w.Write(openParenBytes) + w.Write([]byte(iface.Error())) + w.Write(closeParenBytes) + w.Write(spaceBytes) + return false + } + + w.Write([]byte(iface.Error())) + return true + + case fmt.Stringer: + defer catchPanic(w, v) + if cs.ContinueOnMethod { + w.Write(openParenBytes) + w.Write([]byte(iface.String())) + w.Write(closeParenBytes) + w.Write(spaceBytes) + return false + } + w.Write([]byte(iface.String())) + return true + } + return false +} + +// printBool outputs a boolean value as true or false to Writer w. +func printBool(w io.Writer, val bool) { + if val { + w.Write(trueBytes) + } else { + w.Write(falseBytes) + } +} + +// printInt outputs a signed integer value to Writer w. +func printInt(w io.Writer, val int64, base int) { + w.Write([]byte(strconv.FormatInt(val, base))) +} + +// printUint outputs an unsigned integer value to Writer w. +func printUint(w io.Writer, val uint64, base int) { + w.Write([]byte(strconv.FormatUint(val, base))) +} + +// printFloat outputs a floating point value using the specified precision, +// which is expected to be 32 or 64bit, to Writer w. +func printFloat(w io.Writer, val float64, precision int) { + w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) +} + +// printComplex outputs a complex value using the specified float precision +// for the real and imaginary parts to Writer w. +func printComplex(w io.Writer, c complex128, floatPrecision int) { + r := real(c) + w.Write(openParenBytes) + w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) + i := imag(c) + if i >= 0 { + w.Write(plusBytes) + } + w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) + w.Write(iBytes) + w.Write(closeParenBytes) +} + +// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x' +// prefix to Writer w. +func printHexPtr(w io.Writer, p uintptr) { + // Null pointer. + num := uint64(p) + if num == 0 { + w.Write(nilAngleBytes) + return + } + + // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix + buf := make([]byte, 18) + + // It's simpler to construct the hex string right to left. + base := uint64(16) + i := len(buf) - 1 + for num >= base { + buf[i] = hexDigits[num%base] + num /= base + i-- + } + buf[i] = hexDigits[num] + + // Add '0x' prefix. + i-- + buf[i] = 'x' + i-- + buf[i] = '0' + + // Strip unused leading bytes. + buf = buf[i:] + w.Write(buf) +} + +// valuesSorter implements sort.Interface to allow a slice of reflect.Value +// elements to be sorted. +type valuesSorter struct { + values []reflect.Value + strings []string // either nil or same len and values + cs *ConfigState +} + +// newValuesSorter initializes a valuesSorter instance, which holds a set of +// surrogate keys on which the data should be sorted. It uses flags in +// ConfigState to decide if and how to populate those surrogate keys. +func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { + vs := &valuesSorter{values: values, cs: cs} + if canSortSimply(vs.values[0].Kind()) { + return vs + } + if !cs.DisableMethods { + vs.strings = make([]string, len(values)) + for i := range vs.values { + b := bytes.Buffer{} + if !handleMethods(cs, &b, vs.values[i]) { + vs.strings = nil + break + } + vs.strings[i] = b.String() + } + } + if vs.strings == nil && cs.SpewKeys { + vs.strings = make([]string, len(values)) + for i := range vs.values { + vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) + } + } + return vs +} + +// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted +// directly, or whether it should be considered for sorting by surrogate keys +// (if the ConfigState allows it). +func canSortSimply(kind reflect.Kind) bool { + // This switch parallels valueSortLess, except for the default case. + switch kind { + case reflect.Bool: + return true + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return true + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return true + case reflect.Float32, reflect.Float64: + return true + case reflect.String: + return true + case reflect.Uintptr: + return true + case reflect.Array: + return true + } + return false +} + +// Len returns the number of values in the slice. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Len() int { + return len(s.values) +} + +// Swap swaps the values at the passed indices. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Swap(i, j int) { + s.values[i], s.values[j] = s.values[j], s.values[i] + if s.strings != nil { + s.strings[i], s.strings[j] = s.strings[j], s.strings[i] + } +} + +// valueSortLess returns whether the first value should sort before the second +// value. It is used by valueSorter.Less as part of the sort.Interface +// implementation. +func valueSortLess(a, b reflect.Value) bool { + switch a.Kind() { + case reflect.Bool: + return !a.Bool() && b.Bool() + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return a.Int() < b.Int() + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return a.Uint() < b.Uint() + case reflect.Float32, reflect.Float64: + return a.Float() < b.Float() + case reflect.String: + return a.String() < b.String() + case reflect.Uintptr: + return a.Uint() < b.Uint() + case reflect.Array: + // Compare the contents of both arrays. + l := a.Len() + for i := 0; i < l; i++ { + av := a.Index(i) + bv := b.Index(i) + if av.Interface() == bv.Interface() { + continue + } + return valueSortLess(av, bv) + } + } + return a.String() < b.String() +} + +// Less returns whether the value at index i should sort before the +// value at index j. It is part of the sort.Interface implementation. +func (s *valuesSorter) Less(i, j int) bool { + if s.strings == nil { + return valueSortLess(s.values[i], s.values[j]) + } + return s.strings[i] < s.strings[j] +} + +// sortValues is a sort function that handles both native types and any type that +// can be converted to error or Stringer. Other inputs are sorted according to +// their Value.String() value to ensure display stability. +func sortValues(values []reflect.Value, cs *ConfigState) { + if len(values) == 0 { + return + } + sort.Sort(newValuesSorter(values, cs)) +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common_test.go new file mode 100644 index 0000000000..39b7525b3d --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common_test.go @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew_test + +import ( + "fmt" + "reflect" + "testing" + + "github.com/davecgh/go-spew/spew" +) + +// custom type to test Stinger interface on non-pointer receiver. +type stringer string + +// String implements the Stringer interface for testing invocation of custom +// stringers on types with non-pointer receivers. +func (s stringer) String() string { + return "stringer " + string(s) +} + +// custom type to test Stinger interface on pointer receiver. +type pstringer string + +// String implements the Stringer interface for testing invocation of custom +// stringers on types with only pointer receivers. +func (s *pstringer) String() string { + return "stringer " + string(*s) +} + +// xref1 and xref2 are cross referencing structs for testing circular reference +// detection. +type xref1 struct { + ps2 *xref2 +} +type xref2 struct { + ps1 *xref1 +} + +// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular +// reference for testing detection. +type indirCir1 struct { + ps2 *indirCir2 +} +type indirCir2 struct { + ps3 *indirCir3 +} +type indirCir3 struct { + ps1 *indirCir1 +} + +// embed is used to test embedded structures. +type embed struct { + a string +} + +// embedwrap is used to test embedded structures. +type embedwrap struct { + *embed + e *embed +} + +// panicer is used to intentionally cause a panic for testing spew properly +// handles them +type panicer int + +func (p panicer) String() string { + panic("test panic") +} + +// customError is used to test custom error interface invocation. +type customError int + +func (e customError) Error() string { + return fmt.Sprintf("error: %d", int(e)) +} + +// stringizeWants converts a slice of wanted test output into a format suitable +// for a test error message. +func stringizeWants(wants []string) string { + s := "" + for i, want := range wants { + if i > 0 { + s += fmt.Sprintf("want%d: %s", i+1, want) + } else { + s += "want: " + want + } + } + return s +} + +// testFailed returns whether or not a test failed by checking if the result +// of the test is in the slice of wanted strings. +func testFailed(result string, wants []string) bool { + for _, want := range wants { + if result == want { + return false + } + } + return true +} + +type sortableStruct struct { + x int +} + +func (ss sortableStruct) String() string { + return fmt.Sprintf("ss.%d", ss.x) +} + +type unsortableStruct struct { + x int +} + +type sortTestCase struct { + input []reflect.Value + expected []reflect.Value +} + +func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) { + getInterfaces := func(values []reflect.Value) []interface{} { + interfaces := []interface{}{} + for _, v := range values { + interfaces = append(interfaces, v.Interface()) + } + return interfaces + } + + for _, test := range tests { + spew.SortValues(test.input, cs) + // reflect.DeepEqual cannot really make sense of reflect.Value, + // probably because of all the pointer tricks. For instance, + // v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{} + // instead. + input := getInterfaces(test.input) + expected := getInterfaces(test.expected) + if !reflect.DeepEqual(input, expected) { + t.Errorf("Sort mismatch:\n %v != %v", input, expected) + } + } +} + +// TestSortValues ensures the sort functionality for relect.Value based sorting +// works as intended. +func TestSortValues(t *testing.T) { + v := reflect.ValueOf + + a := v("a") + b := v("b") + c := v("c") + embedA := v(embed{"a"}) + embedB := v(embed{"b"}) + embedC := v(embed{"c"}) + tests := []sortTestCase{ + // No values. + { + []reflect.Value{}, + []reflect.Value{}, + }, + // Bools. + { + []reflect.Value{v(false), v(true), v(false)}, + []reflect.Value{v(false), v(false), v(true)}, + }, + // Ints. + { + []reflect.Value{v(2), v(1), v(3)}, + []reflect.Value{v(1), v(2), v(3)}, + }, + // Uints. + { + []reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))}, + []reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))}, + }, + // Floats. + { + []reflect.Value{v(2.0), v(1.0), v(3.0)}, + []reflect.Value{v(1.0), v(2.0), v(3.0)}, + }, + // Strings. + { + []reflect.Value{b, a, c}, + []reflect.Value{a, b, c}, + }, + // Array + { + []reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})}, + []reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})}, + }, + // Uintptrs. + { + []reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))}, + []reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))}, + }, + // SortableStructs. + { + // Note: not sorted - DisableMethods is set. + []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, + []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, + }, + // UnsortableStructs. + { + // Note: not sorted - SpewKeys is false. + []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, + []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, + }, + // Invalid. + { + []reflect.Value{embedB, embedA, embedC}, + []reflect.Value{embedB, embedA, embedC}, + }, + } + cs := spew.ConfigState{DisableMethods: true, SpewKeys: false} + helpTestSortValues(tests, &cs, t) +} + +// TestSortValuesWithMethods ensures the sort functionality for relect.Value +// based sorting works as intended when using string methods. +func TestSortValuesWithMethods(t *testing.T) { + v := reflect.ValueOf + + a := v("a") + b := v("b") + c := v("c") + tests := []sortTestCase{ + // Ints. + { + []reflect.Value{v(2), v(1), v(3)}, + []reflect.Value{v(1), v(2), v(3)}, + }, + // Strings. + { + []reflect.Value{b, a, c}, + []reflect.Value{a, b, c}, + }, + // SortableStructs. + { + []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, + []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})}, + }, + // UnsortableStructs. + { + // Note: not sorted - SpewKeys is false. + []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, + []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, + }, + } + cs := spew.ConfigState{DisableMethods: false, SpewKeys: false} + helpTestSortValues(tests, &cs, t) +} + +// TestSortValuesWithSpew ensures the sort functionality for relect.Value +// based sorting works as intended when using spew to stringify keys. +func TestSortValuesWithSpew(t *testing.T) { + v := reflect.ValueOf + + a := v("a") + b := v("b") + c := v("c") + tests := []sortTestCase{ + // Ints. + { + []reflect.Value{v(2), v(1), v(3)}, + []reflect.Value{v(1), v(2), v(3)}, + }, + // Strings. + { + []reflect.Value{b, a, c}, + []reflect.Value{a, b, c}, + }, + // SortableStructs. + { + []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, + []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})}, + }, + // UnsortableStructs. + { + []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, + []reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})}, + }, + } + cs := spew.ConfigState{DisableMethods: true, SpewKeys: true} + helpTestSortValues(tests, &cs, t) +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/config.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/config.go new file mode 100644 index 0000000000..9e21b38ca2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/config.go @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "io" + "os" +) + +// ConfigState houses the configuration options used by spew to format and +// display values. There is a global instance, Config, that is used to control +// all top-level Formatter and Dump functionality. Each ConfigState instance +// provides methods equivalent to the top-level functions. +// +// The zero value for ConfigState provides no indentation. You would typically +// want to set it to a space or a tab. +// +// Alternatively, you can use NewDefaultConfig to get a ConfigState instance +// with default settings. See the documentation of NewDefaultConfig for default +// values. +type ConfigState struct { + // Indent specifies the string to use for each indentation level. The + // global config instance that all top-level functions use set this to a + // single space by default. If you would like more indentation, you might + // set this to a tab with "\t" or perhaps two spaces with " ". + Indent string + + // MaxDepth controls the maximum number of levels to descend into nested + // data structures. The default, 0, means there is no limit. + // + // NOTE: Circular data structures are properly detected, so it is not + // necessary to set this value unless you specifically want to limit deeply + // nested data structures. + MaxDepth int + + // DisableMethods specifies whether or not error and Stringer interfaces are + // invoked for types that implement them. + DisableMethods bool + + // DisablePointerMethods specifies whether or not to check for and invoke + // error and Stringer interfaces on types which only accept a pointer + // receiver when the current type is not a pointer. + // + // NOTE: This might be an unsafe action since calling one of these methods + // with a pointer receiver could technically mutate the value, however, + // in practice, types which choose to satisify an error or Stringer + // interface with a pointer receiver should not be mutating their state + // inside these interface methods. + DisablePointerMethods bool + + // ContinueOnMethod specifies whether or not recursion should continue once + // a custom error or Stringer interface is invoked. The default, false, + // means it will print the results of invoking the custom error or Stringer + // interface and return immediately instead of continuing to recurse into + // the internals of the data type. + // + // NOTE: This flag does not have any effect if method invocation is disabled + // via the DisableMethods or DisablePointerMethods options. + ContinueOnMethod bool + + // SortKeys specifies map keys should be sorted before being printed. Use + // this to have a more deterministic, diffable output. Note that only + // native types (bool, int, uint, floats, uintptr and string) and types + // that support the error or Stringer interfaces (if methods are + // enabled) are supported, with other types sorted according to the + // reflect.Value.String() output which guarantees display stability. + SortKeys bool + + // SpewKeys specifies that, as a last resort attempt, map keys should + // be spewed to strings and sorted by those strings. This is only + // considered if SortKeys is true. + SpewKeys bool +} + +// Config is the active configuration of the top-level functions. +// The configuration can be changed by modifying the contents of spew.Config. +var Config = ConfigState{Indent: " "} + +// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the formatted string as a value that satisfies error. See NewFormatter +// for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) { + return fmt.Errorf(format, c.convertArgs(a)...) +} + +// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprint(w, c.convertArgs(a)...) +} + +// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + return fmt.Fprintf(w, format, c.convertArgs(a)...) +} + +// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it +// passed with a Formatter interface returned by c.NewFormatter. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprintln(w, c.convertArgs(a)...) +} + +// Print is a wrapper for fmt.Print that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Print(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Print(a ...interface{}) (n int, err error) { + return fmt.Print(c.convertArgs(a)...) +} + +// Printf is a wrapper for fmt.Printf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) { + return fmt.Printf(format, c.convertArgs(a)...) +} + +// Println is a wrapper for fmt.Println that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Println(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Println(a ...interface{}) (n int, err error) { + return fmt.Println(c.convertArgs(a)...) +} + +// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprint(a ...interface{}) string { + return fmt.Sprint(c.convertArgs(a)...) +} + +// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, c.convertArgs(a)...) +} + +// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it +// were passed with a Formatter interface returned by c.NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprintln(a ...interface{}) string { + return fmt.Sprintln(c.convertArgs(a)...) +} + +/* +NewFormatter returns a custom formatter that satisfies the fmt.Formatter +interface. As a result, it integrates cleanly with standard fmt package +printing functions. The formatter is useful for inline printing of smaller data +types similar to the standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Typically this function shouldn't be called directly. It is much easier to make +use of the custom formatter by calling one of the convenience functions such as +c.Printf, c.Println, or c.Printf. +*/ +func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter { + return newFormatter(c, v) +} + +// Fdump formats and displays the passed arguments to io.Writer w. It formats +// exactly the same as Dump. +func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) { + fdump(c, w, a...) +} + +/* +Dump displays the passed parameters to standard out with newlines, customizable +indentation, and additional debug information such as complete types and all +pointer addresses used to indirect to the final value. It provides the +following features over the built-in printing facilities provided by the fmt +package: + + * Pointers are dereferenced and followed + * Circular data structures are detected and handled properly + * Custom Stringer/error interfaces are optionally invoked, including + on unexported types + * Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + * Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output + +The configuration options are controlled by modifying the public members +of c. See ConfigState for options documentation. + +See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to +get the formatted result as a string. +*/ +func (c *ConfigState) Dump(a ...interface{}) { + fdump(c, os.Stdout, a...) +} + +// Sdump returns a string with the passed arguments formatted exactly the same +// as Dump. +func (c *ConfigState) Sdump(a ...interface{}) string { + var buf bytes.Buffer + fdump(c, &buf, a...) + return buf.String() +} + +// convertArgs accepts a slice of arguments and returns a slice of the same +// length with each argument converted to a spew Formatter interface using +// the ConfigState associated with s. +func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) { + formatters = make([]interface{}, len(args)) + for index, arg := range args { + formatters[index] = newFormatter(c, arg) + } + return formatters +} + +// NewDefaultConfig returns a ConfigState with the following default settings. +// +// Indent: " " +// MaxDepth: 0 +// DisableMethods: false +// DisablePointerMethods: false +// ContinueOnMethod: false +// SortKeys: false +func NewDefaultConfig() *ConfigState { + return &ConfigState{Indent: " "} +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/doc.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/doc.go new file mode 100644 index 0000000000..5be0c40609 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/doc.go @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +Package spew implements a deep pretty printer for Go data structures to aid in +debugging. + +A quick overview of the additional features spew provides over the built-in +printing facilities for Go data types are as follows: + + * Pointers are dereferenced and followed + * Circular data structures are detected and handled properly + * Custom Stringer/error interfaces are optionally invoked, including + on unexported types + * Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + * Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output (only when using + Dump style) + +There are two different approaches spew allows for dumping Go data structures: + + * Dump style which prints with newlines, customizable indentation, + and additional debug information such as types and all pointer addresses + used to indirect to the final value + * A custom Formatter interface that integrates cleanly with the standard fmt + package and replaces %v, %+v, %#v, and %#+v to provide inline printing + similar to the default %v while providing the additional functionality + outlined above and passing unsupported format verbs such as %x and %q + along to fmt + +Quick Start + +This section demonstrates how to quickly get started with spew. See the +sections below for further details on formatting and configuration options. + +To dump a variable with full newlines, indentation, type, and pointer +information use Dump, Fdump, or Sdump: + spew.Dump(myVar1, myVar2, ...) + spew.Fdump(someWriter, myVar1, myVar2, ...) + str := spew.Sdump(myVar1, myVar2, ...) + +Alternatively, if you would prefer to use format strings with a compacted inline +printing style, use the convenience wrappers Printf, Fprintf, etc with +%v (most compact), %+v (adds pointer addresses), %#v (adds types), or +%#+v (adds types and pointer addresses): + spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + +Configuration Options + +Configuration of spew is handled by fields in the ConfigState type. For +convenience, all of the top-level functions use a global state available +via the spew.Config global. + +It is also possible to create a ConfigState instance that provides methods +equivalent to the top-level functions. This allows concurrent configuration +options. See the ConfigState documentation for more details. + +The following configuration options are available: + * Indent + String to use for each indentation level for Dump functions. + It is a single space by default. A popular alternative is "\t". + + * MaxDepth + Maximum number of levels to descend into nested data structures. + There is no limit by default. + + * DisableMethods + Disables invocation of error and Stringer interface methods. + Method invocation is enabled by default. + + * DisablePointerMethods + Disables invocation of error and Stringer interface methods on types + which only accept pointer receivers from non-pointer variables. + Pointer method invocation is enabled by default. + + * ContinueOnMethod + Enables recursion into types after invoking error and Stringer interface + methods. Recursion after method invocation is disabled by default. + + * SortKeys + Specifies map keys should be sorted before being printed. Use + this to have a more deterministic, diffable output. Note that + only native types (bool, int, uint, floats, uintptr and string) + and types which implement error or Stringer interfaces are + supported with other types sorted according to the + reflect.Value.String() output which guarantees display + stability. Natural map order is used by default. + + * SpewKeys + Specifies that, as a last resort attempt, map keys should be + spewed to strings and sorted by those strings. This is only + considered if SortKeys is true. + +Dump Usage + +Simply call spew.Dump with a list of variables you want to dump: + + spew.Dump(myVar1, myVar2, ...) + +You may also call spew.Fdump if you would prefer to output to an arbitrary +io.Writer. For example, to dump to standard error: + + spew.Fdump(os.Stderr, myVar1, myVar2, ...) + +A third option is to call spew.Sdump to get the formatted output as a string: + + str := spew.Sdump(myVar1, myVar2, ...) + +Sample Dump Output + +See the Dump example for details on the setup of the types and variables being +shown here. + + (main.Foo) { + unexportedField: (*main.Bar)(0xf84002e210)({ + flag: (main.Flag) flagTwo, + data: (uintptr) + }), + ExportedField: (map[interface {}]interface {}) (len=1) { + (string) (len=3) "one": (bool) true + } + } + +Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C +command as shown. + ([]uint8) (len=32 cap=32) { + 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | + 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| + 00000020 31 32 |12| + } + +Custom Formatter + +Spew provides a custom formatter that implements the fmt.Formatter interface +so that it integrates cleanly with standard fmt package printing functions. The +formatter is useful for inline printing of smaller data types similar to the +standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Custom Formatter Usage + +The simplest way to make use of the spew custom formatter is to call one of the +convenience functions such as spew.Printf, spew.Println, or spew.Printf. The +functions have syntax you are most likely already familiar with: + + spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + spew.Println(myVar, myVar2) + spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + +See the Index for the full list convenience functions. + +Sample Formatter Output + +Double pointer to a uint8: + %v: <**>5 + %+v: <**>(0xf8400420d0->0xf8400420c8)5 + %#v: (**uint8)5 + %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 + +Pointer to circular struct with a uint8 field and a pointer to itself: + %v: <*>{1 <*>} + %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} + %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} + %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} + +See the Printf example for details on the setup of variables being shown +here. + +Errors + +Since it is possible for custom Stringer/error interfaces to panic, spew +detects them and handles them internally by printing the panic information +inline with the output. Since spew is intended to provide deep pretty printing +capabilities on structures, it intentionally does not return any errors. +*/ +package spew diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump.go new file mode 100644 index 0000000000..5783145b78 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump.go @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "os" + "reflect" + "regexp" + "strconv" + "strings" +) + +var ( + // uint8Type is a reflect.Type representing a uint8. It is used to + // convert cgo types to uint8 slices for hexdumping. + uint8Type = reflect.TypeOf(uint8(0)) + + // cCharRE is a regular expression that matches a cgo char. + // It is used to detect character arrays to hexdump them. + cCharRE = regexp.MustCompile("^.*\\._Ctype_char$") + + // cUnsignedCharRE is a regular expression that matches a cgo unsigned + // char. It is used to detect unsigned character arrays to hexdump + // them. + cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$") + + // cUint8tCharRE is a regular expression that matches a cgo uint8_t. + // It is used to detect uint8_t arrays to hexdump them. + cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$") +) + +// dumpState contains information about the state of a dump operation. +type dumpState struct { + w io.Writer + depth int + pointers map[uintptr]int + ignoreNextType bool + ignoreNextIndent bool + cs *ConfigState +} + +// indent performs indentation according to the depth level and cs.Indent +// option. +func (d *dumpState) indent() { + if d.ignoreNextIndent { + d.ignoreNextIndent = false + return + } + d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth)) +} + +// unpackValue returns values inside of non-nil interfaces when possible. +// This is useful for data types like structs, arrays, slices, and maps which +// can contain varying types packed inside an interface. +func (d *dumpState) unpackValue(v reflect.Value) reflect.Value { + if v.Kind() == reflect.Interface && !v.IsNil() { + v = v.Elem() + } + return v +} + +// dumpPtr handles formatting of pointers by indirecting them as necessary. +func (d *dumpState) dumpPtr(v reflect.Value) { + // Remove pointers at or below the current depth from map used to detect + // circular refs. + for k, depth := range d.pointers { + if depth >= d.depth { + delete(d.pointers, k) + } + } + + // Keep list of all dereferenced pointers to show later. + pointerChain := make([]uintptr, 0) + + // Figure out how many levels of indirection there are by dereferencing + // pointers and unpacking interfaces down the chain while detecting circular + // references. + nilFound := false + cycleFound := false + indirects := 0 + ve := v + for ve.Kind() == reflect.Ptr { + if ve.IsNil() { + nilFound = true + break + } + indirects++ + addr := ve.Pointer() + pointerChain = append(pointerChain, addr) + if pd, ok := d.pointers[addr]; ok && pd < d.depth { + cycleFound = true + indirects-- + break + } + d.pointers[addr] = d.depth + + ve = ve.Elem() + if ve.Kind() == reflect.Interface { + if ve.IsNil() { + nilFound = true + break + } + ve = ve.Elem() + } + } + + // Display type information. + d.w.Write(openParenBytes) + d.w.Write(bytes.Repeat(asteriskBytes, indirects)) + d.w.Write([]byte(ve.Type().String())) + d.w.Write(closeParenBytes) + + // Display pointer information. + if len(pointerChain) > 0 { + d.w.Write(openParenBytes) + for i, addr := range pointerChain { + if i > 0 { + d.w.Write(pointerChainBytes) + } + printHexPtr(d.w, addr) + } + d.w.Write(closeParenBytes) + } + + // Display dereferenced value. + d.w.Write(openParenBytes) + switch { + case nilFound == true: + d.w.Write(nilAngleBytes) + + case cycleFound == true: + d.w.Write(circularBytes) + + default: + d.ignoreNextType = true + d.dump(ve) + } + d.w.Write(closeParenBytes) +} + +// dumpSlice handles formatting of arrays and slices. Byte (uint8 under +// reflection) arrays and slices are dumped in hexdump -C fashion. +func (d *dumpState) dumpSlice(v reflect.Value) { + // Determine whether this type should be hex dumped or not. Also, + // for types which should be hexdumped, try to use the underlying data + // first, then fall back to trying to convert them to a uint8 slice. + var buf []uint8 + doConvert := false + doHexDump := false + numEntries := v.Len() + if numEntries > 0 { + vt := v.Index(0).Type() + vts := vt.String() + switch { + // C types that need to be converted. + case cCharRE.MatchString(vts): + fallthrough + case cUnsignedCharRE.MatchString(vts): + fallthrough + case cUint8tCharRE.MatchString(vts): + doConvert = true + + // Try to use existing uint8 slices and fall back to converting + // and copying if that fails. + case vt.Kind() == reflect.Uint8: + // We need an addressable interface to convert the type back + // into a byte slice. However, the reflect package won't give + // us an interface on certain things like unexported struct + // fields in order to enforce visibility rules. We use unsafe + // to bypass these restrictions since this package does not + // mutate the values. + vs := v + if !vs.CanInterface() || !vs.CanAddr() { + vs = unsafeReflectValue(vs) + } + vs = vs.Slice(0, numEntries) + + // Use the existing uint8 slice if it can be type + // asserted. + iface := vs.Interface() + if slice, ok := iface.([]uint8); ok { + buf = slice + doHexDump = true + break + } + + // The underlying data needs to be converted if it can't + // be type asserted to a uint8 slice. + doConvert = true + } + + // Copy and convert the underlying type if needed. + if doConvert && vt.ConvertibleTo(uint8Type) { + // Convert and copy each element into a uint8 byte + // slice. + buf = make([]uint8, numEntries) + for i := 0; i < numEntries; i++ { + vv := v.Index(i) + buf[i] = uint8(vv.Convert(uint8Type).Uint()) + } + doHexDump = true + } + } + + // Hexdump the entire slice as needed. + if doHexDump { + indent := strings.Repeat(d.cs.Indent, d.depth) + str := indent + hex.Dump(buf) + str = strings.Replace(str, "\n", "\n"+indent, -1) + str = strings.TrimRight(str, d.cs.Indent) + d.w.Write([]byte(str)) + return + } + + // Recursively call dump for each item. + for i := 0; i < numEntries; i++ { + d.dump(d.unpackValue(v.Index(i))) + if i < (numEntries - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } +} + +// dump is the main workhorse for dumping a value. It uses the passed reflect +// value to figure out what kind of object we are dealing with and formats it +// appropriately. It is a recursive function, however circular data structures +// are detected and handled properly. +func (d *dumpState) dump(v reflect.Value) { + // Handle invalid reflect values immediately. + kind := v.Kind() + if kind == reflect.Invalid { + d.w.Write(invalidAngleBytes) + return + } + + // Handle pointers specially. + if kind == reflect.Ptr { + d.indent() + d.dumpPtr(v) + return + } + + // Print type information unless already handled elsewhere. + if !d.ignoreNextType { + d.indent() + d.w.Write(openParenBytes) + d.w.Write([]byte(v.Type().String())) + d.w.Write(closeParenBytes) + d.w.Write(spaceBytes) + } + d.ignoreNextType = false + + // Display length and capacity if the built-in len and cap functions + // work with the value's kind and the len/cap itself is non-zero. + valueLen, valueCap := 0, 0 + switch v.Kind() { + case reflect.Array, reflect.Slice, reflect.Chan: + valueLen, valueCap = v.Len(), v.Cap() + case reflect.Map, reflect.String: + valueLen = v.Len() + } + if valueLen != 0 || valueCap != 0 { + d.w.Write(openParenBytes) + if valueLen != 0 { + d.w.Write(lenEqualsBytes) + printInt(d.w, int64(valueLen), 10) + } + if valueCap != 0 { + if valueLen != 0 { + d.w.Write(spaceBytes) + } + d.w.Write(capEqualsBytes) + printInt(d.w, int64(valueCap), 10) + } + d.w.Write(closeParenBytes) + d.w.Write(spaceBytes) + } + + // Call Stringer/error interfaces if they exist and the handle methods flag + // is enabled + if !d.cs.DisableMethods { + if (kind != reflect.Invalid) && (kind != reflect.Interface) { + if handled := handleMethods(d.cs, d.w, v); handled { + return + } + } + } + + switch kind { + case reflect.Invalid: + // Do nothing. We should never get here since invalid has already + // been handled above. + + case reflect.Bool: + printBool(d.w, v.Bool()) + + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + printInt(d.w, v.Int(), 10) + + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + printUint(d.w, v.Uint(), 10) + + case reflect.Float32: + printFloat(d.w, v.Float(), 32) + + case reflect.Float64: + printFloat(d.w, v.Float(), 64) + + case reflect.Complex64: + printComplex(d.w, v.Complex(), 32) + + case reflect.Complex128: + printComplex(d.w, v.Complex(), 64) + + case reflect.Slice: + if v.IsNil() { + d.w.Write(nilAngleBytes) + break + } + fallthrough + + case reflect.Array: + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + d.dumpSlice(v) + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.String: + d.w.Write([]byte(strconv.Quote(v.String()))) + + case reflect.Interface: + // The only time we should get here is for nil interfaces due to + // unpackValue calls. + if v.IsNil() { + d.w.Write(nilAngleBytes) + } + + case reflect.Ptr: + // Do nothing. We should never get here since pointers have already + // been handled above. + + case reflect.Map: + // nil maps should be indicated as different than empty maps + if v.IsNil() { + d.w.Write(nilAngleBytes) + break + } + + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + numEntries := v.Len() + keys := v.MapKeys() + if d.cs.SortKeys { + sortValues(keys, d.cs) + } + for i, key := range keys { + d.dump(d.unpackValue(key)) + d.w.Write(colonSpaceBytes) + d.ignoreNextIndent = true + d.dump(d.unpackValue(v.MapIndex(key))) + if i < (numEntries - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.Struct: + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + vt := v.Type() + numFields := v.NumField() + for i := 0; i < numFields; i++ { + d.indent() + vtf := vt.Field(i) + d.w.Write([]byte(vtf.Name)) + d.w.Write(colonSpaceBytes) + d.ignoreNextIndent = true + d.dump(d.unpackValue(v.Field(i))) + if i < (numFields - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.Uintptr: + printHexPtr(d.w, uintptr(v.Uint())) + + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + printHexPtr(d.w, v.Pointer()) + + // There were not any other types at the time this code was written, but + // fall back to letting the default fmt package handle it in case any new + // types are added. + default: + if v.CanInterface() { + fmt.Fprintf(d.w, "%v", v.Interface()) + } else { + fmt.Fprintf(d.w, "%v", v.String()) + } + } +} + +// fdump is a helper function to consolidate the logic from the various public +// methods which take varying writers and config states. +func fdump(cs *ConfigState, w io.Writer, a ...interface{}) { + for _, arg := range a { + if arg == nil { + w.Write(interfaceBytes) + w.Write(spaceBytes) + w.Write(nilAngleBytes) + w.Write(newlineBytes) + continue + } + + d := dumpState{w: w, cs: cs} + d.pointers = make(map[uintptr]int) + d.dump(reflect.ValueOf(arg)) + d.w.Write(newlineBytes) + } +} + +// Fdump formats and displays the passed arguments to io.Writer w. It formats +// exactly the same as Dump. +func Fdump(w io.Writer, a ...interface{}) { + fdump(&Config, w, a...) +} + +// Sdump returns a string with the passed arguments formatted exactly the same +// as Dump. +func Sdump(a ...interface{}) string { + var buf bytes.Buffer + fdump(&Config, &buf, a...) + return buf.String() +} + +/* +Dump displays the passed parameters to standard out with newlines, customizable +indentation, and additional debug information such as complete types and all +pointer addresses used to indirect to the final value. It provides the +following features over the built-in printing facilities provided by the fmt +package: + + * Pointers are dereferenced and followed + * Circular data structures are detected and handled properly + * Custom Stringer/error interfaces are optionally invoked, including + on unexported types + * Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + * Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output + +The configuration options are controlled by an exported package global, +spew.Config. See ConfigState for options documentation. + +See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to +get the formatted result as a string. +*/ +func Dump(a ...interface{}) { + fdump(&Config, os.Stdout, a...) +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump_test.go new file mode 100644 index 0000000000..3dd9089177 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump_test.go @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +Test Summary: +NOTE: For each test, a nil pointer, a single pointer and double pointer to the +base test element are also tested to ensure proper indirection across all types. + +- Max int8, int16, int32, int64, int +- Max uint8, uint16, uint32, uint64, uint +- Boolean true and false +- Standard complex64 and complex128 +- Array containing standard ints +- Array containing type with custom formatter on pointer receiver only +- Array containing interfaces +- Array containing bytes +- Slice containing standard float32 values +- Slice containing type with custom formatter on pointer receiver only +- Slice containing interfaces +- Slice containing bytes +- Nil slice +- Standard string +- Nil interface +- Sub-interface +- Map with string keys and int vals +- Map with custom formatter type on pointer receiver only keys and vals +- Map with interface keys and values +- Map with nil interface value +- Struct with primitives +- Struct that contains another struct +- Struct that contains custom type with Stringer pointer interface via both + exported and unexported fields +- Struct that contains embedded struct and field to same struct +- Uintptr to 0 (null pointer) +- Uintptr address of real variable +- Unsafe.Pointer to 0 (null pointer) +- Unsafe.Pointer to address of real variable +- Nil channel +- Standard int channel +- Function with no params and no returns +- Function with param and no returns +- Function with multiple params and multiple returns +- Struct that is circular through self referencing +- Structs that are circular through cross referencing +- Structs that are indirectly circular +- Type that panics in its Stringer interface +*/ + +package spew_test + +import ( + "bytes" + "fmt" + "testing" + "unsafe" + + "github.com/davecgh/go-spew/spew" +) + +// dumpTest is used to describe a test to be perfomed against the Dump method. +type dumpTest struct { + in interface{} + wants []string +} + +// dumpTests houses all of the tests to be performed against the Dump method. +var dumpTests = make([]dumpTest, 0) + +// addDumpTest is a helper method to append the passed input and desired result +// to dumpTests +func addDumpTest(in interface{}, wants ...string) { + test := dumpTest{in, wants} + dumpTests = append(dumpTests, test) +} + +func addIntDumpTests() { + // Max int8. + v := int8(127) + nv := (*int8)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "int8" + vs := "127" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Max int16. + v2 := int16(32767) + nv2 := (*int16)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "int16" + v2s := "32767" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") + + // Max int32. + v3 := int32(2147483647) + nv3 := (*int32)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "int32" + v3s := "2147483647" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Max int64. + v4 := int64(9223372036854775807) + nv4 := (*int64)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "int64" + v4s := "9223372036854775807" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") + + // Max int. + v5 := int(2147483647) + nv5 := (*int)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "int" + v5s := "2147483647" + addDumpTest(v5, "("+v5t+") "+v5s+"\n") + addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") + addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") + addDumpTest(nv5, "(*"+v5t+")()\n") +} + +func addUintDumpTests() { + // Max uint8. + v := uint8(255) + nv := (*uint8)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "uint8" + vs := "255" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Max uint16. + v2 := uint16(65535) + nv2 := (*uint16)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uint16" + v2s := "65535" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") + + // Max uint32. + v3 := uint32(4294967295) + nv3 := (*uint32)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "uint32" + v3s := "4294967295" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Max uint64. + v4 := uint64(18446744073709551615) + nv4 := (*uint64)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "uint64" + v4s := "18446744073709551615" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") + + // Max uint. + v5 := uint(4294967295) + nv5 := (*uint)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "uint" + v5s := "4294967295" + addDumpTest(v5, "("+v5t+") "+v5s+"\n") + addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") + addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") + addDumpTest(nv5, "(*"+v5t+")()\n") +} + +func addBoolDumpTests() { + // Boolean true. + v := bool(true) + nv := (*bool)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "bool" + vs := "true" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Boolean false. + v2 := bool(false) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "bool" + v2s := "false" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") +} + +func addFloatDumpTests() { + // Standard float32. + v := float32(3.1415) + nv := (*float32)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "float32" + vs := "3.1415" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Standard float64. + v2 := float64(3.1415926) + nv2 := (*float64)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "float64" + v2s := "3.1415926" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") +} + +func addComplexDumpTests() { + // Standard complex64. + v := complex(float32(6), -2) + nv := (*complex64)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "complex64" + vs := "(6-2i)" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Standard complex128. + v2 := complex(float64(-6), 2) + nv2 := (*complex128)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "complex128" + v2s := "(-6+2i)" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") +} + +func addArrayDumpTests() { + // Array containing standard ints. + v := [3]int{1, 2, 3} + vLen := fmt.Sprintf("%d", len(v)) + vCap := fmt.Sprintf("%d", cap(v)) + nv := (*[3]int)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "int" + vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" + + vt + ") 2,\n (" + vt + ") 3\n}" + addDumpTest(v, "([3]"+vt+") "+vs+"\n") + addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*[3]"+vt+")()\n") + + // Array containing type with custom formatter on pointer receiver only. + v2i0 := pstringer("1") + v2i1 := pstringer("2") + v2i2 := pstringer("3") + v2 := [3]pstringer{v2i0, v2i1, v2i2} + v2i0Len := fmt.Sprintf("%d", len(v2i0)) + v2i1Len := fmt.Sprintf("%d", len(v2i1)) + v2i2Len := fmt.Sprintf("%d", len(v2i2)) + v2Len := fmt.Sprintf("%d", len(v2)) + v2Cap := fmt.Sprintf("%d", cap(v2)) + nv2 := (*[3]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.pstringer" + v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" + + v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len + + ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " + + "stringer 3\n}" + addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*[3]"+v2t+")()\n") + + // Array containing interfaces. + v3i0 := "one" + v3 := [3]interface{}{v3i0, int(2), uint(3)} + v3i0Len := fmt.Sprintf("%d", len(v3i0)) + v3Len := fmt.Sprintf("%d", len(v3)) + v3Cap := fmt.Sprintf("%d", cap(v3)) + nv3 := (*[3]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "[3]interface {}" + v3t2 := "string" + v3t3 := "int" + v3t4 := "uint" + v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + + "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + + v3t4 + ") 3\n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Array containing bytes. + v4 := [34]byte{ + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, + } + v4Len := fmt.Sprintf("%d", len(v4)) + v4Cap := fmt.Sprintf("%d", cap(v4)) + nv4 := (*[34]byte)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "[34]uint8" + v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + + "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + + " |............... |\n" + + " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + + " |!\"#$%&'()*+,-./0|\n" + + " 00000020 31 32 " + + " |12|\n}" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") +} + +func addSliceDumpTests() { + // Slice containing standard float32 values. + v := []float32{3.14, 6.28, 12.56} + vLen := fmt.Sprintf("%d", len(v)) + vCap := fmt.Sprintf("%d", cap(v)) + nv := (*[]float32)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "float32" + vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" + + vt + ") 6.28,\n (" + vt + ") 12.56\n}" + addDumpTest(v, "([]"+vt+") "+vs+"\n") + addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*[]"+vt+")()\n") + + // Slice containing type with custom formatter on pointer receiver only. + v2i0 := pstringer("1") + v2i1 := pstringer("2") + v2i2 := pstringer("3") + v2 := []pstringer{v2i0, v2i1, v2i2} + v2i0Len := fmt.Sprintf("%d", len(v2i0)) + v2i1Len := fmt.Sprintf("%d", len(v2i1)) + v2i2Len := fmt.Sprintf("%d", len(v2i2)) + v2Len := fmt.Sprintf("%d", len(v2)) + v2Cap := fmt.Sprintf("%d", cap(v2)) + nv2 := (*[]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.pstringer" + v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" + + v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len + + ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " + + "stringer 3\n}" + addDumpTest(v2, "([]"+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*[]"+v2t+")()\n") + + // Slice containing interfaces. + v3i0 := "one" + v3 := []interface{}{v3i0, int(2), uint(3), nil} + v3i0Len := fmt.Sprintf("%d", len(v3i0)) + v3Len := fmt.Sprintf("%d", len(v3)) + v3Cap := fmt.Sprintf("%d", cap(v3)) + nv3 := (*[]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "[]interface {}" + v3t2 := "string" + v3t3 := "int" + v3t4 := "uint" + v3t5 := "interface {}" + v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + + "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + + v3t4 + ") 3,\n (" + v3t5 + ") \n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Slice containing bytes. + v4 := []byte{ + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, + } + v4Len := fmt.Sprintf("%d", len(v4)) + v4Cap := fmt.Sprintf("%d", cap(v4)) + nv4 := (*[]byte)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "[]uint8" + v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + + "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + + " |............... |\n" + + " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + + " |!\"#$%&'()*+,-./0|\n" + + " 00000020 31 32 " + + " |12|\n}" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") + + // Nil slice. + v5 := []int(nil) + nv5 := (*[]int)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "[]int" + v5s := "" + addDumpTest(v5, "("+v5t+") "+v5s+"\n") + addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") + addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") + addDumpTest(nv5, "(*"+v5t+")()\n") +} + +func addStringDumpTests() { + // Standard string. + v := "test" + vLen := fmt.Sprintf("%d", len(v)) + nv := (*string)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "string" + vs := "(len=" + vLen + ") \"test\"" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") +} + +func addInterfaceDumpTests() { + // Nil interface. + var v interface{} + nv := (*interface{})(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "interface {}" + vs := "" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Sub-interface. + v2 := interface{}(uint16(65535)) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uint16" + v2s := "65535" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") +} + +func addMapDumpTests() { + // Map with string keys and int vals. + k := "one" + kk := "two" + m := map[string]int{k: 1, kk: 2} + klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up + kkLen := fmt.Sprintf("%d", len(kk)) + mLen := fmt.Sprintf("%d", len(m)) + nilMap := map[string]int(nil) + nm := (*map[string]int)(nil) + pm := &m + mAddr := fmt.Sprintf("%p", pm) + pmAddr := fmt.Sprintf("%p", &pm) + mt := "map[string]int" + mt1 := "string" + mt2 := "int" + ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " + + "\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen + + ") \"two\": (" + mt2 + ") 2\n}" + ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " + + "\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen + + ") \"one\": (" + mt2 + ") 1\n}" + addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n") + addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n", + "(*"+mt+")("+mAddr+")("+ms2+")\n") + addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n", + "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n") + addDumpTest(nm, "(*"+mt+")()\n") + addDumpTest(nilMap, "("+mt+") \n") + + // Map with custom formatter type on pointer receiver only keys and vals. + k2 := pstringer("one") + v2 := pstringer("1") + m2 := map[pstringer]pstringer{k2: v2} + k2Len := fmt.Sprintf("%d", len(k2)) + v2Len := fmt.Sprintf("%d", len(v2)) + m2Len := fmt.Sprintf("%d", len(m2)) + nilMap2 := map[pstringer]pstringer(nil) + nm2 := (*map[pstringer]pstringer)(nil) + pm2 := &m2 + m2Addr := fmt.Sprintf("%p", pm2) + pm2Addr := fmt.Sprintf("%p", &pm2) + m2t := "map[spew_test.pstringer]spew_test.pstringer" + m2t1 := "spew_test.pstringer" + m2t2 := "spew_test.pstringer" + m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " + + "stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}" + addDumpTest(m2, "("+m2t+") "+m2s+"\n") + addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n") + addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n") + addDumpTest(nm2, "(*"+m2t+")()\n") + addDumpTest(nilMap2, "("+m2t+") \n") + + // Map with interface keys and values. + k3 := "one" + k3Len := fmt.Sprintf("%d", len(k3)) + m3 := map[interface{}]interface{}{k3: 1} + m3Len := fmt.Sprintf("%d", len(m3)) + nilMap3 := map[interface{}]interface{}(nil) + nm3 := (*map[interface{}]interface{})(nil) + pm3 := &m3 + m3Addr := fmt.Sprintf("%p", pm3) + pm3Addr := fmt.Sprintf("%p", &pm3) + m3t := "map[interface {}]interface {}" + m3t1 := "string" + m3t2 := "int" + m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " + + "\"one\": (" + m3t2 + ") 1\n}" + addDumpTest(m3, "("+m3t+") "+m3s+"\n") + addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n") + addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n") + addDumpTest(nm3, "(*"+m3t+")()\n") + addDumpTest(nilMap3, "("+m3t+") \n") + + // Map with nil interface value. + k4 := "nil" + k4Len := fmt.Sprintf("%d", len(k4)) + m4 := map[string]interface{}{k4: nil} + m4Len := fmt.Sprintf("%d", len(m4)) + nilMap4 := map[string]interface{}(nil) + nm4 := (*map[string]interface{})(nil) + pm4 := &m4 + m4Addr := fmt.Sprintf("%p", pm4) + pm4Addr := fmt.Sprintf("%p", &pm4) + m4t := "map[string]interface {}" + m4t1 := "string" + m4t2 := "interface {}" + m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" + + " \"nil\": (" + m4t2 + ") \n}" + addDumpTest(m4, "("+m4t+") "+m4s+"\n") + addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n") + addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n") + addDumpTest(nm4, "(*"+m4t+")()\n") + addDumpTest(nilMap4, "("+m4t+") \n") +} + +func addStructDumpTests() { + // Struct with primitives. + type s1 struct { + a int8 + b uint8 + } + v := s1{127, 255} + nv := (*s1)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.s1" + vt2 := "int8" + vt3 := "uint8" + vs := "{\n a: (" + vt2 + ") 127,\n b: (" + vt3 + ") 255\n}" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Struct that contains another struct. + type s2 struct { + s1 s1 + b bool + } + v2 := s2{s1{127, 255}, true} + nv2 := (*s2)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.s2" + v2t2 := "spew_test.s1" + v2t3 := "int8" + v2t4 := "uint8" + v2t5 := "bool" + v2s := "{\n s1: (" + v2t2 + ") {\n a: (" + v2t3 + ") 127,\n b: (" + + v2t4 + ") 255\n },\n b: (" + v2t5 + ") true\n}" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") + + // Struct that contains custom type with Stringer pointer interface via both + // exported and unexported fields. + type s3 struct { + s pstringer + S pstringer + } + v3 := s3{"test", "test2"} + nv3 := (*s3)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "spew_test.s3" + v3t2 := "spew_test.pstringer" + v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 + + ") (len=5) stringer test2\n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Struct that contains embedded struct and field to same struct. + e := embed{"embedstr"} + eLen := fmt.Sprintf("%d", len("embedstr")) + v4 := embedwrap{embed: &e, e: &e} + nv4 := (*embedwrap)(nil) + pv4 := &v4 + eAddr := fmt.Sprintf("%p", &e) + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "spew_test.embedwrap" + v4t2 := "spew_test.embed" + v4t3 := "string" + v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n a: (" + v4t3 + + ") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 + + ")(" + eAddr + ")({\n a: (" + v4t3 + ") (len=" + eLen + ")" + + " \"embedstr\"\n })\n}" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") +} + +func addUintptrDumpTests() { + // Null pointer. + v := uintptr(0) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "uintptr" + vs := "" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + + // Address of real variable. + i := 1 + v2 := uintptr(unsafe.Pointer(&i)) + nv2 := (*uintptr)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uintptr" + v2s := fmt.Sprintf("%p", &i) + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") +} + +func addUnsafePointerDumpTests() { + // Null pointer. + v := unsafe.Pointer(uintptr(0)) + nv := (*unsafe.Pointer)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "unsafe.Pointer" + vs := "" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Address of real variable. + i := 1 + v2 := unsafe.Pointer(&i) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "unsafe.Pointer" + v2s := fmt.Sprintf("%p", &i) + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv, "(*"+vt+")()\n") +} + +func addChanDumpTests() { + // Nil channel. + var v chan int + pv := &v + nv := (*chan int)(nil) + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "chan int" + vs := "" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Real channel. + v2 := make(chan int) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "chan int" + v2s := fmt.Sprintf("%p", v2) + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") +} + +func addFuncDumpTests() { + // Function with no params and no returns. + v := addIntDumpTests + nv := (*func())(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "func()" + vs := fmt.Sprintf("%p", v) + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Function with param and no returns. + v2 := TestDump + nv2 := (*func(*testing.T))(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "func(*testing.T)" + v2s := fmt.Sprintf("%p", v2) + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") + + // Function with multiple params and multiple returns. + var v3 = func(i int, s string) (b bool, err error) { + return true, nil + } + nv3 := (*func(int, string) (bool, error))(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "func(int, string) (bool, error)" + v3s := fmt.Sprintf("%p", v3) + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") +} + +func addCircularDumpTests() { + // Struct that is circular through self referencing. + type circular struct { + c *circular + } + v := circular{nil} + v.c = &v + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.circular" + vs := "{\n c: (*" + vt + ")(" + vAddr + ")({\n c: (*" + vt + ")(" + + vAddr + ")()\n })\n}" + vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")()\n}" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs2+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n") + + // Structs that are circular through cross referencing. + v2 := xref1{nil} + ts2 := xref2{&v2} + v2.ps2 = &ts2 + pv2 := &v2 + ts2Addr := fmt.Sprintf("%p", &ts2) + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.xref1" + v2t2 := "spew_test.xref2" + v2s := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + + ")(" + v2Addr + ")({\n ps2: (*" + v2t2 + ")(" + ts2Addr + + ")()\n })\n })\n}" + v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + + ")(" + v2Addr + ")()\n })\n}" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s2+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s2+")\n") + + // Structs that are indirectly circular. + v3 := indirCir1{nil} + tic2 := indirCir2{nil} + tic3 := indirCir3{&v3} + tic2.ps3 = &tic3 + v3.ps2 = &tic2 + pv3 := &v3 + tic2Addr := fmt.Sprintf("%p", &tic2) + tic3Addr := fmt.Sprintf("%p", &tic3) + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "spew_test.indirCir1" + v3t2 := "spew_test.indirCir2" + v3t3 := "spew_test.indirCir3" + v3s := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + + ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + + ")({\n ps2: (*" + v3t2 + ")(" + tic2Addr + + ")()\n })\n })\n })\n}" + v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + + ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + + ")()\n })\n })\n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s2+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s2+")\n") +} + +func addPanicDumpTests() { + // Type that panics in its Stringer interface. + v := panicer(127) + nv := (*panicer)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.panicer" + vs := "(PANIC=test panic)127" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") +} + +func addErrorDumpTests() { + // Type that has a custom Error interface. + v := customError(127) + nv := (*customError)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.customError" + vs := "error: 127" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") +} + +// TestDump executes all of the tests described by dumpTests. +func TestDump(t *testing.T) { + // Setup tests. + addIntDumpTests() + addUintDumpTests() + addBoolDumpTests() + addFloatDumpTests() + addComplexDumpTests() + addArrayDumpTests() + addSliceDumpTests() + addStringDumpTests() + addInterfaceDumpTests() + addMapDumpTests() + addStructDumpTests() + addUintptrDumpTests() + addUnsafePointerDumpTests() + addChanDumpTests() + addFuncDumpTests() + addCircularDumpTests() + addPanicDumpTests() + addErrorDumpTests() + addCgoDumpTests() + + t.Logf("Running %d tests", len(dumpTests)) + for i, test := range dumpTests { + buf := new(bytes.Buffer) + spew.Fdump(buf, test.in) + s := buf.String() + if testFailed(s, test.wants) { + t.Errorf("Dump #%d\n got: %s %s", i, s, stringizeWants(test.wants)) + continue + } + } +} + +func TestDumpSortedKeys(t *testing.T) { + cfg := spew.ConfigState{SortKeys: true} + s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"}) + expected := `(map[int]string) (len=3) { +(int) 1: (string) (len=1) "1", +(int) 2: (string) (len=1) "2", +(int) 3: (string) (len=1) "3" +} +` + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } + + s = cfg.Sdump(map[stringer]int{"1": 1, "3": 3, "2": 2}) + expected = `(map[spew_test.stringer]int) (len=3) { +(spew_test.stringer) (len=1) stringer 1: (int) 1, +(spew_test.stringer) (len=1) stringer 2: (int) 2, +(spew_test.stringer) (len=1) stringer 3: (int) 3 +} +` + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } + + s = cfg.Sdump(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2}) + expected = `(map[spew_test.pstringer]int) (len=3) { +(spew_test.pstringer) (len=1) stringer 1: (int) 1, +(spew_test.pstringer) (len=1) stringer 2: (int) 2, +(spew_test.pstringer) (len=1) stringer 3: (int) 3 +} +` + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } + + s = cfg.Sdump(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2}) + expected = `(map[spew_test.customError]int) (len=3) { +(spew_test.customError) error: 1: (int) 1, +(spew_test.customError) error: 2: (int) 2, +(spew_test.customError) error: 3: (int) 3 +} +` + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } + +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpcgo_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpcgo_test.go new file mode 100644 index 0000000000..9b8a358ec8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpcgo_test.go @@ -0,0 +1,97 @@ +// Copyright (c) 2013 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when both cgo is supported and "-tags testcgo" is added to the go test +// command line. This means the cgo tests are only added (and hence run) when +// specifially requested. This configuration is used because spew itself +// does not require cgo to run even though it does handle certain cgo types +// specially. Rather than forcing all clients to require cgo and an external +// C compiler just to run the tests, this scheme makes them optional. +// +build cgo,testcgo + +package spew_test + +import ( + "fmt" + "github.com/davecgh/go-spew/spew/testdata" +) + +func addCgoDumpTests() { + // C char pointer. + v := testdata.GetCgoCharPointer() + nv := testdata.GetCgoNullCharPointer() + pv := &v + vcAddr := fmt.Sprintf("%p", v) + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "*testdata._Ctype_char" + vs := "116" + addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n") + addDumpTest(nv, "("+vt+")()\n") + + // C char array. + v2, v2l, v2c := testdata.GetCgoCharArray() + v2Len := fmt.Sprintf("%d", v2l) + v2Cap := fmt.Sprintf("%d", v2c) + v2t := "[6]testdata._Ctype_char" + v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " + + "{\n 00000000 74 65 73 74 32 00 " + + " |test2.|\n}" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + + // C unsigned char array. + v3, v3l, v3c := testdata.GetCgoUnsignedCharArray() + v3Len := fmt.Sprintf("%d", v3l) + v3Cap := fmt.Sprintf("%d", v3c) + v3t := "[6]testdata._Ctype_unsignedchar" + v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " + + "{\n 00000000 74 65 73 74 33 00 " + + " |test3.|\n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + + // C signed char array. + v4, v4l, v4c := testdata.GetCgoSignedCharArray() + v4Len := fmt.Sprintf("%d", v4l) + v4Cap := fmt.Sprintf("%d", v4c) + v4t := "[6]testdata._Ctype_schar" + v4t2 := "testdata._Ctype_schar" + v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + + "{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 + + ") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 + + ") 0\n}" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + + // C uint8_t array. + v5, v5l, v5c := testdata.GetCgoUint8tArray() + v5Len := fmt.Sprintf("%d", v5l) + v5Cap := fmt.Sprintf("%d", v5c) + v5t := "[6]testdata._Ctype_uint8_t" + v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " + + "{\n 00000000 74 65 73 74 35 00 " + + " |test5.|\n}" + addDumpTest(v5, "("+v5t+") "+v5s+"\n") + + // C typedefed unsigned char array. + v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray() + v6Len := fmt.Sprintf("%d", v6l) + v6Cap := fmt.Sprintf("%d", v6c) + v6t := "[6]testdata._Ctype_custom_uchar_t" + v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " + + "{\n 00000000 74 65 73 74 36 00 " + + " |test6.|\n}" + addDumpTest(v6, "("+v6t+") "+v6s+"\n") +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpnocgo_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpnocgo_test.go new file mode 100644 index 0000000000..52a0971fb3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpnocgo_test.go @@ -0,0 +1,26 @@ +// Copyright (c) 2013 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when either cgo is not supported or "-tags testcgo" is not added to the go +// test command line. This file intentionally does not setup any cgo tests in +// this scenario. +// +build !cgo !testcgo + +package spew_test + +func addCgoDumpTests() { + // Don't add any tests for cgo since this file is only compiled when + // there should not be any cgo tests. +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/example_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/example_test.go new file mode 100644 index 0000000000..a7acd14125 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/example_test.go @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew_test + +import ( + "fmt" + "github.com/davecgh/go-spew/spew" +) + +type Flag int + +const ( + flagOne Flag = iota + flagTwo +) + +var flagStrings = map[Flag]string{ + flagOne: "flagOne", + flagTwo: "flagTwo", +} + +func (f Flag) String() string { + if s, ok := flagStrings[f]; ok { + return s + } + return fmt.Sprintf("Unknown flag (%d)", int(f)) +} + +type Bar struct { + flag Flag + data uintptr +} + +type Foo struct { + unexportedField Bar + ExportedField map[interface{}]interface{} +} + +// This example demonstrates how to use Dump to dump variables to stdout. +func ExampleDump() { + // The following package level declarations are assumed for this example: + /* + type Flag int + + const ( + flagOne Flag = iota + flagTwo + ) + + var flagStrings = map[Flag]string{ + flagOne: "flagOne", + flagTwo: "flagTwo", + } + + func (f Flag) String() string { + if s, ok := flagStrings[f]; ok { + return s + } + return fmt.Sprintf("Unknown flag (%d)", int(f)) + } + + type Bar struct { + flag Flag + data uintptr + } + + type Foo struct { + unexportedField Bar + ExportedField map[interface{}]interface{} + } + */ + + // Setup some sample data structures for the example. + bar := Bar{Flag(flagTwo), uintptr(0)} + s1 := Foo{bar, map[interface{}]interface{}{"one": true}} + f := Flag(5) + b := []byte{ + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, + } + + // Dump! + spew.Dump(s1, f, b) + + // Output: + // (spew_test.Foo) { + // unexportedField: (spew_test.Bar) { + // flag: (spew_test.Flag) flagTwo, + // data: (uintptr) + // }, + // ExportedField: (map[interface {}]interface {}) (len=1) { + // (string) (len=3) "one": (bool) true + // } + // } + // (spew_test.Flag) Unknown flag (5) + // ([]uint8) (len=34 cap=34) { + // 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | + // 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| + // 00000020 31 32 |12| + // } + // +} + +// This example demonstrates how to use Printf to display a variable with a +// format string and inline formatting. +func ExamplePrintf() { + // Create a double pointer to a uint 8. + ui8 := uint8(5) + pui8 := &ui8 + ppui8 := &pui8 + + // Create a circular data type. + type circular struct { + ui8 uint8 + c *circular + } + c := circular{ui8: 1} + c.c = &c + + // Print! + spew.Printf("ppui8: %v\n", ppui8) + spew.Printf("circular: %v\n", c) + + // Output: + // ppui8: <**>5 + // circular: {1 <*>{1 <*>}} +} + +// This example demonstrates how to use a ConfigState. +func ExampleConfigState() { + // Modify the indent level of the ConfigState only. The global + // configuration is not modified. + scs := spew.ConfigState{Indent: "\t"} + + // Output using the ConfigState instance. + v := map[string]int{"one": 1} + scs.Printf("v: %v\n", v) + scs.Dump(v) + + // Output: + // v: map[one:1] + // (map[string]int) (len=1) { + // (string) (len=3) "one": (int) 1 + // } +} + +// This example demonstrates how to use ConfigState.Dump to dump variables to +// stdout +func ExampleConfigState_Dump() { + // See the top-level Dump example for details on the types used in this + // example. + + // Create two ConfigState instances with different indentation. + scs := spew.ConfigState{Indent: "\t"} + scs2 := spew.ConfigState{Indent: " "} + + // Setup some sample data structures for the example. + bar := Bar{Flag(flagTwo), uintptr(0)} + s1 := Foo{bar, map[interface{}]interface{}{"one": true}} + + // Dump using the ConfigState instances. + scs.Dump(s1) + scs2.Dump(s1) + + // Output: + // (spew_test.Foo) { + // unexportedField: (spew_test.Bar) { + // flag: (spew_test.Flag) flagTwo, + // data: (uintptr) + // }, + // ExportedField: (map[interface {}]interface {}) (len=1) { + // (string) (len=3) "one": (bool) true + // } + // } + // (spew_test.Foo) { + // unexportedField: (spew_test.Bar) { + // flag: (spew_test.Flag) flagTwo, + // data: (uintptr) + // }, + // ExportedField: (map[interface {}]interface {}) (len=1) { + // (string) (len=3) "one": (bool) true + // } + // } + // +} + +// This example demonstrates how to use ConfigState.Printf to display a variable +// with a format string and inline formatting. +func ExampleConfigState_Printf() { + // See the top-level Dump example for details on the types used in this + // example. + + // Create two ConfigState instances and modify the method handling of the + // first ConfigState only. + scs := spew.NewDefaultConfig() + scs2 := spew.NewDefaultConfig() + scs.DisableMethods = true + + // Alternatively + // scs := spew.ConfigState{Indent: " ", DisableMethods: true} + // scs2 := spew.ConfigState{Indent: " "} + + // This is of type Flag which implements a Stringer and has raw value 1. + f := flagTwo + + // Dump using the ConfigState instances. + scs.Printf("f: %v\n", f) + scs2.Printf("f: %v\n", f) + + // Output: + // f: 1 + // f: flagTwo +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format.go new file mode 100644 index 0000000000..ecf3b80e24 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format.go @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "reflect" + "strconv" + "strings" +) + +// supportedFlags is a list of all the character flags supported by fmt package. +const supportedFlags = "0-+# " + +// formatState implements the fmt.Formatter interface and contains information +// about the state of a formatting operation. The NewFormatter function can +// be used to get a new Formatter which can be used directly as arguments +// in standard fmt package printing calls. +type formatState struct { + value interface{} + fs fmt.State + depth int + pointers map[uintptr]int + ignoreNextType bool + cs *ConfigState +} + +// buildDefaultFormat recreates the original format string without precision +// and width information to pass in to fmt.Sprintf in the case of an +// unrecognized type. Unless new types are added to the language, this +// function won't ever be called. +func (f *formatState) buildDefaultFormat() (format string) { + buf := bytes.NewBuffer(percentBytes) + + for _, flag := range supportedFlags { + if f.fs.Flag(int(flag)) { + buf.WriteRune(flag) + } + } + + buf.WriteRune('v') + + format = buf.String() + return format +} + +// constructOrigFormat recreates the original format string including precision +// and width information to pass along to the standard fmt package. This allows +// automatic deferral of all format strings this package doesn't support. +func (f *formatState) constructOrigFormat(verb rune) (format string) { + buf := bytes.NewBuffer(percentBytes) + + for _, flag := range supportedFlags { + if f.fs.Flag(int(flag)) { + buf.WriteRune(flag) + } + } + + if width, ok := f.fs.Width(); ok { + buf.WriteString(strconv.Itoa(width)) + } + + if precision, ok := f.fs.Precision(); ok { + buf.Write(precisionBytes) + buf.WriteString(strconv.Itoa(precision)) + } + + buf.WriteRune(verb) + + format = buf.String() + return format +} + +// unpackValue returns values inside of non-nil interfaces when possible and +// ensures that types for values which have been unpacked from an interface +// are displayed when the show types flag is also set. +// This is useful for data types like structs, arrays, slices, and maps which +// can contain varying types packed inside an interface. +func (f *formatState) unpackValue(v reflect.Value) reflect.Value { + if v.Kind() == reflect.Interface { + f.ignoreNextType = false + if !v.IsNil() { + v = v.Elem() + } + } + return v +} + +// formatPtr handles formatting of pointers by indirecting them as necessary. +func (f *formatState) formatPtr(v reflect.Value) { + // Display nil if top level pointer is nil. + showTypes := f.fs.Flag('#') + if v.IsNil() && (!showTypes || f.ignoreNextType) { + f.fs.Write(nilAngleBytes) + return + } + + // Remove pointers at or below the current depth from map used to detect + // circular refs. + for k, depth := range f.pointers { + if depth >= f.depth { + delete(f.pointers, k) + } + } + + // Keep list of all dereferenced pointers to possibly show later. + pointerChain := make([]uintptr, 0) + + // Figure out how many levels of indirection there are by derferencing + // pointers and unpacking interfaces down the chain while detecting circular + // references. + nilFound := false + cycleFound := false + indirects := 0 + ve := v + for ve.Kind() == reflect.Ptr { + if ve.IsNil() { + nilFound = true + break + } + indirects++ + addr := ve.Pointer() + pointerChain = append(pointerChain, addr) + if pd, ok := f.pointers[addr]; ok && pd < f.depth { + cycleFound = true + indirects-- + break + } + f.pointers[addr] = f.depth + + ve = ve.Elem() + if ve.Kind() == reflect.Interface { + if ve.IsNil() { + nilFound = true + break + } + ve = ve.Elem() + } + } + + // Display type or indirection level depending on flags. + if showTypes && !f.ignoreNextType { + f.fs.Write(openParenBytes) + f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) + f.fs.Write([]byte(ve.Type().String())) + f.fs.Write(closeParenBytes) + } else { + if nilFound || cycleFound { + indirects += strings.Count(ve.Type().String(), "*") + } + f.fs.Write(openAngleBytes) + f.fs.Write([]byte(strings.Repeat("*", indirects))) + f.fs.Write(closeAngleBytes) + } + + // Display pointer information depending on flags. + if f.fs.Flag('+') && (len(pointerChain) > 0) { + f.fs.Write(openParenBytes) + for i, addr := range pointerChain { + if i > 0 { + f.fs.Write(pointerChainBytes) + } + printHexPtr(f.fs, addr) + } + f.fs.Write(closeParenBytes) + } + + // Display dereferenced value. + switch { + case nilFound == true: + f.fs.Write(nilAngleBytes) + + case cycleFound == true: + f.fs.Write(circularShortBytes) + + default: + f.ignoreNextType = true + f.format(ve) + } +} + +// format is the main workhorse for providing the Formatter interface. It +// uses the passed reflect value to figure out what kind of object we are +// dealing with and formats it appropriately. It is a recursive function, +// however circular data structures are detected and handled properly. +func (f *formatState) format(v reflect.Value) { + // Handle invalid reflect values immediately. + kind := v.Kind() + if kind == reflect.Invalid { + f.fs.Write(invalidAngleBytes) + return + } + + // Handle pointers specially. + if kind == reflect.Ptr { + f.formatPtr(v) + return + } + + // Print type information unless already handled elsewhere. + if !f.ignoreNextType && f.fs.Flag('#') { + f.fs.Write(openParenBytes) + f.fs.Write([]byte(v.Type().String())) + f.fs.Write(closeParenBytes) + } + f.ignoreNextType = false + + // Call Stringer/error interfaces if they exist and the handle methods + // flag is enabled. + if !f.cs.DisableMethods { + if (kind != reflect.Invalid) && (kind != reflect.Interface) { + if handled := handleMethods(f.cs, f.fs, v); handled { + return + } + } + } + + switch kind { + case reflect.Invalid: + // Do nothing. We should never get here since invalid has already + // been handled above. + + case reflect.Bool: + printBool(f.fs, v.Bool()) + + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + printInt(f.fs, v.Int(), 10) + + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + printUint(f.fs, v.Uint(), 10) + + case reflect.Float32: + printFloat(f.fs, v.Float(), 32) + + case reflect.Float64: + printFloat(f.fs, v.Float(), 64) + + case reflect.Complex64: + printComplex(f.fs, v.Complex(), 32) + + case reflect.Complex128: + printComplex(f.fs, v.Complex(), 64) + + case reflect.Slice: + if v.IsNil() { + f.fs.Write(nilAngleBytes) + break + } + fallthrough + + case reflect.Array: + f.fs.Write(openBracketBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + numEntries := v.Len() + for i := 0; i < numEntries; i++ { + if i > 0 { + f.fs.Write(spaceBytes) + } + f.ignoreNextType = true + f.format(f.unpackValue(v.Index(i))) + } + } + f.depth-- + f.fs.Write(closeBracketBytes) + + case reflect.String: + f.fs.Write([]byte(v.String())) + + case reflect.Interface: + // The only time we should get here is for nil interfaces due to + // unpackValue calls. + if v.IsNil() { + f.fs.Write(nilAngleBytes) + } + + case reflect.Ptr: + // Do nothing. We should never get here since pointers have already + // been handled above. + + case reflect.Map: + // nil maps should be indicated as different than empty maps + if v.IsNil() { + f.fs.Write(nilAngleBytes) + break + } + + f.fs.Write(openMapBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + keys := v.MapKeys() + if f.cs.SortKeys { + sortValues(keys, f.cs) + } + for i, key := range keys { + if i > 0 { + f.fs.Write(spaceBytes) + } + f.ignoreNextType = true + f.format(f.unpackValue(key)) + f.fs.Write(colonBytes) + f.ignoreNextType = true + f.format(f.unpackValue(v.MapIndex(key))) + } + } + f.depth-- + f.fs.Write(closeMapBytes) + + case reflect.Struct: + numFields := v.NumField() + f.fs.Write(openBraceBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + vt := v.Type() + for i := 0; i < numFields; i++ { + if i > 0 { + f.fs.Write(spaceBytes) + } + vtf := vt.Field(i) + if f.fs.Flag('+') || f.fs.Flag('#') { + f.fs.Write([]byte(vtf.Name)) + f.fs.Write(colonBytes) + } + f.format(f.unpackValue(v.Field(i))) + } + } + f.depth-- + f.fs.Write(closeBraceBytes) + + case reflect.Uintptr: + printHexPtr(f.fs, uintptr(v.Uint())) + + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + printHexPtr(f.fs, v.Pointer()) + + // There were not any other types at the time this code was written, but + // fall back to letting the default fmt package handle it if any get added. + default: + format := f.buildDefaultFormat() + if v.CanInterface() { + fmt.Fprintf(f.fs, format, v.Interface()) + } else { + fmt.Fprintf(f.fs, format, v.String()) + } + } +} + +// Format satisfies the fmt.Formatter interface. See NewFormatter for usage +// details. +func (f *formatState) Format(fs fmt.State, verb rune) { + f.fs = fs + + // Use standard formatting for verbs that are not v. + if verb != 'v' { + format := f.constructOrigFormat(verb) + fmt.Fprintf(fs, format, f.value) + return + } + + if f.value == nil { + if fs.Flag('#') { + fs.Write(interfaceBytes) + } + fs.Write(nilAngleBytes) + return + } + + f.format(reflect.ValueOf(f.value)) +} + +// newFormatter is a helper function to consolidate the logic from the various +// public methods which take varying config states. +func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { + fs := &formatState{value: v, cs: cs} + fs.pointers = make(map[uintptr]int) + return fs +} + +/* +NewFormatter returns a custom formatter that satisfies the fmt.Formatter +interface. As a result, it integrates cleanly with standard fmt package +printing functions. The formatter is useful for inline printing of smaller data +types similar to the standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Typically this function shouldn't be called directly. It is much easier to make +use of the custom formatter by calling one of the convenience functions such as +Printf, Println, or Fprintf. +*/ +func NewFormatter(v interface{}) fmt.Formatter { + return newFormatter(&Config, v) +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format_test.go new file mode 100644 index 0000000000..b0f9761a4c --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format_test.go @@ -0,0 +1,1535 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +Test Summary: +NOTE: For each test, a nil pointer, a single pointer and double pointer to the +base test element are also tested to ensure proper indirection across all types. + +- Max int8, int16, int32, int64, int +- Max uint8, uint16, uint32, uint64, uint +- Boolean true and false +- Standard complex64 and complex128 +- Array containing standard ints +- Array containing type with custom formatter on pointer receiver only +- Array containing interfaces +- Slice containing standard float32 values +- Slice containing type with custom formatter on pointer receiver only +- Slice containing interfaces +- Nil slice +- Standard string +- Nil interface +- Sub-interface +- Map with string keys and int vals +- Map with custom formatter type on pointer receiver only keys and vals +- Map with interface keys and values +- Map with nil interface value +- Struct with primitives +- Struct that contains another struct +- Struct that contains custom type with Stringer pointer interface via both + exported and unexported fields +- Struct that contains embedded struct and field to same struct +- Uintptr to 0 (null pointer) +- Uintptr address of real variable +- Unsafe.Pointer to 0 (null pointer) +- Unsafe.Pointer to address of real variable +- Nil channel +- Standard int channel +- Function with no params and no returns +- Function with param and no returns +- Function with multiple params and multiple returns +- Struct that is circular through self referencing +- Structs that are circular through cross referencing +- Structs that are indirectly circular +- Type that panics in its Stringer interface +- Type that has a custom Error interface +- %x passthrough with uint +- %#x passthrough with uint +- %f passthrough with precision +- %f passthrough with width and precision +- %d passthrough with width +- %q passthrough with string +*/ + +package spew_test + +import ( + "bytes" + "fmt" + "testing" + "unsafe" + + "github.com/davecgh/go-spew/spew" +) + +// formatterTest is used to describe a test to be perfomed against NewFormatter. +type formatterTest struct { + format string + in interface{} + wants []string +} + +// formatterTests houses all of the tests to be performed against NewFormatter. +var formatterTests = make([]formatterTest, 0) + +// addFormatterTest is a helper method to append the passed input and desired +// result to formatterTests. +func addFormatterTest(format string, in interface{}, wants ...string) { + test := formatterTest{format, in, wants} + formatterTests = append(formatterTests, test) +} + +func addIntFormatterTests() { + // Max int8. + v := int8(127) + nv := (*int8)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "int8" + vs := "127" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Max int16. + v2 := int16(32767) + nv2 := (*int16)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "int16" + v2s := "32767" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Max int32. + v3 := int32(2147483647) + nv3 := (*int32)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "int32" + v3s := "2147483647" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + + // Max int64. + v4 := int64(9223372036854775807) + nv4 := (*int64)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "int64" + v4s := "9223372036854775807" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%v", nv4, "") + addFormatterTest("%+v", v4, v4s) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") + + // Max int. + v5 := int(2147483647) + nv5 := (*int)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "int" + v5s := "2147483647" + addFormatterTest("%v", v5, v5s) + addFormatterTest("%v", pv5, "<*>"+v5s) + addFormatterTest("%v", &pv5, "<**>"+v5s) + addFormatterTest("%v", nv5, "") + addFormatterTest("%+v", v5, v5s) + addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) + addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) + addFormatterTest("%+v", nv5, "") + addFormatterTest("%#v", v5, "("+v5t+")"+v5s) + addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) + addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) + addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") + addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) + addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) + addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) + addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"") +} + +func addUintFormatterTests() { + // Max uint8. + v := uint8(255) + nv := (*uint8)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "uint8" + vs := "255" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Max uint16. + v2 := uint16(65535) + nv2 := (*uint16)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uint16" + v2s := "65535" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Max uint32. + v3 := uint32(4294967295) + nv3 := (*uint32)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "uint32" + v3s := "4294967295" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + + // Max uint64. + v4 := uint64(18446744073709551615) + nv4 := (*uint64)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "uint64" + v4s := "18446744073709551615" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%v", nv4, "") + addFormatterTest("%+v", v4, v4s) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") + + // Max uint. + v5 := uint(4294967295) + nv5 := (*uint)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "uint" + v5s := "4294967295" + addFormatterTest("%v", v5, v5s) + addFormatterTest("%v", pv5, "<*>"+v5s) + addFormatterTest("%v", &pv5, "<**>"+v5s) + addFormatterTest("%v", nv5, "") + addFormatterTest("%+v", v5, v5s) + addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) + addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) + addFormatterTest("%+v", nv5, "") + addFormatterTest("%#v", v5, "("+v5t+")"+v5s) + addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) + addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) + addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") + addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) + addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) + addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) + addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") +} + +func addBoolFormatterTests() { + // Boolean true. + v := bool(true) + nv := (*bool)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "bool" + vs := "true" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Boolean false. + v2 := bool(false) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "bool" + v2s := "false" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addFloatFormatterTests() { + // Standard float32. + v := float32(3.1415) + nv := (*float32)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "float32" + vs := "3.1415" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Standard float64. + v2 := float64(3.1415926) + nv2 := (*float64)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "float64" + v2s := "3.1415926" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") +} + +func addComplexFormatterTests() { + // Standard complex64. + v := complex(float32(6), -2) + nv := (*complex64)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "complex64" + vs := "(6-2i)" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Standard complex128. + v2 := complex(float64(-6), 2) + nv2 := (*complex128)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "complex128" + v2s := "(-6+2i)" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") +} + +func addArrayFormatterTests() { + // Array containing standard ints. + v := [3]int{1, 2, 3} + nv := (*[3]int)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "[3]int" + vs := "[1 2 3]" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Array containing type with custom formatter on pointer receiver only. + v2 := [3]pstringer{"1", "2", "3"} + nv2 := (*[3]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "[3]spew_test.pstringer" + v2s := "[stringer 1 stringer 2 stringer 3]" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Array containing interfaces. + v3 := [3]interface{}{"one", int(2), uint(3)} + nv3 := (*[3]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "[3]interface {}" + v3t2 := "string" + v3t3 := "int" + v3t4 := "uint" + v3s := "[one 2 3]" + v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3]" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") +} + +func addSliceFormatterTests() { + // Slice containing standard float32 values. + v := []float32{3.14, 6.28, 12.56} + nv := (*[]float32)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "[]float32" + vs := "[3.14 6.28 12.56]" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Slice containing type with custom formatter on pointer receiver only. + v2 := []pstringer{"1", "2", "3"} + nv2 := (*[]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "[]spew_test.pstringer" + v2s := "[stringer 1 stringer 2 stringer 3]" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Slice containing interfaces. + v3 := []interface{}{"one", int(2), uint(3), nil} + nv3 := (*[]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "[]interface {}" + v3t2 := "string" + v3t3 := "int" + v3t4 := "uint" + v3t5 := "interface {}" + v3s := "[one 2 3 ]" + v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 + + ")]" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") + + // Nil slice. + var v4 []int + nv4 := (*[]int)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "[]int" + v4s := "" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%+v", v4, v4s) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") +} + +func addStringFormatterTests() { + // Standard string. + v := "test" + nv := (*string)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "string" + vs := "test" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") +} + +func addInterfaceFormatterTests() { + // Nil interface. + var v interface{} + nv := (*interface{})(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "interface {}" + vs := "" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Sub-interface. + v2 := interface{}(uint16(65535)) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uint16" + v2s := "65535" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addMapFormatterTests() { + // Map with string keys and int vals. + v := map[string]int{"one": 1, "two": 2} + nilMap := map[string]int(nil) + nv := (*map[string]int)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "map[string]int" + vs := "map[one:1 two:2]" + vs2 := "map[two:2 one:1]" + addFormatterTest("%v", v, vs, vs2) + addFormatterTest("%v", pv, "<*>"+vs, "<*>"+vs2) + addFormatterTest("%v", &pv, "<**>"+vs, "<**>"+vs2) + addFormatterTest("%+v", nilMap, "") + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs, vs2) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs, + "<**>("+pvAddr+"->"+vAddr+")"+vs2) + addFormatterTest("%+v", nilMap, "") + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs, "("+vt+")"+vs2) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs, "(*"+vt+")"+vs2) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs, "(**"+vt+")"+vs2) + addFormatterTest("%#v", nilMap, "("+vt+")"+"") + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs, "("+vt+")"+vs2) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs, + "(*"+vt+")("+vAddr+")"+vs2) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs, + "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs2) + addFormatterTest("%#+v", nilMap, "("+vt+")"+"") + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Map with custom formatter type on pointer receiver only keys and vals. + v2 := map[pstringer]pstringer{"one": "1"} + nv2 := (*map[pstringer]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "map[spew_test.pstringer]spew_test.pstringer" + v2s := "map[stringer one:stringer 1]" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Map with interface keys and values. + v3 := map[interface{}]interface{}{"one": 1} + nv3 := (*map[interface{}]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "map[interface {}]interface {}" + v3t1 := "string" + v3t2 := "int" + v3s := "map[one:1]" + v3s2 := "map[(" + v3t1 + ")one:(" + v3t2 + ")1]" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") + + // Map with nil interface value + v4 := map[string]interface{}{"nil": nil} + nv4 := (*map[string]interface{})(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "map[string]interface {}" + v4t1 := "interface {}" + v4s := "map[nil:]" + v4s2 := "map[nil:(" + v4t1 + ")]" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%+v", v4, v4s) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s2) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s2) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s2) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s2) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s2) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s2) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") +} + +func addStructFormatterTests() { + // Struct with primitives. + type s1 struct { + a int8 + b uint8 + } + v := s1{127, 255} + nv := (*s1)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.s1" + vt2 := "int8" + vt3 := "uint8" + vs := "{127 255}" + vs2 := "{a:127 b:255}" + vs3 := "{a:(" + vt2 + ")127 b:(" + vt3 + ")255}" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs2) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs3) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs3) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs3) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs3) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs3) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs3) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Struct that contains another struct. + type s2 struct { + s1 s1 + b bool + } + v2 := s2{s1{127, 255}, true} + nv2 := (*s2)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.s2" + v2t2 := "spew_test.s1" + v2t3 := "int8" + v2t4 := "uint8" + v2t5 := "bool" + v2s := "{{127 255} true}" + v2s2 := "{s1:{a:127 b:255} b:true}" + v2s3 := "{s1:(" + v2t2 + "){a:(" + v2t3 + ")127 b:(" + v2t4 + ")255} b:(" + + v2t5 + ")true}" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s2) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s3) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s3) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s3) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s3) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s3) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s3) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Struct that contains custom type with Stringer pointer interface via both + // exported and unexported fields. + type s3 struct { + s pstringer + S pstringer + } + v3 := s3{"test", "test2"} + nv3 := (*s3)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "spew_test.s3" + v3t2 := "spew_test.pstringer" + v3s := "{stringer test stringer test2}" + v3s2 := "{s:stringer test S:stringer test2}" + v3s3 := "{s:(" + v3t2 + ")stringer test S:(" + v3t2 + ")stringer test2}" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s2) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s3) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s3) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s3) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s3) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s3) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s3) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") + + // Struct that contains embedded struct and field to same struct. + e := embed{"embedstr"} + v4 := embedwrap{embed: &e, e: &e} + nv4 := (*embedwrap)(nil) + pv4 := &v4 + eAddr := fmt.Sprintf("%p", &e) + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "spew_test.embedwrap" + v4t2 := "spew_test.embed" + v4t3 := "string" + v4s := "{<*>{embedstr} <*>{embedstr}}" + v4s2 := "{embed:<*>(" + eAddr + "){a:embedstr} e:<*>(" + eAddr + + "){a:embedstr}}" + v4s3 := "{embed:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 + + "){a:(" + v4t3 + ")embedstr}}" + v4s4 := "{embed:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + + ")embedstr} e:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr}}" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%+v", v4, v4s2) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s2) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s2) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s3) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s3) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s3) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s4) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s4) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s4) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") +} + +func addUintptrFormatterTests() { + // Null pointer. + v := uintptr(0) + nv := (*uintptr)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "uintptr" + vs := "" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Address of real variable. + i := 1 + v2 := uintptr(unsafe.Pointer(&i)) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uintptr" + v2s := fmt.Sprintf("%p", &i) + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addUnsafePointerFormatterTests() { + // Null pointer. + v := unsafe.Pointer(uintptr(0)) + nv := (*unsafe.Pointer)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "unsafe.Pointer" + vs := "" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Address of real variable. + i := 1 + v2 := unsafe.Pointer(&i) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "unsafe.Pointer" + v2s := fmt.Sprintf("%p", &i) + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addChanFormatterTests() { + // Nil channel. + var v chan int + pv := &v + nv := (*chan int)(nil) + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "chan int" + vs := "" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Real channel. + v2 := make(chan int) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "chan int" + v2s := fmt.Sprintf("%p", v2) + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addFuncFormatterTests() { + // Function with no params and no returns. + v := addIntFormatterTests + nv := (*func())(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "func()" + vs := fmt.Sprintf("%p", v) + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Function with param and no returns. + v2 := TestFormatter + nv2 := (*func(*testing.T))(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "func(*testing.T)" + v2s := fmt.Sprintf("%p", v2) + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Function with multiple params and multiple returns. + var v3 = func(i int, s string) (b bool, err error) { + return true, nil + } + nv3 := (*func(int, string) (bool, error))(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "func(int, string) (bool, error)" + v3s := fmt.Sprintf("%p", v3) + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") +} + +func addCircularFormatterTests() { + // Struct that is circular through self referencing. + type circular struct { + c *circular + } + v := circular{nil} + v.c = &v + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.circular" + vs := "{<*>{<*>}}" + vs2 := "{<*>}" + vs3 := "{c:<*>(" + vAddr + "){c:<*>(" + vAddr + ")}}" + vs4 := "{c:<*>(" + vAddr + ")}" + vs5 := "{c:(*" + vt + "){c:(*" + vt + ")}}" + vs6 := "{c:(*" + vt + ")}" + vs7 := "{c:(*" + vt + ")(" + vAddr + "){c:(*" + vt + ")(" + vAddr + + ")}}" + vs8 := "{c:(*" + vt + ")(" + vAddr + ")}" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs2) + addFormatterTest("%v", &pv, "<**>"+vs2) + addFormatterTest("%+v", v, vs3) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs4) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs4) + addFormatterTest("%#v", v, "("+vt+")"+vs5) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs6) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs6) + addFormatterTest("%#+v", v, "("+vt+")"+vs7) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs8) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs8) + + // Structs that are circular through cross referencing. + v2 := xref1{nil} + ts2 := xref2{&v2} + v2.ps2 = &ts2 + pv2 := &v2 + ts2Addr := fmt.Sprintf("%p", &ts2) + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.xref1" + v2t2 := "spew_test.xref2" + v2s := "{<*>{<*>{<*>}}}" + v2s2 := "{<*>{<*>}}" + v2s3 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + "){ps2:<*>(" + + ts2Addr + ")}}}" + v2s4 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + ")}}" + v2s5 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + "){ps2:(*" + v2t2 + + ")}}}" + v2s6 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + ")}}" + v2s7 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + + ")(" + v2Addr + "){ps2:(*" + v2t2 + ")(" + ts2Addr + + ")}}}" + v2s8 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + + ")(" + v2Addr + ")}}" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s2) + addFormatterTest("%v", &pv2, "<**>"+v2s2) + addFormatterTest("%+v", v2, v2s3) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s4) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s4) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s5) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s6) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s6) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s7) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s8) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s8) + + // Structs that are indirectly circular. + v3 := indirCir1{nil} + tic2 := indirCir2{nil} + tic3 := indirCir3{&v3} + tic2.ps3 = &tic3 + v3.ps2 = &tic2 + pv3 := &v3 + tic2Addr := fmt.Sprintf("%p", &tic2) + tic3Addr := fmt.Sprintf("%p", &tic3) + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "spew_test.indirCir1" + v3t2 := "spew_test.indirCir2" + v3t3 := "spew_test.indirCir3" + v3s := "{<*>{<*>{<*>{<*>}}}}" + v3s2 := "{<*>{<*>{<*>}}}" + v3s3 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + + v3Addr + "){ps2:<*>(" + tic2Addr + ")}}}}" + v3s4 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + + v3Addr + ")}}}" + v3s5 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + + "){ps2:(*" + v3t2 + ")}}}}" + v3s6 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + + ")}}}" + v3s7 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + + tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + "){ps2:(*" + v3t2 + + ")(" + tic2Addr + ")}}}}" + v3s8 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + + tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + ")}}}" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s2) + addFormatterTest("%v", &pv3, "<**>"+v3s2) + addFormatterTest("%+v", v3, v3s3) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s4) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s4) + addFormatterTest("%#v", v3, "("+v3t+")"+v3s5) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s6) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s6) + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s7) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s8) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s8) +} + +func addPanicFormatterTests() { + // Type that panics in its Stringer interface. + v := panicer(127) + nv := (*panicer)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.panicer" + vs := "(PANIC=test panic)127" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") +} + +func addErrorFormatterTests() { + // Type that has a custom Error interface. + v := customError(127) + nv := (*customError)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.customError" + vs := "error: 127" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") +} + +func addPassthroughFormatterTests() { + // %x passthrough with uint. + v := uint(4294967295) + pv := &v + vAddr := fmt.Sprintf("%x", pv) + pvAddr := fmt.Sprintf("%x", &pv) + vs := "ffffffff" + addFormatterTest("%x", v, vs) + addFormatterTest("%x", pv, vAddr) + addFormatterTest("%x", &pv, pvAddr) + + // %#x passthrough with uint. + v2 := int(2147483647) + pv2 := &v2 + v2Addr := fmt.Sprintf("%#x", pv2) + pv2Addr := fmt.Sprintf("%#x", &pv2) + v2s := "0x7fffffff" + addFormatterTest("%#x", v2, v2s) + addFormatterTest("%#x", pv2, v2Addr) + addFormatterTest("%#x", &pv2, pv2Addr) + + // %f passthrough with precision. + addFormatterTest("%.2f", 3.1415, "3.14") + addFormatterTest("%.3f", 3.1415, "3.142") + addFormatterTest("%.4f", 3.1415, "3.1415") + + // %f passthrough with width and precision. + addFormatterTest("%5.2f", 3.1415, " 3.14") + addFormatterTest("%6.3f", 3.1415, " 3.142") + addFormatterTest("%7.4f", 3.1415, " 3.1415") + + // %d passthrough with width. + addFormatterTest("%3d", 127, "127") + addFormatterTest("%4d", 127, " 127") + addFormatterTest("%5d", 127, " 127") + + // %q passthrough with string. + addFormatterTest("%q", "test", "\"test\"") +} + +// TestFormatter executes all of the tests described by formatterTests. +func TestFormatter(t *testing.T) { + // Setup tests. + addIntFormatterTests() + addUintFormatterTests() + addBoolFormatterTests() + addFloatFormatterTests() + addComplexFormatterTests() + addArrayFormatterTests() + addSliceFormatterTests() + addStringFormatterTests() + addInterfaceFormatterTests() + addMapFormatterTests() + addStructFormatterTests() + addUintptrFormatterTests() + addUnsafePointerFormatterTests() + addChanFormatterTests() + addFuncFormatterTests() + addCircularFormatterTests() + addPanicFormatterTests() + addErrorFormatterTests() + addPassthroughFormatterTests() + + t.Logf("Running %d tests", len(formatterTests)) + for i, test := range formatterTests { + buf := new(bytes.Buffer) + spew.Fprintf(buf, test.format, test.in) + s := buf.String() + if testFailed(s, test.wants) { + t.Errorf("Formatter #%d format: %s got: %s %s", i, test.format, s, + stringizeWants(test.wants)) + continue + } + } +} + +type testStruct struct { + x int +} + +func (ts testStruct) String() string { + return fmt.Sprintf("ts.%d", ts.x) +} + +type testStructP struct { + x int +} + +func (ts *testStructP) String() string { + return fmt.Sprintf("ts.%d", ts.x) +} + +func TestPrintSortedKeys(t *testing.T) { + cfg := spew.ConfigState{SortKeys: true} + s := cfg.Sprint(map[int]string{1: "1", 3: "3", 2: "2"}) + expected := "map[1:1 2:2 3:3]" + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } + + s = cfg.Sprint(map[stringer]int{"1": 1, "3": 3, "2": 2}) + expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]" + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } + + s = cfg.Sprint(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2}) + expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]" + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } + + s = cfg.Sprint(map[testStruct]int{testStruct{1}: 1, testStruct{3}: 3, testStruct{2}: 2}) + expected = "map[ts.1:1 ts.2:2 ts.3:3]" + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } + + s = cfg.Sprint(map[testStructP]int{testStructP{1}: 1, testStructP{3}: 3, testStructP{2}: 2}) + expected = "map[ts.1:1 ts.2:2 ts.3:3]" + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } + + s = cfg.Sprint(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2}) + expected = "map[error: 1:1 error: 2:2 error: 3:3]" + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/internal_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/internal_test.go new file mode 100644 index 0000000000..b583bfdef3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/internal_test.go @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +This test file is part of the spew package rather than than the spew_test +package because it needs access to internals to properly test certain cases +which are not possible via the public interface since they should never happen. +*/ + +package spew + +import ( + "bytes" + "reflect" + "testing" + "unsafe" +) + +// dummyFmtState implements a fake fmt.State to use for testing invalid +// reflect.Value handling. This is necessary because the fmt package catches +// invalid values before invoking the formatter on them. +type dummyFmtState struct { + bytes.Buffer +} + +func (dfs *dummyFmtState) Flag(f int) bool { + if f == int('+') { + return true + } + return false +} + +func (dfs *dummyFmtState) Precision() (int, bool) { + return 0, false +} + +func (dfs *dummyFmtState) Width() (int, bool) { + return 0, false +} + +// TestInvalidReflectValue ensures the dump and formatter code handles an +// invalid reflect value properly. This needs access to internal state since it +// should never happen in real code and therefore can't be tested via the public +// API. +func TestInvalidReflectValue(t *testing.T) { + i := 1 + + // Dump invalid reflect value. + v := new(reflect.Value) + buf := new(bytes.Buffer) + d := dumpState{w: buf, cs: &Config} + d.dump(*v) + s := buf.String() + want := "" + if s != want { + t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want) + } + i++ + + // Formatter invalid reflect value. + buf2 := new(dummyFmtState) + f := formatState{value: *v, cs: &Config, fs: buf2} + f.format(*v) + s = buf2.String() + want = "" + if s != want { + t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want) + } +} + +// changeKind uses unsafe to intentionally change the kind of a reflect.Value to +// the maximum kind value which does not exist. This is needed to test the +// fallback code which punts to the standard fmt library for new types that +// might get added to the language. +func changeKind(v *reflect.Value, readOnly bool) { + rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag)) + *rvf = *rvf | ((1< + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "fmt" + "io" +) + +// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the formatted string as a value that satisfies error. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Errorf(format string, a ...interface{}) (err error) { + return fmt.Errorf(format, convertArgs(a)...) +} + +// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprint(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprint(w, convertArgs(a)...) +} + +// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + return fmt.Fprintf(w, format, convertArgs(a)...) +} + +// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it +// passed with a default Formatter interface returned by NewFormatter. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprintln(w, convertArgs(a)...) +} + +// Print is a wrapper for fmt.Print that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) +func Print(a ...interface{}) (n int, err error) { + return fmt.Print(convertArgs(a)...) +} + +// Printf is a wrapper for fmt.Printf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Printf(format string, a ...interface{}) (n int, err error) { + return fmt.Printf(format, convertArgs(a)...) +} + +// Println is a wrapper for fmt.Println that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) +func Println(a ...interface{}) (n int, err error) { + return fmt.Println(convertArgs(a)...) +} + +// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprint(a ...interface{}) string { + return fmt.Sprint(convertArgs(a)...) +} + +// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, convertArgs(a)...) +} + +// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it +// were passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprintln(a ...interface{}) string { + return fmt.Sprintln(convertArgs(a)...) +} + +// convertArgs accepts a slice of arguments and returns a slice of the same +// length with each argument converted to a default spew Formatter interface. +func convertArgs(args []interface{}) (formatters []interface{}) { + formatters = make([]interface{}, len(args)) + for index, arg := range args { + formatters[index] = NewFormatter(arg) + } + return formatters +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew_test.go new file mode 100644 index 0000000000..3831ed2fb5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew_test.go @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew_test + +import ( + "bytes" + "fmt" + "github.com/davecgh/go-spew/spew" + "io/ioutil" + "os" + "testing" +) + +// spewFunc is used to identify which public function of the spew package or +// ConfigState a test applies to. +type spewFunc int + +const ( + fCSFdump spewFunc = iota + fCSFprint + fCSFprintf + fCSFprintln + fCSPrint + fCSPrintln + fCSSdump + fCSSprint + fCSSprintf + fCSSprintln + fCSErrorf + fCSNewFormatter + fErrorf + fFprint + fFprintln + fPrint + fPrintln + fSdump + fSprint + fSprintf + fSprintln +) + +// Map of spewFunc values to names for pretty printing. +var spewFuncStrings = map[spewFunc]string{ + fCSFdump: "ConfigState.Fdump", + fCSFprint: "ConfigState.Fprint", + fCSFprintf: "ConfigState.Fprintf", + fCSFprintln: "ConfigState.Fprintln", + fCSSdump: "ConfigState.Sdump", + fCSPrint: "ConfigState.Print", + fCSPrintln: "ConfigState.Println", + fCSSprint: "ConfigState.Sprint", + fCSSprintf: "ConfigState.Sprintf", + fCSSprintln: "ConfigState.Sprintln", + fCSErrorf: "ConfigState.Errorf", + fCSNewFormatter: "ConfigState.NewFormatter", + fErrorf: "spew.Errorf", + fFprint: "spew.Fprint", + fFprintln: "spew.Fprintln", + fPrint: "spew.Print", + fPrintln: "spew.Println", + fSdump: "spew.Sdump", + fSprint: "spew.Sprint", + fSprintf: "spew.Sprintf", + fSprintln: "spew.Sprintln", +} + +func (f spewFunc) String() string { + if s, ok := spewFuncStrings[f]; ok { + return s + } + return fmt.Sprintf("Unknown spewFunc (%d)", int(f)) +} + +// spewTest is used to describe a test to be performed against the public +// functions of the spew package or ConfigState. +type spewTest struct { + cs *spew.ConfigState + f spewFunc + format string + in interface{} + want string +} + +// spewTests houses the tests to be performed against the public functions of +// the spew package and ConfigState. +// +// These tests are only intended to ensure the public functions are exercised +// and are intentionally not exhaustive of types. The exhaustive type +// tests are handled in the dump and format tests. +var spewTests []spewTest + +// redirStdout is a helper function to return the standard output from f as a +// byte slice. +func redirStdout(f func()) ([]byte, error) { + tempFile, err := ioutil.TempFile("", "ss-test") + if err != nil { + return nil, err + } + fileName := tempFile.Name() + defer os.Remove(fileName) // Ignore error + + origStdout := os.Stdout + os.Stdout = tempFile + f() + os.Stdout = origStdout + tempFile.Close() + + return ioutil.ReadFile(fileName) +} + +func initSpewTests() { + // Config states with various settings. + scsDefault := spew.NewDefaultConfig() + scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true} + scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true} + scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1} + scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true} + + // Variables for tests on types which implement Stringer interface with and + // without a pointer receiver. + ts := stringer("test") + tps := pstringer("test") + + // depthTester is used to test max depth handling for structs, array, slices + // and maps. + type depthTester struct { + ic indirCir1 + arr [1]string + slice []string + m map[string]int + } + dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"}, + map[string]int{"one": 1}} + + // Variable for tests on types which implement error interface. + te := customError(10) + + spewTests = []spewTest{ + {scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"}, + {scsDefault, fCSFprint, "", int16(32767), "32767"}, + {scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"}, + {scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"}, + {scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"}, + {scsDefault, fCSPrintln, "", uint8(255), "255\n"}, + {scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"}, + {scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"}, + {scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"}, + {scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"}, + {scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"}, + {scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"}, + {scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"}, + {scsDefault, fFprint, "", float32(3.14), "3.14"}, + {scsDefault, fFprintln, "", float64(6.28), "6.28\n"}, + {scsDefault, fPrint, "", true, "true"}, + {scsDefault, fPrintln, "", false, "false\n"}, + {scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"}, + {scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"}, + {scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"}, + {scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"}, + {scsNoMethods, fCSFprint, "", ts, "test"}, + {scsNoMethods, fCSFprint, "", &ts, "<*>test"}, + {scsNoMethods, fCSFprint, "", tps, "test"}, + {scsNoMethods, fCSFprint, "", &tps, "<*>test"}, + {scsNoPmethods, fCSFprint, "", ts, "stringer test"}, + {scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"}, + {scsNoPmethods, fCSFprint, "", tps, "test"}, + {scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"}, + {scsMaxDepth, fCSFprint, "", dt, "{{} [] [] map[]}"}, + {scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" + + " ic: (spew_test.indirCir1) {\n \n },\n" + + " arr: ([1]string) (len=1 cap=1) {\n \n },\n" + + " slice: ([]string) (len=1 cap=1) {\n \n },\n" + + " m: (map[string]int) (len=1) {\n \n }\n}\n"}, + {scsContinue, fCSFprint, "", ts, "(stringer test) test"}, + {scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " + + "(len=4) (stringer test) \"test\"\n"}, + {scsContinue, fCSFprint, "", te, "(error: 10) 10"}, + {scsContinue, fCSFdump, "", te, "(spew_test.customError) " + + "(error: 10) 10\n"}, + } +} + +// TestSpew executes all of the tests described by spewTests. +func TestSpew(t *testing.T) { + initSpewTests() + + t.Logf("Running %d tests", len(spewTests)) + for i, test := range spewTests { + buf := new(bytes.Buffer) + switch test.f { + case fCSFdump: + test.cs.Fdump(buf, test.in) + + case fCSFprint: + test.cs.Fprint(buf, test.in) + + case fCSFprintf: + test.cs.Fprintf(buf, test.format, test.in) + + case fCSFprintln: + test.cs.Fprintln(buf, test.in) + + case fCSPrint: + b, err := redirStdout(func() { test.cs.Print(test.in) }) + if err != nil { + t.Errorf("%v #%d %v", test.f, i, err) + continue + } + buf.Write(b) + + case fCSPrintln: + b, err := redirStdout(func() { test.cs.Println(test.in) }) + if err != nil { + t.Errorf("%v #%d %v", test.f, i, err) + continue + } + buf.Write(b) + + case fCSSdump: + str := test.cs.Sdump(test.in) + buf.WriteString(str) + + case fCSSprint: + str := test.cs.Sprint(test.in) + buf.WriteString(str) + + case fCSSprintf: + str := test.cs.Sprintf(test.format, test.in) + buf.WriteString(str) + + case fCSSprintln: + str := test.cs.Sprintln(test.in) + buf.WriteString(str) + + case fCSErrorf: + err := test.cs.Errorf(test.format, test.in) + buf.WriteString(err.Error()) + + case fCSNewFormatter: + fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in)) + + case fErrorf: + err := spew.Errorf(test.format, test.in) + buf.WriteString(err.Error()) + + case fFprint: + spew.Fprint(buf, test.in) + + case fFprintln: + spew.Fprintln(buf, test.in) + + case fPrint: + b, err := redirStdout(func() { spew.Print(test.in) }) + if err != nil { + t.Errorf("%v #%d %v", test.f, i, err) + continue + } + buf.Write(b) + + case fPrintln: + b, err := redirStdout(func() { spew.Println(test.in) }) + if err != nil { + t.Errorf("%v #%d %v", test.f, i, err) + continue + } + buf.Write(b) + + case fSdump: + str := spew.Sdump(test.in) + buf.WriteString(str) + + case fSprint: + str := spew.Sprint(test.in) + buf.WriteString(str) + + case fSprintf: + str := spew.Sprintf(test.format, test.in) + buf.WriteString(str) + + case fSprintln: + str := spew.Sprintln(test.in) + buf.WriteString(str) + + default: + t.Errorf("%v #%d unrecognized function", test.f, i) + continue + } + s := buf.String() + if test.want != s { + t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want) + continue + } + } +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go new file mode 100644 index 0000000000..5c87dd456e --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go @@ -0,0 +1,82 @@ +// Copyright (c) 2013 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when both cgo is supported and "-tags testcgo" is added to the go test +// command line. This code should really only be in the dumpcgo_test.go file, +// but unfortunately Go will not allow cgo in test files, so this is a +// workaround to allow cgo types to be tested. This configuration is used +// because spew itself does not require cgo to run even though it does handle +// certain cgo types specially. Rather than forcing all clients to require cgo +// and an external C compiler just to run the tests, this scheme makes them +// optional. +// +build cgo,testcgo + +package testdata + +/* +#include +typedef unsigned char custom_uchar_t; + +char *ncp = 0; +char *cp = "test"; +char ca[6] = {'t', 'e', 's', 't', '2', '\0'}; +unsigned char uca[6] = {'t', 'e', 's', 't', '3', '\0'}; +signed char sca[6] = {'t', 'e', 's', 't', '4', '\0'}; +uint8_t ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'}; +custom_uchar_t tuca[6] = {'t', 'e', 's', 't', '6', '\0'}; +*/ +import "C" + +// GetCgoNullCharPointer returns a null char pointer via cgo. This is only +// used for tests. +func GetCgoNullCharPointer() interface{} { + return C.ncp +} + +// GetCgoCharPointer returns a char pointer via cgo. This is only used for +// tests. +func GetCgoCharPointer() interface{} { + return C.cp +} + +// GetCgoCharArray returns a char array via cgo and the array's len and cap. +// This is only used for tests. +func GetCgoCharArray() (interface{}, int, int) { + return C.ca, len(C.ca), cap(C.ca) +} + +// GetCgoUnsignedCharArray returns an unsigned char array via cgo and the +// array's len and cap. This is only used for tests. +func GetCgoUnsignedCharArray() (interface{}, int, int) { + return C.uca, len(C.uca), cap(C.uca) +} + +// GetCgoSignedCharArray returns a signed char array via cgo and the array's len +// and cap. This is only used for tests. +func GetCgoSignedCharArray() (interface{}, int, int) { + return C.sca, len(C.sca), cap(C.sca) +} + +// GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and +// cap. This is only used for tests. +func GetCgoUint8tArray() (interface{}, int, int) { + return C.ui8ta, len(C.ui8ta), cap(C.ui8ta) +} + +// GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via +// cgo and the array's len and cap. This is only used for tests. +func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) { + return C.tuca, len(C.tuca), cap(C.tuca) +} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/.gitignore b/Godeps/_workspace/src/github.com/ethereum/ethash/.gitignore new file mode 100644 index 0000000000..da074e6b3a --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/.gitignore @@ -0,0 +1,12 @@ +.idea/ +.DS_Store +*/**/*un~ +.vagrant/ +*.pyc +build/ +pyethash.egg-info/ +*.so +*~ +*.swp +MANIFEST +dist/ diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/.travis.yml b/Godeps/_workspace/src/github.com/ethereum/ethash/.travis.yml new file mode 100644 index 0000000000..b83b02bf3c --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/.travis.yml @@ -0,0 +1,23 @@ +language: go +go: + - 1.4.2 + +before_install: + # for g++4.8 and C++11 + - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test + + # Set up go-ethereum + - sudo apt-get update -y -qq + - sudo apt-get install -yqq libgmp3-dev + - git clone --depth=10 https://github.com/ethereum/go-ethereum ${GOPATH}/src/github.com/ethereum/go-ethereum + # use canned dependencies from the go-ethereum repository + - export GOPATH=$GOPATH:$GOPATH/src/github.com/ethereum/go-ethereum/Godeps/_workspace/ + - echo $GOPATH + +install: + # need to explicitly request version 1.48 since by default we get 1.46 which does not work with C++11 + - sudo apt-get install -qq --yes --force-yes g++-4.8 + - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50 + - sudo apt-get install -qq wget cmake bash libboost-test1.48-dev libboost-system1.48-dev libboost-filesystem1.48-dev nodejs python-pip python-dev valgrind + - sudo pip install virtualenv -q +script: "./test/test.sh" diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/CMakeLists.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/CMakeLists.txt new file mode 100644 index 0000000000..807c43e963 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 2.8.7) +project(ethash) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/") +set(ETHHASH_LIBS ethash) + +if (WIN32 AND WANT_CRYPTOPP) + add_subdirectory(cryptopp) +endif() + +add_subdirectory(src/libethash) + +add_subdirectory(src/benchmark EXCLUDE_FROM_ALL) +add_subdirectory(test/c) diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/MANIFEST.in b/Godeps/_workspace/src/github.com/ethereum/ethash/MANIFEST.in new file mode 100644 index 0000000000..74e73c8be4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/MANIFEST.in @@ -0,0 +1,17 @@ +include setup.py + +# C sources +include src/libethash/internal.c +include src/libethash/sha3.c +include src/libethash/util.c +include src/python/core.c + +# Headers +include src/libethash/compiler.h +include src/libethash/data_sizes.h +include src/libethash/endian.h +include src/libethash/ethash.h +include src/libethash/fnv.h +include src/libethash/internal.h +include src/libethash/sha3.h +include src/libethash/util.h diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/Makefile b/Godeps/_workspace/src/github.com/ethereum/ethash/Makefile new file mode 100644 index 0000000000..741d3b56dc --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/Makefile @@ -0,0 +1,6 @@ +.PHONY: clean test +test: + ./test/test.sh + +clean: + rm -rf *.so pyethash.egg-info/ build/ test/python/python-virtual-env/ test/c/build/ pyethash.so test/python/*.pyc dist/ MANIFEST diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/README.md b/Godeps/_workspace/src/github.com/ethereum/ethash/README.md new file mode 100644 index 0000000000..2b2c3b544c --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/README.md @@ -0,0 +1,22 @@ +[![Build Status](https://travis-ci.org/ethereum/ethash.svg?branch=master)](https://travis-ci.org/ethereum/ethash) +[![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/debris/ethash?branch=master&svg=true)](https://ci.appveyor.com/project/debris/ethash-nr37r/branch/master) + +# Ethash + +For details on this project, please see the Ethereum wiki: +https://github.com/ethereum/wiki/wiki/Ethash + +### Coding Style for C++ code: + +Follow the same exact style as in [cpp-ethereum](https://github.com/ethereum/cpp-ethereum/blob/develop/CodingStandards.txt) + +### Coding Style for C code: + +The main thing above all is code consistency. + +- Tabs for indentation. A tab is 4 spaces +- Try to stick to the [K&R](http://en.wikipedia.org/wiki/Indent_style#K.26R_style), + especially for the C code. +- Keep the line lengths reasonable. No hard limit on 80 characters but don't go further + than 110. Some people work with multiple buffers next to each other. + Make them like you :) diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/Vagrantfile b/Godeps/_workspace/src/github.com/ethereum/ethash/Vagrantfile new file mode 100644 index 0000000000..03891653f0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/Vagrantfile @@ -0,0 +1,7 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure(2) do |config| + config.vm.box = "Ubuntu 12.04" + config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-amd64-vagrant-disk1.box" +end diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/appveyor.yml b/Godeps/_workspace/src/github.com/ethereum/ethash/appveyor.yml new file mode 100644 index 0000000000..ac36a06261 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/appveyor.yml @@ -0,0 +1,43 @@ +version: 1.0.0.{build} + +environment: + BOOST_ROOT: "c:/projects/ethash/deps/boost" + +branches: + only: + - master + - develop + +os: Windows Server 2012 R2 + +clone_folder: c:\projects\ethash + +#platform: Any CPU +#configuration: Debug + +install: + # by default, all script lines are interpreted as batch + +# scripts to run before build +before_build: + - echo "Downloading boost..." + - mkdir c:\projects\ethash\deps + - cd c:\projects\ethash\deps + - curl -O https://build.ethdev.com/builds/windows-precompiled/boost.tar.gz + - echo "Unzipping boost..." + - 7z x boost.tar.gz > nul + - 7z x boost.tar > nul + - ls + - echo "Running cmake..." + - cd c:\projects\ethash + - cmake . + +build: + project: ALL_BUILD.vcxproj # path to Visual Studio solution or project + +after_build: + - echo "Running tests..." + - cd c:\projects\ethash\test\c\Debug + - Test.exe + - echo "Finished!" + diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/CMakeParseArguments.cmake b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/CMakeParseArguments.cmake new file mode 100644 index 0000000000..8553f38f5f --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/CMakeParseArguments.cmake @@ -0,0 +1,161 @@ +#.rst: +# CMakeParseArguments +# ------------------- +# +# +# +# CMAKE_PARSE_ARGUMENTS( +# args...) +# +# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions +# for parsing the arguments given to that macro or function. It +# processes the arguments and defines a set of variables which hold the +# values of the respective options. +# +# The argument contains all options for the respective macro, +# i.e. keywords which can be used when calling the macro without any +# value following, like e.g. the OPTIONAL keyword of the install() +# command. +# +# The argument contains all keywords for this macro +# which are followed by one value, like e.g. DESTINATION keyword of the +# install() command. +# +# The argument contains all keywords for this +# macro which can be followed by more than one value, like e.g. the +# TARGETS or FILES keywords of the install() command. +# +# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the +# keywords listed in , and +# a variable composed of the given +# followed by "_" and the name of the respective keyword. These +# variables will then hold the respective value from the argument list. +# For the keywords this will be TRUE or FALSE. +# +# All remaining arguments are collected in a variable +# _UNPARSED_ARGUMENTS, this can be checked afterwards to see +# whether your macro was called with unrecognized parameters. +# +# As an example here a my_install() macro, which takes similar arguments +# as the real install() command: +# +# :: +# +# function(MY_INSTALL) +# set(options OPTIONAL FAST) +# set(oneValueArgs DESTINATION RENAME) +# set(multiValueArgs TARGETS CONFIGURATIONS) +# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" +# "${multiValueArgs}" ${ARGN} ) +# ... +# +# +# +# Assume my_install() has been called like this: +# +# :: +# +# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) +# +# +# +# After the cmake_parse_arguments() call the macro will have set the +# following variables: +# +# :: +# +# MY_INSTALL_OPTIONAL = TRUE +# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() +# MY_INSTALL_DESTINATION = "bin" +# MY_INSTALL_RENAME = "" (was not used) +# MY_INSTALL_TARGETS = "foo;bar" +# MY_INSTALL_CONFIGURATIONS = "" (was not used) +# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" +# +# +# +# You can then continue and process these variables. +# +# Keywords terminate lists of values, e.g. if directly after a +# one_value_keyword another recognized keyword follows, this is +# interpreted as the beginning of the new option. E.g. +# my_install(TARGETS foo DESTINATION OPTIONAL) would result in +# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION +# would be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor. + +#============================================================================= +# Copyright 2010 Alexander Neundorf +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) + return() +endif() +set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) + + +function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) + # first set all result variables to empty/FALSE + foreach(arg_name ${_singleArgNames} ${_multiArgNames}) + set(${prefix}_${arg_name}) + endforeach() + + foreach(option ${_optionNames}) + set(${prefix}_${option} FALSE) + endforeach() + + set(${prefix}_UNPARSED_ARGUMENTS) + + set(insideValues FALSE) + set(currentArgName) + + # now iterate over all arguments and fill the result variables + foreach(currentArg ${ARGN}) + list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword + + if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) + if(insideValues) + if("${insideValues}" STREQUAL "SINGLE") + set(${prefix}_${currentArgName} ${currentArg}) + set(insideValues FALSE) + elseif("${insideValues}" STREQUAL "MULTI") + list(APPEND ${prefix}_${currentArgName} ${currentArg}) + endif() + else() + list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) + endif() + else() + if(NOT ${optionIndex} EQUAL -1) + set(${prefix}_${currentArg} TRUE) + set(insideValues FALSE) + elseif(NOT ${singleArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "SINGLE") + elseif(NOT ${multiArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "MULTI") + endif() + endif() + + endforeach() + + # propagate the result variables to the caller: + foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) + set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) + endforeach() + set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) + +endfunction() diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindCryptoPP.cmake b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindCryptoPP.cmake new file mode 100644 index 0000000000..5ca01e4468 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindCryptoPP.cmake @@ -0,0 +1,108 @@ +# Module for locating the Crypto++ encryption library. +# +# Customizable variables: +# CRYPTOPP_ROOT_DIR +# This variable points to the CryptoPP root directory. On Windows the +# library location typically will have to be provided explicitly using the +# -D command-line option. The directory should include the include/cryptopp, +# lib and/or bin sub-directories. +# +# Read-only variables: +# CRYPTOPP_FOUND +# Indicates whether the library has been found. +# +# CRYPTOPP_INCLUDE_DIRS +# Points to the CryptoPP include directory. +# +# CRYPTOPP_LIBRARIES +# Points to the CryptoPP libraries that should be passed to +# target_link_libararies. +# +# +# Copyright (c) 2012 Sergiu Dotenco +# +# 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. + +INCLUDE (FindPackageHandleStandardArgs) + +FIND_PATH (CRYPTOPP_ROOT_DIR + NAMES cryptopp/cryptlib.h include/cryptopp/cryptlib.h + PATHS ENV CRYPTOPPROOT + DOC "CryptoPP root directory") + +# Re-use the previous path: +FIND_PATH (CRYPTOPP_INCLUDE_DIR + NAMES cryptopp/cryptlib.h + HINTS ${CRYPTOPP_ROOT_DIR} + PATH_SUFFIXES include + DOC "CryptoPP include directory") + +FIND_LIBRARY (CRYPTOPP_LIBRARY_DEBUG + NAMES cryptlibd cryptoppd + HINTS ${CRYPTOPP_ROOT_DIR} + PATH_SUFFIXES lib + DOC "CryptoPP debug library") + +FIND_LIBRARY (CRYPTOPP_LIBRARY_RELEASE + NAMES cryptlib cryptopp + HINTS ${CRYPTOPP_ROOT_DIR} + PATH_SUFFIXES lib + DOC "CryptoPP release library") + +IF (CRYPTOPP_LIBRARY_DEBUG AND CRYPTOPP_LIBRARY_RELEASE) + SET (CRYPTOPP_LIBRARY + optimized ${CRYPTOPP_LIBRARY_RELEASE} + debug ${CRYPTOPP_LIBRARY_DEBUG} CACHE DOC "CryptoPP library") +ELSEIF (CRYPTOPP_LIBRARY_RELEASE) + SET (CRYPTOPP_LIBRARY ${CRYPTOPP_LIBRARY_RELEASE} CACHE DOC + "CryptoPP library") +ENDIF (CRYPTOPP_LIBRARY_DEBUG AND CRYPTOPP_LIBRARY_RELEASE) + +IF (CRYPTOPP_INCLUDE_DIR) + SET (_CRYPTOPP_VERSION_HEADER ${CRYPTOPP_INCLUDE_DIR}/cryptopp/config.h) + + IF (EXISTS ${_CRYPTOPP_VERSION_HEADER}) + FILE (STRINGS ${_CRYPTOPP_VERSION_HEADER} _CRYPTOPP_VERSION_TMP REGEX + "^#define CRYPTOPP_VERSION[ \t]+[0-9]+$") + + STRING (REGEX REPLACE + "^#define CRYPTOPP_VERSION[ \t]+([0-9]+)" "\\1" _CRYPTOPP_VERSION_TMP + ${_CRYPTOPP_VERSION_TMP}) + + STRING (REGEX REPLACE "([0-9]+)[0-9][0-9]" "\\1" CRYPTOPP_VERSION_MAJOR + ${_CRYPTOPP_VERSION_TMP}) + STRING (REGEX REPLACE "[0-9]([0-9])[0-9]" "\\1" CRYPTOPP_VERSION_MINOR + ${_CRYPTOPP_VERSION_TMP}) + STRING (REGEX REPLACE "[0-9][0-9]([0-9])" "\\1" CRYPTOPP_VERSION_PATCH + ${_CRYPTOPP_VERSION_TMP}) + + SET (CRYPTOPP_VERSION_COUNT 3) + SET (CRYPTOPP_VERSION + ${CRYPTOPP_VERSION_MAJOR}.${CRYPTOPP_VERSION_MINOR}.${CRYPTOPP_VERSION_PATCH}) + ENDIF (EXISTS ${_CRYPTOPP_VERSION_HEADER}) +ENDIF (CRYPTOPP_INCLUDE_DIR) + +SET (CRYPTOPP_INCLUDE_DIRS ${CRYPTOPP_INCLUDE_DIR}) +SET (CRYPTOPP_LIBRARIES ${CRYPTOPP_LIBRARY}) + +MARK_AS_ADVANCED (CRYPTOPP_INCLUDE_DIR CRYPTOPP_LIBRARY CRYPTOPP_LIBRARY_DEBUG + CRYPTOPP_LIBRARY_RELEASE) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS (CryptoPP REQUIRED_VARS CRYPTOPP_ROOT_DIR + CRYPTOPP_INCLUDE_DIR CRYPTOPP_LIBRARY VERSION_VAR CRYPTOPP_VERSION) \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindOpenCL.cmake b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindOpenCL.cmake new file mode 100644 index 0000000000..415c95dbd0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindOpenCL.cmake @@ -0,0 +1,148 @@ +#.rst: +# FindOpenCL +# ---------- +# +# Try to find OpenCL +# +# Once done this will define:: +# +# OpenCL_FOUND - True if OpenCL was found +# OpenCL_INCLUDE_DIRS - include directories for OpenCL +# OpenCL_LIBRARIES - link against this library to use OpenCL +# OpenCL_VERSION_STRING - Highest supported OpenCL version (eg. 1.2) +# OpenCL_VERSION_MAJOR - The major version of the OpenCL implementation +# OpenCL_VERSION_MINOR - The minor version of the OpenCL implementation +# +# The module will also define two cache variables:: +# +# OpenCL_INCLUDE_DIR - the OpenCL include directory +# OpenCL_LIBRARY - the path to the OpenCL library +# + +#============================================================================= +# Copyright 2014 Matthaeus G. Chajdas +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +function(_FIND_OPENCL_VERSION) + include(CheckSymbolExists) + include(CMakePushCheckState) + set(CMAKE_REQUIRED_QUIET ${OpenCL_FIND_QUIETLY}) + + CMAKE_PUSH_CHECK_STATE() + foreach(VERSION "2_0" "1_2" "1_1" "1_0") + set(CMAKE_REQUIRED_INCLUDES "${OpenCL_INCLUDE_DIR}") + + if(APPLE) + CHECK_SYMBOL_EXISTS( + CL_VERSION_${VERSION} + "${OpenCL_INCLUDE_DIR}/OpenCL/cl.h" + OPENCL_VERSION_${VERSION}) + else() + CHECK_SYMBOL_EXISTS( + CL_VERSION_${VERSION} + "${OpenCL_INCLUDE_DIR}/CL/cl.h" + OPENCL_VERSION_${VERSION}) + endif() + + if(OPENCL_VERSION_${VERSION}) + string(REPLACE "_" "." VERSION "${VERSION}") + set(OpenCL_VERSION_STRING ${VERSION} PARENT_SCOPE) + string(REGEX MATCHALL "[0-9]+" version_components "${VERSION}") + list(GET version_components 0 major_version) + list(GET version_components 1 minor_version) + set(OpenCL_VERSION_MAJOR ${major_version} PARENT_SCOPE) + set(OpenCL_VERSION_MINOR ${minor_version} PARENT_SCOPE) + break() + endif() + endforeach() + CMAKE_POP_CHECK_STATE() +endfunction() + +find_path(OpenCL_INCLUDE_DIR + NAMES + CL/cl.h OpenCL/cl.h + PATHS + ENV "PROGRAMFILES(X86)" + ENV AMDAPPSDKROOT + ENV INTELOCLSDKROOT + ENV NVSDKCOMPUTE_ROOT + ENV CUDA_PATH + ENV ATISTREAMSDKROOT + PATH_SUFFIXES + include + OpenCL/common/inc + "AMD APP/include") + +_FIND_OPENCL_VERSION() + +if(WIN32) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + find_library(OpenCL_LIBRARY + NAMES OpenCL + PATHS + ENV "PROGRAMFILES(X86)" + ENV AMDAPPSDKROOT + ENV INTELOCLSDKROOT + ENV CUDA_PATH + ENV NVSDKCOMPUTE_ROOT + ENV ATISTREAMSDKROOT + PATH_SUFFIXES + "AMD APP/lib/x86" + lib/x86 + lib/Win32 + OpenCL/common/lib/Win32) + elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) + find_library(OpenCL_LIBRARY + NAMES OpenCL + PATHS + ENV "PROGRAMFILES(X86)" + ENV AMDAPPSDKROOT + ENV INTELOCLSDKROOT + ENV CUDA_PATH + ENV NVSDKCOMPUTE_ROOT + ENV ATISTREAMSDKROOT + PATH_SUFFIXES + "AMD APP/lib/x86_64" + lib/x86_64 + lib/x64 + OpenCL/common/lib/x64) + endif() +else() + find_library(OpenCL_LIBRARY + NAMES OpenCL + PATHS + ENV "PROGRAMFILES(X86)" + ENV AMDAPPSDKROOT + ENV INTELOCLSDKROOT + ENV CUDA_PATH + ENV NVSDKCOMPUTE_ROOT + ENV ATISTREAMSDKROOT + PATH_SUFFIXES + "AMD APP/lib/x86_64" + lib/x86_64 + lib/x64 + OpenCL/common/lib/x64) +endif() + +set(OpenCL_LIBRARIES ${OpenCL_LIBRARY}) +set(OpenCL_INCLUDE_DIRS ${OpenCL_INCLUDE_DIR}) + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +find_package_handle_standard_args( + OpenCL + FOUND_VAR OpenCL_FOUND + REQUIRED_VARS OpenCL_LIBRARY OpenCL_INCLUDE_DIR + VERSION_VAR OpenCL_VERSION_STRING) + +mark_as_advanced( + OpenCL_INCLUDE_DIR + OpenCL_LIBRARY) diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageHandleStandardArgs.cmake b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageHandleStandardArgs.cmake new file mode 100644 index 0000000000..6bcf1e788b --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageHandleStandardArgs.cmake @@ -0,0 +1,382 @@ +#.rst: +# FindPackageHandleStandardArgs +# ----------------------------- +# +# +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS( ... ) +# +# This function is intended to be used in FindXXX.cmake modules files. +# It handles the REQUIRED, QUIET and version-related arguments to +# find_package(). It also sets the _FOUND variable. The +# package is considered found if all variables ... listed contain +# valid results, e.g. valid filepaths. +# +# There are two modes of this function. The first argument in both +# modes is the name of the Find-module where it is called (in original +# casing). +# +# The first simple mode looks like this: +# +# :: +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS( +# (DEFAULT_MSG|"Custom failure message") ... ) +# +# If the variables to are all valid, then +# _FOUND will be set to TRUE. If DEFAULT_MSG is given +# as second argument, then the function will generate itself useful +# success and error messages. You can also supply a custom error +# message for the failure case. This is not recommended. +# +# The second mode is more powerful and also supports version checking: +# +# :: +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME +# [FOUND_VAR ] +# [REQUIRED_VARS ...] +# [VERSION_VAR ] +# [HANDLE_COMPONENTS] +# [CONFIG_MODE] +# [FAIL_MESSAGE "Custom failure message"] ) +# +# In this mode, the name of the result-variable can be set either to +# either _FOUND or _FOUND using the +# FOUND_VAR option. Other names for the result-variable are not +# allowed. So for a Find-module named FindFooBar.cmake, the two +# possible names are FooBar_FOUND and FOOBAR_FOUND. It is recommended +# to use the original case version. If the FOUND_VAR option is not +# used, the default is _FOUND. +# +# As in the simple mode, if through are all valid, +# _FOUND will be set to TRUE. After REQUIRED_VARS the +# variables which are required for this package are listed. Following +# VERSION_VAR the name of the variable can be specified which holds the +# version of the package which has been found. If this is done, this +# version will be checked against the (potentially) specified required +# version used in the find_package() call. The EXACT keyword is also +# handled. The default messages include information about the required +# version and the version which has been actually found, both if the +# version is ok or not. If the package supports components, use the +# HANDLE_COMPONENTS option to enable handling them. In this case, +# find_package_handle_standard_args() will report which components have +# been found and which are missing, and the _FOUND variable +# will be set to FALSE if any of the required components (i.e. not the +# ones listed after OPTIONAL_COMPONENTS) are missing. Use the option +# CONFIG_MODE if your FindXXX.cmake module is a wrapper for a +# find_package(... NO_MODULE) call. In this case VERSION_VAR will be +# set to _VERSION and the macro will automatically check whether +# the Config module was found. Via FAIL_MESSAGE a custom failure +# message can be specified, if this is not used, the default message +# will be displayed. +# +# Example for mode 1: +# +# :: +# +# find_package_handle_standard_args(LibXml2 DEFAULT_MSG +# LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) +# +# +# +# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and +# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to +# TRUE. If it is not found and REQUIRED was used, it fails with +# FATAL_ERROR, independent whether QUIET was used or not. If it is +# found, success will be reported, including the content of . On +# repeated Cmake runs, the same message won't be printed again. +# +# Example for mode 2: +# +# :: +# +# find_package_handle_standard_args(LibXslt +# FOUND_VAR LibXslt_FOUND +# REQUIRED_VARS LibXslt_LIBRARIES LibXslt_INCLUDE_DIRS +# VERSION_VAR LibXslt_VERSION_STRING) +# +# In this case, LibXslt is considered to be found if the variable(s) +# listed after REQUIRED_VAR are all valid, i.e. LibXslt_LIBRARIES and +# LibXslt_INCLUDE_DIRS in this case. The result will then be stored in +# LibXslt_FOUND . Also the version of LibXslt will be checked by using +# the version contained in LibXslt_VERSION_STRING. Since no +# FAIL_MESSAGE is given, the default messages will be printed. +# +# Another example for mode 2: +# +# :: +# +# find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4) +# find_package_handle_standard_args(Automoc4 CONFIG_MODE) +# +# In this case, FindAutmoc4.cmake wraps a call to find_package(Automoc4 +# NO_MODULE) and adds an additional search directory for automoc4. Here +# the result will be stored in AUTOMOC4_FOUND. The following +# FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper +# success/error message. + +#============================================================================= +# Copyright 2007-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseArguments.cmake) + +# internal helper macro +macro(_FPHSA_FAILURE_MESSAGE _msg) + if (${_NAME}_FIND_REQUIRED) + message(FATAL_ERROR "${_msg}") + else () + if (NOT ${_NAME}_FIND_QUIETLY) + message(STATUS "${_msg}") + endif () + endif () +endmacro() + + +# internal helper macro to generate the failure message when used in CONFIG_MODE: +macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) + # _CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found: + if(${_NAME}_CONFIG) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})") + else() + # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version. + # List them all in the error message: + if(${_NAME}_CONSIDERED_CONFIGS) + set(configsText "") + list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount) + math(EXPR configsCount "${configsCount} - 1") + foreach(currentConfigIndex RANGE ${configsCount}) + list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) + list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) + set(configsText "${configsText} ${filename} (version ${version})\n") + endforeach() + if (${_NAME}_NOT_FOUND_MESSAGE) + set(configsText "${configsText} Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n") + endif() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}") + + else() + # Simple case: No Config-file was found at all: + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}") + endif() + endif() +endmacro() + + +function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) + +# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in +# new extended or in the "old" mode: + set(options CONFIG_MODE HANDLE_COMPONENTS) + set(oneValueArgs FAIL_MESSAGE VERSION_VAR FOUND_VAR) + set(multiValueArgs REQUIRED_VARS) + set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} ) + list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX) + + if(${INDEX} EQUAL -1) + set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG}) + set(FPHSA_REQUIRED_VARS ${ARGN}) + set(FPHSA_VERSION_VAR) + else() + + CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) + + if(FPHSA_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") + endif() + + if(NOT FPHSA_FAIL_MESSAGE) + set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG") + endif() + endif() + +# now that we collected all arguments, process them + + if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG") + set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}") + endif() + + # In config-mode, we rely on the variable _CONFIG, which is set by find_package() + # when it successfully found the config-file, including version checking: + if(FPHSA_CONFIG_MODE) + list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG) + list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS) + set(FPHSA_VERSION_VAR ${_NAME}_VERSION) + endif() + + if(NOT FPHSA_REQUIRED_VARS) + message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()") + endif() + + list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR) + + string(TOUPPER ${_NAME} _NAME_UPPER) + string(TOLOWER ${_NAME} _NAME_LOWER) + + if(FPHSA_FOUND_VAR) + if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$" OR FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$") + set(_FOUND_VAR ${FPHSA_FOUND_VAR}) + else() + message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.") + endif() + else() + set(_FOUND_VAR ${_NAME_UPPER}_FOUND) + endif() + + # collect all variables which were not found, so they can be printed, so the + # user knows better what went wrong (#6375) + set(MISSING_VARS "") + set(DETAILS "") + # check if all passed variables are valid + unset(${_FOUND_VAR}) + foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS}) + if(NOT ${_CURRENT_VAR}) + set(${_FOUND_VAR} FALSE) + set(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}") + else() + set(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]") + endif() + endforeach() + if(NOT "${${_FOUND_VAR}}" STREQUAL "FALSE") + set(${_FOUND_VAR} TRUE) + endif() + + # component handling + unset(FOUND_COMPONENTS_MSG) + unset(MISSING_COMPONENTS_MSG) + + if(FPHSA_HANDLE_COMPONENTS) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(${_NAME}_${comp}_FOUND) + + if(NOT DEFINED FOUND_COMPONENTS_MSG) + set(FOUND_COMPONENTS_MSG "found components: ") + endif() + set(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}") + + else() + + if(NOT DEFINED MISSING_COMPONENTS_MSG) + set(MISSING_COMPONENTS_MSG "missing components: ") + endif() + set(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}") + + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_FOUND_VAR} FALSE) + set(MISSING_VARS "${MISSING_VARS} ${comp}") + endif() + + endif() + endforeach() + set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}") + set(DETAILS "${DETAILS}[c${COMPONENT_MSG}]") + endif() + + # version handling: + set(VERSION_MSG "") + set(VERSION_OK TRUE) + set(VERSION ${${FPHSA_VERSION_VAR}}) + + # check with DEFINED here as the requested or found version may be "0" + if (DEFINED ${_NAME}_FIND_VERSION) + if(DEFINED ${FPHSA_VERSION_VAR}) + + if(${_NAME}_FIND_VERSION_EXACT) # exact version required + # count the dots in the version string + string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${VERSION}") + # add one dot because there is one dot more than there are components + string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS) + if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT) + # Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT + # is at most 4 here. Therefore a simple lookup table is used. + if (${_NAME}_FIND_VERSION_COUNT EQUAL 1) + set(_VERSION_REGEX "[^.]*") + elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2) + set(_VERSION_REGEX "[^.]*\\.[^.]*") + elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3) + set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*") + else () + set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*") + endif () + string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${VERSION}") + unset(_VERSION_REGEX) + if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD) + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable exact version \"${VERSION}\")") + endif () + unset(_VERSION_HEAD) + else () + if (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}") + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable exact version \"${VERSION}\")") + endif () + endif () + unset(_VERSION_DOTS) + + else() # minimum version specified: + if ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}") + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable version \"${VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")") + endif () + endif() + + else() + + # if the package was not found, but a version was given, add that to the output: + if(${_NAME}_FIND_VERSION_EXACT) + set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")") + else() + set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")") + endif() + + endif() + else () + if(VERSION) + set(VERSION_MSG "(found version \"${VERSION}\")") + endif() + endif () + + if(VERSION_OK) + set(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]") + else() + set(${_FOUND_VAR} FALSE) + endif() + + + # print the result: + if (${_FOUND_VAR}) + FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}") + else () + + if(FPHSA_CONFIG_MODE) + _FPHSA_HANDLE_FAILURE_CONFIG_MODE() + else() + if(NOT VERSION_OK) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})") + else() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}") + endif() + endif() + + endif () + + set(${_FOUND_VAR} ${${_FOUND_VAR}} PARENT_SCOPE) + +endfunction() diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageMessage.cmake b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageMessage.cmake new file mode 100644 index 0000000000..a0349d3db9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageMessage.cmake @@ -0,0 +1,57 @@ +#.rst: +# FindPackageMessage +# ------------------ +# +# +# +# FIND_PACKAGE_MESSAGE( "message for user" "find result details") +# +# This macro is intended to be used in FindXXX.cmake modules files. It +# will print a message once for each unique find result. This is useful +# for telling the user where a package was found. The first argument +# specifies the name (XXX) of the package. The second argument +# specifies the message to display. The third argument lists details +# about the find result so that if they change the message will be +# displayed again. The macro also obeys the QUIET argument to the +# find_package command. +# +# Example: +# +# :: +# +# if(X11_FOUND) +# FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}" +# "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") +# else() +# ... +# endif() + +#============================================================================= +# Copyright 2008-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +function(FIND_PACKAGE_MESSAGE pkg msg details) + # Avoid printing a message repeatedly for the same find result. + if(NOT ${pkg}_FIND_QUIETLY) + string(REPLACE "\n" "" details "${details}") + set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) + if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") + # The message has not yet been printed. + message(STATUS "${msg}") + + # Save the find details in the cache to avoid printing the same + # message again. + set("${DETAILS_VAR}" "${details}" + CACHE INTERNAL "Details about finding ${pkg}") + endif() + endif() +endfunction() diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/cryptopp/CMakeLists.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/cryptopp/CMakeLists.txt new file mode 100644 index 0000000000..6f42805329 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/cryptopp/CMakeLists.txt @@ -0,0 +1,13 @@ +set(LIBRARY cryptopp) + +include_directories(../../cryptopp) + +# todo, subset +file(GLOB HEADERS "../../cryptopp/*.h") +file(GLOB SOURCE "../../cryptopp/*.cpp") + +add_library(${LIBRARY} ${HEADERS} ${SOURCE}) + +set(CRYPTOPP_INCLUDE_DIRS "../.." "../../../" PARENT_SCOPE) +set(CRYPTOPP_LIBRARIES ${LIBRARY} PARENT_SCOPE) +set(CRYPTOPP_FOUND TRUE PARENT_SCOPE) diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go new file mode 100644 index 0000000000..d0864da7f7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go @@ -0,0 +1,376 @@ +package ethash + +/* +#include "src/libethash/internal.h" + +int ethashGoCallback_cgo(unsigned); +*/ +import "C" + +import ( + "errors" + "fmt" + "io/ioutil" + "math/big" + "math/rand" + "os" + "os/user" + "path/filepath" + "runtime" + "sync" + "sync/atomic" + "time" + "unsafe" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" + "github.com/ethereum/go-ethereum/pow" +) + +var ( + minDifficulty = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) + sharedLight = new(Light) +) + +const ( + epochLength uint64 = 30000 + cacheSizeForTesting C.uint64_t = 1024 + dagSizeForTesting C.uint64_t = 1024 * 32 +) + +var DefaultDir = defaultDir() + +func defaultDir() string { + home := os.Getenv("HOME") + if user, err := user.Current(); err == nil { + home = user.HomeDir + } + if runtime.GOOS == "windows" { + return filepath.Join(home, "AppData", "Ethash") + } + return filepath.Join(home, ".ethash") +} + +// cache wraps an ethash_light_t with some metadata +// and automatic memory management. +type cache struct { + epoch uint64 + test bool + + gen sync.Once // ensures cache is only generated once. + ptr *C.struct_ethash_light +} + +// generate creates the actual cache. it can be called from multiple +// goroutines. the first call will generate the cache, subsequent +// calls wait until it is generated. +func (cache *cache) generate() { + cache.gen.Do(func() { + started := time.Now() + seedHash := makeSeedHash(cache.epoch) + glog.V(logger.Debug).Infof("Generating cache for epoch %d (%x)", cache.epoch, seedHash) + size := C.ethash_get_cachesize(C.uint64_t(cache.epoch * epochLength)) + if cache.test { + size = cacheSizeForTesting + } + cache.ptr = C.ethash_light_new_internal(size, (*C.ethash_h256_t)(unsafe.Pointer(&seedHash[0]))) + runtime.SetFinalizer(cache, freeCache) + glog.V(logger.Debug).Infof("Done generating cache for epoch %d, it took %v", cache.epoch, time.Since(started)) + }) +} + +func freeCache(cache *cache) { + C.ethash_light_delete(cache.ptr) + cache.ptr = nil +} + +// Light implements the Verify half of the proof of work. +// It uses a small in-memory cache to verify the nonces +// found by Full. +type Light struct { + test bool // if set use a smaller cache size + mu sync.Mutex // protects current + current *cache // last cache which was generated. + // TODO: keep multiple caches. +} + +// Verify checks whether the block's nonce is valid. +func (l *Light) Verify(block pow.Block) bool { + // TODO: do ethash_quick_verify before getCache in order + // to prevent DOS attacks. + blockNum := block.NumberU64() + if blockNum >= epochLength*2048 { + glog.V(logger.Debug).Infof("block number %d too high, limit is %d", epochLength*2048) + return false + } + + difficulty := block.Difficulty() + /* Cannot happen if block header diff is validated prior to PoW, but can + happen if PoW is checked first due to parallel PoW checking. + We could check the minimum valid difficulty but for SoC we avoid (duplicating) + Ethereum protocol consensus rules here which are not in scope of Ethash + */ + if difficulty.Cmp(common.Big0) == 0 { + glog.V(logger.Debug).Infof("invalid block difficulty") + return false + } + + cache := l.getCache(blockNum) + dagSize := C.ethash_get_datasize(C.uint64_t(blockNum)) + + if l.test { + dagSize = dagSizeForTesting + } + // Recompute the hash using the cache. + hash := hashToH256(block.HashNoNonce()) + ret := C.ethash_light_compute_internal(cache.ptr, dagSize, hash, C.uint64_t(block.Nonce())) + if !ret.success { + return false + } + + // avoid mixdigest malleability as it's not included in a block's "hashNononce" + if block.MixDigest() != h256ToHash(ret.mix_hash) { + return false + } + + // Make sure cache is live until after the C call. + // This is important because a GC might happen and execute + // the finalizer before the call completes. + _ = cache + // The actual check. + target := new(big.Int).Div(minDifficulty, difficulty) + return h256ToHash(ret.result).Big().Cmp(target) <= 0 +} + +func h256ToHash(in C.ethash_h256_t) common.Hash { + return *(*common.Hash)(unsafe.Pointer(&in.b)) +} + +func hashToH256(in common.Hash) C.ethash_h256_t { + return C.ethash_h256_t{b: *(*[32]C.uint8_t)(unsafe.Pointer(&in[0]))} +} + +func (l *Light) getCache(blockNum uint64) *cache { + var c *cache + epoch := blockNum / epochLength + // Update or reuse the last cache. + l.mu.Lock() + if l.current != nil && l.current.epoch == epoch { + c = l.current + } else { + c = &cache{epoch: epoch, test: l.test} + l.current = c + } + l.mu.Unlock() + // Wait for the cache to finish generating. + c.generate() + return c +} + +// dag wraps an ethash_full_t with some metadata +// and automatic memory management. +type dag struct { + epoch uint64 + test bool + dir string + + gen sync.Once // ensures DAG is only generated once. + ptr *C.struct_ethash_full +} + +// generate creates the actual DAG. it can be called from multiple +// goroutines. the first call will generate the DAG, subsequent +// calls wait until it is generated. +func (d *dag) generate() { + d.gen.Do(func() { + var ( + started = time.Now() + seedHash = makeSeedHash(d.epoch) + blockNum = C.uint64_t(d.epoch * epochLength) + cacheSize = C.ethash_get_cachesize(blockNum) + dagSize = C.ethash_get_datasize(blockNum) + ) + if d.test { + cacheSize = cacheSizeForTesting + dagSize = dagSizeForTesting + } + if d.dir == "" { + d.dir = DefaultDir + } + glog.V(logger.Info).Infof("Generating DAG for epoch %d (%x)", d.epoch, seedHash) + // Generate a temporary cache. + // TODO: this could share the cache with Light + cache := C.ethash_light_new_internal(cacheSize, (*C.ethash_h256_t)(unsafe.Pointer(&seedHash[0]))) + defer C.ethash_light_delete(cache) + // Generate the actual DAG. + d.ptr = C.ethash_full_new_internal( + C.CString(d.dir), + hashToH256(seedHash), + dagSize, + cache, + (C.ethash_callback_t)(unsafe.Pointer(C.ethashGoCallback_cgo)), + ) + if d.ptr == nil { + panic("ethash_full_new IO or memory error") + } + runtime.SetFinalizer(d, freeDAG) + glog.V(logger.Info).Infof("Done generating DAG for epoch %d, it took %v", d.epoch, time.Since(started)) + }) +} + +func freeDAG(h *dag) { + C.ethash_full_delete(h.ptr) + h.ptr = nil +} + +//export ethashGoCallback +func ethashGoCallback(percent C.unsigned) C.int { + glog.V(logger.Info).Infof("Still generating DAG: %d%%", percent) + return 0 +} + +// MakeDAG pre-generates a DAG file for the given block number in the +// given directory. If dir is the empty string, the default directory +// is used. +func MakeDAG(blockNum uint64, dir string) error { + d := &dag{epoch: blockNum / epochLength, dir: dir} + if blockNum >= epochLength*2048 { + return fmt.Errorf("block number too high, limit is %d", epochLength*2048) + } + d.generate() + if d.ptr == nil { + return errors.New("failed") + } + return nil +} + +// Full implements the Search half of the proof of work. +type Full struct { + Dir string // use this to specify a non-default DAG directory + + test bool // if set use a smaller DAG size + turbo bool + hashRate int32 + + mu sync.Mutex // protects dag + current *dag // current full DAG +} + +func (pow *Full) getDAG(blockNum uint64) (d *dag) { + epoch := blockNum / epochLength + pow.mu.Lock() + if pow.current != nil && pow.current.epoch == epoch { + d = pow.current + } else { + d = &dag{epoch: epoch, test: pow.test, dir: pow.Dir} + pow.current = d + } + pow.mu.Unlock() + // wait for it to finish generating. + d.generate() + return d +} + +func (pow *Full) Search(block pow.Block, stop <-chan struct{}) (nonce uint64, mixDigest []byte) { + dag := pow.getDAG(block.NumberU64()) + + r := rand.New(rand.NewSource(time.Now().UnixNano())) + diff := block.Difficulty() + + i := int64(0) + starti := i + start := time.Now().UnixNano() + previousHashrate := int32(0) + + nonce = uint64(r.Int63()) + hash := hashToH256(block.HashNoNonce()) + target := new(big.Int).Div(minDifficulty, diff) + for { + select { + case <-stop: + atomic.AddInt32(&pow.hashRate, -previousHashrate) + return 0, nil + default: + i++ + + // we don't have to update hash rate on every nonce, so update after + // first nonce check and then after 2^X nonces + if i == 2 || ((i % (1 << 16)) == 0) { + elapsed := time.Now().UnixNano() - start + hashes := (float64(1e9) / float64(elapsed)) * float64(i-starti) + hashrateDiff := int32(hashes) - previousHashrate + previousHashrate = int32(hashes) + atomic.AddInt32(&pow.hashRate, hashrateDiff) + } + + ret := C.ethash_full_compute(dag.ptr, hash, C.uint64_t(nonce)) + result := h256ToHash(ret.result).Big() + + // TODO: disagrees with the spec https://github.com/ethereum/wiki/wiki/Ethash#mining + if ret.success && result.Cmp(target) <= 0 { + mixDigest = C.GoBytes(unsafe.Pointer(&ret.mix_hash), C.int(32)) + atomic.AddInt32(&pow.hashRate, -previousHashrate) + return nonce, mixDigest + } + nonce += 1 + } + + if !pow.turbo { + time.Sleep(20 * time.Microsecond) + } + } +} + +func (pow *Full) GetHashrate() int64 { + return int64(atomic.LoadInt32(&pow.hashRate)) +} + +func (pow *Full) Turbo(on bool) { + // TODO: this needs to use an atomic operation. + pow.turbo = on +} + +// Ethash combines block verification with Light and +// nonce searching with Full into a single proof of work. +type Ethash struct { + *Light + *Full +} + +// New creates an instance of the proof of work. +// A single instance of Light is shared across all instances +// created with New. +func New() *Ethash { + return &Ethash{sharedLight, &Full{turbo: true}} +} + +// NewForTesting creates a proof of work for use in unit tests. +// It uses a smaller DAG and cache size to keep test times low. +// DAG files are stored in a temporary directory. +// +// Nonces found by a testing instance are not verifiable with a +// regular-size cache. +func NewForTesting() (*Ethash, error) { + dir, err := ioutil.TempDir("", "ethash-test") + if err != nil { + return nil, err + } + return &Ethash{&Light{test: true}, &Full{Dir: dir, test: true}}, nil +} + +func GetSeedHash(blockNum uint64) ([]byte, error) { + if blockNum >= epochLength*2048 { + return nil, fmt.Errorf("block number too high, limit is %d", epochLength*2048) + } + sh := makeSeedHash(blockNum / epochLength) + return sh[:], nil +} + +func makeSeedHash(epoch uint64) (sh common.Hash) { + for ; epoch > 0; epoch-- { + sh = crypto.Sha3Hash(sh[:]) + } + return sh +} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash_test.go b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash_test.go new file mode 100644 index 0000000000..1e1de989d1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash_test.go @@ -0,0 +1,204 @@ +package ethash + +import ( + "bytes" + "crypto/rand" + "encoding/hex" + "log" + "math/big" + "os" + "sync" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +func init() { + // glog.SetV(6) + // glog.SetToStderr(true) +} + +type testBlock struct { + difficulty *big.Int + hashNoNonce common.Hash + nonce uint64 + mixDigest common.Hash + number uint64 +} + +func (b *testBlock) Difficulty() *big.Int { return b.difficulty } +func (b *testBlock) HashNoNonce() common.Hash { return b.hashNoNonce } +func (b *testBlock) Nonce() uint64 { return b.nonce } +func (b *testBlock) MixDigest() common.Hash { return b.mixDigest } +func (b *testBlock) NumberU64() uint64 { return b.number } + +var validBlocks = []*testBlock{ + // from proof of concept nine testnet, epoch 0 + { + number: 22, + hashNoNonce: common.HexToHash("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d"), + difficulty: big.NewInt(132416), + nonce: 0x495732e0ed7a801c, + mixDigest: common.HexToHash("2f74cdeb198af0b9abe65d22d372e22fb2d474371774a9583c1cc427a07939f5"), + }, + // from proof of concept nine testnet, epoch 1 + { + number: 30001, + hashNoNonce: common.HexToHash("7e44356ee3441623bc72a683fd3708fdf75e971bbe294f33e539eedad4b92b34"), + difficulty: big.NewInt(1532671), + nonce: 0x318df1c8adef7e5e, + mixDigest: common.HexToHash("144b180aad09ae3c81fb07be92c8e6351b5646dda80e6844ae1b697e55ddde84"), + }, + // from proof of concept nine testnet, epoch 2 + { + number: 60000, + hashNoNonce: common.HexToHash("5fc898f16035bf5ac9c6d9077ae1e3d5fc1ecc3c9fd5bee8bb00e810fdacbaa0"), + difficulty: big.NewInt(2467358), + nonce: 0x50377003e5d830ca, + mixDigest: common.HexToHash("ab546a5b73c452ae86dadd36f0ed83a6745226717d3798832d1b20b489e82063"), + }, +} + +var invalidZeroDiffBlock = testBlock{ + number: 61440000, + hashNoNonce: crypto.Sha3Hash([]byte("foo")), + difficulty: big.NewInt(0), + nonce: 0xcafebabec00000fe, + mixDigest: crypto.Sha3Hash([]byte("bar")), +} + +func TestEthashVerifyValid(t *testing.T) { + eth := New() + for i, block := range validBlocks { + if !eth.Verify(block) { + t.Errorf("block %d (%x) did not validate.", i, block.hashNoNonce[:6]) + } + } +} + +func TestEthashVerifyInvalid(t *testing.T) { + eth := New() + if eth.Verify(&invalidZeroDiffBlock) { + t.Errorf("should not validate - we just ensure it does not panic on this block") + } +} + +func TestEthashConcurrentVerify(t *testing.T) { + eth, err := NewForTesting() + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(eth.Full.Dir) + + block := &testBlock{difficulty: big.NewInt(10)} + nonce, md := eth.Search(block, nil) + block.nonce = nonce + block.mixDigest = common.BytesToHash(md) + + // Verify the block concurrently to check for data races. + var wg sync.WaitGroup + wg.Add(100) + for i := 0; i < 100; i++ { + go func() { + if !eth.Verify(block) { + t.Error("Block could not be verified") + } + wg.Done() + }() + } + wg.Wait() +} + +func TestEthashConcurrentSearch(t *testing.T) { + eth, err := NewForTesting() + if err != nil { + t.Fatal(err) + } + eth.Turbo(true) + defer os.RemoveAll(eth.Full.Dir) + + type searchRes struct { + n uint64 + md []byte + } + + var ( + block = &testBlock{difficulty: big.NewInt(35000)} + nsearch = 10 + wg = new(sync.WaitGroup) + found = make(chan searchRes) + stop = make(chan struct{}) + ) + rand.Read(block.hashNoNonce[:]) + wg.Add(nsearch) + // launch n searches concurrently. + for i := 0; i < nsearch; i++ { + go func() { + nonce, md := eth.Search(block, stop) + select { + case found <- searchRes{n: nonce, md: md}: + case <-stop: + } + wg.Done() + }() + } + + // wait for one of them to find the nonce + res := <-found + // stop the others + close(stop) + wg.Wait() + + block.nonce = res.n + block.mixDigest = common.BytesToHash(res.md) + if !eth.Verify(block) { + t.Error("Block could not be verified") + } +} + +func TestEthashSearchAcrossEpoch(t *testing.T) { + eth, err := NewForTesting() + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(eth.Full.Dir) + + for i := epochLength - 40; i < epochLength+40; i++ { + block := &testBlock{number: i, difficulty: big.NewInt(90)} + rand.Read(block.hashNoNonce[:]) + nonce, md := eth.Search(block, nil) + block.nonce = nonce + block.mixDigest = common.BytesToHash(md) + if !eth.Verify(block) { + t.Fatalf("Block could not be verified") + } + } +} + +func TestGetSeedHash(t *testing.T) { + seed0, err := GetSeedHash(0) + if err != nil { + t.Errorf("Failed to get seedHash for block 0: %v", err) + } + if bytes.Compare(seed0, make([]byte, 32)) != 0 { + log.Printf("seedHash for block 0 should be 0s, was: %v\n", seed0) + } + seed1, err := GetSeedHash(30000) + if err != nil { + t.Error(err) + } + + // From python: + // > from pyethash import get_seedhash + // > get_seedhash(30000) + expectedSeed1, err := hex.DecodeString("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") + if err != nil { + t.Error(err) + } + + if bytes.Compare(seed1, expectedSeed1) != 0 { + log.Printf("seedHash for block 1 should be: %v,\nactual value: %v\n", expectedSeed1, seed1) + } + +} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/ethashc.go b/Godeps/_workspace/src/github.com/ethereum/ethash/ethashc.go new file mode 100644 index 0000000000..8a441525d8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/ethashc.go @@ -0,0 +1,35 @@ +package ethash + +/* + -mno-stack-arg-probe disables stack probing which avoids the function + __chkstk_ms being linked. this avoids a clash of this symbol as we also + separately link the secp256k1 lib which ends up defining this symbol + + 1. https://gcc.gnu.org/onlinedocs/gccint/Stack-Checking.html + 2. https://groups.google.com/forum/#!msg/golang-dev/v1bziURSQ4k/88fXuJ24e-gJ + 3. https://groups.google.com/forum/#!topic/golang-nuts/VNP6Mwz_B6o + +*/ + +/* +#cgo CFLAGS: -std=gnu99 -Wall +#cgo windows CFLAGS: -mno-stack-arg-probe +#cgo LDFLAGS: -lm + +#include "src/libethash/internal.c" +#include "src/libethash/sha3.c" +#include "src/libethash/io.c" + +#ifdef _WIN32 +# include "src/libethash/io_win32.c" +# include "src/libethash/mmap_win32.c" +#else +# include "src/libethash/io_posix.c" +#endif + +// 'gateway function' for calling back into go. +extern int ethashGoCallback(unsigned); +int ethashGoCallback_cgo(unsigned percent) { return ethashGoCallback(percent); } + +*/ +import "C" diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/LICENSE b/Godeps/_workspace/src/github.com/ethereum/ethash/js/LICENSE new file mode 100644 index 0000000000..070be633d1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Tim Hughes + +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/Godeps/_workspace/src/github.com/ethereum/ethash/js/ethash.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/ethash.js new file mode 100644 index 0000000000..bec1284f61 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/ethash.js @@ -0,0 +1,190 @@ +// ethash.js +// Tim Hughes +// Revision 19 + +/*jslint node: true, shadow:true */ +"use strict"; + +var Keccak = require('./keccak'); +var util = require('./util'); + +// 32-bit unsigned modulo +function mod32(x, n) +{ + return (x>>>0) % (n>>>0); +} + +function fnv(x, y) +{ + // js integer multiply by 0x01000193 will lose precision + return ((x*0x01000000 | 0) + (x*0x193 | 0)) ^ y; +} + +function computeCache(params, seedWords) +{ + var cache = new Uint32Array(params.cacheSize >> 2); + var cacheNodeCount = params.cacheSize >> 6; + + // Initialize cache + var keccak = new Keccak(); + keccak.digestWords(cache, 0, 16, seedWords, 0, seedWords.length); + for (var n = 1; n < cacheNodeCount; ++n) + { + keccak.digestWords(cache, n<<4, 16, cache, (n-1)<<4, 16); + } + + var tmp = new Uint32Array(16); + + // Do randmemohash passes + for (var r = 0; r < params.cacheRounds; ++r) + { + for (var n = 0; n < cacheNodeCount; ++n) + { + var p0 = mod32(n + cacheNodeCount - 1, cacheNodeCount) << 4; + var p1 = mod32(cache[n<<4|0], cacheNodeCount) << 4; + + for (var w = 0; w < 16; w=(w+1)|0) + { + tmp[w] = cache[p0 | w] ^ cache[p1 | w]; + } + + keccak.digestWords(cache, n<<4, 16, tmp, 0, tmp.length); + } + } + return cache; +} + +function computeDagNode(o_node, params, cache, keccak, nodeIndex) +{ + var cacheNodeCount = params.cacheSize >> 6; + var dagParents = params.dagParents; + + var c = (nodeIndex % cacheNodeCount) << 4; + var mix = o_node; + for (var w = 0; w < 16; ++w) + { + mix[w] = cache[c|w]; + } + mix[0] ^= nodeIndex; + keccak.digestWords(mix, 0, 16, mix, 0, 16); + + for (var p = 0; p < dagParents; ++p) + { + // compute cache node (word) index + c = mod32(fnv(nodeIndex ^ p, mix[p&15]), cacheNodeCount) << 4; + + for (var w = 0; w < 16; ++w) + { + mix[w] = fnv(mix[w], cache[c|w]); + } + } + + keccak.digestWords(mix, 0, 16, mix, 0, 16); +} + +function computeHashInner(mix, params, cache, keccak, tempNode) +{ + var mixParents = params.mixParents|0; + var mixWordCount = params.mixSize >> 2; + var mixNodeCount = mixWordCount >> 4; + var dagPageCount = (params.dagSize / params.mixSize) >> 0; + + // grab initial first word + var s0 = mix[0]; + + // initialise mix from initial 64 bytes + for (var w = 16; w < mixWordCount; ++w) + { + mix[w] = mix[w & 15]; + } + + for (var a = 0; a < mixParents; ++a) + { + var p = mod32(fnv(s0 ^ a, mix[a & (mixWordCount-1)]), dagPageCount); + var d = (p * mixNodeCount)|0; + + for (var n = 0, w = 0; n < mixNodeCount; ++n, w += 16) + { + computeDagNode(tempNode, params, cache, keccak, (d + n)|0); + + for (var v = 0; v < 16; ++v) + { + mix[w|v] = fnv(mix[w|v], tempNode[v]); + } + } + } +} + +function convertSeed(seed) +{ + // todo, reconcile with spec, byte ordering? + // todo, big-endian conversion + var newSeed = util.toWords(seed); + if (newSeed === null) + throw Error("Invalid seed '" + seed + "'"); + return newSeed; +} + +exports.defaultParams = function() +{ + return { + cacheSize: 1048384, + cacheRounds: 3, + dagSize: 1073739904, + dagParents: 256, + mixSize: 128, + mixParents: 64, + }; +}; + +exports.Ethash = function(params, seed) +{ + // precompute cache and related values + seed = convertSeed(seed); + var cache = computeCache(params, seed); + + // preallocate buffers/etc + var initBuf = new ArrayBuffer(96); + var initBytes = new Uint8Array(initBuf); + var initWords = new Uint32Array(initBuf); + var mixWords = new Uint32Array(params.mixSize / 4); + var tempNode = new Uint32Array(16); + var keccak = new Keccak(); + + var retWords = new Uint32Array(8); + var retBytes = new Uint8Array(retWords.buffer); // supposedly read-only + + this.hash = function(header, nonce) + { + // compute initial hash + initBytes.set(header, 0); + initBytes.set(nonce, 32); + keccak.digestWords(initWords, 0, 16, initWords, 0, 8 + nonce.length/4); + + // compute mix + for (var i = 0; i != 16; ++i) + { + mixWords[i] = initWords[i]; + } + computeHashInner(mixWords, params, cache, keccak, tempNode); + + // compress mix and append to initWords + for (var i = 0; i != mixWords.length; i += 4) + { + initWords[16 + i/4] = fnv(fnv(fnv(mixWords[i], mixWords[i+1]), mixWords[i+2]), mixWords[i+3]); + } + + // final Keccak hashes + keccak.digestWords(retWords, 0, 8, initWords, 0, 24); // Keccak-256(s + cmix) + return retBytes; + }; + + this.cacheDigest = function() + { + return keccak.digest(32, new Uint8Array(cache.buffer)); + }; +}; + + + + diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/keccak.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/keccak.js new file mode 100644 index 0000000000..84ddde6451 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/keccak.js @@ -0,0 +1,404 @@ +// keccak.js +// Tim Hughes +// derived from Markku-Juhani O. Saarinen's C code (http://keccak.noekeon.org/readable_code.html) + +/*jslint node: true, shadow:true */ +"use strict"; + +var Keccak_f1600_RC = new Uint32Array([ + 0x00000001, 0x00000000, + 0x00008082, 0x00000000, + 0x0000808a, 0x80000000, + 0x80008000, 0x80000000, + 0x0000808b, 0x00000000, + 0x80000001, 0x00000000, + 0x80008081, 0x80000000, + 0x00008009, 0x80000000, + 0x0000008a, 0x00000000, + 0x00000088, 0x00000000, + 0x80008009, 0x00000000, + 0x8000000a, 0x00000000, + 0x8000808b, 0x00000000, + 0x0000008b, 0x80000000, + 0x00008089, 0x80000000, + 0x00008003, 0x80000000, + 0x00008002, 0x80000000, + 0x00000080, 0x80000000, + 0x0000800a, 0x00000000, + 0x8000000a, 0x80000000, + 0x80008081, 0x80000000, + 0x00008080, 0x80000000, + 0x80000001, 0x00000000, + 0x80008008, 0x80000000 +]); + +function keccak_f1600(outState, outOffset, outSize, inState) +{ + // todo, handle big endian loads + var a00l = inState[0]|0; + var a00h = inState[1]|0; + var a01l = inState[2]|0; + var a01h = inState[3]|0; + var a02l = inState[4]|0; + var a02h = inState[5]|0; + var a03l = inState[6]|0; + var a03h = inState[7]|0; + var a04l = inState[8]|0; + var a04h = inState[9]|0; + var a05l = inState[10]|0; + var a05h = inState[11]|0; + var a06l = inState[12]|0; + var a06h = inState[13]|0; + var a07l = inState[14]|0; + var a07h = inState[15]|0; + var a08l = inState[16]|0; + var a08h = inState[17]|0; + var a09l = inState[18]|0; + var a09h = inState[19]|0; + var a10l = inState[20]|0; + var a10h = inState[21]|0; + var a11l = inState[22]|0; + var a11h = inState[23]|0; + var a12l = inState[24]|0; + var a12h = inState[25]|0; + var a13l = inState[26]|0; + var a13h = inState[27]|0; + var a14l = inState[28]|0; + var a14h = inState[29]|0; + var a15l = inState[30]|0; + var a15h = inState[31]|0; + var a16l = inState[32]|0; + var a16h = inState[33]|0; + var a17l = inState[34]|0; + var a17h = inState[35]|0; + var a18l = inState[36]|0; + var a18h = inState[37]|0; + var a19l = inState[38]|0; + var a19h = inState[39]|0; + var a20l = inState[40]|0; + var a20h = inState[41]|0; + var a21l = inState[42]|0; + var a21h = inState[43]|0; + var a22l = inState[44]|0; + var a22h = inState[45]|0; + var a23l = inState[46]|0; + var a23h = inState[47]|0; + var a24l = inState[48]|0; + var a24h = inState[49]|0; + var b00l, b00h, b01l, b01h, b02l, b02h, b03l, b03h, b04l, b04h; + var b05l, b05h, b06l, b06h, b07l, b07h, b08l, b08h, b09l, b09h; + var b10l, b10h, b11l, b11h, b12l, b12h, b13l, b13h, b14l, b14h; + var b15l, b15h, b16l, b16h, b17l, b17h, b18l, b18h, b19l, b19h; + var b20l, b20h, b21l, b21h, b22l, b22h, b23l, b23h, b24l, b24h; + var tl, nl; + var th, nh; + + for (var r = 0; r < 48; r = (r+2)|0) + { + // Theta + b00l = a00l ^ a05l ^ a10l ^ a15l ^ a20l; + b00h = a00h ^ a05h ^ a10h ^ a15h ^ a20h; + b01l = a01l ^ a06l ^ a11l ^ a16l ^ a21l; + b01h = a01h ^ a06h ^ a11h ^ a16h ^ a21h; + b02l = a02l ^ a07l ^ a12l ^ a17l ^ a22l; + b02h = a02h ^ a07h ^ a12h ^ a17h ^ a22h; + b03l = a03l ^ a08l ^ a13l ^ a18l ^ a23l; + b03h = a03h ^ a08h ^ a13h ^ a18h ^ a23h; + b04l = a04l ^ a09l ^ a14l ^ a19l ^ a24l; + b04h = a04h ^ a09h ^ a14h ^ a19h ^ a24h; + tl = b04l ^ (b01l << 1 | b01h >>> 31); + th = b04h ^ (b01h << 1 | b01l >>> 31); + a00l ^= tl; + a00h ^= th; + a05l ^= tl; + a05h ^= th; + a10l ^= tl; + a10h ^= th; + a15l ^= tl; + a15h ^= th; + a20l ^= tl; + a20h ^= th; + tl = b00l ^ (b02l << 1 | b02h >>> 31); + th = b00h ^ (b02h << 1 | b02l >>> 31); + a01l ^= tl; + a01h ^= th; + a06l ^= tl; + a06h ^= th; + a11l ^= tl; + a11h ^= th; + a16l ^= tl; + a16h ^= th; + a21l ^= tl; + a21h ^= th; + tl = b01l ^ (b03l << 1 | b03h >>> 31); + th = b01h ^ (b03h << 1 | b03l >>> 31); + a02l ^= tl; + a02h ^= th; + a07l ^= tl; + a07h ^= th; + a12l ^= tl; + a12h ^= th; + a17l ^= tl; + a17h ^= th; + a22l ^= tl; + a22h ^= th; + tl = b02l ^ (b04l << 1 | b04h >>> 31); + th = b02h ^ (b04h << 1 | b04l >>> 31); + a03l ^= tl; + a03h ^= th; + a08l ^= tl; + a08h ^= th; + a13l ^= tl; + a13h ^= th; + a18l ^= tl; + a18h ^= th; + a23l ^= tl; + a23h ^= th; + tl = b03l ^ (b00l << 1 | b00h >>> 31); + th = b03h ^ (b00h << 1 | b00l >>> 31); + a04l ^= tl; + a04h ^= th; + a09l ^= tl; + a09h ^= th; + a14l ^= tl; + a14h ^= th; + a19l ^= tl; + a19h ^= th; + a24l ^= tl; + a24h ^= th; + + // Rho Pi + b00l = a00l; + b00h = a00h; + b10l = a01l << 1 | a01h >>> 31; + b10h = a01h << 1 | a01l >>> 31; + b07l = a10l << 3 | a10h >>> 29; + b07h = a10h << 3 | a10l >>> 29; + b11l = a07l << 6 | a07h >>> 26; + b11h = a07h << 6 | a07l >>> 26; + b17l = a11l << 10 | a11h >>> 22; + b17h = a11h << 10 | a11l >>> 22; + b18l = a17l << 15 | a17h >>> 17; + b18h = a17h << 15 | a17l >>> 17; + b03l = a18l << 21 | a18h >>> 11; + b03h = a18h << 21 | a18l >>> 11; + b05l = a03l << 28 | a03h >>> 4; + b05h = a03h << 28 | a03l >>> 4; + b16l = a05h << 4 | a05l >>> 28; + b16h = a05l << 4 | a05h >>> 28; + b08l = a16h << 13 | a16l >>> 19; + b08h = a16l << 13 | a16h >>> 19; + b21l = a08h << 23 | a08l >>> 9; + b21h = a08l << 23 | a08h >>> 9; + b24l = a21l << 2 | a21h >>> 30; + b24h = a21h << 2 | a21l >>> 30; + b04l = a24l << 14 | a24h >>> 18; + b04h = a24h << 14 | a24l >>> 18; + b15l = a04l << 27 | a04h >>> 5; + b15h = a04h << 27 | a04l >>> 5; + b23l = a15h << 9 | a15l >>> 23; + b23h = a15l << 9 | a15h >>> 23; + b19l = a23h << 24 | a23l >>> 8; + b19h = a23l << 24 | a23h >>> 8; + b13l = a19l << 8 | a19h >>> 24; + b13h = a19h << 8 | a19l >>> 24; + b12l = a13l << 25 | a13h >>> 7; + b12h = a13h << 25 | a13l >>> 7; + b02l = a12h << 11 | a12l >>> 21; + b02h = a12l << 11 | a12h >>> 21; + b20l = a02h << 30 | a02l >>> 2; + b20h = a02l << 30 | a02h >>> 2; + b14l = a20l << 18 | a20h >>> 14; + b14h = a20h << 18 | a20l >>> 14; + b22l = a14h << 7 | a14l >>> 25; + b22h = a14l << 7 | a14h >>> 25; + b09l = a22h << 29 | a22l >>> 3; + b09h = a22l << 29 | a22h >>> 3; + b06l = a09l << 20 | a09h >>> 12; + b06h = a09h << 20 | a09l >>> 12; + b01l = a06h << 12 | a06l >>> 20; + b01h = a06l << 12 | a06h >>> 20; + + // Chi + a00l = b00l ^ ~b01l & b02l; + a00h = b00h ^ ~b01h & b02h; + a01l = b01l ^ ~b02l & b03l; + a01h = b01h ^ ~b02h & b03h; + a02l = b02l ^ ~b03l & b04l; + a02h = b02h ^ ~b03h & b04h; + a03l = b03l ^ ~b04l & b00l; + a03h = b03h ^ ~b04h & b00h; + a04l = b04l ^ ~b00l & b01l; + a04h = b04h ^ ~b00h & b01h; + a05l = b05l ^ ~b06l & b07l; + a05h = b05h ^ ~b06h & b07h; + a06l = b06l ^ ~b07l & b08l; + a06h = b06h ^ ~b07h & b08h; + a07l = b07l ^ ~b08l & b09l; + a07h = b07h ^ ~b08h & b09h; + a08l = b08l ^ ~b09l & b05l; + a08h = b08h ^ ~b09h & b05h; + a09l = b09l ^ ~b05l & b06l; + a09h = b09h ^ ~b05h & b06h; + a10l = b10l ^ ~b11l & b12l; + a10h = b10h ^ ~b11h & b12h; + a11l = b11l ^ ~b12l & b13l; + a11h = b11h ^ ~b12h & b13h; + a12l = b12l ^ ~b13l & b14l; + a12h = b12h ^ ~b13h & b14h; + a13l = b13l ^ ~b14l & b10l; + a13h = b13h ^ ~b14h & b10h; + a14l = b14l ^ ~b10l & b11l; + a14h = b14h ^ ~b10h & b11h; + a15l = b15l ^ ~b16l & b17l; + a15h = b15h ^ ~b16h & b17h; + a16l = b16l ^ ~b17l & b18l; + a16h = b16h ^ ~b17h & b18h; + a17l = b17l ^ ~b18l & b19l; + a17h = b17h ^ ~b18h & b19h; + a18l = b18l ^ ~b19l & b15l; + a18h = b18h ^ ~b19h & b15h; + a19l = b19l ^ ~b15l & b16l; + a19h = b19h ^ ~b15h & b16h; + a20l = b20l ^ ~b21l & b22l; + a20h = b20h ^ ~b21h & b22h; + a21l = b21l ^ ~b22l & b23l; + a21h = b21h ^ ~b22h & b23h; + a22l = b22l ^ ~b23l & b24l; + a22h = b22h ^ ~b23h & b24h; + a23l = b23l ^ ~b24l & b20l; + a23h = b23h ^ ~b24h & b20h; + a24l = b24l ^ ~b20l & b21l; + a24h = b24h ^ ~b20h & b21h; + + // Iota + a00l ^= Keccak_f1600_RC[r|0]; + a00h ^= Keccak_f1600_RC[r|1]; + } + + // todo, handle big-endian stores + outState[outOffset|0] = a00l; + outState[outOffset|1] = a00h; + outState[outOffset|2] = a01l; + outState[outOffset|3] = a01h; + outState[outOffset|4] = a02l; + outState[outOffset|5] = a02h; + outState[outOffset|6] = a03l; + outState[outOffset|7] = a03h; + if (outSize == 8) + return; + outState[outOffset|8] = a04l; + outState[outOffset|9] = a04h; + outState[outOffset|10] = a05l; + outState[outOffset|11] = a05h; + outState[outOffset|12] = a06l; + outState[outOffset|13] = a06h; + outState[outOffset|14] = a07l; + outState[outOffset|15] = a07h; + if (outSize == 16) + return; + outState[outOffset|16] = a08l; + outState[outOffset|17] = a08h; + outState[outOffset|18] = a09l; + outState[outOffset|19] = a09h; + outState[outOffset|20] = a10l; + outState[outOffset|21] = a10h; + outState[outOffset|22] = a11l; + outState[outOffset|23] = a11h; + outState[outOffset|24] = a12l; + outState[outOffset|25] = a12h; + outState[outOffset|26] = a13l; + outState[outOffset|27] = a13h; + outState[outOffset|28] = a14l; + outState[outOffset|29] = a14h; + outState[outOffset|30] = a15l; + outState[outOffset|31] = a15h; + outState[outOffset|32] = a16l; + outState[outOffset|33] = a16h; + outState[outOffset|34] = a17l; + outState[outOffset|35] = a17h; + outState[outOffset|36] = a18l; + outState[outOffset|37] = a18h; + outState[outOffset|38] = a19l; + outState[outOffset|39] = a19h; + outState[outOffset|40] = a20l; + outState[outOffset|41] = a20h; + outState[outOffset|42] = a21l; + outState[outOffset|43] = a21h; + outState[outOffset|44] = a22l; + outState[outOffset|45] = a22h; + outState[outOffset|46] = a23l; + outState[outOffset|47] = a23h; + outState[outOffset|48] = a24l; + outState[outOffset|49] = a24h; +} + +var Keccak = function() +{ + var stateBuf = new ArrayBuffer(200); + var stateBytes = new Uint8Array(stateBuf); + var stateWords = new Uint32Array(stateBuf); + + this.digest = function(oSize, iBytes) + { + for (var i = 0; i < 50; ++i) + { + stateWords[i] = 0; + } + + var r = 200 - oSize*2; + var iLength = iBytes.length; + var iOffset = 0; + for ( ; ;) + { + var len = iLength < r ? iLength : r; + for (i = 0; i < len; ++i, ++iOffset) + { + stateBytes[i] ^= iBytes[iOffset]; + } + + if (iLength < r) + break; + iLength -= len; + + keccak_f1600(stateWords, 0, 50, stateWords); + } + + stateBytes[iLength] ^= 1; + stateBytes[r-1] ^= 0x80; + keccak_f1600(stateWords, 0, 50, stateWords); + return stateBytes.subarray(0, oSize); + }; + + this.digestWords = function(oWords, oOffset, oLength, iWords, iOffset, iLength) + { + for (var i = 0; i < 50; ++i) + { + stateWords[i] = 0; + } + + var r = 50 - oLength*2; + for (; ; ) + { + var len = iLength < r ? iLength : r; + for (i = 0; i < len; ++i, ++iOffset) + { + stateWords[i] ^= iWords[iOffset]; + } + + if (iLength < r) + break; + iLength -= len; + + keccak_f1600(stateWords, 0, 50, stateWords); + } + + stateBytes[iLength<<2] ^= 1; + stateBytes[(r<<2) - 1] ^= 0x80; + keccak_f1600(oWords, oOffset, oLength, stateWords); + }; +}; + +module.exports = Keccak; + + diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/makekeccak.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/makekeccak.js new file mode 100644 index 0000000000..c4db2b80a0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/makekeccak.js @@ -0,0 +1,201 @@ +#!/usr/bin/env node +// makekeccak.js +// Tim Hughes + +/*jslint node: true, shadow:true */ +"use strict"; + +var Keccak_f1600_Rho = [ + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 +]; + +var Keccak_f1600_Pi= [ + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 +]; + +var Keccak_f1600_RC = [ + 0x00000001, 0x00000000, + 0x00008082, 0x00000000, + 0x0000808a, 0x80000000, + 0x80008000, 0x80000000, + 0x0000808b, 0x00000000, + 0x80000001, 0x00000000, + 0x80008081, 0x80000000, + 0x00008009, 0x80000000, + 0x0000008a, 0x00000000, + 0x00000088, 0x00000000, + 0x80008009, 0x00000000, + 0x8000000a, 0x00000000, + 0x8000808b, 0x00000000, + 0x0000008b, 0x80000000, + 0x00008089, 0x80000000, + 0x00008003, 0x80000000, + 0x00008002, 0x80000000, + 0x00000080, 0x80000000, + 0x0000800a, 0x00000000, + 0x8000000a, 0x80000000, + 0x80008081, 0x80000000, + 0x00008080, 0x80000000, + 0x80000001, 0x00000000, + 0x80008008, 0x80000000, +]; + +function makeRotLow(lo, hi, n) +{ + if (n === 0 || n === 32) throw Error("unsupported"); + if ((n & 0x20) !== 0) + { + n &= ~0x20; + var t = hi; + hi = lo; + lo = t; + } + var hir = hi + " >>> " + (32 - n); + var los = lo + " << " + n; + return los + " | " + hir; +} + +function makeRotHigh(lo, hi, n) +{ + if (n === 0 || n === 32) throw Error("unsupported"); + if ((n & 0x20) !== 0) + { + n &= ~0x20; + var t = hi; + hi = lo; + lo = t; + } + var his = hi + " << " + n; + var lor = lo + " >>> " + (32 - n); + return his + " | " + lor; +} + +function makeKeccak_f1600() +{ + var format = function(n) + { + return n < 10 ? "0"+n : ""+n; + }; + + var a = function(n, w) + { + return "a" + format(n) + (w !== 0?'h':'l'); + }; + + var b = function(n, w) + { + return "b" + format(n) + (w !== 0?'h':'l'); + }; + + var str = ""; + str += "function keccak_f1600(outState, outOffset, outSize, inState)\n"; + str += "{\n"; + + for (var i = 0; i < 25; ++i) + { + for (var w = 0; w <= 1; ++w) + { + str += "\tvar " + a(i,w) + " = inState["+(i<<1|w)+"]|0;\n"; + } + } + + for (var j = 0; j < 5; ++j) + { + str += "\tvar "; + for (var i = 0; i < 5; ++i) + { + if (i !== 0) + str += ", "; + str += b(j*5+i,0) + ", " + b(j*5+i,1); + } + str += ";\n"; + } + + str += "\tvar tl, th;\n"; + str += "\n"; + str += "\tfor (var r = 0; r < 48; r = (r+2)|0)\n"; + str += "\t{\n"; + + + // Theta + str += "\t\t// Theta\n"; + for (var i = 0; i < 5; ++i) + { + for (var w = 0; w <= 1; ++w) + { + str += "\t\t" + b(i,w) + " = " + a(i,w) + " ^ " + a(i+5,w) + " ^ " + a(i+10,w) + " ^ " + a(i+15,w) + " ^ " + a(i+20,w) + ";\n"; + } + } + + for (var i = 0; i < 5; ++i) + { + var i4 = (i + 4) % 5; + var i1 = (i + 1) % 5; + str += "\t\ttl = " + b(i4,0) + " ^ (" + b(i1,0) + " << 1 | " + b(i1,1) + " >>> 31);\n"; + str += "\t\tth = " + b(i4,1) + " ^ (" + b(i1,1) + " << 1 | " + b(i1,0) + " >>> 31);\n"; + + for (var j = 0; j < 25; j = (j+5)|0) + { + str += "\t\t" + a((j+i),0) + " ^= tl;\n"; + str += "\t\t" + a((j+i),1) + " ^= th;\n"; + } + } + + + // Rho Pi + str += "\n\t\t// Rho Pi\n"; + for (var w = 0; w <= 1; ++w) + { + str += "\t\t" + b(0,w) + " = " + a(0,w) + ";\n"; + } + var opi = 1; + for (var i = 0; i < 24; ++i) + { + var pi = Keccak_f1600_Pi[i]; + str += "\t\t" + b(pi,0) + " = " + makeRotLow(a(opi,0), a(opi,1), Keccak_f1600_Rho[i]) + ";\n"; + str += "\t\t" + b(pi,1) + " = " + makeRotHigh(a(opi,0), a(opi,1), Keccak_f1600_Rho[i]) + ";\n"; + opi = pi; + } + + // Chi + str += "\n\t\t// Chi\n"; + for (var j = 0; j < 25; j += 5) + { + for (var i = 0; i < 5; ++i) + { + for (var w = 0; w <= 1; ++w) + { + str += "\t\t" + a(j+i,w) + " = " + b(j+i,w) + " ^ ~" + b(j+(i+1)%5,w) + " & " + b(j+(i+2)%5,w) + ";\n"; + } + } + } + + // Iota + str += "\n\t\t// Iota\n"; + for (var w = 0; w <= 1; ++w) + { + str += "\t\t" + a(0,w) + " ^= Keccak_f1600_RC[r|" + w + "];\n"; + } + + + str += "\t}\n"; + + for (var i = 0; i < 25; ++i) + { + if (i == 4 || i == 8) + { + str += "\tif (outSize == " + i*2 + ")\n\t\treturn;\n"; + } + for (var w = 0; w <= 1; ++w) + { + str += "\toutState[outOffset|"+(i<<1|w)+"] = " + a(i,w) + ";\n"; + } + } + str += "}\n"; + + return str; +} + +console.log(makeKeccak_f1600()); diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/test.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/test.js new file mode 100644 index 0000000000..7ebb733ff5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/test.js @@ -0,0 +1,53 @@ +// test.js +// Tim Hughes + +/*jslint node: true, shadow:true */ +"use strict"; + +var ethash = require('./ethash'); +var util = require('./util'); +var Keccak = require('./keccak'); + +// sanity check hash functions +var src = util.stringToBytes(""); +if (util.bytesToHexString(new Keccak().digest(32, src)) != "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") throw Error("Keccak-256 failed"); +if (util.bytesToHexString(new Keccak().digest(64, src)) != "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e") throw Error("Keccak-512 failed"); + +src = new Uint32Array(src.buffer); +var dst = new Uint32Array(8); +new Keccak().digestWords(dst, 0, dst.length, src, 0, src.length); +if (util.wordsToHexString(dst) != "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") throw Error("Keccak-256 Fast failed"); + +var dst = new Uint32Array(16); +new Keccak().digestWords(dst, 0, dst.length, src, 0, src.length); +if (util.wordsToHexString(dst) != "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e") throw Error("Keccak-512 Fast failed"); + + +// init params +var ethashParams = ethash.defaultParams(); +//ethashParams.cacheRounds = 0; + +// create hasher +var seed = util.hexStringToBytes("9410b944535a83d9adf6bbdcc80e051f30676173c16ca0d32d6f1263fc246466") +var startTime = new Date().getTime(); +var hasher = new ethash.Ethash(ethashParams, seed); +console.log('Ethash startup took: '+(new Date().getTime() - startTime) + "ms"); +console.log('Ethash cache hash: ' + util.bytesToHexString(hasher.cacheDigest())); + +var testHexString = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; +if (testHexString != util.bytesToHexString(util.hexStringToBytes(testHexString))) + throw Error("bytesToHexString or hexStringToBytes broken"); + + +var header = util.hexStringToBytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); +var nonce = util.hexStringToBytes("0000000000000000"); +var hash; + +startTime = new Date().getTime(); +var trials = 10; +for (var i = 0; i < trials; ++i) +{ + hash = hasher.hash(header, nonce); +} +console.log("Light client hashes averaged: " + (new Date().getTime() - startTime)/trials + "ms"); +console.log("Hash = " + util.bytesToHexString(hash)); diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/util.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/util.js new file mode 100644 index 0000000000..79743cd915 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/util.js @@ -0,0 +1,100 @@ +// util.js +// Tim Hughes + +/*jslint node: true, shadow:true */ +"use strict"; + +function nibbleToChar(nibble) +{ + return String.fromCharCode((nibble < 10 ? 48 : 87) + nibble); +} + +function charToNibble(chr) +{ + if (chr >= 48 && chr <= 57) + { + return chr - 48; + } + if (chr >= 65 && chr <= 70) + { + return chr - 65 + 10; + } + if (chr >= 97 && chr <= 102) + { + return chr - 97 + 10; + } + return 0; +} + +function stringToBytes(str) +{ + var bytes = new Uint8Array(str.length); + for (var i = 0; i != str.length; ++i) + { + bytes[i] = str.charCodeAt(i); + } + return bytes; +} + +function hexStringToBytes(str) +{ + var bytes = new Uint8Array(str.length>>>1); + for (var i = 0; i != bytes.length; ++i) + { + bytes[i] = charToNibble(str.charCodeAt(i<<1 | 0)) << 4; + bytes[i] |= charToNibble(str.charCodeAt(i<<1 | 1)); + } + return bytes; +} + +function bytesToHexString(bytes) +{ + var str = ""; + for (var i = 0; i != bytes.length; ++i) + { + str += nibbleToChar(bytes[i] >>> 4); + str += nibbleToChar(bytes[i] & 0xf); + } + return str; +} + +function wordsToHexString(words) +{ + return bytesToHexString(new Uint8Array(words.buffer)); +} + +function uint32ToHexString(num) +{ + var buf = new Uint8Array(4); + buf[0] = (num >> 24) & 0xff; + buf[1] = (num >> 16) & 0xff; + buf[2] = (num >> 8) & 0xff; + buf[3] = (num >> 0) & 0xff; + return bytesToHexString(buf); +} + +function toWords(input) +{ + if (input instanceof Uint32Array) + { + return input; + } + else if (input instanceof Uint8Array) + { + var tmp = new Uint8Array((input.length + 3) & ~3); + tmp.set(input); + return new Uint32Array(tmp.buffer); + } + else if (typeof input === typeof "") + { + return toWords(stringToBytes(input)); + } + return null; +} + +exports.stringToBytes = stringToBytes; +exports.hexStringToBytes = hexStringToBytes; +exports.bytesToHexString = bytesToHexString; +exports.wordsToHexString = wordsToHexString; +exports.uint32ToHexString = uint32ToHexString; +exports.toWords = toWords; \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/setup.py b/Godeps/_workspace/src/github.com/ethereum/ethash/setup.py new file mode 100644 index 0000000000..18aa20f6db --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/setup.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +import os +from distutils.core import setup, Extension +sources = [ + 'src/python/core.c', + 'src/libethash/io.c', + 'src/libethash/internal.c', + 'src/libethash/sha3.c'] +if os.name == 'nt': + sources += [ + 'src/libethash/util_win32.c', + 'src/libethash/io_win32.c', + 'src/libethash/mmap_win32.c', + ] +else: + sources += [ + 'src/libethash/io_posix.c' + ] +depends = [ + 'src/libethash/ethash.h', + 'src/libethash/compiler.h', + 'src/libethash/data_sizes.h', + 'src/libethash/endian.h', + 'src/libethash/ethash.h', + 'src/libethash/io.h', + 'src/libethash/fnv.h', + 'src/libethash/internal.h', + 'src/libethash/sha3.h', + 'src/libethash/util.h', +] +pyethash = Extension('pyethash', + sources=sources, + depends=depends, + extra_compile_args=["-Isrc/", "-std=gnu99", "-Wall"]) + +setup( + name='pyethash', + author="Matthew Wampler-Doty", + author_email="matthew.wampler.doty@gmail.com", + license='GPL', + version='0.1.23', + url='https://github.com/ethereum/ethash', + download_url='https://github.com/ethereum/ethash/tarball/v23', + description=('Python wrappers for ethash, the ethereum proof of work' + 'hashing function'), + ext_modules=[pyethash], +) diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/CMakeLists.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/CMakeLists.txt new file mode 100644 index 0000000000..3df4ab5967 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/CMakeLists.txt @@ -0,0 +1,58 @@ +include_directories(..) + +set(CMAKE_BUILD_TYPE Release) + +if (MSVC) + add_definitions("/openmp") +endif() + +# enable C++11, should probably be a bit more specific about compiler +if (NOT MSVC) + SET(CMAKE_CXX_FLAGS "-std=c++11") +endif() + +if (NOT MPI_FOUND) + find_package(MPI) +endif() + +if (NOT CRYPTOPP_FOUND) + find_package(CryptoPP 5.6.2) +endif() + +if (CRYPTOPP_FOUND) + add_definitions(-DWITH_CRYPTOPP) + find_package (Threads REQUIRED) +endif() + +if (NOT OpenCL_FOUND) + find_package(OpenCL) +endif() +if (OpenCL_FOUND) + add_definitions(-DWITH_OPENCL) + include_directories(${OpenCL_INCLUDE_DIRS}) + list(APPEND FILES ethash_cl_miner.cpp ethash_cl_miner.h) +endif() + +if (MPI_FOUND) + include_directories(${MPI_INCLUDE_PATH}) + add_executable (Benchmark_MPI_FULL benchmark.cpp) + target_link_libraries (Benchmark_MPI_FULL ${ETHHASH_LIBS} ${MPI_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + SET_TARGET_PROPERTIES(Benchmark_MPI_FULL PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} ${MPI_COMPILE_FLAGS} -DFULL -DMPI") + + add_executable (Benchmark_MPI_LIGHT benchmark.cpp) + target_link_libraries (Benchmark_MPI_LIGHT ${ETHHASH_LIBS} ${MPI_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + SET_TARGET_PROPERTIES(Benchmark_MPI_LIGHT PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} ${MPI_COMPILE_FLAGS} -DMPI") +endif() + +add_executable (Benchmark_FULL benchmark.cpp) +target_link_libraries (Benchmark_FULL ${ETHHASH_LIBS} ${CMAKE_THREAD_LIBS_INIT}) +SET_TARGET_PROPERTIES(Benchmark_FULL PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -DFULL") + +add_executable (Benchmark_LIGHT benchmark.cpp) +target_link_libraries (Benchmark_LIGHT ${ETHHASH_LIBS} ${CMAKE_THREAD_LIBS_INIT}) + +if (OpenCL_FOUND) + add_executable (Benchmark_CL benchmark.cpp) + target_link_libraries (Benchmark_CL ${ETHHASH_LIBS} ethash-cl ${CMAKE_THREAD_LIBS_INIT}) + SET_TARGET_PROPERTIES(Benchmark_CL PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -DOPENCL") +endif() \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/benchmark.cpp b/Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/benchmark.cpp new file mode 100644 index 0000000000..1a648edf42 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/benchmark.cpp @@ -0,0 +1,278 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum 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. + + cpp-ethereum 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 cpp-ethereum. If not, see . +*/ +/** @file benchmark.cpp + * @author Tim Hughes + * @date 2015 + */ + +#include +#include +#include +#include +#include +#ifdef OPENCL +#include +#endif +#include +#include + +#ifdef WITH_CRYPTOPP +#include +#include + +#else +#include "libethash/sha3.h" +#endif // WITH_CRYPTOPP + +#undef min +#undef max + +using std::chrono::high_resolution_clock; + +#if defined(OPENCL) +const unsigned trials = 1024*1024*32; +#elif defined(FULL) +const unsigned trials = 1024*1024/8; +#else +const unsigned trials = 1024*1024/1024; +#endif +uint8_t g_hashes[1024*32]; + +static char nibbleToChar(unsigned nibble) +{ + return (char) ((nibble >= 10 ? 'a'-10 : '0') + nibble); +} + +static uint8_t charToNibble(char chr) +{ + if (chr >= '0' && chr <= '9') + { + return (uint8_t) (chr - '0'); + } + if (chr >= 'a' && chr <= 'z') + { + return (uint8_t) (chr - 'a' + 10); + } + if (chr >= 'A' && chr <= 'Z') + { + return (uint8_t) (chr - 'A' + 10); + } + return 0; +} + +static std::vector hexStringToBytes(char const* str) +{ + std::vector bytes(strlen(str) >> 1); + for (unsigned i = 0; i != bytes.size(); ++i) + { + bytes[i] = charToNibble(str[i*2 | 0]) << 4; + bytes[i] |= charToNibble(str[i*2 | 1]); + } + return bytes; +} + +static std::string bytesToHexString(uint8_t const* bytes, unsigned size) +{ + std::string str; + for (unsigned i = 0; i != size; ++i) + { + str += nibbleToChar(bytes[i] >> 4); + str += nibbleToChar(bytes[i] & 0xf); + } + return str; +} + +static std::string bytesToHexString(ethash_h256_t const *hash, unsigned size) +{ + return bytesToHexString((uint8_t*)hash, size); +} + +extern "C" int main(void) +{ + // params for ethash + ethash_params params; + ethash_params_init(¶ms, 0); + //params.full_size = 262147 * 4096; // 1GBish; + //params.full_size = 32771 * 4096; // 128MBish; + //params.full_size = 8209 * 4096; // 8MBish; + //params.cache_size = 8209*4096; + //params.cache_size = 2053*4096; + ethash_h256_t seed; + ethash_h256_t previous_hash; + + memcpy(&seed, hexStringToBytes("9410b944535a83d9adf6bbdcc80e051f30676173c16ca0d32d6f1263fc246466").data(), 32); + memcpy(&previous_hash, hexStringToBytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").data(), 32); + + // allocate page aligned buffer for dataset +#ifdef FULL + void* full_mem_buf = malloc(params.full_size + 4095); + void* full_mem = (void*)((uintptr_t(full_mem_buf) + 4095) & ~4095); +#endif + void* cache_mem_buf = malloc(params.cache_size + 63); + void* cache_mem = (void*)((uintptr_t(cache_mem_buf) + 63) & ~63); + + ethash_cache cache; + cache.mem = cache_mem; + + // compute cache or full data + { + auto startTime = high_resolution_clock::now(); + ethash_mkcache(&cache, ¶ms, &seed); + auto time = std::chrono::duration_cast(high_resolution_clock::now() - startTime).count(); + + ethash_h256_t cache_hash; + SHA3_256(&cache_hash, (uint8_t const*)cache_mem, params.cache_size); + debugf("ethash_mkcache: %ums, sha3: %s\n", (unsigned)((time*1000)/CLOCKS_PER_SEC), bytesToHexString(&cache_hash, sizeof(cache_hash)).data()); + + // print a couple of test hashes + { + auto startTime = high_resolution_clock::now(); + ethash_return_value hash; + ethash_light(&hash, &cache, ¶ms, &previous_hash, 0); + auto time = std::chrono::duration_cast(high_resolution_clock::now() - startTime).count(); + debugf("ethash_light test: %ums, %s\n", (unsigned)time, bytesToHexString(&hash.result, 32).data()); + } + + #ifdef FULL + startTime = high_resolution_clock::now(); + ethash_compute_full_data(full_mem, ¶ms, &cache); + time = std::chrono::duration_cast(high_resolution_clock::now() - startTime).count(); + debugf("ethash_compute_full_data: %ums\n", (unsigned)time); + #endif // FULL + } + +#ifdef OPENCL + ethash_cl_miner miner; + { + auto startTime = high_resolution_clock::now(); + if (!miner.init(params, &seed)) + exit(-1); + auto time = std::chrono::duration_cast(high_resolution_clock::now() - startTime).count(); + debugf("ethash_cl_miner init: %ums\n", (unsigned)time); + } +#endif + + +#ifdef FULL + { + auto startTime = high_resolution_clock::now(); + ethash_return_value hash; + ethash_full(&hash, full_mem, ¶ms, &previous_hash, 0); + auto time = std::chrono::duration_cast(high_resolution_clock::now() - startTime).count(); + debugf("ethash_full test: %uns\n", (unsigned)time); + } +#endif + +#ifdef OPENCL + // validate 1024 hashes against CPU + miner.hash(g_hashes, (uint8_t*)&previous_hash, 0, 1024); + for (unsigned i = 0; i != 1024; ++i) + { + ethash_return_value hash; + ethash_light(&hash, &cache, ¶ms, &previous_hash, i); + if (memcmp(&hash.result, g_hashes + 32*i, 32) != 0) + { + debugf("nonce %u failed: %s %s\n", i, bytesToHexString(g_hashes + 32*i, 32).c_str(), bytesToHexString(&hash.result, 32).c_str()); + static unsigned c = 0; + if (++c == 16) + { + exit(-1); + } + } + } + + // ensure nothing else is going on + miner.finish(); +#endif + + auto startTime = high_resolution_clock::now(); + unsigned hash_count = trials; + + #ifdef OPENCL + { + struct search_hook : ethash_cl_miner::search_hook + { + unsigned hash_count; + std::vector nonce_vec; + + virtual bool found(uint64_t const* nonces, uint32_t count) + { + nonce_vec.insert(nonce_vec.end(), nonces, nonces + count); + return false; + } + + virtual bool searched(uint64_t start_nonce, uint32_t count) + { + // do nothing + hash_count += count; + return hash_count >= trials; + } + }; + search_hook hook; + hook.hash_count = 0; + + miner.search((uint8_t*)&previous_hash, 0x000000ffffffffff, hook); + + for (unsigned i = 0; i != hook.nonce_vec.size(); ++i) + { + uint64_t nonce = hook.nonce_vec[i]; + ethash_return_value hash; + ethash_light(&hash, &cache, ¶ms, &previous_hash, nonce); + debugf("found: %.8x%.8x -> %s\n", unsigned(nonce>>32), unsigned(nonce), bytesToHexString(&hash.result, 32).c_str()); + } + + hash_count = hook.hash_count; + } + #else + { + //#pragma omp parallel for + for (int nonce = 0; nonce < trials; ++nonce) + { + ethash_return_value hash; + #ifdef FULL + ethash_full(&hash, full_mem, ¶ms, &previous_hash, nonce); + #else + ethash_light(&hash, &cache, ¶ms, &previous_hash, nonce); + #endif // FULL + } + } + #endif + auto time = std::chrono::duration_cast(high_resolution_clock::now() - startTime).count(); + debugf("Search took: %ums\n", (unsigned)time/1000); + + unsigned read_size = ETHASH_ACCESSES * ETHASH_MIX_BYTES; +#if defined(OPENCL) || defined(FULL) + debugf( + "hashrate: %8.2f Mh/s, bw: %8.2f GB/s\n", + (double)hash_count * (1000*1000)/time / (1000*1000), + (double)hash_count*read_size * (1000*1000)/time / (1024*1024*1024) + ); +#else + debugf( + "hashrate: %8.2f Kh/s, bw: %8.2f MB/s\n", + (double)hash_count * (1000*1000)/time / (1000), + (double)hash_count*read_size * (1000*1000)/time / (1024*1024) + ); +#endif + + free(cache_mem_buf); +#ifdef FULL + free(full_mem_buf); +#endif + + return 0; +} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/CMakeLists.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/CMakeLists.txt new file mode 100644 index 0000000000..a65621c3e9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/CMakeLists.txt @@ -0,0 +1,44 @@ +set(LIBRARY ethash) + +if (CPPETHEREUM) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") +endif () + +set(CMAKE_BUILD_TYPE Release) + +if (NOT MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") +endif() + +set(FILES util.h + io.c + internal.c + ethash.h + endian.h + compiler.h + fnv.h + data_sizes.h) + +if (MSVC) + list(APPEND FILES util_win32.c io_win32.c mmap_win32.c) +else() + list(APPEND FILES io_posix.c) +endif() + +if (NOT CRYPTOPP_FOUND) + find_package(CryptoPP 5.6.2) +endif() + +if (CRYPTOPP_FOUND) + add_definitions(-DWITH_CRYPTOPP) + include_directories( ${CRYPTOPP_INCLUDE_DIRS} ) + list(APPEND FILES sha3_cryptopp.cpp sha3_cryptopp.h) +else() + list(APPEND FILES sha3.c sha3.h) +endif() + +add_library(${LIBRARY} ${FILES}) + +if (CRYPTOPP_FOUND) + TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES}) +endif() diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/compiler.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/compiler.h new file mode 100644 index 0000000000..9695871cdc --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/compiler.h @@ -0,0 +1,33 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum 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. + + cpp-ethereum 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 cpp-ethereum. If not, see . +*/ +/** @file compiler.h + * @date 2014 + */ +#pragma once + +// Visual Studio doesn't support the inline keyword in C mode +#if defined(_MSC_VER) && !defined(__cplusplus) +#define inline __inline +#endif + +// pretend restrict is a standard keyword +#if defined(_MSC_VER) +#define restrict __restrict +#else +#define restrict __restrict__ +#endif + diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h new file mode 100644 index 0000000000..83cc30bcba --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h @@ -0,0 +1,812 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum 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 FoundationUUU,either version 3 of the LicenseUUU,or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be usefulU, + 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 cpp-ethereum. If notUUU,see . +*/ + +/** @file data_sizes.h +* @author Matthew Wampler-Doty +* @date 2015 +*/ + +#pragma once + +#include +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +// 2048 Epochs (~20 years) worth of tabulated DAG sizes + +// Generated with the following Mathematica Code: + +// GetCacheSizes[n_] := Module[{ +// CacheSizeBytesInit = 2^24, +// CacheGrowth = 2^17, +// HashBytes = 64, +// j = 0}, +// Reap[ +// While[j < n, +// Module[{i = +// Floor[(CacheSizeBytesInit + CacheGrowth * j) / HashBytes]}, +// While[! PrimeQ[i], i--]; +// Sow[i*HashBytes]; j++]]]][[2]][[1]] + + +static const uint64_t dag_sizes[2048] = { + 1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U, + 1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U, + 1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U, + 1199568512U, 1207958912U, 1216345216U, 1224732032U, 1233124736U, + 1241513344U, 1249902464U, 1258290304U, 1266673792U, 1275067264U, + 1283453312U, 1291844992U, 1300234112U, 1308619904U, 1317010048U, + 1325397376U, 1333787776U, 1342176128U, 1350561664U, 1358954368U, + 1367339392U, 1375731584U, 1384118144U, 1392507008U, 1400897408U, + 1409284736U, 1417673344U, 1426062464U, 1434451072U, 1442839168U, + 1451229056U, 1459615616U, 1468006016U, 1476394112U, 1484782976U, + 1493171584U, 1501559168U, 1509948032U, 1518337664U, 1526726528U, + 1535114624U, 1543503488U, 1551892096U, 1560278656U, 1568669056U, + 1577056384U, 1585446272U, 1593831296U, 1602219392U, 1610610304U, + 1619000192U, 1627386752U, 1635773824U, 1644164224U, 1652555648U, + 1660943488U, 1669332608U, 1677721216U, 1686109312U, 1694497664U, + 1702886272U, 1711274624U, 1719661184U, 1728047744U, 1736434816U, + 1744829056U, 1753218944U, 1761606272U, 1769995904U, 1778382464U, + 1786772864U, 1795157888U, 1803550592U, 1811937664U, 1820327552U, + 1828711552U, 1837102976U, 1845488768U, 1853879936U, 1862269312U, + 1870656896U, 1879048064U, 1887431552U, 1895825024U, 1904212096U, + 1912601216U, 1920988544U, 1929379456U, 1937765504U, 1946156672U, + 1954543232U, 1962932096U, 1971321728U, 1979707264U, 1988093056U, + 1996487552U, 2004874624U, 2013262208U, 2021653888U, 2030039936U, + 2038430848U, 2046819968U, 2055208576U, 2063596672U, 2071981952U, + 2080373632U, 2088762752U, 2097149056U, 2105539712U, 2113928576U, + 2122315136U, 2130700672U, 2139092608U, 2147483264U, 2155872128U, + 2164257664U, 2172642176U, 2181035392U, 2189426048U, 2197814912U, + 2206203008U, 2214587264U, 2222979712U, 2231367808U, 2239758208U, + 2248145024U, 2256527744U, 2264922752U, 2273312128U, 2281701248U, + 2290086272U, 2298476672U, 2306867072U, 2315251072U, 2323639168U, + 2332032128U, 2340420224U, 2348808064U, 2357196416U, 2365580416U, + 2373966976U, 2382363008U, 2390748544U, 2399139968U, 2407530368U, + 2415918976U, 2424307328U, 2432695424U, 2441084288U, 2449472384U, + 2457861248U, 2466247808U, 2474637184U, 2483026816U, 2491414144U, + 2499803776U, 2508191872U, 2516582272U, 2524970368U, 2533359232U, + 2541743488U, 2550134144U, 2558525056U, 2566913408U, 2575301504U, + 2583686528U, 2592073856U, 2600467328U, 2608856192U, 2617240448U, + 2625631616U, 2634022016U, 2642407552U, 2650796416U, 2659188352U, + 2667574912U, 2675965312U, 2684352896U, 2692738688U, 2701130624U, + 2709518464U, 2717907328U, 2726293376U, 2734685056U, 2743073152U, + 2751462016U, 2759851648U, 2768232832U, 2776625536U, 2785017728U, + 2793401984U, 2801794432U, 2810182016U, 2818571648U, 2826959488U, + 2835349376U, 2843734144U, 2852121472U, 2860514432U, 2868900992U, + 2877286784U, 2885676928U, 2894069632U, 2902451584U, 2910843008U, + 2919234688U, 2927622784U, 2936011648U, 2944400768U, 2952789376U, + 2961177728U, 2969565568U, 2977951616U, 2986338944U, 2994731392U, + 3003120256U, 3011508352U, 3019895936U, 3028287104U, 3036675968U, + 3045063808U, 3053452928U, 3061837696U, 3070228352U, 3078615424U, + 3087003776U, 3095394944U, 3103782272U, 3112173184U, 3120562048U, + 3128944768U, 3137339264U, 3145725056U, 3154109312U, 3162505088U, + 3170893184U, 3179280256U, 3187669376U, 3196056704U, 3204445568U, + 3212836736U, 3221224064U, 3229612928U, 3238002304U, 3246391168U, + 3254778496U, 3263165824U, 3271556224U, 3279944576U, 3288332416U, + 3296719232U, 3305110912U, 3313500032U, 3321887104U, 3330273152U, + 3338658944U, 3347053184U, 3355440512U, 3363827072U, 3372220288U, + 3380608384U, 3388997504U, 3397384576U, 3405774208U, 3414163072U, + 3422551936U, 3430937984U, 3439328384U, 3447714176U, 3456104576U, + 3464493952U, 3472883584U, 3481268864U, 3489655168U, 3498048896U, + 3506434432U, 3514826368U, 3523213952U, 3531603584U, 3539987072U, + 3548380288U, 3556763264U, 3565157248U, 3573545344U, 3581934464U, + 3590324096U, 3598712704U, 3607098752U, 3615488384U, 3623877248U, + 3632265856U, 3640646528U, 3649043584U, 3657430144U, 3665821568U, + 3674207872U, 3682597504U, 3690984832U, 3699367808U, 3707764352U, + 3716152448U, 3724541056U, 3732925568U, 3741318016U, 3749706368U, + 3758091136U, 3766481536U, 3774872704U, 3783260032U, 3791650432U, + 3800036224U, 3808427648U, 3816815488U, 3825204608U, 3833592704U, + 3841981568U, 3850370432U, 3858755968U, 3867147904U, 3875536256U, + 3883920512U, 3892313728U, 3900702592U, 3909087872U, 3917478784U, + 3925868416U, 3934256512U, 3942645376U, 3951032192U, 3959422336U, + 3967809152U, 3976200064U, 3984588416U, 3992974976U, 4001363584U, + 4009751168U, 4018141312U, 4026530432U, 4034911616U, 4043308928U, + 4051695488U, 4060084352U, 4068472448U, 4076862848U, 4085249408U, + 4093640576U, 4102028416U, 4110413696U, 4118805632U, 4127194496U, + 4135583104U, 4143971968U, 4152360832U, 4160746112U, 4169135744U, + 4177525888U, 4185912704U, 4194303616U, 4202691968U, 4211076736U, + 4219463552U, 4227855488U, 4236246656U, 4244633728U, 4253022848U, + 4261412224U, 4269799808U, 4278184832U, 4286578048U, 4294962304U, + 4303349632U, 4311743104U, 4320130432U, 4328521088U, 4336909184U, + 4345295488U, 4353687424U, 4362073472U, 4370458496U, 4378852736U, + 4387238528U, 4395630208U, 4404019072U, 4412407424U, 4420790656U, + 4429182848U, 4437571456U, 4445962112U, 4454344064U, 4462738048U, + 4471119232U, 4479516544U, 4487904128U, 4496289664U, 4504682368U, + 4513068416U, 4521459584U, 4529846144U, 4538232704U, 4546619776U, + 4555010176U, 4563402112U, 4571790208U, 4580174464U, 4588567936U, + 4596957056U, 4605344896U, 4613734016U, 4622119808U, 4630511488U, + 4638898816U, 4647287936U, 4655675264U, 4664065664U, 4672451968U, + 4680842624U, 4689231488U, 4697620352U, 4706007424U, 4714397056U, + 4722786176U, 4731173248U, 4739562368U, 4747951744U, 4756340608U, + 4764727936U, 4773114496U, 4781504384U, 4789894784U, 4798283648U, + 4806667648U, 4815059584U, 4823449472U, 4831835776U, 4840226176U, + 4848612224U, 4857003392U, 4865391488U, 4873780096U, 4882169728U, + 4890557312U, 4898946944U, 4907333248U, 4915722368U, 4924110976U, + 4932499328U, 4940889728U, 4949276032U, 4957666432U, 4966054784U, + 4974438016U, 4982831488U, 4991221376U, 4999607168U, 5007998848U, + 5016386432U, 5024763776U, 5033164672U, 5041544576U, 5049941888U, + 5058329728U, 5066717056U, 5075107456U, 5083494272U, 5091883904U, + 5100273536U, 5108662144U, 5117048192U, 5125436032U, 5133827456U, + 5142215296U, 5150605184U, 5158993024U, 5167382144U, 5175769472U, + 5184157568U, 5192543872U, 5200936064U, 5209324928U, 5217711232U, + 5226102656U, 5234490496U, 5242877312U, 5251263872U, 5259654016U, + 5268040832U, 5276434304U, 5284819328U, 5293209728U, 5301598592U, + 5309986688U, 5318374784U, 5326764416U, 5335151488U, 5343542144U, + 5351929472U, 5360319872U, 5368706944U, 5377096576U, 5385484928U, + 5393871232U, 5402263424U, 5410650496U, 5419040384U, 5427426944U, + 5435816576U, 5444205952U, 5452594816U, 5460981376U, 5469367936U, + 5477760896U, 5486148736U, 5494536832U, 5502925952U, 5511315328U, + 5519703424U, 5528089984U, 5536481152U, 5544869504U, 5553256064U, + 5561645696U, 5570032768U, 5578423936U, 5586811264U, 5595193216U, + 5603585408U, 5611972736U, 5620366208U, 5628750464U, 5637143936U, + 5645528192U, 5653921408U, 5662310272U, 5670694784U, 5679082624U, + 5687474048U, 5695864448U, 5704251008U, 5712641408U, 5721030272U, + 5729416832U, 5737806208U, 5746194304U, 5754583936U, 5762969984U, + 5771358592U, 5779748224U, 5788137856U, 5796527488U, 5804911232U, + 5813300608U, 5821692544U, 5830082176U, 5838468992U, 5846855552U, + 5855247488U, 5863636096U, 5872024448U, 5880411008U, 5888799872U, + 5897186432U, 5905576832U, 5913966976U, 5922352768U, 5930744704U, + 5939132288U, 5947522432U, 5955911296U, 5964299392U, 5972688256U, + 5981074304U, 5989465472U, 5997851008U, 6006241408U, 6014627968U, + 6023015552U, 6031408256U, 6039796096U, 6048185216U, 6056574848U, + 6064963456U, 6073351808U, 6081736064U, 6090128768U, 6098517632U, + 6106906496U, 6115289216U, 6123680896U, 6132070016U, 6140459648U, + 6148849024U, 6157237376U, 6165624704U, 6174009728U, 6182403712U, + 6190792064U, 6199176064U, 6207569792U, 6215952256U, 6224345216U, + 6232732544U, 6241124224U, 6249510272U, 6257899136U, 6266287744U, + 6274676864U, 6283065728U, 6291454336U, 6299843456U, 6308232064U, + 6316620928U, 6325006208U, 6333395584U, 6341784704U, 6350174848U, + 6358562176U, 6366951296U, 6375337856U, 6383729536U, 6392119168U, + 6400504192U, 6408895616U, 6417283456U, 6425673344U, 6434059136U, + 6442444672U, 6450837376U, 6459223424U, 6467613056U, 6476004224U, + 6484393088U, 6492781952U, 6501170048U, 6509555072U, 6517947008U, + 6526336384U, 6534725504U, 6543112832U, 6551500672U, 6559888768U, + 6568278656U, 6576662912U, 6585055616U, 6593443456U, 6601834112U, + 6610219648U, 6618610304U, 6626999168U, 6635385472U, 6643777408U, + 6652164224U, 6660552832U, 6668941952U, 6677330048U, 6685719424U, + 6694107776U, 6702493568U, 6710882176U, 6719274112U, 6727662976U, + 6736052096U, 6744437632U, 6752825984U, 6761213824U, 6769604224U, + 6777993856U, 6786383488U, 6794770816U, 6803158144U, 6811549312U, + 6819937664U, 6828326528U, 6836706176U, 6845101696U, 6853491328U, + 6861880448U, 6870269312U, 6878655104U, 6887046272U, 6895433344U, + 6903822208U, 6912212864U, 6920596864U, 6928988288U, 6937377152U, + 6945764992U, 6954149248U, 6962544256U, 6970928768U, 6979317376U, + 6987709312U, 6996093824U, 7004487296U, 7012875392U, 7021258624U, + 7029652352U, 7038038912U, 7046427776U, 7054818944U, 7063207808U, + 7071595136U, 7079980928U, 7088372608U, 7096759424U, 7105149824U, + 7113536896U, 7121928064U, 7130315392U, 7138699648U, 7147092352U, + 7155479168U, 7163865728U, 7172249984U, 7180648064U, 7189036672U, + 7197424768U, 7205810816U, 7214196608U, 7222589824U, 7230975104U, + 7239367552U, 7247755904U, 7256145536U, 7264533376U, 7272921472U, + 7281308032U, 7289694848U, 7298088832U, 7306471808U, 7314864512U, + 7323253888U, 7331643008U, 7340029568U, 7348419712U, 7356808832U, + 7365196672U, 7373585792U, 7381973888U, 7390362752U, 7398750592U, + 7407138944U, 7415528576U, 7423915648U, 7432302208U, 7440690304U, + 7449080192U, 7457472128U, 7465860992U, 7474249088U, 7482635648U, + 7491023744U, 7499412608U, 7507803008U, 7516192384U, 7524579968U, + 7532967296U, 7541358464U, 7549745792U, 7558134656U, 7566524032U, + 7574912896U, 7583300992U, 7591690112U, 7600075136U, 7608466816U, + 7616854912U, 7625244544U, 7633629824U, 7642020992U, 7650410368U, + 7658794112U, 7667187328U, 7675574912U, 7683961984U, 7692349568U, + 7700739712U, 7709130368U, 7717519232U, 7725905536U, 7734295424U, + 7742683264U, 7751069056U, 7759457408U, 7767849088U, 7776238208U, + 7784626816U, 7793014912U, 7801405312U, 7809792128U, 7818179968U, + 7826571136U, 7834957184U, 7843347328U, 7851732352U, 7860124544U, + 7868512384U, 7876902016U, 7885287808U, 7893679744U, 7902067072U, + 7910455936U, 7918844288U, 7927230848U, 7935622784U, 7944009344U, + 7952400256U, 7960786048U, 7969176704U, 7977565312U, 7985953408U, + 7994339968U, 8002730368U, 8011119488U, 8019508096U, 8027896192U, + 8036285056U, 8044674688U, 8053062272U, 8061448832U, 8069838464U, + 8078227328U, 8086616704U, 8095006592U, 8103393664U, 8111783552U, + 8120171392U, 8128560256U, 8136949376U, 8145336704U, 8153726848U, + 8162114944U, 8170503296U, 8178891904U, 8187280768U, 8195669632U, + 8204058496U, 8212444544U, 8220834176U, 8229222272U, 8237612672U, + 8246000768U, 8254389376U, 8262775168U, 8271167104U, 8279553664U, + 8287944064U, 8296333184U, 8304715136U, 8313108352U, 8321497984U, + 8329885568U, 8338274432U, 8346663296U, 8355052928U, 8363441536U, + 8371828352U, 8380217984U, 8388606592U, 8396996224U, 8405384576U, + 8413772672U, 8422161536U, 8430549376U, 8438939008U, 8447326592U, + 8455715456U, 8464104832U, 8472492928U, 8480882048U, 8489270656U, + 8497659776U, 8506045312U, 8514434944U, 8522823808U, 8531208832U, + 8539602304U, 8547990656U, 8556378752U, 8564768384U, 8573154176U, + 8581542784U, 8589933952U, 8598322816U, 8606705024U, 8615099264U, + 8623487872U, 8631876992U, 8640264064U, 8648653952U, 8657040256U, + 8665430656U, 8673820544U, 8682209152U, 8690592128U, 8698977152U, + 8707374464U, 8715763328U, 8724151424U, 8732540032U, 8740928384U, + 8749315712U, 8757704576U, 8766089344U, 8774480768U, 8782871936U, + 8791260032U, 8799645824U, 8808034432U, 8816426368U, 8824812928U, + 8833199488U, 8841591424U, 8849976448U, 8858366336U, 8866757248U, + 8875147136U, 8883532928U, 8891923328U, 8900306816U, 8908700288U, + 8917088384U, 8925478784U, 8933867392U, 8942250368U, 8950644608U, + 8959032704U, 8967420544U, 8975809664U, 8984197504U, 8992584064U, + 9000976256U, 9009362048U, 9017752448U, 9026141312U, 9034530688U, + 9042917504U, 9051307904U, 9059694208U, 9068084864U, 9076471424U, + 9084861824U, 9093250688U, 9101638528U, 9110027648U, 9118416512U, + 9126803584U, 9135188096U, 9143581312U, 9151969664U, 9160356224U, + 9168747136U, 9177134464U, 9185525632U, 9193910144U, 9202302848U, + 9210690688U, 9219079552U, 9227465344U, 9235854464U, 9244244864U, + 9252633472U, 9261021824U, 9269411456U, 9277799296U, 9286188928U, + 9294574208U, 9302965888U, 9311351936U, 9319740032U, 9328131968U, + 9336516736U, 9344907392U, 9353296768U, 9361685888U, 9370074752U, + 9378463616U, 9386849408U, 9395239808U, 9403629184U, 9412016512U, + 9420405376U, 9428795008U, 9437181568U, 9445570688U, 9453960832U, + 9462346624U, 9470738048U, 9479121536U, 9487515008U, 9495903616U, + 9504289664U, 9512678528U, 9521067904U, 9529456256U, 9537843584U, + 9546233728U, 9554621312U, 9563011456U, 9571398784U, 9579788672U, + 9588178304U, 9596567168U, 9604954496U, 9613343104U, 9621732992U, + 9630121856U, 9638508416U, 9646898816U, 9655283584U, 9663675776U, + 9672061312U, 9680449664U, 9688840064U, 9697230464U, 9705617536U, + 9714003584U, 9722393984U, 9730772608U, 9739172224U, 9747561088U, + 9755945344U, 9764338816U, 9772726144U, 9781116544U, 9789503872U, + 9797892992U, 9806282624U, 9814670464U, 9823056512U, 9831439232U, + 9839833984U, 9848224384U, 9856613504U, 9865000576U, 9873391232U, + 9881772416U, 9890162816U, 9898556288U, 9906940544U, 9915333248U, + 9923721088U, 9932108672U, 9940496512U, 9948888448U, 9957276544U, + 9965666176U, 9974048384U, 9982441088U, 9990830464U, 9999219584U, + 10007602816U, 10015996544U, 10024385152U, 10032774016U, 10041163648U, + 10049548928U, 10057940096U, 10066329472U, 10074717824U, 10083105152U, + 10091495296U, 10099878784U, 10108272256U, 10116660608U, 10125049216U, + 10133437312U, 10141825664U, 10150213504U, 10158601088U, 10166991232U, + 10175378816U, 10183766144U, 10192157312U, 10200545408U, 10208935552U, + 10217322112U, 10225712768U, 10234099328U, 10242489472U, 10250876032U, + 10259264896U, 10267656064U, 10276042624U, 10284429184U, 10292820352U, + 10301209472U, 10309598848U, 10317987712U, 10326375296U, 10334763392U, + 10343153536U, 10351541632U, 10359930752U, 10368318592U, 10376707456U, + 10385096576U, 10393484672U, 10401867136U, 10410262144U, 10418647424U, + 10427039104U, 10435425664U, 10443810176U, 10452203648U, 10460589952U, + 10468982144U, 10477369472U, 10485759104U, 10494147712U, 10502533504U, + 10510923392U, 10519313536U, 10527702656U, 10536091264U, 10544478592U, + 10552867712U, 10561255808U, 10569642368U, 10578032768U, 10586423168U, + 10594805632U, 10603200128U, 10611588992U, 10619976064U, 10628361344U, + 10636754048U, 10645143424U, 10653531776U, 10661920384U, 10670307968U, + 10678696832U, 10687086464U, 10695475072U, 10703863168U, 10712246144U, + 10720639616U, 10729026688U, 10737414784U, 10745806208U, 10754190976U, + 10762581376U, 10770971264U, 10779356288U, 10787747456U, 10796135552U, + 10804525184U, 10812915584U, 10821301888U, 10829692288U, 10838078336U, + 10846469248U, 10854858368U, 10863247232U, 10871631488U, 10880023424U, + 10888412032U, 10896799616U, 10905188992U, 10913574016U, 10921964672U, + 10930352768U, 10938742912U, 10947132544U, 10955518592U, 10963909504U, + 10972298368U, 10980687488U, 10989074816U, 10997462912U, 11005851776U, + 11014241152U, 11022627712U, 11031017344U, 11039403904U, 11047793024U, + 11056184704U, 11064570752U, 11072960896U, 11081343872U, 11089737856U, + 11098128256U, 11106514816U, 11114904448U, 11123293568U, 11131680128U, + 11140065152U, 11148458368U, 11156845696U, 11165236864U, 11173624192U, + 11182013824U, 11190402688U, 11198790784U, 11207179136U, 11215568768U, + 11223957376U, 11232345728U, 11240734592U, 11249122688U, 11257511296U, + 11265899648U, 11274285952U, 11282675584U, 11291065472U, 11299452544U, + 11307842432U, 11316231296U, 11324616832U, 11333009024U, 11341395584U, + 11349782656U, 11358172288U, 11366560384U, 11374950016U, 11383339648U, + 11391721856U, 11400117376U, 11408504192U, 11416893568U, 11425283456U, + 11433671552U, 11442061184U, 11450444672U, 11458837888U, 11467226752U, + 11475611776U, 11484003968U, 11492392064U, 11500780672U, 11509169024U, + 11517550976U, 11525944448U, 11534335616U, 11542724224U, 11551111808U, + 11559500672U, 11567890304U, 11576277376U, 11584667008U, 11593056128U, + 11601443456U, 11609830016U, 11618221952U, 11626607488U, 11634995072U, + 11643387776U, 11651775104U, 11660161664U, 11668552576U, 11676940928U, + 11685330304U, 11693718656U, 11702106496U, 11710496128U, 11718882688U, + 11727273088U, 11735660416U, 11744050048U, 11752437376U, 11760824704U, + 11769216128U, 11777604736U, 11785991296U, 11794381952U, 11802770048U, + 11811157888U, 11819548544U, 11827932544U, 11836324736U, 11844713344U, + 11853100928U, 11861486464U, 11869879936U, 11878268032U, 11886656896U, + 11895044992U, 11903433088U, 11911822976U, 11920210816U, 11928600448U, + 11936987264U, 11945375872U, 11953761152U, 11962151296U, 11970543488U, + 11978928512U, 11987320448U, 11995708288U, 12004095104U, 12012486272U, + 12020875136U, 12029255552U, 12037652096U, 12046039168U, 12054429568U, + 12062813824U, 12071206528U, 12079594624U, 12087983744U, 12096371072U, + 12104759936U, 12113147264U, 12121534592U, 12129924992U, 12138314624U, + 12146703232U, 12155091584U, 12163481216U, 12171864704U, 12180255872U, + 12188643968U, 12197034112U, 12205424512U, 12213811328U, 12222199424U, + 12230590336U, 12238977664U, 12247365248U, 12255755392U, 12264143488U, + 12272531584U, 12280920448U, 12289309568U, 12297694592U, 12306086528U, + 12314475392U, 12322865024U, 12331253632U, 12339640448U, 12348029312U, + 12356418944U, 12364805248U, 12373196672U, 12381580928U, 12389969024U, + 12398357632U, 12406750592U, 12415138432U, 12423527552U, 12431916416U, + 12440304512U, 12448692352U, 12457081216U, 12465467776U, 12473859968U, + 12482245504U, 12490636672U, 12499025536U, 12507411584U, 12515801728U, + 12524190592U, 12532577152U, 12540966272U, 12549354368U, 12557743232U, + 12566129536U, 12574523264U, 12582911872U, 12591299456U, 12599688064U, + 12608074624U, 12616463488U, 12624845696U, 12633239936U, 12641631616U, + 12650019968U, 12658407296U, 12666795136U, 12675183232U, 12683574656U, + 12691960192U, 12700350592U, 12708740224U, 12717128576U, 12725515904U, + 12733906816U, 12742295168U, 12750680192U, 12759071872U, 12767460736U, + 12775848832U, 12784236928U, 12792626816U, 12801014656U, 12809404288U, + 12817789312U, 12826181504U, 12834568832U, 12842954624U, 12851345792U, + 12859732352U, 12868122496U, 12876512128U, 12884901248U, 12893289088U, + 12901672832U, 12910067584U, 12918455168U, 12926842496U, 12935232896U, + 12943620736U, 12952009856U, 12960396928U, 12968786816U, 12977176192U, + 12985563776U, 12993951104U, 13002341504U, 13010730368U, 13019115392U, + 13027506304U, 13035895168U, 13044272512U, 13052673152U, 13061062528U, + 13069446272U, 13077838976U, 13086227072U, 13094613632U, 13103000192U, + 13111393664U, 13119782528U, 13128157568U, 13136559232U, 13144945024U, + 13153329536U, 13161724288U, 13170111872U, 13178502784U, 13186884736U, + 13195279744U, 13203667072U, 13212057472U, 13220445824U, 13228832128U, + 13237221248U, 13245610624U, 13254000512U, 13262388352U, 13270777472U, + 13279166336U, 13287553408U, 13295943296U, 13304331904U, 13312719488U, + 13321108096U, 13329494656U, 13337885824U, 13346274944U, 13354663808U, + 13363051136U, 13371439232U, 13379825024U, 13388210816U, 13396605056U, + 13404995456U, 13413380224U, 13421771392U, 13430159744U, 13438546048U, + 13446937216U, 13455326848U, 13463708288U, 13472103808U, 13480492672U, + 13488875648U, 13497269888U, 13505657728U, 13514045312U, 13522435712U, + 13530824576U, 13539210112U, 13547599232U, 13555989376U, 13564379008U, + 13572766336U, 13581154432U, 13589544832U, 13597932928U, 13606320512U, + 13614710656U, 13623097472U, 13631477632U, 13639874944U, 13648264064U, + 13656652928U, 13665041792U, 13673430656U, 13681818496U, 13690207616U, + 13698595712U, 13706982272U, 13715373184U, 13723762048U, 13732150144U, + 13740536704U, 13748926592U, 13757316224U, 13765700992U, 13774090112U, + 13782477952U, 13790869376U, 13799259008U, 13807647872U, 13816036736U, + 13824425344U, 13832814208U, 13841202304U, 13849591424U, 13857978752U, + 13866368896U, 13874754688U, 13883145344U, 13891533184U, 13899919232U, + 13908311168U, 13916692096U, 13925085056U, 13933473152U, 13941866368U, + 13950253696U, 13958643584U, 13967032192U, 13975417216U, 13983807616U, + 13992197504U, 14000582272U, 14008973696U, 14017363072U, 14025752192U, + 14034137984U, 14042528384U, 14050918016U, 14059301504U, 14067691648U, + 14076083584U, 14084470144U, 14092852352U, 14101249664U, 14109635968U, + 14118024832U, 14126407552U, 14134804352U, 14143188608U, 14151577984U, + 14159968384U, 14168357248U, 14176741504U, 14185127296U, 14193521024U, + 14201911424U, 14210301824U, 14218685056U, 14227067264U, 14235467392U, + 14243855488U, 14252243072U, 14260630144U, 14269021568U, 14277409408U, + 14285799296U, 14294187904U, 14302571392U, 14310961792U, 14319353728U, + 14327738752U, 14336130944U, 14344518784U, 14352906368U, 14361296512U, + 14369685376U, 14378071424U, 14386462592U, 14394848128U, 14403230848U, + 14411627392U, 14420013952U, 14428402304U, 14436793472U, 14445181568U, + 14453569664U, 14461959808U, 14470347904U, 14478737024U, 14487122816U, + 14495511424U, 14503901824U, 14512291712U, 14520677504U, 14529064832U, + 14537456768U, 14545845632U, 14554234496U, 14562618496U, 14571011456U, + 14579398784U, 14587789184U, 14596172672U, 14604564608U, 14612953984U, + 14621341312U, 14629724288U, 14638120832U, 14646503296U, 14654897536U, + 14663284864U, 14671675264U, 14680061056U, 14688447616U, 14696835968U, + 14705228416U, 14713616768U, 14722003328U, 14730392192U, 14738784128U, + 14747172736U, 14755561088U, 14763947648U, 14772336512U, 14780725376U, + 14789110144U, 14797499776U, 14805892736U, 14814276992U, 14822670208U, + 14831056256U, 14839444352U, 14847836032U, 14856222848U, 14864612992U, + 14872997504U, 14881388672U, 14889775744U, 14898165376U, 14906553472U, + 14914944896U, 14923329664U, 14931721856U, 14940109696U, 14948497024U, + 14956887424U, 14965276544U, 14973663616U, 14982053248U, 14990439808U, + 14998830976U, 15007216768U, 15015605888U, 15023995264U, 15032385152U, + 15040768384U, 15049154944U, 15057549184U, 15065939072U, 15074328448U, + 15082715008U, 15091104128U, 15099493504U, 15107879296U, 15116269184U, + 15124659584U, 15133042304U, 15141431936U, 15149824384U, 15158214272U, + 15166602368U, 15174991232U, 15183378304U, 15191760512U, 15200154496U, + 15208542592U, 15216931712U, 15225323392U, 15233708416U, 15242098048U, + 15250489216U, 15258875264U, 15267265408U, 15275654528U, 15284043136U, + 15292431488U, 15300819584U, 15309208192U, 15317596544U, 15325986176U, + 15334374784U, 15342763648U, 15351151744U, 15359540608U, 15367929728U, + 15376318336U, 15384706432U, 15393092992U, 15401481856U, 15409869952U, + 15418258816U, 15426649984U, 15435037568U, 15443425664U, 15451815296U, + 15460203392U, 15468589184U, 15476979328U, 15485369216U, 15493755776U, + 15502146944U, 15510534272U, 15518924416U, 15527311232U, 15535699072U, + 15544089472U, 15552478336U, 15560866688U, 15569254528U, 15577642624U, + 15586031488U, 15594419072U, 15602809472U, 15611199104U, 15619586432U, + 15627975296U, 15636364928U, 15644753792U, 15653141888U, 15661529216U, + 15669918848U, 15678305152U, 15686696576U, 15695083136U, 15703474048U, + 15711861632U, 15720251264U, 15728636288U, 15737027456U, 15745417088U, + 15753804928U, 15762194048U, 15770582656U, 15778971008U, 15787358336U, + 15795747712U, 15804132224U, 15812523392U, 15820909696U, 15829300096U, + 15837691264U, 15846071936U, 15854466944U, 15862855808U, 15871244672U, + 15879634816U, 15888020608U, 15896409728U, 15904799104U, 15913185152U, + 15921577088U, 15929966464U, 15938354816U, 15946743424U, 15955129472U, + 15963519872U, 15971907968U, 15980296064U, 15988684928U, 15997073024U, + 16005460864U, 16013851264U, 16022241152U, 16030629248U, 16039012736U, + 16047406976U, 16055794816U, 16064181376U, 16072571264U, 16080957824U, + 16089346688U, 16097737856U, 16106125184U, 16114514816U, 16122904192U, + 16131292544U, 16139678848U, 16148066944U, 16156453504U, 16164839552U, + 16173236096U, 16181623424U, 16190012032U, 16198401152U, 16206790528U, + 16215177344U, 16223567744U, 16231956352U, 16240344704U, 16248731008U, + 16257117824U, 16265504384U, 16273898624U, 16282281856U, 16290668672U, + 16299064192U, 16307449216U, 16315842176U, 16324230016U, 16332613504U, + 16341006464U, 16349394304U, 16357783168U, 16366172288U, 16374561664U, + 16382951296U, 16391337856U, 16399726208U, 16408116352U, 16416505472U, + 16424892032U, 16433282176U, 16441668224U, 16450058624U, 16458448768U, + 16466836864U, 16475224448U, 16483613056U, 16492001408U, 16500391808U, + 16508779648U, 16517166976U, 16525555328U, 16533944192U, 16542330752U, + 16550719616U, 16559110528U, 16567497088U, 16575888512U, 16584274816U, + 16592665472U, 16601051008U, 16609442944U, 16617832064U, 16626218624U, + 16634607488U, 16642996096U, 16651385728U, 16659773824U, 16668163712U, + 16676552576U, 16684938112U, 16693328768U, 16701718144U, 16710095488U, + 16718492288U, 16726883968U, 16735272832U, 16743661184U, 16752049792U, + 16760436608U, 16768827008U, 16777214336U, 16785599104U, 16793992832U, + 16802381696U, 16810768768U, 16819151744U, 16827542656U, 16835934848U, + 16844323712U, 16852711552U, 16861101952U, 16869489536U, 16877876864U, + 16886265728U, 16894653056U, 16903044736U, 16911431296U, 16919821696U, + 16928207488U, 16936592768U, 16944987776U, 16953375616U, 16961763968U, + 16970152832U, 16978540928U, 16986929536U, 16995319168U, 17003704448U, + 17012096896U, 17020481152U, 17028870784U, 17037262208U, 17045649536U, + 17054039936U, 17062426496U, 17070814336U, 17079205504U, 17087592064U, + 17095978112U, 17104369024U, 17112759424U, 17121147776U, 17129536384U, + 17137926016U, 17146314368U, 17154700928U, 17163089792U, 17171480192U, + 17179864192U, 17188256896U, 17196644992U, 17205033856U, 17213423488U, + 17221811072U, 17230198912U, 17238588032U, 17246976896U, 17255360384U, + 17263754624U, 17272143232U, 17280530048U, 17288918912U, 17297309312U, + 17305696384U, 17314085504U, 17322475136U, 17330863744U, 17339252096U, + 17347640192U, 17356026496U, 17364413824U, 17372796544U, 17381190016U, + 17389583488U, 17397972608U, 17406360704U, 17414748544U, 17423135872U, + 17431527296U, 17439915904U, 17448303232U, 17456691584U, 17465081728U, + 17473468288U, 17481857408U, 17490247552U, 17498635904U, 17507022464U, + 17515409024U, 17523801728U, 17532189824U, 17540577664U, 17548966016U, + 17557353344U, 17565741184U, 17574131584U, 17582519168U, 17590907008U, + 17599296128U, 17607687808U, 17616076672U, 17624455808U, 17632852352U, + 17641238656U, 17649630848U, 17658018944U, 17666403968U, 17674794112U, + 17683178368U, 17691573376U, 17699962496U, 17708350592U, 17716739968U, + 17725126528U, 17733517184U, 17741898112U, 17750293888U, 17758673024U, + 17767070336U, 17775458432U, 17783848832U, 17792236928U, 17800625536U, + 17809012352U, 17817402752U, 17825785984U, 17834178944U, 17842563968U, + 17850955648U, 17859344512U, 17867732864U, 17876119424U, 17884511872U, + 17892900224U, 17901287296U, 17909677696U, 17918058112U, 17926451072U, + 17934843776U, 17943230848U, 17951609216U, 17960008576U, 17968397696U, + 17976784256U, 17985175424U, 17993564032U, 18001952128U, 18010339712U, + 18018728576U, 18027116672U, 18035503232U, 18043894144U, 18052283264U, + 18060672128U, 18069056384U, 18077449856U, 18085837184U, 18094225792U, + 18102613376U, 18111004544U, 18119388544U, 18127781248U, 18136170368U, + 18144558976U, 18152947328U, 18161336192U, 18169724288U, 18178108544U, + 18186498944U, 18194886784U, 18203275648U, 18211666048U, 18220048768U, + 18228444544U, 18236833408U, 18245220736U +}; + + +// Generated with the following Mathematica Code: + +// GetCacheSizes[n_] := Module[{ +// DataSetSizeBytesInit = 2^30, +// MixBytes = 128, +// DataSetGrowth = 2^23, +// HashBytes = 64, +// CacheMultiplier = 1024, +// j = 0}, +// Reap[ +// While[j < n, +// Module[{i = Floor[(DataSetSizeBytesInit + DataSetGrowth * j) / (CacheMultiplier * HashBytes)]}, +// While[! PrimeQ[i], i--]; +// Sow[i*HashBytes]; j++]]]][[2]][[1]] + +const uint64_t cache_sizes[2048] = { + 16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U, + 17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U, + 18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U, + 19529408U, 19660096U, 19791424U, 19922752U, 20053952U, 20184896U, 20315968U, + 20446912U, 20576576U, 20709184U, 20840384U, 20971072U, 21102272U, 21233216U, + 21364544U, 21494848U, 21626816U, 21757376U, 21887552U, 22019392U, 22151104U, + 22281536U, 22412224U, 22543936U, 22675264U, 22806464U, 22935872U, 23068096U, + 23198272U, 23330752U, 23459008U, 23592512U, 23723968U, 23854912U, 23986112U, + 24116672U, 24247616U, 24378688U, 24509504U, 24640832U, 24772544U, 24903488U, + 25034432U, 25165376U, 25296704U, 25427392U, 25558592U, 25690048U, 25820096U, + 25951936U, 26081728U, 26214208U, 26345024U, 26476096U, 26606656U, 26737472U, + 26869184U, 26998208U, 27131584U, 27262528U, 27393728U, 27523904U, 27655744U, + 27786688U, 27917888U, 28049344U, 28179904U, 28311488U, 28441792U, 28573504U, + 28700864U, 28835648U, 28966208U, 29096768U, 29228608U, 29359808U, 29490752U, + 29621824U, 29752256U, 29882816U, 30014912U, 30144448U, 30273728U, 30406976U, + 30538432U, 30670784U, 30799936U, 30932672U, 31063744U, 31195072U, 31325248U, + 31456192U, 31588288U, 31719232U, 31850432U, 31981504U, 32110784U, 32243392U, + 32372672U, 32505664U, 32636608U, 32767808U, 32897344U, 33029824U, 33160768U, + 33289664U, 33423296U, 33554368U, 33683648U, 33816512U, 33947456U, 34076992U, + 34208704U, 34340032U, 34471744U, 34600256U, 34734016U, 34864576U, 34993984U, + 35127104U, 35258176U, 35386688U, 35518528U, 35650624U, 35782336U, 35910976U, + 36044608U, 36175808U, 36305728U, 36436672U, 36568384U, 36699968U, 36830656U, + 36961984U, 37093312U, 37223488U, 37355072U, 37486528U, 37617472U, 37747904U, + 37879232U, 38009792U, 38141888U, 38272448U, 38403392U, 38535104U, 38660672U, + 38795584U, 38925632U, 39059264U, 39190336U, 39320768U, 39452096U, 39581632U, + 39713984U, 39844928U, 39974848U, 40107968U, 40238144U, 40367168U, 40500032U, + 40631744U, 40762816U, 40894144U, 41023552U, 41155904U, 41286208U, 41418304U, + 41547712U, 41680448U, 41811904U, 41942848U, 42073792U, 42204992U, 42334912U, + 42467008U, 42597824U, 42729152U, 42860096U, 42991552U, 43122368U, 43253696U, + 43382848U, 43515712U, 43646912U, 43777088U, 43907648U, 44039104U, 44170432U, + 44302144U, 44433344U, 44564288U, 44694976U, 44825152U, 44956864U, 45088448U, + 45219008U, 45350464U, 45481024U, 45612608U, 45744064U, 45874496U, 46006208U, + 46136768U, 46267712U, 46399424U, 46529344U, 46660672U, 46791488U, 46923328U, + 47053504U, 47185856U, 47316928U, 47447872U, 47579072U, 47710144U, 47839936U, + 47971648U, 48103232U, 48234176U, 48365248U, 48496192U, 48627136U, 48757312U, + 48889664U, 49020736U, 49149248U, 49283008U, 49413824U, 49545152U, 49675712U, + 49807168U, 49938368U, 50069056U, 50200256U, 50331584U, 50462656U, 50593472U, + 50724032U, 50853952U, 50986048U, 51117632U, 51248576U, 51379904U, 51510848U, + 51641792U, 51773248U, 51903296U, 52035136U, 52164032U, 52297664U, 52427968U, + 52557376U, 52690112U, 52821952U, 52952896U, 53081536U, 53213504U, 53344576U, + 53475776U, 53608384U, 53738816U, 53870528U, 54000832U, 54131776U, 54263744U, + 54394688U, 54525248U, 54655936U, 54787904U, 54918592U, 55049152U, 55181248U, + 55312064U, 55442752U, 55574336U, 55705024U, 55836224U, 55967168U, 56097856U, + 56228672U, 56358592U, 56490176U, 56621888U, 56753728U, 56884928U, 57015488U, + 57146816U, 57278272U, 57409216U, 57540416U, 57671104U, 57802432U, 57933632U, + 58064576U, 58195264U, 58326976U, 58457408U, 58588864U, 58720192U, 58849984U, + 58981696U, 59113024U, 59243456U, 59375552U, 59506624U, 59637568U, 59768512U, + 59897792U, 60030016U, 60161984U, 60293056U, 60423872U, 60554432U, 60683968U, + 60817216U, 60948032U, 61079488U, 61209664U, 61341376U, 61471936U, 61602752U, + 61733696U, 61865792U, 61996736U, 62127808U, 62259136U, 62389568U, 62520512U, + 62651584U, 62781632U, 62910784U, 63045056U, 63176128U, 63307072U, 63438656U, + 63569216U, 63700928U, 63831616U, 63960896U, 64093888U, 64225088U, 64355392U, + 64486976U, 64617664U, 64748608U, 64879424U, 65009216U, 65142464U, 65273792U, + 65402816U, 65535424U, 65666752U, 65797696U, 65927744U, 66060224U, 66191296U, + 66321344U, 66453056U, 66584384U, 66715328U, 66846656U, 66977728U, 67108672U, + 67239104U, 67370432U, 67501888U, 67631296U, 67763776U, 67895104U, 68026304U, + 68157248U, 68287936U, 68419264U, 68548288U, 68681408U, 68811968U, 68942912U, + 69074624U, 69205568U, 69337024U, 69467584U, 69599168U, 69729472U, 69861184U, + 69989824U, 70122944U, 70253888U, 70385344U, 70515904U, 70647232U, 70778816U, + 70907968U, 71040832U, 71171648U, 71303104U, 71432512U, 71564992U, 71695168U, + 71826368U, 71958464U, 72089536U, 72219712U, 72350144U, 72482624U, 72613568U, + 72744512U, 72875584U, 73006144U, 73138112U, 73268672U, 73400128U, 73530944U, + 73662272U, 73793344U, 73924544U, 74055104U, 74185792U, 74316992U, 74448832U, + 74579392U, 74710976U, 74841664U, 74972864U, 75102784U, 75233344U, 75364544U, + 75497024U, 75627584U, 75759296U, 75890624U, 76021696U, 76152256U, 76283072U, + 76414144U, 76545856U, 76676672U, 76806976U, 76937792U, 77070016U, 77200832U, + 77331392U, 77462464U, 77593664U, 77725376U, 77856448U, 77987776U, 78118336U, + 78249664U, 78380992U, 78511424U, 78642496U, 78773056U, 78905152U, 79033664U, + 79166656U, 79297472U, 79429568U, 79560512U, 79690816U, 79822784U, 79953472U, + 80084672U, 80214208U, 80346944U, 80477632U, 80608576U, 80740288U, 80870848U, + 81002048U, 81133504U, 81264448U, 81395648U, 81525952U, 81657536U, 81786304U, + 81919808U, 82050112U, 82181312U, 82311616U, 82443968U, 82573376U, 82705984U, + 82835776U, 82967744U, 83096768U, 83230528U, 83359552U, 83491264U, 83622464U, + 83753536U, 83886016U, 84015296U, 84147776U, 84277184U, 84409792U, 84540608U, + 84672064U, 84803008U, 84934336U, 85065152U, 85193792U, 85326784U, 85458496U, + 85589312U, 85721024U, 85851968U, 85982656U, 86112448U, 86244416U, 86370112U, + 86506688U, 86637632U, 86769344U, 86900672U, 87031744U, 87162304U, 87293632U, + 87424576U, 87555392U, 87687104U, 87816896U, 87947968U, 88079168U, 88211264U, + 88341824U, 88473152U, 88603712U, 88735424U, 88862912U, 88996672U, 89128384U, + 89259712U, 89390272U, 89521984U, 89652544U, 89783872U, 89914816U, 90045376U, + 90177088U, 90307904U, 90438848U, 90569152U, 90700096U, 90832832U, 90963776U, + 91093696U, 91223744U, 91356992U, 91486784U, 91618496U, 91749824U, 91880384U, + 92012224U, 92143552U, 92273344U, 92405696U, 92536768U, 92666432U, 92798912U, + 92926016U, 93060544U, 93192128U, 93322816U, 93453632U, 93583936U, 93715136U, + 93845056U, 93977792U, 94109504U, 94240448U, 94371776U, 94501184U, 94632896U, + 94764224U, 94895552U, 95023424U, 95158208U, 95287744U, 95420224U, 95550016U, + 95681216U, 95811904U, 95943872U, 96075328U, 96203584U, 96337856U, 96468544U, + 96599744U, 96731072U, 96860992U, 96992576U, 97124288U, 97254848U, 97385536U, + 97517248U, 97647808U, 97779392U, 97910464U, 98041408U, 98172608U, 98303168U, + 98434496U, 98565568U, 98696768U, 98827328U, 98958784U, 99089728U, 99220928U, + 99352384U, 99482816U, 99614272U, 99745472U, 99876416U, 100007104U, + 100138048U, 100267072U, 100401088U, 100529984U, 100662592U, 100791872U, + 100925248U, 101056064U, 101187392U, 101317952U, 101449408U, 101580608U, + 101711296U, 101841728U, 101973824U, 102104896U, 102235712U, 102366016U, + 102498112U, 102628672U, 102760384U, 102890432U, 103021888U, 103153472U, + 103284032U, 103415744U, 103545152U, 103677248U, 103808576U, 103939648U, + 104070976U, 104201792U, 104332736U, 104462528U, 104594752U, 104725952U, + 104854592U, 104988608U, 105118912U, 105247808U, 105381184U, 105511232U, + 105643072U, 105774784U, 105903296U, 106037056U, 106167872U, 106298944U, + 106429504U, 106561472U, 106691392U, 106822592U, 106954304U, 107085376U, + 107216576U, 107346368U, 107478464U, 107609792U, 107739712U, 107872192U, + 108003136U, 108131392U, 108265408U, 108396224U, 108527168U, 108657344U, + 108789568U, 108920384U, 109049792U, 109182272U, 109312576U, 109444928U, + 109572928U, 109706944U, 109837888U, 109969088U, 110099648U, 110230976U, + 110362432U, 110492992U, 110624704U, 110755264U, 110886208U, 111017408U, + 111148864U, 111279296U, 111410752U, 111541952U, 111673024U, 111803456U, + 111933632U, 112066496U, 112196416U, 112328512U, 112457792U, 112590784U, + 112715968U, 112852672U, 112983616U, 113114944U, 113244224U, 113376448U, + 113505472U, 113639104U, 113770304U, 113901376U, 114031552U, 114163264U, + 114294592U, 114425536U, 114556864U, 114687424U, 114818624U, 114948544U, + 115080512U, 115212224U, 115343296U, 115473472U, 115605184U, 115736128U, + 115867072U, 115997248U, 116128576U, 116260288U, 116391488U, 116522944U, + 116652992U, 116784704U, 116915648U, 117046208U, 117178304U, 117308608U, + 117440192U, 117569728U, 117701824U, 117833024U, 117964096U, 118094656U, + 118225984U, 118357312U, 118489024U, 118617536U, 118749632U, 118882112U, + 119012416U, 119144384U, 119275328U, 119406016U, 119537344U, 119668672U, + 119798464U, 119928896U, 120061376U, 120192832U, 120321728U, 120454336U, + 120584512U, 120716608U, 120848192U, 120979136U, 121109056U, 121241408U, + 121372352U, 121502912U, 121634752U, 121764416U, 121895744U, 122027072U, + 122157632U, 122289088U, 122421184U, 122550592U, 122682944U, 122813888U, + 122945344U, 123075776U, 123207488U, 123338048U, 123468736U, 123600704U, + 123731264U, 123861952U, 123993664U, 124124608U, 124256192U, 124386368U, + 124518208U, 124649024U, 124778048U, 124911296U, 125041088U, 125173696U, + 125303744U, 125432896U, 125566912U, 125696576U, 125829056U, 125958592U, + 126090304U, 126221248U, 126352832U, 126483776U, 126615232U, 126746432U, + 126876608U, 127008704U, 127139392U, 127270336U, 127401152U, 127532224U, + 127663552U, 127794752U, 127925696U, 128055232U, 128188096U, 128319424U, + 128449856U, 128581312U, 128712256U, 128843584U, 128973632U, 129103808U, + 129236288U, 129365696U, 129498944U, 129629888U, 129760832U, 129892288U, + 130023104U, 130154048U, 130283968U, 130416448U, 130547008U, 130678336U, + 130807616U, 130939456U, 131071552U, 131202112U, 131331776U, 131464384U, + 131594048U, 131727296U, 131858368U, 131987392U, 132120256U, 132250816U, + 132382528U, 132513728U, 132644672U, 132774976U, 132905792U, 133038016U, + 133168832U, 133299392U, 133429312U, 133562048U, 133692992U, 133823296U, + 133954624U, 134086336U, 134217152U, 134348608U, 134479808U, 134607296U, + 134741056U, 134872384U, 135002944U, 135134144U, 135265472U, 135396544U, + 135527872U, 135659072U, 135787712U, 135921472U, 136052416U, 136182848U, + 136313792U, 136444864U, 136576448U, 136707904U, 136837952U, 136970048U, + 137099584U, 137232064U, 137363392U, 137494208U, 137625536U, 137755712U, + 137887424U, 138018368U, 138149824U, 138280256U, 138411584U, 138539584U, + 138672832U, 138804928U, 138936128U, 139066688U, 139196864U, 139328704U, + 139460032U, 139590208U, 139721024U, 139852864U, 139984576U, 140115776U, + 140245696U, 140376512U, 140508352U, 140640064U, 140769856U, 140902336U, + 141032768U, 141162688U, 141294016U, 141426496U, 141556544U, 141687488U, + 141819584U, 141949888U, 142080448U, 142212544U, 142342336U, 142474432U, + 142606144U, 142736192U, 142868288U, 142997824U, 143129408U, 143258944U, + 143392448U, 143523136U, 143653696U, 143785024U, 143916992U, 144045632U, + 144177856U, 144309184U, 144440768U, 144570688U, 144701888U, 144832448U, + 144965056U, 145096384U, 145227584U, 145358656U, 145489856U, 145620928U, + 145751488U, 145883072U, 146011456U, 146144704U, 146275264U, 146407232U, + 146538176U, 146668736U, 146800448U, 146931392U, 147062336U, 147193664U, + 147324224U, 147455936U, 147586624U, 147717056U, 147848768U, 147979456U, + 148110784U, 148242368U, 148373312U, 148503232U, 148635584U, 148766144U, + 148897088U, 149028416U, 149159488U, 149290688U, 149420224U, 149551552U, + 149683136U, 149814976U, 149943616U, 150076352U, 150208064U, 150338624U, + 150470464U, 150600256U, 150732224U, 150862784U, 150993088U, 151125952U, + 151254976U, 151388096U, 151519168U, 151649728U, 151778752U, 151911104U, + 152042944U, 152174144U, 152304704U, 152435648U, 152567488U, 152698816U, + 152828992U, 152960576U, 153091648U, 153222976U, 153353792U, 153484096U, + 153616192U, 153747008U, 153878336U, 154008256U, 154139968U, 154270912U, + 154402624U, 154533824U, 154663616U, 154795712U, 154926272U, 155057984U, + 155188928U, 155319872U, 155450816U, 155580608U, 155712064U, 155843392U, + 155971136U, 156106688U, 156237376U, 156367424U, 156499264U, 156630976U, + 156761536U, 156892352U, 157024064U, 157155008U, 157284416U, 157415872U, + 157545536U, 157677248U, 157810496U, 157938112U, 158071744U, 158203328U, + 158334656U, 158464832U, 158596288U, 158727616U, 158858048U, 158988992U, + 159121216U, 159252416U, 159381568U, 159513152U, 159645632U, 159776192U, + 159906496U, 160038464U, 160169536U, 160300352U, 160430656U, 160563008U, + 160693952U, 160822208U, 160956352U, 161086784U, 161217344U, 161349184U, + 161480512U, 161611456U, 161742272U, 161873216U, 162002752U, 162135872U, + 162266432U, 162397888U, 162529216U, 162660032U, 162790976U, 162922048U, + 163052096U, 163184576U, 163314752U, 163446592U, 163577408U, 163707968U, + 163839296U, 163969984U, 164100928U, 164233024U, 164364224U, 164494912U, + 164625856U, 164756672U, 164887616U, 165019072U, 165150016U, 165280064U, + 165412672U, 165543104U, 165674944U, 165805888U, 165936832U, 166067648U, + 166198336U, 166330048U, 166461248U, 166591552U, 166722496U, 166854208U, + 166985408U, 167116736U, 167246656U, 167378368U, 167508416U, 167641024U, + 167771584U, 167903168U, 168034112U, 168164032U, 168295744U, 168427456U, + 168557632U, 168688448U, 168819136U, 168951616U, 169082176U, 169213504U, + 169344832U, 169475648U, 169605952U, 169738048U, 169866304U, 169999552U, + 170131264U, 170262464U, 170393536U, 170524352U, 170655424U, 170782016U, + 170917696U, 171048896U, 171179072U, 171310784U, 171439936U, 171573184U, + 171702976U, 171835072U, 171966272U, 172097216U, 172228288U, 172359232U, + 172489664U, 172621376U, 172747712U, 172883264U, 173014208U, 173144512U, + 173275072U, 173407424U, 173539136U, 173669696U, 173800768U, 173931712U, + 174063424U, 174193472U, 174325696U, 174455744U, 174586816U, 174718912U, + 174849728U, 174977728U, 175109696U, 175242688U, 175374272U, 175504832U, + 175636288U, 175765696U, 175898432U, 176028992U, 176159936U, 176291264U, + 176422592U, 176552512U, 176684864U, 176815424U, 176946496U, 177076544U, + 177209152U, 177340096U, 177470528U, 177600704U, 177731648U, 177864256U, + 177994816U, 178126528U, 178257472U, 178387648U, 178518464U, 178650176U, + 178781888U, 178912064U, 179044288U, 179174848U, 179305024U, 179436736U, + 179568448U, 179698496U, 179830208U, 179960512U, 180092608U, 180223808U, + 180354752U, 180485696U, 180617152U, 180748096U, 180877504U, 181009984U, + 181139264U, 181272512U, 181402688U, 181532608U, 181663168U, 181795136U, + 181926592U, 182057536U, 182190016U, 182320192U, 182451904U, 182582336U, + 182713792U, 182843072U, 182976064U, 183107264U, 183237056U, 183368384U, + 183494848U, 183631424U, 183762752U, 183893824U, 184024768U, 184154816U, + 184286656U, 184417984U, 184548928U, 184680128U, 184810816U, 184941248U, + 185072704U, 185203904U, 185335616U, 185465408U, 185596352U, 185727296U, + 185859904U, 185989696U, 186121664U, 186252992U, 186383552U, 186514112U, + 186645952U, 186777152U, 186907328U, 187037504U, 187170112U, 187301824U, + 187429184U, 187562048U, 187693504U, 187825472U, 187957184U, 188087104U, + 188218304U, 188349376U, 188481344U, 188609728U, 188743616U, 188874304U, + 189005248U, 189136448U, 189265088U, 189396544U, 189528128U, 189660992U, + 189791936U, 189923264U, 190054208U, 190182848U, 190315072U, 190447424U, + 190577984U, 190709312U, 190840768U, 190971328U, 191102656U, 191233472U, + 191364032U, 191495872U, 191626816U, 191758016U, 191888192U, 192020288U, + 192148928U, 192282176U, 192413504U, 192542528U, 192674752U, 192805952U, + 192937792U, 193068608U, 193198912U, 193330496U, 193462208U, 193592384U, + 193723456U, 193854272U, 193985984U, 194116672U, 194247232U, 194379712U, + 194508352U, 194641856U, 194772544U, 194900672U, 195035072U, 195166016U, + 195296704U, 195428032U, 195558592U, 195690304U, 195818176U, 195952576U, + 196083392U, 196214336U, 196345792U, 196476736U, 196607552U, 196739008U, + 196869952U, 197000768U, 197130688U, 197262784U, 197394368U, 197523904U, + 197656384U, 197787584U, 197916608U, 198049472U, 198180544U, 198310208U, + 198442432U, 198573632U, 198705088U, 198834368U, 198967232U, 199097792U, + 199228352U, 199360192U, 199491392U, 199621696U, 199751744U, 199883968U, + 200014016U, 200146624U, 200276672U, 200408128U, 200540096U, 200671168U, + 200801984U, 200933312U, 201062464U, 201194944U, 201326144U, 201457472U, + 201588544U, 201719744U, 201850816U, 201981632U, 202111552U, 202244032U, + 202374464U, 202505152U, 202636352U, 202767808U, 202898368U, 203030336U, + 203159872U, 203292608U, 203423296U, 203553472U, 203685824U, 203816896U, + 203947712U, 204078272U, 204208192U, 204341056U, 204472256U, 204603328U, + 204733888U, 204864448U, 204996544U, 205125568U, 205258304U, 205388864U, + 205517632U, 205650112U, 205782208U, 205913536U, 206044736U, 206176192U, + 206307008U, 206434496U, 206569024U, 206700224U, 206831168U, 206961856U, + 207093056U, 207223616U, 207355328U, 207486784U, 207616832U, 207749056U, + 207879104U, 208010048U, 208141888U, 208273216U, 208404032U, 208534336U, + 208666048U, 208796864U, 208927424U, 209059264U, 209189824U, 209321792U, + 209451584U, 209582656U, 209715136U, 209845568U, 209976896U, 210106432U, + 210239296U, 210370112U, 210501568U, 210630976U, 210763712U, 210894272U, + 211024832U, 211156672U, 211287616U, 211418176U, 211549376U, 211679296U, + 211812032U, 211942592U, 212074432U, 212204864U, 212334016U, 212467648U, + 212597824U, 212727616U, 212860352U, 212991424U, 213120832U, 213253952U, + 213385024U, 213515584U, 213645632U, 213777728U, 213909184U, 214040128U, + 214170688U, 214302656U, 214433728U, 214564544U, 214695232U, 214826048U, + 214956992U, 215089088U, 215219776U, 215350592U, 215482304U, 215613248U, + 215743552U, 215874752U, 216005312U, 216137024U, 216267328U, 216399296U, + 216530752U, 216661696U, 216790592U, 216923968U, 217054528U, 217183168U, + 217316672U, 217448128U, 217579072U, 217709504U, 217838912U, 217972672U, + 218102848U, 218233024U, 218364736U, 218496832U, 218627776U, 218759104U, + 218888896U, 219021248U, 219151936U, 219281728U, 219413056U, 219545024U, + 219675968U, 219807296U, 219938624U, 220069312U, 220200128U, 220331456U, + 220461632U, 220592704U, 220725184U, 220855744U, 220987072U, 221117888U, + 221249216U, 221378368U, 221510336U, 221642048U, 221772736U, 221904832U, + 222031808U, 222166976U, 222297536U, 222428992U, 222559936U, 222690368U, + 222820672U, 222953152U, 223083968U, 223213376U, 223345984U, 223476928U, + 223608512U, 223738688U, 223869376U, 224001472U, 224132672U, 224262848U, + 224394944U, 224524864U, 224657344U, 224788288U, 224919488U, 225050432U, + 225181504U, 225312704U, 225443776U, 225574592U, 225704768U, 225834176U, + 225966784U, 226097216U, 226229824U, 226360384U, 226491712U, 226623424U, + 226754368U, 226885312U, 227015104U, 227147456U, 227278528U, 227409472U, + 227539904U, 227669696U, 227802944U, 227932352U, 228065216U, 228196288U, + 228326464U, 228457792U, 228588736U, 228720064U, 228850112U, 228981056U, + 229113152U, 229243328U, 229375936U, 229505344U, 229636928U, 229769152U, + 229894976U, 230030272U, 230162368U, 230292416U, 230424512U, 230553152U, + 230684864U, 230816704U, 230948416U, 231079616U, 231210944U, 231342016U, + 231472448U, 231603776U, 231733952U, 231866176U, 231996736U, 232127296U, + 232259392U, 232388672U, 232521664U, 232652608U, 232782272U, 232914496U, + 233043904U, 233175616U, 233306816U, 233438528U, 233569984U, 233699776U, + 233830592U, 233962688U, 234092224U, 234221888U, 234353984U, 234485312U, + 234618304U, 234749888U, 234880832U, 235011776U, 235142464U, 235274048U, + 235403456U, 235535936U, 235667392U, 235797568U, 235928768U, 236057152U, + 236190272U, 236322752U, 236453312U, 236583616U, 236715712U, 236846528U, + 236976448U, 237108544U, 237239104U, 237371072U, 237501632U, 237630784U, + 237764416U, 237895232U, 238026688U, 238157632U, 238286912U, 238419392U, + 238548032U, 238681024U, 238812608U, 238941632U, 239075008U, 239206336U, + 239335232U, 239466944U, 239599168U, 239730496U, 239861312U, 239992384U, + 240122816U, 240254656U, 240385856U, 240516928U, 240647872U, 240779072U, + 240909632U, 241040704U, 241171904U, 241302848U, 241433408U, 241565248U, + 241696192U, 241825984U, 241958848U, 242088256U, 242220224U, 242352064U, + 242481856U, 242611648U, 242744896U, 242876224U, 243005632U, 243138496U, + 243268672U, 243400384U, 243531712U, 243662656U, 243793856U, 243924544U, + 244054592U, 244187072U, 244316608U, 244448704U, 244580032U, 244710976U, + 244841536U, 244972864U, 245104448U, 245233984U, 245365312U, 245497792U, + 245628736U, 245759936U, 245889856U, 246021056U, 246152512U, 246284224U, + 246415168U, 246545344U, 246675904U, 246808384U, 246939584U, 247070144U, + 247199552U, 247331648U, 247463872U, 247593536U, 247726016U, 247857088U, + 247987648U, 248116928U, 248249536U, 248380736U, 248512064U, 248643008U, + 248773312U, 248901056U, 249036608U, 249167552U, 249298624U, 249429184U, + 249560512U, 249692096U, 249822784U, 249954112U, 250085312U, 250215488U, + 250345792U, 250478528U, 250608704U, 250739264U, 250870976U, 251002816U, + 251133632U, 251263552U, 251395136U, 251523904U, 251657792U, 251789248U, + 251919424U, 252051392U, 252182464U, 252313408U, 252444224U, 252575552U, + 252706624U, 252836032U, 252968512U, 253099712U, 253227584U, 253361728U, + 253493056U, 253623488U, 253754432U, 253885504U, 254017216U, 254148032U, + 254279488U, 254410432U, 254541376U, 254672576U, 254803264U, 254933824U, + 255065792U, 255196736U, 255326528U, 255458752U, 255589952U, 255721408U, + 255851072U, 255983296U, 256114624U, 256244416U, 256374208U, 256507712U, + 256636096U, 256768832U, 256900544U, 257031616U, 257162176U, 257294272U, + 257424448U, 257555776U, 257686976U, 257818432U, 257949632U, 258079552U, + 258211136U, 258342464U, 258473408U, 258603712U, 258734656U, 258867008U, + 258996544U, 259127744U, 259260224U, 259391296U, 259522112U, 259651904U, + 259784384U, 259915328U, 260045888U, 260175424U, 260308544U, 260438336U, + 260570944U, 260700992U, 260832448U, 260963776U, 261092672U, 261226304U, + 261356864U, 261487936U, 261619648U, 261750592U, 261879872U, 262011968U, + 262143424U, 262274752U, 262404416U, 262537024U, 262667968U, 262799296U, + 262928704U, 263061184U, 263191744U, 263322944U, 263454656U, 263585216U, + 263716672U, 263847872U, 263978944U, 264108608U, 264241088U, 264371648U, + 264501184U, 264632768U, 264764096U, 264895936U, 265024576U, 265158464U, + 265287488U, 265418432U, 265550528U, 265681216U, 265813312U, 265943488U, + 266075968U, 266206144U, 266337728U, 266468032U, 266600384U, 266731072U, + 266862272U, 266993344U, 267124288U, 267255616U, 267386432U, 267516992U, + 267648704U, 267777728U, 267910592U, 268040512U, 268172096U, 268302784U, + 268435264U, 268566208U, 268696256U, 268828096U, 268959296U, 269090368U, + 269221312U, 269352256U, 269482688U, 269614784U, 269745856U, 269876416U, + 270007616U, 270139328U, 270270272U, 270401216U, 270531904U, 270663616U, + 270791744U, 270924736U, 271056832U, 271186112U, 271317184U, 271449536U, + 271580992U, 271711936U, 271843136U, 271973056U, 272105408U, 272236352U, + 272367296U, 272498368U, 272629568U, 272759488U, 272891456U, 273022784U, + 273153856U, 273284672U, 273415616U, 273547072U, 273677632U, 273808448U, + 273937088U, 274071488U, 274200896U, 274332992U, 274463296U, 274595392U, + 274726208U, 274857536U, 274988992U, 275118656U, 275250496U, 275382208U, + 275513024U, 275643968U, 275775296U, 275906368U, 276037184U, 276167872U, + 276297664U, 276429376U, 276560576U, 276692672U, 276822976U, 276955072U, + 277085632U, 277216832U, 277347008U, 277478848U, 277609664U, 277740992U, + 277868608U, 278002624U, 278134336U, 278265536U, 278395328U, 278526784U, + 278657728U, 278789824U, 278921152U, 279052096U, 279182912U, 279313088U, + 279443776U, 279576256U, 279706048U, 279838528U, 279969728U, 280099648U, + 280230976U, 280361408U, 280493632U, 280622528U, 280755392U, 280887104U, + 281018176U, 281147968U, 281278912U, 281411392U, 281542592U, 281673152U, + 281803712U, 281935552U, 282066496U, 282197312U, 282329024U, 282458816U, + 282590272U, 282720832U, 282853184U, 282983744U, 283115072U, 283246144U, + 283377344U, 283508416U, 283639744U, 283770304U, 283901504U, 284032576U, + 284163136U, 284294848U, 284426176U, 284556992U, 284687296U, 284819264U, + 284950208U, 285081536U +}; + +#ifdef __cplusplus +} +#endif diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/endian.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/endian.h new file mode 100644 index 0000000000..6ca6cc0364 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/endian.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include "compiler.h" + +#if defined(__MINGW32__) || defined(_WIN32) + # define LITTLE_ENDIAN 1234 + # define BYTE_ORDER LITTLE_ENDIAN +#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) + # include +#elif defined(__OpenBSD__) || defined(__SVR4) + # include +#elif defined(__APPLE__) +# include +#elif defined( BSD ) && (BSD >= 199103) + # include +#elif defined( __QNXNTO__ ) && defined( __LITTLEENDIAN__ ) + # define LITTLE_ENDIAN 1234 + # define BYTE_ORDER LITTLE_ENDIAN +#elif defined( __QNXNTO__ ) && defined( __BIGENDIAN__ ) + # define BIG_ENDIAN 1234 + # define BYTE_ORDER BIG_ENDIAN +#else +# include +#endif + +#if defined(_WIN32) +#include +#define ethash_swap_u32(input_) _byteswap_ulong(input_) +#define ethash_swap_u64(input_) _byteswap_uint64(input_) +#elif defined(__APPLE__) +#include +#define ethash_swap_u32(input_) OSSwapInt32(input_) +#define ethash_swap_u64(input_) OSSwapInt64(input_) +#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) +#define ethash_swap_u32(input_) bswap32(input_) +#define ethash_swap_u64(input_) bswap64(input_) +#else // posix +#include +#define ethash_swap_u32(input_) __bswap_32(input_) +#define ethash_swap_u64(input_) __bswap_64(input_) +#endif + + +#if LITTLE_ENDIAN == BYTE_ORDER + +#define fix_endian32(dst_ ,src_) dst_ = src_ +#define fix_endian32_same(val_) +#define fix_endian64(dst_, src_) dst_ = src_ +#define fix_endian64_same(val_) +#define fix_endian_arr32(arr_, size_) +#define fix_endian_arr64(arr_, size_) + +#elif BIG_ENDIAN == BYTE_ORDER + +#define fix_endian32(dst_, src_) dst_ = ethash_swap_u32(src_) +#define fix_endian32_same(val_) val_ = ethash_swap_u32(val_) +#define fix_endian64(dst_, src_) dst_ = ethash_swap_u64(src_ +#define fix_endian64_same(val_) val_ = ethash_swap_u64(val_) +#define fix_endian_arr32(arr_, size_) \ + do { \ + for (unsigned i_ = 0; i_ < (size_), ++i_) { \ + arr_[i_] = ethash_swap_u32(arr_[i_]); \ + } \ + while (0) +#define fix_endian_arr64(arr_, size_) \ + do { \ + for (unsigned i_ = 0; i_ < (size_), ++i_) { \ + arr_[i_] = ethash_swap_u64(arr_[i_]); \ + } \ + while (0) \ + +#else +# error "endian not supported" +#endif // BYTE_ORDER diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h new file mode 100644 index 0000000000..0c6a1f9e90 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h @@ -0,0 +1,147 @@ +/* + This file is part of ethash. + + ethash 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. + + ethash 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 ethash. If not, see . +*/ + +/** @file ethash.h +* @date 2015 +*/ +#pragma once + +#include +#include +#include +#include +#include "compiler.h" + +#define ETHASH_REVISION 23 +#define ETHASH_DATASET_BYTES_INIT 1073741824U // 2**30 +#define ETHASH_DATASET_BYTES_GROWTH 8388608U // 2**23 +#define ETHASH_CACHE_BYTES_INIT 1073741824U // 2**24 +#define ETHASH_CACHE_BYTES_GROWTH 131072U // 2**17 +#define ETHASH_EPOCH_LENGTH 30000U +#define ETHASH_MIX_BYTES 128 +#define ETHASH_HASH_BYTES 64 +#define ETHASH_DATASET_PARENTS 256 +#define ETHASH_CACHE_ROUNDS 3 +#define ETHASH_ACCESSES 64 +#define ETHASH_DAG_MAGIC_NUM_SIZE 8 +#define ETHASH_DAG_MAGIC_NUM 0xFEE1DEADBADDCAFE + +#ifdef __cplusplus +extern "C" { +#endif + +/// Type of a seedhash/blockhash e.t.c. +typedef struct ethash_h256 { uint8_t b[32]; } ethash_h256_t; + +// convenience macro to statically initialize an h256_t +// usage: +// ethash_h256_t a = ethash_h256_static_init(1, 2, 3, ... ) +// have to provide all 32 values. If you don't provide all the rest +// will simply be unitialized (not guranteed to be 0) +#define ethash_h256_static_init(...) \ + { {__VA_ARGS__} } + +struct ethash_light; +typedef struct ethash_light* ethash_light_t; +struct ethash_full; +typedef struct ethash_full* ethash_full_t; +typedef int(*ethash_callback_t)(unsigned); + +typedef struct ethash_return_value { + ethash_h256_t result; + ethash_h256_t mix_hash; + bool success; +} ethash_return_value_t; + +/** + * Allocate and initialize a new ethash_light handler + * + * @param block_number The block number for which to create the handler + * @return Newly allocated ethash_light handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes() + */ +ethash_light_t ethash_light_new(uint64_t block_number); +/** + * Frees a previously allocated ethash_light handler + * @param light The light handler to free + */ +void ethash_light_delete(ethash_light_t light); +/** + * Calculate the light client data + * + * @param light The light client handler + * @param header_hash The header hash to pack into the mix + * @param nonce The nonce to pack into the mix + * @return an object of ethash_return_value_t holding the return values + */ +ethash_return_value_t ethash_light_compute( + ethash_light_t light, + ethash_h256_t const header_hash, + uint64_t nonce +); + +/** + * Allocate and initialize a new ethash_full handler + * + * @param light The light handler containing the cache. + * @param callback A callback function with signature of @ref ethash_callback_t + * It accepts an unsigned with which a progress of DAG calculation + * can be displayed. If all goes well the callback should return 0. + * If a non-zero value is returned then DAG generation will stop. + * Be advised. A progress value of 100 means that DAG creation is + * almost complete and that this function will soon return succesfully. + * It does not mean that the function has already had a succesfull return. + * @return Newly allocated ethash_full handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data() + */ +ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback); + +/** + * Frees a previously allocated ethash_full handler + * @param full The light handler to free + */ +void ethash_full_delete(ethash_full_t full); +/** + * Calculate the full client data + * + * @param full The full client handler + * @param header_hash The header hash to pack into the mix + * @param nonce The nonce to pack into the mix + * @return An object of ethash_return_value to hold the return value + */ +ethash_return_value_t ethash_full_compute( + ethash_full_t full, + ethash_h256_t const header_hash, + uint64_t nonce +); +/** + * Get a pointer to the full DAG data + */ +void const* ethash_full_dag(ethash_full_t full); +/** + * Get the size of the DAG data + */ +uint64_t ethash_full_dag_size(ethash_full_t full); + +/** + * Calculate the seedhash for a given block number + */ +ethash_h256_t ethash_get_seedhash(uint64_t block_number); + +#ifdef __cplusplus +} +#endif diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/fnv.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/fnv.h new file mode 100644 index 0000000000..d23c4e2474 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/fnv.h @@ -0,0 +1,39 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum 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. + + cpp-ethereum 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 cpp-ethereum. If not, see . +*/ +/** @file fnv.h +* @author Matthew Wampler-Doty +* @date 2015 +*/ + +#pragma once +#include +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FNV_PRIME 0x01000193 + +static inline uint32_t fnv_hash(uint32_t const x, uint32_t const y) +{ + return x * FNV_PRIME ^ y; +} + +#ifdef __cplusplus +} +#endif diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c new file mode 100644 index 0000000000..338aa5ecd3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c @@ -0,0 +1,507 @@ +/* + This file is part of ethash. + + ethash 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. + + ethash 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 cpp-ethereum. If not, see . +*/ +/** @file internal.c +* @author Tim Hughes +* @author Matthew Wampler-Doty +* @date 2015 +*/ + +#include +#include +#include +#include +#include +#include "mmap.h" +#include "ethash.h" +#include "fnv.h" +#include "endian.h" +#include "internal.h" +#include "data_sizes.h" +#include "io.h" + +#ifdef WITH_CRYPTOPP + +#include "sha3_cryptopp.h" + +#else +#include "sha3.h" +#endif // WITH_CRYPTOPP + +uint64_t ethash_get_datasize(uint64_t const block_number) +{ + assert(block_number / ETHASH_EPOCH_LENGTH < 2048); + return dag_sizes[block_number / ETHASH_EPOCH_LENGTH]; +} + +uint64_t ethash_get_cachesize(uint64_t const block_number) +{ + assert(block_number / ETHASH_EPOCH_LENGTH < 2048); + return cache_sizes[block_number / ETHASH_EPOCH_LENGTH]; +} + +// Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014) +// https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf +// SeqMemoHash(s, R, N) +bool static ethash_compute_cache_nodes( + node* const nodes, + uint64_t cache_size, + ethash_h256_t const* seed +) +{ + if (cache_size % sizeof(node) != 0) { + return false; + } + uint32_t const num_nodes = (uint32_t) (cache_size / sizeof(node)); + + SHA3_512(nodes[0].bytes, (uint8_t*)seed, 32); + + for (uint32_t i = 1; i != num_nodes; ++i) { + SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64); + } + + for (uint32_t j = 0; j != ETHASH_CACHE_ROUNDS; j++) { + for (uint32_t i = 0; i != num_nodes; i++) { + uint32_t const idx = nodes[i].words[0] % num_nodes; + node data; + data = nodes[(num_nodes - 1 + i) % num_nodes]; + for (uint32_t w = 0; w != NODE_WORDS; ++w) { + data.words[w] ^= nodes[idx].words[w]; + } + SHA3_512(nodes[i].bytes, data.bytes, sizeof(data)); + } + } + + // now perform endian conversion + fix_endian_arr32(nodes->words, num_nodes * NODE_WORDS); + return true; +} + +void ethash_calculate_dag_item( + node* const ret, + uint32_t node_index, + ethash_light_t const light +) +{ + uint32_t num_parent_nodes = (uint32_t) (light->cache_size / sizeof(node)); + node const* cache_nodes = (node const *) light->cache; + node const* init = &cache_nodes[node_index % num_parent_nodes]; + memcpy(ret, init, sizeof(node)); + ret->words[0] ^= node_index; + SHA3_512(ret->bytes, ret->bytes, sizeof(node)); +#if defined(_M_X64) && ENABLE_SSE + __m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME); + __m128i xmm0 = ret->xmm[0]; + __m128i xmm1 = ret->xmm[1]; + __m128i xmm2 = ret->xmm[2]; + __m128i xmm3 = ret->xmm[3]; +#endif + + for (uint32_t i = 0; i != ETHASH_DATASET_PARENTS; ++i) { + uint32_t parent_index = fnv_hash(node_index ^ i, ret->words[i % NODE_WORDS]) % num_parent_nodes; + node const *parent = &cache_nodes[parent_index]; + +#if defined(_M_X64) && ENABLE_SSE + { + xmm0 = _mm_mullo_epi32(xmm0, fnv_prime); + xmm1 = _mm_mullo_epi32(xmm1, fnv_prime); + xmm2 = _mm_mullo_epi32(xmm2, fnv_prime); + xmm3 = _mm_mullo_epi32(xmm3, fnv_prime); + xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]); + xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]); + xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]); + xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]); + + // have to write to ret as values are used to compute index + ret->xmm[0] = xmm0; + ret->xmm[1] = xmm1; + ret->xmm[2] = xmm2; + ret->xmm[3] = xmm3; + } + #else + { + for (unsigned w = 0; w != NODE_WORDS; ++w) { + ret->words[w] = fnv_hash(ret->words[w], parent->words[w]); + } + } +#endif + } + SHA3_512(ret->bytes, ret->bytes, sizeof(node)); +} + +bool ethash_compute_full_data( + void* mem, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +) +{ + if (full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 || + (full_size % sizeof(node)) != 0) { + return false; + } + uint32_t const max_n = (uint32_t)(full_size / sizeof(node)); + node* full_nodes = mem; + double const progress_change = 1.0f / max_n; + double progress = 0.0f; + // now compute full nodes + for (uint32_t n = 0; n != max_n; ++n) { + if (callback && + n % (max_n / 100) == 0 && + callback((unsigned int)(ceil(progress * 100.0f))) != 0) { + + return false; + } + progress += progress_change; + ethash_calculate_dag_item(&(full_nodes[n]), n, light); + } + return true; +} + +static bool ethash_hash( + ethash_return_value_t* ret, + node const* full_nodes, + ethash_light_t const light, + uint64_t full_size, + ethash_h256_t const header_hash, + uint64_t const nonce +) +{ + if (full_size % MIX_WORDS != 0) { + return false; + } + + // pack hash and nonce together into first 40 bytes of s_mix + assert(sizeof(node) * 8 == 512); + node s_mix[MIX_NODES + 1]; + memcpy(s_mix[0].bytes, &header_hash, 32); + fix_endian64(s_mix[0].double_words[4], nonce); + + // compute sha3-512 hash and replicate across mix + SHA3_512(s_mix->bytes, s_mix->bytes, 40); + fix_endian_arr32(s_mix[0].words, 16); + + node* const mix = s_mix + 1; + for (uint32_t w = 0; w != MIX_WORDS; ++w) { + mix->words[w] = s_mix[0].words[w % NODE_WORDS]; + } + + unsigned const page_size = sizeof(uint32_t) * MIX_WORDS; + unsigned const num_full_pages = (unsigned) (full_size / page_size); + + for (unsigned i = 0; i != ETHASH_ACCESSES; ++i) { + uint32_t const index = fnv_hash(s_mix->words[0] ^ i, mix->words[i % MIX_WORDS]) % num_full_pages; + + for (unsigned n = 0; n != MIX_NODES; ++n) { + node const* dag_node; + if (full_nodes) { + dag_node = &full_nodes[MIX_NODES * index + n]; + } else { + node tmp_node; + ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, light); + dag_node = &tmp_node; + } + +#if defined(_M_X64) && ENABLE_SSE + { + __m128i fnv_prime = _mm_set1_epi32(FNV_PRIME); + __m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]); + __m128i xmm1 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[1]); + __m128i xmm2 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[2]); + __m128i xmm3 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[3]); + mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]); + mix[n].xmm[1] = _mm_xor_si128(xmm1, dag_node->xmm[1]); + mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]); + mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]); + } + #else + { + for (unsigned w = 0; w != NODE_WORDS; ++w) { + mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]); + } + } +#endif + } + + } + + // compress mix + for (uint32_t w = 0; w != MIX_WORDS; w += 4) { + uint32_t reduction = mix->words[w + 0]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 1]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 2]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 3]; + mix->words[w / 4] = reduction; + } + + fix_endian_arr32(mix->words, MIX_WORDS / 4); + memcpy(&ret->mix_hash, mix->bytes, 32); + // final Keccak hash + SHA3_256(&ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix) + return true; +} + +void ethash_quick_hash( + ethash_h256_t* return_hash, + ethash_h256_t const* header_hash, + uint64_t const nonce, + ethash_h256_t const* mix_hash +) +{ + uint8_t buf[64 + 32]; + memcpy(buf, header_hash, 32); + fix_endian64_same(nonce); + memcpy(&(buf[32]), &nonce, 8); + SHA3_512(buf, buf, 40); + memcpy(&(buf[64]), mix_hash, 32); + SHA3_256(return_hash, buf, 64 + 32); +} + +ethash_h256_t ethash_get_seedhash(uint64_t block_number) +{ + ethash_h256_t ret; + ethash_h256_reset(&ret); + uint64_t const epochs = block_number / ETHASH_EPOCH_LENGTH; + for (uint32_t i = 0; i < epochs; ++i) + SHA3_256(&ret, (uint8_t*)&ret, 32); + return ret; +} + +bool ethash_quick_check_difficulty( + ethash_h256_t const* header_hash, + uint64_t const nonce, + ethash_h256_t const* mix_hash, + ethash_h256_t const* boundary +) +{ + + ethash_h256_t return_hash; + ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash); + return ethash_check_difficulty(&return_hash, boundary); +} + +ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed) +{ + struct ethash_light *ret; + ret = calloc(sizeof(*ret), 1); + if (!ret) { + return NULL; + } + ret->cache = malloc((size_t)cache_size); + if (!ret->cache) { + goto fail_free_light; + } + node* nodes = (node*)ret->cache; + if (!ethash_compute_cache_nodes(nodes, cache_size, seed)) { + goto fail_free_cache_mem; + } + ret->cache_size = cache_size; + return ret; + +fail_free_cache_mem: + free(ret->cache); +fail_free_light: + free(ret); + return NULL; +} + +ethash_light_t ethash_light_new(uint64_t block_number) +{ + ethash_h256_t seedhash = ethash_get_seedhash(block_number); + ethash_light_t ret; + ret = ethash_light_new_internal(ethash_get_cachesize(block_number), &seedhash); + ret->block_number = block_number; + return ret; +} + +void ethash_light_delete(ethash_light_t light) +{ + if (light->cache) { + free(light->cache); + } + free(light); +} + +ethash_return_value_t ethash_light_compute_internal( + ethash_light_t light, + uint64_t full_size, + ethash_h256_t const header_hash, + uint64_t nonce +) +{ + ethash_return_value_t ret; + ret.success = true; + if (!ethash_hash(&ret, NULL, light, full_size, header_hash, nonce)) { + ret.success = false; + } + return ret; +} + +ethash_return_value_t ethash_light_compute( + ethash_light_t light, + ethash_h256_t const header_hash, + uint64_t nonce +) +{ + uint64_t full_size = ethash_get_datasize(light->block_number); + return ethash_light_compute_internal(light, full_size, header_hash, nonce); +} + +static bool ethash_mmap(struct ethash_full* ret, FILE* f) +{ + int fd; + char* mmapped_data; + errno = 0; + ret->file = f; + if ((fd = ethash_fileno(ret->file)) == -1) { + return false; + } + mmapped_data= mmap( + NULL, + (size_t)ret->file_size + ETHASH_DAG_MAGIC_NUM_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + 0 + ); + if (mmapped_data == MAP_FAILED) { + return false; + } + ret->data = (node*)(mmapped_data + ETHASH_DAG_MAGIC_NUM_SIZE); + return true; +} + +ethash_full_t ethash_full_new_internal( + char const* dirname, + ethash_h256_t const seed_hash, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +) +{ + struct ethash_full* ret; + FILE *f = NULL; + ret = calloc(sizeof(*ret), 1); + if (!ret) { + return NULL; + } + ret->file_size = (size_t)full_size; + switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) { + case ETHASH_IO_FAIL: + // ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case + goto fail_free_full; + case ETHASH_IO_MEMO_MATCH: + if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); + goto fail_close_file; + } + return ret; + case ETHASH_IO_MEMO_SIZE_MISMATCH: + // if a DAG of same filename but unexpected size is found, silently force new file creation + if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) { + ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size."); + goto fail_free_full; + } + // fallthrough to the mismatch case here, DO NOT go through match + case ETHASH_IO_MEMO_MISMATCH: + if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); + goto fail_close_file; + } + break; + } + + if (!ethash_compute_full_data(ret->data, full_size, light, callback)) { + ETHASH_CRITICAL("Failure at computing DAG data."); + goto fail_free_full_data; + } + + // after the DAG has been filled then we finalize it by writting the magic number at the beginning + if (fseek(f, 0, SEEK_SET) != 0) { + ETHASH_CRITICAL("Could not seek to DAG file start to write magic number."); + goto fail_free_full_data; + } + uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM; + if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { + ETHASH_CRITICAL("Could not write magic number to DAG's beginning."); + goto fail_free_full_data; + } + if (fflush(f) != 0) {// make sure the magic number IS there + ETHASH_CRITICAL("Could not flush memory mapped data to DAG file. Insufficient space?"); + goto fail_free_full_data; + } + return ret; + +fail_free_full_data: + // could check that munmap(..) == 0 but even if it did not can't really do anything here + munmap(ret->data, (size_t)full_size); +fail_close_file: + fclose(ret->file); +fail_free_full: + free(ret); + return NULL; +} + +ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback) +{ + char strbuf[256]; + if (!ethash_get_default_dirname(strbuf, 256)) { + return NULL; + } + uint64_t full_size = ethash_get_datasize(light->block_number); + ethash_h256_t seedhash = ethash_get_seedhash(light->block_number); + return ethash_full_new_internal(strbuf, seedhash, full_size, light, callback); +} + +void ethash_full_delete(ethash_full_t full) +{ + // could check that munmap(..) == 0 but even if it did not can't really do anything here + munmap(full->data, (size_t)full->file_size); + if (full->file) { + fclose(full->file); + } + free(full); +} + +ethash_return_value_t ethash_full_compute( + ethash_full_t full, + ethash_h256_t const header_hash, + uint64_t nonce +) +{ + ethash_return_value_t ret; + ret.success = true; + if (!ethash_hash( + &ret, + (node const*)full->data, + NULL, + full->file_size, + header_hash, + nonce)) { + ret.success = false; + } + return ret; +} + +void const* ethash_full_dag(ethash_full_t full) +{ + return full->data; +} + +uint64_t ethash_full_dag_size(ethash_full_t full) +{ + return full->file_size; +} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h new file mode 100644 index 0000000000..26c395ad6f --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h @@ -0,0 +1,179 @@ +#pragma once +#include "compiler.h" +#include "endian.h" +#include "ethash.h" +#include + +#define ENABLE_SSE 0 + +#if defined(_M_X64) && ENABLE_SSE +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// compile time settings +#define NODE_WORDS (64/4) +#define MIX_WORDS (ETHASH_MIX_BYTES/4) +#define MIX_NODES (MIX_WORDS / NODE_WORDS) +#include + +typedef union node { + uint8_t bytes[NODE_WORDS * 4]; + uint32_t words[NODE_WORDS]; + uint64_t double_words[NODE_WORDS / 2]; + +#if defined(_M_X64) && ENABLE_SSE + __m128i xmm[NODE_WORDS/4]; +#endif + +} node; + +static inline uint8_t ethash_h256_get(ethash_h256_t const* hash, unsigned int i) +{ + return hash->b[i]; +} + +static inline void ethash_h256_set(ethash_h256_t* hash, unsigned int i, uint8_t v) +{ + hash->b[i] = v; +} + +static inline void ethash_h256_reset(ethash_h256_t* hash) +{ + memset(hash, 0, 32); +} + +// Returns if hash is less than or equal to boundary (2^256/difficulty) +static inline bool ethash_check_difficulty( + ethash_h256_t const* hash, + ethash_h256_t const* boundary +) +{ + // Boundary is big endian + for (int i = 0; i < 32; i++) { + if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) { + continue; + } + return ethash_h256_get(hash, i) < ethash_h256_get(boundary, i); + } + return true; +} + +/** + * Difficulty quick check for POW preverification + * + * @param header_hash The hash of the header + * @param nonce The block's nonce + * @param mix_hash The mix digest hash + * @param boundary The boundary is defined as (2^256 / difficulty) + * @return true for succesful pre-verification and false otherwise + */ +bool ethash_quick_check_difficulty( + ethash_h256_t const* header_hash, + uint64_t const nonce, + ethash_h256_t const* mix_hash, + ethash_h256_t const* boundary +); + +struct ethash_light { + void* cache; + uint64_t cache_size; + uint64_t block_number; +}; + +/** + * Allocate and initialize a new ethash_light handler. Internal version + * + * @param cache_size The size of the cache in bytes + * @param seed Block seedhash to be used during the computation of the + * cache nodes + * @return Newly allocated ethash_light handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes() + */ +ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed); + +/** + * Calculate the light client data. Internal version. + * + * @param light The light client handler + * @param full_size The size of the full data in bytes. + * @param header_hash The header hash to pack into the mix + * @param nonce The nonce to pack into the mix + * @return The resulting hash. + */ +ethash_return_value_t ethash_light_compute_internal( + ethash_light_t light, + uint64_t full_size, + ethash_h256_t const header_hash, + uint64_t nonce +); + +struct ethash_full { + FILE* file; + uint64_t file_size; + node* data; +}; + +/** + * Allocate and initialize a new ethash_full handler. Internal version. + * + * @param dirname The directory in which to put the DAG file. + * @param seedhash The seed hash of the block. Used in the DAG file naming. + * @param full_size The size of the full data in bytes. + * @param cache A cache object to use that was allocated with @ref ethash_cache_new(). + * Iff this function succeeds the ethash_full_t will take memory + * memory ownership of the cache and free it at deletion. If + * not then the user still has to handle freeing of the cache himself. + * @param callback A callback function with signature of @ref ethash_callback_t + * It accepts an unsigned with which a progress of DAG calculation + * can be displayed. If all goes well the callback should return 0. + * If a non-zero value is returned then DAG generation will stop. + * @return Newly allocated ethash_full handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data() + */ +ethash_full_t ethash_full_new_internal( + char const* dirname, + ethash_h256_t const seed_hash, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +); + +void ethash_calculate_dag_item( + node* const ret, + uint32_t node_index, + ethash_light_t const cache +); + +void ethash_quick_hash( + ethash_h256_t* return_hash, + ethash_h256_t const* header_hash, + const uint64_t nonce, + ethash_h256_t const* mix_hash +); + +uint64_t ethash_get_datasize(uint64_t const block_number); +uint64_t ethash_get_cachesize(uint64_t const block_number); + +/** + * Compute the memory data for a full node's memory + * + * @param mem A pointer to an ethash full's memory + * @param full_size The size of the full data in bytes + * @param cache A cache object to use in the calculation + * @param callback The callback function. Check @ref ethash_full_new() for details. + * @return true if all went fine and false for invalid parameters + */ +bool ethash_compute_full_data( + void* mem, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +); + +#ifdef __cplusplus +} +#endif diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.c new file mode 100644 index 0000000000..f4db477c20 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.c @@ -0,0 +1,119 @@ +/* + This file is part of ethash. + + ethash 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. + + ethash 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 ethash. If not, see . +*/ +/** @file io.c + * @author Lefteris Karapetsas + * @date 2015 + */ +#include "io.h" +#include +#include +#include + +enum ethash_io_rc ethash_io_prepare( + char const* dirname, + ethash_h256_t const seedhash, + FILE** output_file, + uint64_t file_size, + bool force_create +) +{ + char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE]; + enum ethash_io_rc ret = ETHASH_IO_FAIL; + // reset errno before io calls + errno = 0; + + // assert directory exists + if (!ethash_mkdir(dirname)) { + ETHASH_CRITICAL("Could not create the ethash directory"); + goto end; + } + + ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name); + char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name)); + if (!tmpfile) { + ETHASH_CRITICAL("Could not create the full DAG pathname"); + goto end; + } + + FILE *f; + if (!force_create) { + // try to open the file + f = ethash_fopen(tmpfile, "rb+"); + if (f) { + size_t found_size; + if (!ethash_file_size(f, &found_size)) { + fclose(f); + ETHASH_CRITICAL("Could not query size of DAG file: \"%s\"", tmpfile); + goto free_memo; + } + if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) { + fclose(f); + ret = ETHASH_IO_MEMO_SIZE_MISMATCH; + goto free_memo; + } + // compare the magic number, no need to care about endianess since it's local + uint64_t magic_num; + if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { + // I/O error + fclose(f); + ETHASH_CRITICAL("Could not read from DAG file: \"%s\"", tmpfile); + ret = ETHASH_IO_MEMO_SIZE_MISMATCH; + goto free_memo; + } + if (magic_num != ETHASH_DAG_MAGIC_NUM) { + fclose(f); + ret = ETHASH_IO_MEMO_SIZE_MISMATCH; + goto free_memo; + } + ret = ETHASH_IO_MEMO_MATCH; + goto set_file; + } + } + + // file does not exist, will need to be created + f = ethash_fopen(tmpfile, "wb+"); + if (!f) { + ETHASH_CRITICAL("Could not create DAG file: \"%s\"", tmpfile); + goto free_memo; + } + // make sure it's of the proper size + if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) { + fclose(f); + ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fputc('\n', f) == EOF) { + fclose(f); + ETHASH_CRITICAL("Could not write in the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fflush(f) != 0) { + fclose(f); + ETHASH_CRITICAL("Could not flush at end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + ret = ETHASH_IO_MEMO_MISMATCH; + goto set_file; + + ret = ETHASH_IO_MEMO_MATCH; +set_file: + *output_file = f; +free_memo: + free(tmpfile); +end: + return ret; +} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.h new file mode 100644 index 0000000000..7a27089c7d --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.h @@ -0,0 +1,202 @@ +/* + This file is part of ethash. + + ethash 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. + + ethash 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 ethash. If not, see . +*/ +/** @file io.h + * @author Lefteris Karapetsas + * @date 2015 + */ +#pragma once +#include +#include +#include +#include +#ifdef __cplusplus +#define __STDC_FORMAT_MACROS 1 +#endif +#include +#include "endian.h" +#include "ethash.h" + +#ifdef __cplusplus +extern "C" { +#endif +// Maximum size for mutable part of DAG file name +// 6 is for "full-R", the suffix of the filename +// 10 is for maximum number of digits of a uint32_t (for REVISION) +// 1 is for - and 16 is for the first 16 hex digits for first 8 bytes of +// the seedhash and last 1 is for the null terminating character +// Reference: https://github.com/ethereum/wiki/wiki/Ethash-DAG +#define DAG_MUTABLE_NAME_MAX_SIZE (6 + 10 + 1 + 16 + 1) +/// Possible return values of @see ethash_io_prepare +enum ethash_io_rc { + ETHASH_IO_FAIL = 0, ///< There has been an IO failure + ETHASH_IO_MEMO_SIZE_MISMATCH, ///< DAG with revision/hash match, but file size was wrong. + ETHASH_IO_MEMO_MISMATCH, ///< The DAG file did not exist or there was revision/hash mismatch + ETHASH_IO_MEMO_MATCH, ///< DAG file existed and revision/hash matched. No need to do anything +}; + +// small hack for windows. I don't feel I should use va_args and forward just +// to have this one function properly cross-platform abstracted +#if defined(_WIN32) && !defined(__GNUC__) +#define snprintf(...) sprintf_s(__VA_ARGS__) +#endif + +/** + * Logs a critical error in important parts of ethash. Should mostly help + * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL + * ethash_full_t + */ +#ifdef ETHASH_PRINT_CRITICAL_OUTPUT +#define ETHASH_CRITICAL(...) \ + do \ + { \ + printf("ETHASH CRITICAL ERROR: "__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define ETHASH_CRITICAL(...) +#endif + +/** + * Prepares io for ethash + * + * Create the DAG directory and the DAG file if they don't exist. + * + * @param[in] dirname A null terminated c-string of the path of the ethash + * data directory. If it does not exist it's created. + * @param[in] seedhash The seedhash of the current block number, used in the + * naming of the file as can be seen from the spec at: + * https://github.com/ethereum/wiki/wiki/Ethash-DAG + * @param[out] output_file If there was no failure then this will point to an open + * file descriptor. User is responsible for closing it. + * In the case of memo match then the file is open on read + * mode, while on the case of mismatch a new file is created + * on write mode + * @param[in] file_size The size that the DAG file should have on disk + * @param[out] force_create If true then there is no check to see if the file + * already exists + * @return For possible return values @see enum ethash_io_rc + */ +enum ethash_io_rc ethash_io_prepare( + char const* dirname, + ethash_h256_t const seedhash, + FILE** output_file, + uint64_t file_size, + bool force_create +); + +/** + * An fopen wrapper for no-warnings crossplatform fopen. + * + * Msvc compiler considers fopen to be insecure and suggests to use their + * alternative. This is a wrapper for this alternative. Another way is to + * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does + * not sound like a good idea. + * + * @param file_name The path to the file to open + * @param mode Opening mode. Check fopen() + * @return The FILE* or NULL in failure + */ +FILE* ethash_fopen(char const* file_name, char const* mode); + +/** + * An strncat wrapper for no-warnings crossplatform strncat. + * + * Msvc compiler considers strncat to be insecure and suggests to use their + * alternative. This is a wrapper for this alternative. Another way is to + * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does + * not sound like a good idea. + * + * @param des Destination buffer + * @param dest_size Maximum size of the destination buffer. This is the + * extra argument for the MSVC secure strncat + * @param src Souce buffer + * @param count Number of bytes to copy from source + * @return If all is well returns the dest buffer. If there is an + * error returns NULL + */ +char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count); + +/** + * A cross-platform mkdir wrapper to create a directory or assert it's there + * + * @param dirname The full path of the directory to create + * @return true if the directory was created or if it already + * existed + */ +bool ethash_mkdir(char const* dirname); + +/** + * Get a file's size + * + * @param[in] f The open file stream whose size to get + * @param[out] size Pass a size_t by reference to contain the file size + * @return true in success and false if there was a failure + */ +bool ethash_file_size(FILE* f, size_t* ret_size); + +/** + * Get a file descriptor number from a FILE stream + * + * @param f The file stream whose fd to get + * @return Platform specific fd handler + */ +int ethash_fileno(FILE* f); + +/** + * Create the filename for the DAG. + * + * @param dirname The directory name in which the DAG file should reside + * If it does not end with a directory separator it is appended. + * @param filename The actual name of the file + * @param filename_length The length of the filename in bytes + * @return A char* containing the full name. User must deallocate. + */ +char* ethash_io_create_filename( + char const* dirname, + char const* filename, + size_t filename_length +); + +/** + * Gets the default directory name for the DAG depending on the system + * + * The spec defining this directory is here: https://github.com/ethereum/wiki/wiki/Ethash-DAG + * + * @param[out] strbuf A string buffer of sufficient size to keep the + * null termninated string of the directory name + * @param[in] buffsize Size of @a strbuf in bytes + * @return true for success and false otherwise + */ +bool ethash_get_default_dirname(char* strbuf, size_t buffsize); + +static inline bool ethash_io_mutable_name( + uint32_t revision, + ethash_h256_t const* seed_hash, + char* output +) +{ + uint64_t hash = *((uint64_t*)seed_hash); +#if LITTLE_ENDIAN == BYTE_ORDER + hash = ethash_swap_u64(hash); +#endif + return snprintf(output, DAG_MUTABLE_NAME_MAX_SIZE, "full-R%u-%016" PRIx64, revision, hash) >= 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_posix.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_posix.c new file mode 100644 index 0000000000..c9a17d845e --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_posix.c @@ -0,0 +1,111 @@ +/* + This file is part of ethash. + + ethash 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. + + ethash 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 ethash. If not, see . +*/ +/** @file io_posix.c + * @author Lefteris Karapetsas + * @date 2015 + */ + +#include "io.h" +#include +#include +#include +#include +#include +#include +#include +#include + +FILE* ethash_fopen(char const* file_name, char const* mode) +{ + return fopen(file_name, mode); +} + +char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count) +{ + return strlen(dest) + count + 1 <= dest_size ? strncat(dest, src, count) : NULL; +} + +bool ethash_mkdir(char const* dirname) +{ + int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + return rc != -1 || errno == EEXIST; +} + +int ethash_fileno(FILE *f) +{ + return fileno(f); +} + +char* ethash_io_create_filename( + char const* dirname, + char const* filename, + size_t filename_length +) +{ + size_t dirlen = strlen(dirname); + size_t dest_size = dirlen + filename_length + 1; + if (dirname[dirlen] != '/') { + dest_size += 1; + } + char* name = malloc(dest_size); + if (!name) { + return NULL; + } + + name[0] = '\0'; + ethash_strncat(name, dest_size, dirname, dirlen); + if (dirname[dirlen] != '/') { + ethash_strncat(name, dest_size, "/", 1); + } + ethash_strncat(name, dest_size, filename, filename_length); + return name; +} + +bool ethash_file_size(FILE* f, size_t* ret_size) +{ + struct stat st; + int fd; + if ((fd = fileno(f)) == -1 || fstat(fd, &st) != 0) { + return false; + } + *ret_size = st.st_size; + return true; +} + +bool ethash_get_default_dirname(char* strbuf, size_t buffsize) +{ + static const char dir_suffix[] = ".ethash/"; + strbuf[0] = '\0'; + char* home_dir = getenv("HOME"); + if (!home_dir || strlen(home_dir) == 0) + { + struct passwd* pwd = getpwuid(getuid()); + if (pwd) + home_dir = pwd->pw_dir; + } + + size_t len = strlen(home_dir); + if (!ethash_strncat(strbuf, buffsize, home_dir, len)) { + return false; + } + if (home_dir[len] != '/') { + if (!ethash_strncat(strbuf, buffsize, "/", 1)) { + return false; + } + } + return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix)); +} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_win32.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_win32.c new file mode 100644 index 0000000000..34f1aaa774 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_win32.c @@ -0,0 +1,100 @@ +/* + This file is part of ethash. + + ethash 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. + + ethash 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 ethash. If not, see . +*/ +/** @file io_win32.c + * @author Lefteris Karapetsas + * @date 2015 + */ + +#include "io.h" +#include +#include +#include +#include +#include +#include + +FILE* ethash_fopen(char const* file_name, char const* mode) +{ + FILE* f; + return fopen_s(&f, file_name, mode) == 0 ? f : NULL; +} + +char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count) +{ + return strncat_s(dest, dest_size, src, count) == 0 ? dest : NULL; +} + +bool ethash_mkdir(char const* dirname) +{ + int rc = _mkdir(dirname); + return rc != -1 || errno == EEXIST; +} + +int ethash_fileno(FILE* f) +{ + return _fileno(f); +} + +char* ethash_io_create_filename( + char const* dirname, + char const* filename, + size_t filename_length +) +{ + size_t dirlen = strlen(dirname); + size_t dest_size = dirlen + filename_length + 1; + if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') { + dest_size += 1; + } + char* name = malloc(dest_size); + if (!name) { + return NULL; + } + + name[0] = '\0'; + ethash_strncat(name, dest_size, dirname, dirlen); + if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') { + ethash_strncat(name, dest_size, "\\", 1); + } + ethash_strncat(name, dest_size, filename, filename_length); + return name; +} + +bool ethash_file_size(FILE* f, size_t* ret_size) +{ + struct _stat st; + int fd; + if ((fd = _fileno(f)) == -1 || _fstat(fd, &st) != 0) { + return false; + } + *ret_size = st.st_size; + return true; +} + +bool ethash_get_default_dirname(char* strbuf, size_t buffsize) +{ + static const char dir_suffix[] = "Ethash\\"; + strbuf[0] = '\0'; + if (!SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, (CHAR*)strbuf))) { + return false; + } + if (!ethash_strncat(strbuf, buffsize, "\\", 1)) { + return false; + } + + return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix)); +} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/mmap.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/mmap.h new file mode 100644 index 0000000000..1e226e83fd --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/mmap.h @@ -0,0 +1,47 @@ +/* + This file is part of ethash. + + ethash 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. + + ethash 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 ethash. If not, see . +*/ +/** @file mmap.h + * @author Lefteris Karapetsas + * @date 2015 + */ +#pragma once +#if defined(__MINGW32__) || defined(_WIN32) +#include + +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +/* This flag is only available in WinXP+ */ +#ifdef FILE_MAP_EXECUTE +#define PROT_EXEC 0x4 +#else +#define PROT_EXEC 0x0 +#define FILE_MAP_EXECUTE 0 +#endif + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_ANONYMOUS 0x20 +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FAILED ((void *) -1) + +void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset); +void munmap(void* addr, size_t length); +#else // posix, yay! ^_^ +#include +#endif + + diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/mmap_win32.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/mmap_win32.c new file mode 100644 index 0000000000..42968b98a4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/mmap_win32.c @@ -0,0 +1,84 @@ +/* mmap() replacement for Windows + * + * Author: Mike Frysinger + * Placed into the public domain + */ + +/* References: + * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx + * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx + * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx + * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx + */ + +#include +#include +#include "mmap.h" + +#ifdef __USE_FILE_OFFSET64 +# define DWORD_HI(x) (x >> 32) +# define DWORD_LO(x) ((x) & 0xffffffff) +#else +# define DWORD_HI(x) (0) +# define DWORD_LO(x) (x) +#endif + +void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset) +{ + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return MAP_FAILED; + if (fd == -1) { + if (!(flags & MAP_ANON) || offset) + return MAP_FAILED; + } else if (flags & MAP_ANON) + return MAP_FAILED; + + DWORD flProtect; + if (prot & PROT_WRITE) { + if (prot & PROT_EXEC) + flProtect = PAGE_EXECUTE_READWRITE; + else + flProtect = PAGE_READWRITE; + } else if (prot & PROT_EXEC) { + if (prot & PROT_READ) + flProtect = PAGE_EXECUTE_READ; + else if (prot & PROT_EXEC) + flProtect = PAGE_EXECUTE; + } else + flProtect = PAGE_READONLY; + + off_t end = length + offset; + HANDLE mmap_fd, h; + if (fd == -1) + mmap_fd = INVALID_HANDLE_VALUE; + else + mmap_fd = (HANDLE)_get_osfhandle(fd); + h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL); + if (h == NULL) + return MAP_FAILED; + + DWORD dwDesiredAccess; + if (prot & PROT_WRITE) + dwDesiredAccess = FILE_MAP_WRITE; + else + dwDesiredAccess = FILE_MAP_READ; + if (prot & PROT_EXEC) + dwDesiredAccess |= FILE_MAP_EXECUTE; + if (flags & MAP_PRIVATE) + dwDesiredAccess |= FILE_MAP_COPY; + void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length); + if (ret == NULL) { + ret = MAP_FAILED; + } + // since we are handling the file ourselves with fd, close the Windows Handle here + CloseHandle(h); + return ret; +} + +void munmap(void* addr, size_t length) +{ + UnmapViewOfFile(addr); +} + +#undef DWORD_HI +#undef DWORD_LO diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.c new file mode 100644 index 0000000000..e72fe10184 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.c @@ -0,0 +1,151 @@ +/** libkeccak-tiny +* +* A single-file implementation of SHA-3 and SHAKE. +* +* Implementor: David Leon Gil +* License: CC0, attribution kindly requested. Blame taken too, +* but not liability. +*/ +#include "sha3.h" + +#include +#include +#include +#include + +/******** The Keccak-f[1600] permutation ********/ + +/*** Constants. ***/ +static const uint8_t rho[24] = \ + { 1, 3, 6, 10, 15, 21, + 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, + 62, 18, 39, 61, 20, 44}; +static const uint8_t pi[24] = \ + {10, 7, 11, 17, 18, 3, + 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, + 20, 14, 22, 9, 6, 1}; +static const uint64_t RC[24] = \ + {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, + 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, + 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; + +/*** Helper macros to unroll the permutation. ***/ +#define rol(x, s) (((x) << s) | ((x) >> (64 - s))) +#define REPEAT6(e) e e e e e e +#define REPEAT24(e) REPEAT6(e e e e) +#define REPEAT5(e) e e e e e +#define FOR5(v, s, e) \ + v = 0; \ + REPEAT5(e; v += s;) + +/*** Keccak-f[1600] ***/ +static inline void keccakf(void* state) { + uint64_t* a = (uint64_t*)state; + uint64_t b[5] = {0}; + uint64_t t = 0; + uint8_t x, y; + + for (int i = 0; i < 24; i++) { + // Theta + FOR5(x, 1, + b[x] = 0; + FOR5(y, 5, + b[x] ^= a[x + y]; )) + FOR5(x, 1, + FOR5(y, 5, + a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) + // Rho and pi + t = a[1]; + x = 0; + REPEAT24(b[0] = a[pi[x]]; + a[pi[x]] = rol(t, rho[x]); + t = b[0]; + x++; ) + // Chi + FOR5(y, + 5, + FOR5(x, 1, + b[x] = a[y + x];) + FOR5(x, 1, + a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) + // Iota + a[0] ^= RC[i]; + } +} + +/******** The FIPS202-defined functions. ********/ + +/*** Some helper macros. ***/ + +#define _(S) do { S } while (0) +#define FOR(i, ST, L, S) \ + _(for (size_t i = 0; i < L; i += ST) { S; }) +#define mkapply_ds(NAME, S) \ + static inline void NAME(uint8_t* dst, \ + const uint8_t* src, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } +#define mkapply_sd(NAME, S) \ + static inline void NAME(const uint8_t* src, \ + uint8_t* dst, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } + +mkapply_ds(xorin, dst[i] ^= src[i]) // xorin +mkapply_sd(setout, dst[i] = src[i]) // setout + +#define P keccakf +#define Plen 200 + +// Fold P*F over the full blocks of an input. +#define foldP(I, L, F) \ + while (L >= rate) { \ + F(a, I, rate); \ + P(a); \ + I += rate; \ + L -= rate; \ + } + +/** The sponge-based hash construction. **/ +static inline int hash(uint8_t* out, size_t outlen, + const uint8_t* in, size_t inlen, + size_t rate, uint8_t delim) { + if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { + return -1; + } + uint8_t a[Plen] = {0}; + // Absorb input. + foldP(in, inlen, xorin); + // Xor in the DS and pad frame. + a[inlen] ^= delim; + a[rate - 1] ^= 0x80; + // Xor in the last block. + xorin(a, in, inlen); + // Apply P + P(a); + // Squeeze output. + foldP(out, outlen, setout); + setout(a, out, outlen); + memset(a, 0, 200); + return 0; +} + +#define defsha3(bits) \ + int sha3_##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + if (outlen > (bits/8)) { \ + return -1; \ + } \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ + } + +/*** FIPS202 SHA3 FOFs ***/ +defsha3(256) +defsha3(512) diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.h new file mode 100644 index 0000000000..a38006292f --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.h @@ -0,0 +1,31 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "compiler.h" +#include +#include + +struct ethash_h256; + +#define decsha3(bits) \ + int sha3_##bits(uint8_t*, size_t, uint8_t const*, size_t); + +decsha3(256) +decsha3(512) + +static inline void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t const size) +{ + sha3_256((uint8_t*)ret, 32, data, size); +} + +static inline void SHA3_512(uint8_t* ret, uint8_t const* data, size_t const size) +{ + sha3_512(ret, 64, data, size); +} + +#ifdef __cplusplus +} +#endif diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.cpp b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.cpp new file mode 100644 index 0000000000..2a7c02664c --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.cpp @@ -0,0 +1,37 @@ +/* + This file is part of ethash. + + ethash 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. + + ethash 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 ethash. If not, see . +*/ + +/** @file sha3.cpp +* @author Tim Hughes +* @date 2015 +*/ +#include +#include + +extern "C" { +struct ethash_h256; +typedef struct ethash_h256 ethash_h256_t; +void SHA3_256(ethash_h256_t const* ret, uint8_t const* data, size_t size) +{ + CryptoPP::SHA3_256().CalculateDigest((uint8_t*)ret, data, size); +} + +void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size) +{ + CryptoPP::SHA3_512().CalculateDigest(ret, data, size); +} +} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.h new file mode 100644 index 0000000000..9edc407d50 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.h @@ -0,0 +1,18 @@ +#pragma once + +#include "compiler.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ethash_h256; + +void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t size); +void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size); + +#ifdef __cplusplus +} +#endif diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util.h new file mode 100644 index 0000000000..c5fc6e55b5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util.h @@ -0,0 +1,47 @@ +/* + This file is part of ethash. + + ethash 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. + + ethash 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 ethash. If not, see . +*/ +/** @file util.h + * @author Tim Hughes + * @date 2015 + */ +#pragma once +#include +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +void debugf(char const* str, ...); +#else +#define debugf printf +#endif + +static inline uint32_t min_u32(uint32_t a, uint32_t b) +{ + return a < b ? a : b; +} + +static inline uint32_t clamp_u32(uint32_t x, uint32_t min_, uint32_t max_) +{ + return x < min_ ? min_ : (x > max_ ? max_ : x); +} + +#ifdef __cplusplus +} +#endif diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util_win32.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util_win32.c new file mode 100644 index 0000000000..268e6db056 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util_win32.c @@ -0,0 +1,38 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum 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. + + cpp-ethereum 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 cpp-ethereum. If not, see . +*/ +/** @file util.c + * @author Tim Hughes + * @date 2015 + */ +#include +#include +#include "util.h" + + +// foward declare without all of Windows.h +__declspec(dllimport) void __stdcall OutputDebugStringA(char const* lpOutputString); + +void debugf(char const* str, ...) +{ + va_list args; + va_start(args, str); + + char buf[1<<16]; + _vsnprintf_s(buf, sizeof(buf), sizeof(buf), str, args); + buf[sizeof(buf)-1] = '\0'; + OutputDebugStringA(buf); +} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c new file mode 100644 index 0000000000..c66e03c549 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c @@ -0,0 +1,267 @@ +#include +#include +#include +#include +#include +#include "../libethash/ethash.h" +#include "../libethash/internal.h" + +#if PY_MAJOR_VERSION >= 3 +#define PY_STRING_FORMAT "y#" +#define PY_CONST_STRING_FORMAT "y" +#else +#define PY_STRING_FORMAT "s#" +#define PY_CONST_STRING_FORMAT "s" +#endif + +#define MIX_WORDS (ETHASH_MIX_BYTES/4) + +static PyObject * +mkcache_bytes(PyObject *self, PyObject *args) { + unsigned long block_number; + unsigned long cache_size; + + if (!PyArg_ParseTuple(args, "k", &block_number)) + return 0; + + ethash_light_t L = ethash_light_new(block_number); + PyObject * val = Py_BuildValue(PY_STRING_FORMAT, L->cache, L->cache_size); + free(L->cache); + return val; +} + +/* +static PyObject * +calc_dataset_bytes(PyObject *self, PyObject *args) { + char *cache_bytes; + unsigned long full_size; + int cache_size; + + if (!PyArg_ParseTuple(args, "k" PY_STRING_FORMAT, &full_size, &cache_bytes, &cache_size)) + return 0; + + if (full_size % MIX_WORDS != 0) { + char error_message[1024]; + sprintf(error_message, "The size of data set must be a multiple of %i bytes (was %lu)", MIX_WORDS, full_size); + PyErr_SetString(PyExc_ValueError, error_message); + return 0; + } + + if (cache_size % ETHASH_HASH_BYTES != 0) { + char error_message[1024]; + sprintf(error_message, "The size of the cache must be a multiple of %i bytes (was %i)", ETHASH_HASH_BYTES, cache_size); + PyErr_SetString(PyExc_ValueError, error_message); + return 0; + } + + ethash_params params; + params.cache_size = (size_t) cache_size; + params.full_size = (size_t) full_size; + ethash_cache cache; + cache.mem = (void *) cache_bytes; + void *mem = malloc(params.full_size); + ethash_compute_full_data(mem, ¶ms, &cache); + PyObject * val = Py_BuildValue(PY_STRING_FORMAT, (char *) mem, full_size); + free(mem); + return val; +}*/ + +// hashimoto_light(full_size, cache, header, nonce) +static PyObject * +hashimoto_light(PyObject *self, PyObject *args) { + char *cache_bytes; + char *header; + unsigned long block_number; + unsigned long long nonce; + int cache_size, header_size; + if (!PyArg_ParseTuple(args, "k" PY_STRING_FORMAT PY_STRING_FORMAT "K", &block_number, &cache_bytes, &cache_size, &header, &header_size, &nonce)) + return 0; + if (header_size != 32) { + char error_message[1024]; + sprintf(error_message, "Seed must be 32 bytes long (was %i)", header_size); + PyErr_SetString(PyExc_ValueError, error_message); + return 0; + } + struct ethash_light *s; + s = calloc(sizeof(*s), 1); + s->cache = cache_bytes; + s->cache_size = cache_size; + s->block_number = block_number; + struct ethash_h256 *h; + h = calloc(sizeof(*h), 1); + for (int i = 0; i < 32; i++) h->b[i] = header[i]; + struct ethash_return_value out = ethash_light_compute(s, *h, nonce); + return Py_BuildValue("{" PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT "," PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT "}", + "mix digest", &out.mix_hash, 32, + "result", &out.result, 32); +} +/* +// hashimoto_full(dataset, header, nonce) +static PyObject * +hashimoto_full(PyObject *self, PyObject *args) { + char *full_bytes; + char *header; + unsigned long long nonce; + int full_size, header_size; + + if (!PyArg_ParseTuple(args, PY_STRING_FORMAT PY_STRING_FORMAT "K", &full_bytes, &full_size, &header, &header_size, &nonce)) + return 0; + + if (full_size % MIX_WORDS != 0) { + char error_message[1024]; + sprintf(error_message, "The size of data set must be a multiple of %i bytes (was %i)", MIX_WORDS, full_size); + PyErr_SetString(PyExc_ValueError, error_message); + return 0; + } + + if (header_size != 32) { + char error_message[1024]; + sprintf(error_message, "Header must be 32 bytes long (was %i)", header_size); + PyErr_SetString(PyExc_ValueError, error_message); + return 0; + } + + + ethash_return_value out; + ethash_params params; + params.full_size = (size_t) full_size; + ethash_full(&out, (void *) full_bytes, ¶ms, (ethash_h256_t *) header, nonce); + return Py_BuildValue("{" PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT ", " PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT "}", + "mix digest", &out.mix_hash, 32, + "result", &out.result, 32); +} + +// mine(dataset_bytes, header, difficulty_bytes) +static PyObject * +mine(PyObject *self, PyObject *args) { + char *full_bytes; + char *header; + char *difficulty; + srand(time(0)); + uint64_t nonce = ((uint64_t) rand()) << 32 | rand(); + int full_size, header_size, difficulty_size; + + if (!PyArg_ParseTuple(args, PY_STRING_FORMAT PY_STRING_FORMAT PY_STRING_FORMAT, &full_bytes, &full_size, &header, &header_size, &difficulty, &difficulty_size)) + return 0; + + if (full_size % MIX_WORDS != 0) { + char error_message[1024]; + sprintf(error_message, "The size of data set must be a multiple of %i bytes (was %i)", MIX_WORDS, full_size); + PyErr_SetString(PyExc_ValueError, error_message); + return 0; + } + + if (header_size != 32) { + char error_message[1024]; + sprintf(error_message, "Header must be 32 bytes long (was %i)", header_size); + PyErr_SetString(PyExc_ValueError, error_message); + return 0; + } + + if (difficulty_size != 32) { + char error_message[1024]; + sprintf(error_message, "Difficulty must be an array of 32 bytes (only had %i)", difficulty_size); + PyErr_SetString(PyExc_ValueError, error_message); + return 0; + } + + ethash_return_value out; + ethash_params params; + params.full_size = (size_t) full_size; + + // TODO: Multi threading? + do { + ethash_full(&out, (void *) full_bytes, ¶ms, (const ethash_h256_t *) header, nonce++); + // TODO: disagrees with the spec https://github.com/ethereum/wiki/wiki/Ethash#mining + } while (!ethash_check_difficulty(&out.result, (const ethash_h256_t *) difficulty)); + + return Py_BuildValue("{" PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT ", " PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT ", " PY_CONST_STRING_FORMAT ":K}", + "mix digest", &out.mix_hash, 32, + "result", &out.result, 32, + "nonce", nonce); +} +*/ + +//get_seedhash(block_number) +static PyObject * +get_seedhash(PyObject *self, PyObject *args) { + unsigned long block_number; + if (!PyArg_ParseTuple(args, "k", &block_number)) + return 0; + if (block_number >= ETHASH_EPOCH_LENGTH * 2048) { + char error_message[1024]; + sprintf(error_message, "Block number must be less than %i (was %lu)", ETHASH_EPOCH_LENGTH * 2048, block_number); + + PyErr_SetString(PyExc_ValueError, error_message); + return 0; + } + ethash_h256_t seedhash = ethash_get_seedhash(block_number); + return Py_BuildValue(PY_STRING_FORMAT, (char *) &seedhash, 32); +} + +static PyMethodDef PyethashMethods[] = + { + {"get_seedhash", get_seedhash, METH_VARARGS, + "get_seedhash(block_number)\n\n" + "Gets the seedhash for a block."}, + {"mkcache_bytes", mkcache_bytes, METH_VARARGS, + "mkcache_bytes(block_number)\n\n" + "Makes a byte array for the cache for given block number\n"}, + /*{"calc_dataset_bytes", calc_dataset_bytes, METH_VARARGS, + "calc_dataset_bytes(full_size, cache_bytes)\n\n" + "Makes a byte array for the dataset for a given size given cache bytes"},*/ + {"hashimoto_light", hashimoto_light, METH_VARARGS, + "hashimoto_light(block_number, cache_bytes, header, nonce)\n\n" + "Runs the hashimoto hashing function just using cache bytes. Takes an int (full_size), byte array (cache_bytes), another byte array (header), and an int (nonce). Returns an object containing the mix digest, and hash result."}, + /*{"hashimoto_full", hashimoto_full, METH_VARARGS, + "hashimoto_full(dataset_bytes, header, nonce)\n\n" + "Runs the hashimoto hashing function using the dataset bytes. Useful for testing. Returns an object containing the mix digest (byte array), and hash result (another byte array)."}, + {"mine", mine, METH_VARARGS, + "mine(dataset_bytes, header, difficulty_bytes)\n\n" + "Mine for an adequate header. Returns an object containing the mix digest (byte array), hash result (another byte array) and nonce (an int)."},*/ + {NULL, NULL, 0, NULL} + }; + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef PyethashModule = { + PyModuleDef_HEAD_INIT, + "pyethash", + "...", + -1, + PyethashMethods +}; + +PyMODINIT_FUNC PyInit_pyethash(void) { + PyObject *module = PyModule_Create(&PyethashModule); + // Following Spec: https://github.com/ethereum/wiki/wiki/Ethash#definitions + PyModule_AddIntConstant(module, "REVISION", (long) ETHASH_REVISION); + PyModule_AddIntConstant(module, "DATASET_BYTES_INIT", (long) ETHASH_DATASET_BYTES_INIT); + PyModule_AddIntConstant(module, "DATASET_BYTES_GROWTH", (long) ETHASH_DATASET_BYTES_GROWTH); + PyModule_AddIntConstant(module, "CACHE_BYTES_INIT", (long) ETHASH_CACHE_BYTES_INIT); + PyModule_AddIntConstant(module, "CACHE_BYTES_GROWTH", (long) ETHASH_CACHE_BYTES_GROWTH); + PyModule_AddIntConstant(module, "EPOCH_LENGTH", (long) ETHASH_EPOCH_LENGTH); + PyModule_AddIntConstant(module, "MIX_BYTES", (long) ETHASH_MIX_BYTES); + PyModule_AddIntConstant(module, "HASH_BYTES", (long) ETHASH_HASH_BYTES); + PyModule_AddIntConstant(module, "DATASET_PARENTS", (long) ETHASH_DATASET_PARENTS); + PyModule_AddIntConstant(module, "CACHE_ROUNDS", (long) ETHASH_CACHE_ROUNDS); + PyModule_AddIntConstant(module, "ACCESSES", (long) ETHASH_ACCESSES); + return module; +} +#else +PyMODINIT_FUNC +initpyethash(void) { + PyObject *module = Py_InitModule("pyethash", PyethashMethods); + // Following Spec: https://github.com/ethereum/wiki/wiki/Ethash#definitions + PyModule_AddIntConstant(module, "REVISION", (long) ETHASH_REVISION); + PyModule_AddIntConstant(module, "DATASET_BYTES_INIT", (long) ETHASH_DATASET_BYTES_INIT); + PyModule_AddIntConstant(module, "DATASET_BYTES_GROWTH", (long) ETHASH_DATASET_BYTES_GROWTH); + PyModule_AddIntConstant(module, "CACHE_BYTES_INIT", (long) ETHASH_CACHE_BYTES_INIT); + PyModule_AddIntConstant(module, "CACHE_BYTES_GROWTH", (long) ETHASH_CACHE_BYTES_GROWTH); + PyModule_AddIntConstant(module, "EPOCH_LENGTH", (long) ETHASH_EPOCH_LENGTH); + PyModule_AddIntConstant(module, "MIX_BYTES", (long) ETHASH_MIX_BYTES); + PyModule_AddIntConstant(module, "HASH_BYTES", (long) ETHASH_HASH_BYTES); + PyModule_AddIntConstant(module, "DATASET_PARENTS", (long) ETHASH_DATASET_PARENTS); + PyModule_AddIntConstant(module, "CACHE_ROUNDS", (long) ETHASH_CACHE_ROUNDS); + PyModule_AddIntConstant(module, "ACCESSES", (long) ETHASH_ACCESSES); +} +#endif diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/CMakeLists.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/CMakeLists.txt new file mode 100644 index 0000000000..f94531c3df --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/CMakeLists.txt @@ -0,0 +1,66 @@ +if (MSVC) + if (NOT BOOST_ROOT) + set (BOOST_ROOT "$ENV{BOOST_ROOT}") + endif() + set (CMAKE_PREFIX_PATH BOOST_ROOT) +endif() + +IF( NOT Boost_FOUND ) + # use multithreaded boost libraries, with -mt suffix + set(Boost_USE_MULTITHREADED ON) + + if (MSVC) + # TODO handle other msvc versions or it will fail find them + set(Boost_COMPILER -vc120) + # use static boost libraries *.lib + set(Boost_USE_STATIC_LIBS ON) + elseif (APPLE) + + # use static boost libraries *.a + set(Boost_USE_STATIC_LIBS ON) + + elseif (UNIX) + # use dynamic boost libraries .dll + set(Boost_USE_STATIC_LIBS OFF) + + endif() + find_package(Boost 1.48.0 COMPONENTS unit_test_framework system filesystem) +ENDIF() + +IF (Boost_FOUND) + message(STATUS "boost header: ${Boost_INCLUDE_DIRS}") + message(STATUS "boost libs : ${Boost_LIBRARIES}") + + include_directories( ${Boost_INCLUDE_DIR} ) + include_directories(../../src) + + link_directories(${Boost_LIBRARY_DIRS}) + file(GLOB HEADERS "*.h") + if ((NOT MSVC) AND (NOT APPLE)) + ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK) + endif() + if (NOT CRYPTOPP_FOUND) + find_package (CryptoPP) + endif() + + if (CRYPTOPP_FOUND) + add_definitions(-DWITH_CRYPTOPP) + endif() + + if (NOT MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ") + endif() + + add_executable (Test "./test.cpp" ${HEADERS}) + target_link_libraries(Test ${ETHHASH_LIBS}) + target_link_libraries(Test ${Boost_FILESYSTEM_LIBRARIES}) + target_link_libraries(Test ${Boost_SYSTEM_LIBRARIES}) + target_link_libraries(Test ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) + + if (CRYPTOPP_FOUND) + TARGET_LINK_LIBRARIES(Test ${CRYPTOPP_LIBRARIES}) + endif() + + enable_testing () + add_test(NAME ethash COMMAND Test) +ENDIF() diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp new file mode 100644 index 0000000000..44e0c385bb --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp @@ -0,0 +1,669 @@ +#include +#include +#include +#include +#include + +#ifdef WITH_CRYPTOPP + +#include + +#else +#include +#endif // WITH_CRYPTOPP + +#ifdef _WIN32 +#include +#include +#endif + +#define BOOST_TEST_MODULE Daggerhashimoto +#define BOOST_TEST_MAIN + +#include +#include +#include +#include +#include + +using namespace std; +using byte = uint8_t; +using bytes = std::vector; +namespace fs = boost::filesystem; + +// Just an alloca "wrapper" to silence uint64_t to size_t conversion warnings in windows +// consider replacing alloca calls with something better though! +#define our_alloca(param__) alloca((size_t)(param__)) + + +// some functions taken from eth::dev for convenience. +std::string bytesToHexString(const uint8_t *str, const uint64_t s) +{ + std::ostringstream ret; + + for (size_t i = 0; i < s; ++i) + ret << std::hex << std::setfill('0') << std::setw(2) << std::nouppercase << (int) str[i]; + + return ret.str(); +} + +std::string blockhashToHexString(ethash_h256_t* _hash) +{ + return bytesToHexString((uint8_t*)_hash, 32); +} + +int fromHex(char _i) +{ + if (_i >= '0' && _i <= '9') + return _i - '0'; + if (_i >= 'a' && _i <= 'f') + return _i - 'a' + 10; + if (_i >= 'A' && _i <= 'F') + return _i - 'A' + 10; + + BOOST_REQUIRE_MESSAGE(false, "should never get here"); + return -1; +} + +bytes hexStringToBytes(std::string const& _s) +{ + unsigned s = (_s[0] == '0' && _s[1] == 'x') ? 2 : 0; + std::vector ret; + ret.reserve((_s.size() - s + 1) / 2); + + if (_s.size() % 2) + try + { + ret.push_back(fromHex(_s[s++])); + } + catch (...) + { + ret.push_back(0); + } + for (unsigned i = s; i < _s.size(); i += 2) + try + { + ret.push_back((byte)(fromHex(_s[i]) * 16 + fromHex(_s[i + 1]))); + } + catch (...){ + ret.push_back(0); + } + return ret; +} + +ethash_h256_t stringToBlockhash(std::string const& _s) +{ + ethash_h256_t ret; + bytes b = hexStringToBytes(_s); + memcpy(&ret, b.data(), b.size()); + return ret; +} + + + +BOOST_AUTO_TEST_CASE(fnv_hash_check) { + uint32_t x = 1235U; + const uint32_t + y = 9999999U, + expected = (FNV_PRIME * x) ^y; + + x = fnv_hash(x, y); + + BOOST_REQUIRE_MESSAGE(x == expected, + "\nexpected: " << expected << "\n" + << "actual: " << x << "\n"); + +} + +BOOST_AUTO_TEST_CASE(SHA256_check) { + ethash_h256_t input; + ethash_h256_t out; + memcpy(&input, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); + SHA3_256(&out, (uint8_t*)&input, 32); + const std::string + expected = "2b5ddf6f4d21c23de216f44d5e4bdc68e044b71897837ea74c83908be7037cd7", + actual = bytesToHexString((uint8_t*)&out, 32); + BOOST_REQUIRE_MESSAGE(expected == actual, + "\nexpected: " << expected.c_str() << "\n" + << "actual: " << actual.c_str() << "\n"); +} + +BOOST_AUTO_TEST_CASE(SHA512_check) { + uint8_t input[64], out[64]; + memcpy(input, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 64); + SHA3_512(out, input, 64); + const std::string + expected = "0be8a1d334b4655fe58c6b38789f984bb13225684e86b20517a55ab2386c7b61c306f25e0627c60064cecd6d80cd67a82b3890bd1289b7ceb473aad56a359405", + actual = bytesToHexString(out, 64); + BOOST_REQUIRE_MESSAGE(expected == actual, + "\nexpected: " << expected.c_str() << "\n" + << "actual: " << actual.c_str() << "\n"); +} + +BOOST_AUTO_TEST_CASE(test_swap_endian32) { + uint32_t v32 = (uint32_t)0xBAADF00D; + v32 = ethash_swap_u32(v32); + BOOST_REQUIRE_EQUAL(v32, (uint32_t)0x0DF0ADBA); +} + +BOOST_AUTO_TEST_CASE(test_swap_endian64) { + uint64_t v64 = (uint64_t)0xFEE1DEADDEADBEEF; + v64 = ethash_swap_u64(v64); + BOOST_REQUIRE_EQUAL(v64, (uint64_t)0xEFBEADDEADDEE1FE); +} + +BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_check) { + uint64_t full_size = ethash_get_datasize(0); + uint64_t cache_size = ethash_get_cachesize(0); + BOOST_REQUIRE_MESSAGE(full_size < ETHASH_DATASET_BYTES_INIT, + "\nfull size: " << full_size << "\n" + << "should be less than or equal to: " << ETHASH_DATASET_BYTES_INIT << "\n"); + BOOST_REQUIRE_MESSAGE(full_size + 20 * ETHASH_MIX_BYTES >= ETHASH_DATASET_BYTES_INIT, + "\nfull size + 20*MIX_BYTES: " << full_size + 20 * ETHASH_MIX_BYTES << "\n" + << "should be greater than or equal to: " << ETHASH_DATASET_BYTES_INIT << "\n"); + BOOST_REQUIRE_MESSAGE(cache_size < ETHASH_DATASET_BYTES_INIT / 32, + "\ncache size: " << cache_size << "\n" + << "should be less than or equal to: " << ETHASH_DATASET_BYTES_INIT / 32 << "\n"); +} + +BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_calcifide_check) { + uint64_t full_size = ethash_get_datasize(0); + uint64_t cache_size = ethash_get_cachesize(0); + const uint32_t expected_full_size = 1073739904; + const uint32_t expected_cache_size = 16776896; + BOOST_REQUIRE_MESSAGE(full_size == expected_full_size, + "\nexpected: " << expected_cache_size << "\n" + << "actual: " << full_size << "\n"); + BOOST_REQUIRE_MESSAGE(cache_size == expected_cache_size, + "\nexpected: " << expected_cache_size << "\n" + << "actual: " << cache_size << "\n"); +} + +BOOST_AUTO_TEST_CASE(ethash_check_difficulty_check) { + ethash_h256_t hash; + ethash_h256_t target; + memcpy(&hash, "11111111111111111111111111111111", 32); + memcpy(&target, "22222222222222222222222222222222", 32); + BOOST_REQUIRE_MESSAGE( + ethash_check_difficulty(&hash, &target), + "\nexpected \"" << std::string((char *) &hash, 32).c_str() << "\" to have the same or less difficulty than \"" << std::string((char *) &target, 32).c_str() << "\"\n"); + BOOST_REQUIRE_MESSAGE( + ethash_check_difficulty(&hash, &hash), ""); + // "\nexpected \"" << hash << "\" to have the same or less difficulty than \"" << hash << "\"\n"); + memcpy(&target, "11111111111111111111111111111112", 32); + BOOST_REQUIRE_MESSAGE( + ethash_check_difficulty(&hash, &target), ""); + // "\nexpected \"" << hash << "\" to have the same or less difficulty than \"" << target << "\"\n"); + memcpy(&target, "11111111111111111111111111111110", 32); + BOOST_REQUIRE_MESSAGE( + !ethash_check_difficulty(&hash, &target), ""); + // "\nexpected \"" << hash << "\" to have more difficulty than \"" << target << "\"\n"); +} + +BOOST_AUTO_TEST_CASE(test_ethash_io_mutable_name) { + char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE]; + // should have at least 8 bytes provided since this is what we test :) + ethash_h256_t seed1 = ethash_h256_static_init(0, 10, 65, 255, 34, 55, 22, 8); + ethash_io_mutable_name(1, &seed1, mutable_name); + BOOST_REQUIRE_EQUAL(0, strcmp(mutable_name, "full-R1-000a41ff22371608")); + ethash_h256_t seed2 = ethash_h256_static_init(0, 0, 0, 0, 0, 0, 0, 0); + ethash_io_mutable_name(44, &seed2, mutable_name); + BOOST_REQUIRE_EQUAL(0, strcmp(mutable_name, "full-R44-0000000000000000")); +} + +BOOST_AUTO_TEST_CASE(test_ethash_dir_creation) { + ethash_h256_t seedhash; + FILE *f = NULL; + memset(&seedhash, 0, 32); + BOOST_REQUIRE_EQUAL( + ETHASH_IO_MEMO_MISMATCH, + ethash_io_prepare("./test_ethash_directory/", seedhash, &f, 64, false) + ); + BOOST_REQUIRE(f); + + // let's make sure that the directory was created + BOOST_REQUIRE(fs::is_directory(fs::path("./test_ethash_directory/"))); + + // cleanup + fclose(f); + fs::remove_all("./test_ethash_directory/"); +} + +BOOST_AUTO_TEST_CASE(test_ethash_io_memo_file_match) { + uint64_t full_size; + uint64_t cache_size; + ethash_h256_t seed; + ethash_h256_t hash; + FILE* f; + memcpy(&seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); + memcpy(&hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); + + cache_size = 1024; + full_size = 1024 * 32; + + ethash_light_t light = ethash_light_new_internal(cache_size, &seed); + ethash_full_t full = ethash_full_new_internal( + "./test_ethash_directory/", + seed, + full_size, + light, + NULL + ); + BOOST_ASSERT(full); + // let's make sure that the directory was created + BOOST_REQUIRE(fs::is_directory(fs::path("./test_ethash_directory/"))); + // delete the full here so that memory is properly unmapped and FILE handler freed + ethash_full_delete(full); + // and check that we have a match when checking again + BOOST_REQUIRE_EQUAL( + ETHASH_IO_MEMO_MATCH, + ethash_io_prepare("./test_ethash_directory/", seed, &f, full_size, false) + ); + BOOST_REQUIRE(f); + + // cleanup + fclose(f); + ethash_light_delete(light); + fs::remove_all("./test_ethash_directory/"); +} + +BOOST_AUTO_TEST_CASE(test_ethash_io_memo_file_size_mismatch) { + static const int blockn = 0; + ethash_h256_t seedhash = ethash_get_seedhash(blockn); + FILE *f = NULL; + BOOST_REQUIRE_EQUAL( + ETHASH_IO_MEMO_MISMATCH, + ethash_io_prepare("./test_ethash_directory/", seedhash, &f, 64, false) + ); + BOOST_REQUIRE(f); + fclose(f); + + // let's make sure that the directory was created + BOOST_REQUIRE(fs::is_directory(fs::path("./test_ethash_directory/"))); + // and check that we get the size mismatch detected if we request diffferent size + BOOST_REQUIRE_EQUAL( + ETHASH_IO_MEMO_SIZE_MISMATCH, + ethash_io_prepare("./test_ethash_directory/", seedhash, &f, 65, false) + ); + + // cleanup + fs::remove_all("./test_ethash_directory/"); +} + +BOOST_AUTO_TEST_CASE(test_ethash_get_default_dirname) { + char result[256]; + // this is really not an easy thing to test for in a unit test + // TODO: Improve this test ... +#ifdef _WIN32 + char homedir[256]; + BOOST_REQUIRE(SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, (CHAR*)homedir))); + BOOST_REQUIRE(ethash_get_default_dirname(result, 256)); + std::string res = std::string(homedir) + std::string("\\AppData\\Local\\Ethash\\"); +#else + char* homedir = getenv("HOME"); + BOOST_REQUIRE(ethash_get_default_dirname(result, 256)); + std::string res = std::string(homedir) + std::string("/.ethash/"); +#endif + BOOST_CHECK_MESSAGE(strcmp(res.c_str(), result) == 0, + "Expected \"" + res + "\" but got \"" + std::string(result) + "\"" + ); +} + +BOOST_AUTO_TEST_CASE(light_and_full_client_checks) { + uint64_t full_size; + uint64_t cache_size; + ethash_h256_t seed; + ethash_h256_t hash; + ethash_h256_t difficulty; + ethash_return_value_t light_out; + ethash_return_value_t full_out; + memcpy(&seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); + memcpy(&hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); + + // Set the difficulty + ethash_h256_set(&difficulty, 0, 197); + ethash_h256_set(&difficulty, 1, 90); + for (int i = 2; i < 32; i++) + ethash_h256_set(&difficulty, i, 255); + + cache_size = 1024; + full_size = 1024 * 32; + + ethash_light_t light = ethash_light_new_internal(cache_size, &seed); + ethash_full_t full = ethash_full_new_internal( + "./test_ethash_directory/", + seed, + full_size, + light, + NULL + ); + BOOST_ASSERT(full); + { + const std::string + expected = "2da2b506f21070e1143d908e867962486d6b0a02e31d468fd5e3a7143aafa76a14201f63374314e2a6aaf84ad2eb57105dea3378378965a1b3873453bb2b78f9a8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995c259440b89fa3481c2c33171477c305c8e1e421f8d8f6d59585449d0034f3e421808d8da6bbd0b6378f567647cc6c4ba6c434592b198ad444e7284905b7c6adaf70bf43ec2daa7bd5e8951aa609ab472c124cf9eba3d38cff5091dc3f58409edcc386c743c3bd66f92408796ee1e82dd149eaefbf52b00ce33014a6eb3e50625413b072a58bc01da28262f42cbe4f87d4abc2bf287d15618405a1fe4e386fcdafbb171064bd99901d8f81dd6789396ce5e364ac944bbbd75a7827291c70b42d26385910cd53ca535ab29433dd5c5714d26e0dce95514c5ef866329c12e958097e84462197c2b32087849dab33e88b11da61d52f9dbc0b92cc61f742c07dbbf751c49d7678624ee60dfbe62e5e8c47a03d8247643f3d16ad8c8e663953bcda1f59d7e2d4a9bf0768e789432212621967a8f41121ad1df6ae1fa78782530695414c6213942865b2730375019105cae91a4c17a558d4b63059661d9f108362143107babe0b848de412e4da59168cce82bfbff3c99e022dd6ac1e559db991f2e3f7bb910cefd173e65ed00a8d5d416534e2c8416ff23977dbf3eb7180b75c71580d08ce95efeb9b0afe904ea12285a392aff0c8561ff79fca67f694a62b9e52377485c57cc3598d84cac0a9d27960de0cc31ff9bbfe455acaa62c8aa5d2cce96f345da9afe843d258a99c4eaf3650fc62efd81c7b81cd0d534d2d71eeda7a6e315d540b4473c80f8730037dc2ae3e47b986240cfc65ccc565f0d8cde0bc68a57e39a271dda57440b3598bee19f799611d25731a96b5dbbbefdff6f4f656161462633030d62560ea4e9c161cf78fc96a2ca5aaa32453a6c5dea206f766244e8c9d9a8dc61185ce37f1fc804459c5f07434f8ecb34141b8dcae7eae704c950b55556c5f40140c3714b45eddb02637513268778cbf937a33e4e33183685f9deb31ef54e90161e76d969587dd782eaa94e289420e7c2ee908517f5893a26fdb5873d68f92d118d4bcf98d7a4916794d6ab290045e30f9ea00ca547c584b8482b0331ba1539a0f2714fddc3a0b06b0cfbb6a607b8339c39bcfd6640b1f653e9d70ef6c985b", + actual = bytesToHexString((uint8_t const *) light->cache, cache_size); + + BOOST_REQUIRE_MESSAGE(expected == actual, + "\nexpected: " << expected.c_str() << "\n" + << "actual: " << actual.c_str() << "\n"); + } + { + node node; + ethash_calculate_dag_item(&node, 0, light); + const std::string + actual = bytesToHexString((uint8_t const *) &node, sizeof(node)), + expected = "b1698f829f90b35455804e5185d78f549fcb1bdce2bee006d4d7e68eb154b596be1427769eb1c3c3e93180c760af75f81d1023da6a0ffbe321c153a7c0103597"; + BOOST_REQUIRE_MESSAGE(actual == expected, + "\n" << "expected: " << expected.c_str() << "\n" + << "actual: " << actual.c_str() << "\n"); + } + { + for (int i = 0; i < full_size / sizeof(node); ++i) { + for (uint32_t j = 0; j < 32; ++j) { + node expected_node; + ethash_calculate_dag_item(&expected_node, j, light); + const std::string + actual = bytesToHexString((uint8_t const *) &(full->data[j]), sizeof(node)), + expected = bytesToHexString((uint8_t const *) &expected_node, sizeof(node)); + BOOST_REQUIRE_MESSAGE(actual == expected, + "\ni: " << j << "\n" + << "expected: " << expected.c_str() << "\n" + << "actual: " << actual.c_str() << "\n"); + } + } + } + { + uint64_t nonce = 0x7c7c597c; + full_out = ethash_full_compute(full, hash, nonce); + BOOST_REQUIRE(full_out.success); + light_out = ethash_light_compute_internal(light, full_size, hash, nonce); + BOOST_REQUIRE(light_out.success); + const std::string + light_result_string = blockhashToHexString(&light_out.result), + full_result_string = blockhashToHexString(&full_out.result); + BOOST_REQUIRE_MESSAGE(light_result_string == full_result_string, + "\nlight result: " << light_result_string.c_str() << "\n" + << "full result: " << full_result_string.c_str() << "\n"); + const std::string + light_mix_hash_string = blockhashToHexString(&light_out.mix_hash), + full_mix_hash_string = blockhashToHexString(&full_out.mix_hash); + BOOST_REQUIRE_MESSAGE(full_mix_hash_string == light_mix_hash_string, + "\nlight mix hash: " << light_mix_hash_string.c_str() << "\n" + << "full mix hash: " << full_mix_hash_string.c_str() << "\n"); + ethash_h256_t check_hash; + ethash_quick_hash(&check_hash, &hash, nonce, &full_out.mix_hash); + const std::string check_hash_string = blockhashToHexString(&check_hash); + BOOST_REQUIRE_MESSAGE(check_hash_string == full_result_string, + "\ncheck hash string: " << check_hash_string.c_str() << "\n" + << "full result: " << full_result_string.c_str() << "\n"); + } + { + full_out = ethash_full_compute(full, hash, 5); + BOOST_REQUIRE(full_out.success); + std::string + light_result_string = blockhashToHexString(&light_out.result), + full_result_string = blockhashToHexString(&full_out.result); + BOOST_REQUIRE_MESSAGE(light_result_string != full_result_string, + "\nlight result and full result should differ: " << light_result_string.c_str() << "\n"); + + light_out = ethash_light_compute_internal(light, full_size, hash, 5); + BOOST_REQUIRE(light_out.success); + light_result_string = blockhashToHexString(&light_out.result); + BOOST_REQUIRE_MESSAGE(light_result_string == full_result_string, + "\nlight result and full result should be the same\n" + << "light result: " << light_result_string.c_str() << "\n" + << "full result: " << full_result_string.c_str() << "\n"); + std::string + light_mix_hash_string = blockhashToHexString(&light_out.mix_hash), + full_mix_hash_string = blockhashToHexString(&full_out.mix_hash); + BOOST_REQUIRE_MESSAGE(full_mix_hash_string == light_mix_hash_string, + "\nlight mix hash: " << light_mix_hash_string.c_str() << "\n" + << "full mix hash: " << full_mix_hash_string.c_str() << "\n"); + BOOST_REQUIRE_MESSAGE(ethash_check_difficulty(&full_out.result, &difficulty), + "ethash_check_difficulty failed" + ); + BOOST_REQUIRE_MESSAGE(ethash_quick_check_difficulty(&hash, 5U, &full_out.mix_hash, &difficulty), + "ethash_quick_check_difficulty failed" + ); + } + ethash_light_delete(light); + ethash_full_delete(full); + fs::remove_all("./test_ethash_directory/"); +} + +BOOST_AUTO_TEST_CASE(ethash_full_new_when_dag_exists_with_wrong_size) { + uint64_t full_size; + uint64_t cache_size; + ethash_h256_t seed; + ethash_h256_t hash; + ethash_return_value_t full_out; + ethash_return_value_t light_out; + memcpy(&seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); + memcpy(&hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); + + cache_size = 1024; + full_size = 1024 * 32; + + // first make a DAG file of "wrong size" + FILE *f; + BOOST_REQUIRE_EQUAL( + ETHASH_IO_MEMO_MISMATCH, + ethash_io_prepare("./test_ethash_directory/", seed, &f, 64, false) + ); + fclose(f); + + // then create new DAG, which should detect the wrong size and force create a new file + ethash_light_t light = ethash_light_new_internal(cache_size, &seed); + BOOST_ASSERT(light); + ethash_full_t full = ethash_full_new_internal( + "./test_ethash_directory/", + seed, + full_size, + light, + NULL + ); + BOOST_ASSERT(full); + { + uint64_t nonce = 0x7c7c597c; + full_out = ethash_full_compute(full, hash, nonce); + BOOST_REQUIRE(full_out.success); + light_out = ethash_light_compute_internal(light, full_size, hash, nonce); + BOOST_REQUIRE(light_out.success); + const std::string + light_result_string = blockhashToHexString(&light_out.result), + full_result_string = blockhashToHexString(&full_out.result); + BOOST_REQUIRE_MESSAGE(light_result_string == full_result_string, + "\nlight result: " << light_result_string.c_str() << "\n" + << "full result: " << full_result_string.c_str() << "\n"); + const std::string + light_mix_hash_string = blockhashToHexString(&light_out.mix_hash), + full_mix_hash_string = blockhashToHexString(&full_out.mix_hash); + BOOST_REQUIRE_MESSAGE(full_mix_hash_string == light_mix_hash_string, + "\nlight mix hash: " << light_mix_hash_string.c_str() << "\n" + << "full mix hash: " << full_mix_hash_string.c_str() << "\n"); + ethash_h256_t check_hash; + ethash_quick_hash(&check_hash, &hash, nonce, &full_out.mix_hash); + const std::string check_hash_string = blockhashToHexString(&check_hash); + BOOST_REQUIRE_MESSAGE(check_hash_string == full_result_string, + "\ncheck hash string: " << check_hash_string.c_str() << "\n" + << "full result: " << full_result_string.c_str() << "\n"); + } + + ethash_light_delete(light); + ethash_full_delete(full); + fs::remove_all("./test_ethash_directory/"); +} + +static bool g_executed = false; +static unsigned g_prev_progress = 0; +static int test_full_callback(unsigned _progress) +{ + g_executed = true; + BOOST_CHECK(_progress >= g_prev_progress); + g_prev_progress = _progress; + return 0; +} + +static int test_full_callback_that_fails(unsigned _progress) +{ + return 1; +} + +static int test_full_callback_create_incomplete_dag(unsigned _progress) +{ + if (_progress >= 30) { + return 1; + } + return 0; +} + +BOOST_AUTO_TEST_CASE(full_client_callback) { + uint64_t full_size; + uint64_t cache_size; + ethash_h256_t seed; + ethash_h256_t hash; + memcpy(&seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); + memcpy(&hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); + + cache_size = 1024; + full_size = 1024 * 32; + + ethash_light_t light = ethash_light_new_internal(cache_size, &seed); + ethash_full_t full = ethash_full_new_internal( + "./test_ethash_directory/", + seed, + full_size, + light, + test_full_callback + ); + BOOST_ASSERT(full); + BOOST_CHECK(g_executed); + BOOST_REQUIRE_EQUAL(g_prev_progress, 100); + + ethash_full_delete(full); + ethash_light_delete(light); + fs::remove_all("./test_ethash_directory/"); +} + +BOOST_AUTO_TEST_CASE(failing_full_client_callback) { + uint64_t full_size; + uint64_t cache_size; + ethash_h256_t seed; + ethash_h256_t hash; + memcpy(&seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); + memcpy(&hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); + + cache_size = 1024; + full_size = 1024 * 32; + + ethash_light_t light = ethash_light_new_internal(cache_size, &seed); + ethash_full_t full = ethash_full_new_internal( + "./test_ethash_directory/", + seed, + full_size, + light, + test_full_callback_that_fails + ); + BOOST_ASSERT(!full); + ethash_light_delete(light); + fs::remove_all("./test_ethash_directory/"); +} + +BOOST_AUTO_TEST_CASE(test_incomplete_dag_file) { + uint64_t full_size; + uint64_t cache_size; + ethash_h256_t seed; + ethash_h256_t hash; + memcpy(&seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); + memcpy(&hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); + + cache_size = 1024; + full_size = 1024 * 32; + + ethash_light_t light = ethash_light_new_internal(cache_size, &seed); + // create a full but stop at 30%, so no magic number is written + ethash_full_t full = ethash_full_new_internal( + "./test_ethash_directory/", + seed, + full_size, + light, + test_full_callback_create_incomplete_dag + ); + BOOST_ASSERT(!full); + FILE *f = NULL; + // confirm that we get a size_mismatch because the magic number is missing + BOOST_REQUIRE_EQUAL( + ETHASH_IO_MEMO_SIZE_MISMATCH, + ethash_io_prepare("./test_ethash_directory/", seed, &f, full_size, false) + ); + ethash_light_delete(light); + fs::remove_all("./test_ethash_directory/"); +} + +BOOST_AUTO_TEST_CASE(test_block22_verification) { + // from POC-9 testnet, epoch 0 + ethash_light_t light = ethash_light_new(22); + ethash_h256_t seedhash = stringToBlockhash("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d"); + BOOST_ASSERT(light); + ethash_return_value_t ret = ethash_light_compute( + light, + seedhash, + 0x495732e0ed7a801cU + ); + BOOST_REQUIRE_EQUAL(blockhashToHexString(&ret.result), "00000b184f1fdd88bfd94c86c39e65db0c36144d5e43f745f722196e730cb614"); + ethash_h256_t difficulty = ethash_h256_static_init(0x2, 0x5, 0x40); + BOOST_REQUIRE(ethash_check_difficulty(&ret.result, &difficulty)); + ethash_light_delete(light); +} + +BOOST_AUTO_TEST_CASE(test_block30001_verification) { + // from POC-9 testnet, epoch 1 + ethash_light_t light = ethash_light_new(30001); + ethash_h256_t seedhash = stringToBlockhash("7e44356ee3441623bc72a683fd3708fdf75e971bbe294f33e539eedad4b92b34"); + BOOST_ASSERT(light); + ethash_return_value_t ret = ethash_light_compute( + light, + seedhash, + 0x318df1c8adef7e5eU + ); + ethash_h256_t difficulty = ethash_h256_static_init(0x17, 0x62, 0xff); + BOOST_REQUIRE(ethash_check_difficulty(&ret.result, &difficulty)); + ethash_light_delete(light); +} + +BOOST_AUTO_TEST_CASE(test_block60000_verification) { + // from POC-9 testnet, epoch 2 + ethash_light_t light = ethash_light_new(60000); + ethash_h256_t seedhash = stringToBlockhash("5fc898f16035bf5ac9c6d9077ae1e3d5fc1ecc3c9fd5bee8bb00e810fdacbaa0"); + BOOST_ASSERT(light); + ethash_return_value_t ret = ethash_light_compute( + light, + seedhash, + 0x50377003e5d830caU + ); + ethash_h256_t difficulty = ethash_h256_static_init(0x25, 0xa6, 0x1e); + BOOST_REQUIRE(ethash_check_difficulty(&ret.result, &difficulty)); + ethash_light_delete(light); +} + +// Test of Full DAG creation with the minimal ethash.h API. +// Commented out since travis tests would take too much time. +// Uncomment and run on your own machine if you want to confirm +// it works fine. +#if 0 +static int progress_cb(unsigned _progress) +{ + printf("CREATING DAG. PROGRESS: %u\n", _progress); + fflush(stdout); + return 0; +} + +BOOST_AUTO_TEST_CASE(full_dag_test) { + ethash_light_t light = ethash_light_new(55); + BOOST_ASSERT(light); + ethash_full_t full = ethash_full_new(light, progress_cb); + BOOST_ASSERT(full); + ethash_light_delete(light); + ethash_full_delete(full); +} +#endif diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.sh b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.sh new file mode 100644 index 0000000000..92b6b8b663 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# Strict mode +set -e + +VALGRIND_ARGS="--tool=memcheck" +VALGRIND_ARGS+=" --leak-check=yes" +VALGRIND_ARGS+=" --track-origins=yes" +VALGRIND_ARGS+=" --show-reachable=yes" +VALGRIND_ARGS+=" --num-callers=20" +VALGRIND_ARGS+=" --track-fds=yes" + +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ]; do + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" +done +TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +rm -rf $TEST_DIR/build +mkdir -p $TEST_DIR/build +cd $TEST_DIR/build ; +cmake ../../.. > /dev/null +make Test +./test/c/Test + +# If we have valgrind also run memory check tests +if hash valgrind 2>/dev/null; then + echo "======== Running tests under valgrind ========"; + cd $TEST_DIR/build/ && valgrind $VALGRIND_ARGS ./test/c/Test +fi diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/.gitignore b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/.gitignore new file mode 100644 index 0000000000..c304fd6150 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/.gitignore @@ -0,0 +1 @@ +python-virtual-env/ diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/requirements.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/requirements.txt new file mode 100644 index 0000000000..378263c627 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/requirements.txt @@ -0,0 +1,3 @@ +pyethereum==0.7.522 +nose==1.3.4 +pysha3==0.3 \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test.sh b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test.sh new file mode 100644 index 0000000000..05c66b550b --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Strict mode +set -e + +if [ -x "$(which virtualenv2)" ] ; then + VIRTUALENV_EXEC=virtualenv2 +elif [ -x "$(which virtualenv)" ] ; then + VIRTUALENV_EXEC=virtualenv +else + echo "Could not find a suitable version of virtualenv" + false +fi + +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ]; do + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" +done +TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +[ -d $TEST_DIR/python-virtual-env ] || $VIRTUALENV_EXEC --system-site-packages $TEST_DIR/python-virtual-env +source $TEST_DIR/python-virtual-env/bin/activate +pip install -r $TEST_DIR/requirements.txt > /dev/null +# force installation of nose in virtualenv even if existing in thereuser's system +pip install nose -I +pip install --upgrade --no-deps --force-reinstall -e $TEST_DIR/../.. +cd $TEST_DIR +nosetests --with-doctest -v --nocapture diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test_pyethash.py b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test_pyethash.py new file mode 100644 index 0000000000..7eb1b60c7b --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test_pyethash.py @@ -0,0 +1,105 @@ +import pyethash +from random import randint + +def test_get_cache_size_not_None(): + for _ in range(100): + block_num = randint(0,12456789) + out = pyethash.get_cache_size(block_num) + assert out != None + +def test_get_full_size_not_None(): + for _ in range(100): + block_num = randint(0,12456789) + out = pyethash.get_full_size(block_num) + assert out != None + +def test_get_cache_size_based_on_EPOCH(): + for _ in range(100): + block_num = randint(0,12456789) + out1 = pyethash.get_cache_size(block_num) + out2 = pyethash.get_cache_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH) + assert out1 == out2 + +def test_get_full_size_based_on_EPOCH(): + for _ in range(100): + block_num = randint(0,12456789) + out1 = pyethash.get_full_size(block_num) + out2 = pyethash.get_full_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH) + assert out1 == out2 + +# See light_and_full_client_checks in test.cpp +def test_mkcache_is_as_expected(): + actual = pyethash.mkcache_bytes( + 1024, + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~").encode('hex') + expected = "2da2b506f21070e1143d908e867962486d6b0a02e31d468fd5e3a7143aafa76a14201f63374314e2a6aaf84ad2eb57105dea3378378965a1b3873453bb2b78f9a8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995c259440b89fa3481c2c33171477c305c8e1e421f8d8f6d59585449d0034f3e421808d8da6bbd0b6378f567647cc6c4ba6c434592b198ad444e7284905b7c6adaf70bf43ec2daa7bd5e8951aa609ab472c124cf9eba3d38cff5091dc3f58409edcc386c743c3bd66f92408796ee1e82dd149eaefbf52b00ce33014a6eb3e50625413b072a58bc01da28262f42cbe4f87d4abc2bf287d15618405a1fe4e386fcdafbb171064bd99901d8f81dd6789396ce5e364ac944bbbd75a7827291c70b42d26385910cd53ca535ab29433dd5c5714d26e0dce95514c5ef866329c12e958097e84462197c2b32087849dab33e88b11da61d52f9dbc0b92cc61f742c07dbbf751c49d7678624ee60dfbe62e5e8c47a03d8247643f3d16ad8c8e663953bcda1f59d7e2d4a9bf0768e789432212621967a8f41121ad1df6ae1fa78782530695414c6213942865b2730375019105cae91a4c17a558d4b63059661d9f108362143107babe0b848de412e4da59168cce82bfbff3c99e022dd6ac1e559db991f2e3f7bb910cefd173e65ed00a8d5d416534e2c8416ff23977dbf3eb7180b75c71580d08ce95efeb9b0afe904ea12285a392aff0c8561ff79fca67f694a62b9e52377485c57cc3598d84cac0a9d27960de0cc31ff9bbfe455acaa62c8aa5d2cce96f345da9afe843d258a99c4eaf3650fc62efd81c7b81cd0d534d2d71eeda7a6e315d540b4473c80f8730037dc2ae3e47b986240cfc65ccc565f0d8cde0bc68a57e39a271dda57440b3598bee19f799611d25731a96b5dbbbefdff6f4f656161462633030d62560ea4e9c161cf78fc96a2ca5aaa32453a6c5dea206f766244e8c9d9a8dc61185ce37f1fc804459c5f07434f8ecb34141b8dcae7eae704c950b55556c5f40140c3714b45eddb02637513268778cbf937a33e4e33183685f9deb31ef54e90161e76d969587dd782eaa94e289420e7c2ee908517f5893a26fdb5873d68f92d118d4bcf98d7a4916794d6ab290045e30f9ea00ca547c584b8482b0331ba1539a0f2714fddc3a0b06b0cfbb6a607b8339c39bcfd6640b1f653e9d70ef6c985b" + assert actual == expected + +def test_calc_dataset_is_not_None(): + cache = pyethash.mkcache_bytes( + 1024, + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") + assert pyethash.calc_dataset_bytes(1024 * 32, cache) != None + +def test_light_and_full_agree(): + cache = pyethash.mkcache_bytes( + 1024, + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") + full_size = 1024 * 32 + header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~" + light_result = pyethash.hashimoto_light(full_size, cache, header, 0) + dataset = pyethash.calc_dataset_bytes(full_size, cache) + full_result = pyethash.hashimoto_full(dataset, header, 0) + assert light_result["mix digest"] != None + assert len(light_result["mix digest"]) == 32 + assert light_result["mix digest"] == full_result["mix digest"] + assert light_result["result"] != None + assert len(light_result["result"]) == 32 + assert light_result["result"] == full_result["result"] + +def int_to_bytes(i): + b = [] + for _ in range(32): + b.append(chr(i & 0xff)) + i >>= 8 + b.reverse() + return "".join(b) + +def test_mining_basic(): + easy_difficulty = int_to_bytes(2**256 - 1) + assert easy_difficulty.encode('hex') == 'f' * 64 + cache = pyethash.mkcache_bytes( + 1024, + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") + full_size = 1024 * 32 + header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~" + dataset = pyethash.calc_dataset_bytes(full_size, cache) + # Check type of outputs + assert type(pyethash.mine(dataset,header,easy_difficulty)) == dict + assert type(pyethash.mine(dataset,header,easy_difficulty)["nonce"]) == long + assert type(pyethash.mine(dataset,header,easy_difficulty)["mix digest"]) == str + assert type(pyethash.mine(dataset,header,easy_difficulty)["result"]) == str + +def test_mining_doesnt_always_return_the_same_value(): + easy_difficulty1 = int_to_bytes(int(2**256 * 0.999)) + # 1 in 1000 difficulty + easy_difficulty2 = int_to_bytes(int(2**256 * 0.001)) + assert easy_difficulty1 != easy_difficulty2 + cache = pyethash.mkcache_bytes( + 1024, + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") + full_size = 1024 * 32 + header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~" + dataset = pyethash.calc_dataset_bytes(full_size, cache) + # Check type of outputs + assert pyethash.mine(dataset, header, easy_difficulty1)['nonce'] != pyethash.mine(dataset, header, easy_difficulty2)['nonce'] + +def test_get_seedhash(): + assert pyethash.get_seedhash(0).encode('hex') == '0' * 64 + import hashlib, sha3 + expected = pyethash.get_seedhash(0) + #print "checking seed hashes:", + for i in range(0, 30000*2048, 30000): + #print i // 30000, + assert pyethash.get_seedhash(i) == expected + expected = hashlib.sha3_256(expected).digest() diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/test.sh b/Godeps/_workspace/src/github.com/ethereum/ethash/test/test.sh new file mode 100644 index 0000000000..aaeaa878c4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/test.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# Strict mode +set -e + +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ]; do + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" +done +TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +echo -e "\n################# Testing JS ##################" +# TODO: Use mocha and real testing tools instead of rolling our own +cd $TEST_DIR/../js +if [ -x "$(which nodejs)" ] ; then + nodejs test.js +fi +if [ -x "$(which node)" ] ; then + node test.js +fi + +echo -e "\n################# Testing C ##################" +$TEST_DIR/c/test.sh + +# Temporarily commenting out python tests until they conform to the API +#echo -e "\n################# Testing Python ##################" +#$TEST_DIR/python/test.sh + +echo "################# Testing Go ##################" +cd $TEST_DIR/.. && go test -timeout 9999s diff --git a/Godeps/_workspace/src/github.com/gizak/termui/.gitignore b/Godeps/_workspace/src/github.com/gizak/termui/.gitignore new file mode 100644 index 0000000000..daf913b1b3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/Godeps/_workspace/src/github.com/gizak/termui/.travis.yml b/Godeps/_workspace/src/github.com/gizak/termui/.travis.yml new file mode 100644 index 0000000000..206e887409 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/.travis.yml @@ -0,0 +1,6 @@ +language: go + +go: + - tip + +script: go test -v ./ \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/gizak/termui/LICENSE b/Godeps/_workspace/src/github.com/gizak/termui/LICENSE new file mode 100644 index 0000000000..311ccc74fb --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Zack Guo + +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/Godeps/_workspace/src/github.com/gizak/termui/README.md b/Godeps/_workspace/src/github.com/gizak/termui/README.md new file mode 100644 index 0000000000..b9bc3024d4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/README.md @@ -0,0 +1,159 @@ +# termui [![Build Status](https://travis-ci.org/gizak/termui.svg?branch=master)](https://travis-ci.org/gizak/termui) [![Doc Status](https://godoc.org/github.com/gizak/termui?status.png)](https://godoc.org/github.com/gizak/termui) + +## Update 23/06/2015 +Pull requests and master branch are freezing, waiting for merging from `refactoring` branch. + +## Notice +termui comes with ABSOLUTELY NO WARRANTY, and there is a breaking change coming up (see refactoring branch) which will change the `Bufferer` interface and many others. These changes reduce calculation overhead and introduce a new drawing buffer with better capacibilities. We will step into the next stage (call it beta) after merging these changes. + +## Introduction +Go terminal dashboard. Inspired by [blessed-contrib](https://github.com/yaronn/blessed-contrib), but purely in Go. + +Cross-platform, easy to compile, and fully-customizable. + +__Demo:__ (cast under osx 10.10; Terminal.app; Menlo Regular 12pt.) + +demo + +__Grid layout:__ + +Expressive syntax, using [12 columns grid system](http://www.w3schools.com/bootstrap/bootstrap_grid_system.asp) +```go + import ui "github.com/gizak/termui" + // init and create widgets... + + // build + ui.Body.AddRows( + ui.NewRow( + ui.NewCol(6, 0, widget0), + ui.NewCol(6, 0, widget1)), + ui.NewRow( + ui.NewCol(3, 0, widget2), + ui.NewCol(3, 0, widget30, widget31, widget32), + ui.NewCol(6, 0, widget4))) + + // calculate layout + ui.Body.Align() + + ui.Render(ui.Body) +``` +[demo code:](https://github.com/gizak/termui/blob/master/example/grid.go) + +grid + +## Installation + + go get github.com/gizak/termui + +## Usage + +Each component's layout is a bit like HTML block (box model), which has border and padding. + +The `Border` property can be chosen to hide or display (with its border label), when it comes to display, the label takes 1 padding space (i.e. in css: `padding: 1;`, innerHeight and innerWidth therefore shrunk by 1). + +`````go + import ui "github.com/gizak/termui" // <- ui shortcut, optional + + func main() { + err := ui.Init() + if err != nil { + panic(err) + } + defer ui.Close() + + p := ui.NewPar(":PRESS q TO QUIT DEMO") + p.Height = 3 + p.Width = 50 + p.TextFgColor = ui.ColorWhite + p.Border.Label = "Text Box" + p.Border.FgColor = ui.ColorCyan + + g := ui.NewGauge() + g.Percent = 50 + g.Width = 50 + g.Height = 3 + g.Y = 11 + g.Border.Label = "Gauge" + g.BarColor = ui.ColorRed + g.Border.FgColor = ui.ColorWhite + g.Border.LabelFgColor = ui.ColorCyan + + ui.Render(p, g) + + // event handler... + } +````` + +Note that components can be overlapped (I'd rather call this a feature...), `Render(rs ...Renderer)` renders its args from left to right (i.e. each component's weight is arising from left to right). + +## Themes + +_All_ colors in _all_ components can be changed at _any_ time, while there provides some predefined color schemes: + +```go +// for now there are only two themes: default and helloworld +termui.UseTheme("helloworld") + +// create components... +``` +The `default ` theme's settings depend on the user's terminal color scheme, which is saying if your terminal default font color is white and background is white, it will be like: + +default + +The `helloworld` color scheme drops in some colors! + +helloworld + +## Widgets + +#### Par + +[demo code](https://github.com/gizak/termui/blob/master/example/par.go) + +par + +#### List +[demo code](https://github.com/gizak/termui/blob/master/example/list.go) + +list + +#### Gauge +[demo code](https://github.com/gizak/termui/blob/master/example/gauge.go) + +gauge + +#### Line Chart +[demo code](https://github.com/gizak/termui/blob/master/example/linechart.go) + +linechart + +#### Bar Chart +[demo code](https://github.com/gizak/termui/blob/master/example/barchart.go) + +barchart + +#### Mult-Bar / Stacked-Bar Chart +[demo code](https://github.com/gizak/termui/blob/master/example/mbarchart.go) + +barchart + +#### Sparklines +[demo code](https://github.com/gizak/termui/blob/master/example/sparklines.go) + +sparklines + + +## GoDoc + +[godoc](https://godoc.org/github.com/gizak/termui) + +## TODO + +- [x] Grid layout +- [ ] Event system +- [ ] Canvas widget +- [ ] Refine APIs +- [ ] Focusable widgets + +## License +This library is under the [MIT License](http://opensource.org/licenses/MIT) diff --git a/Godeps/_workspace/src/github.com/gizak/termui/bar.go b/Godeps/_workspace/src/github.com/gizak/termui/bar.go new file mode 100644 index 0000000000..57bae0ae8d --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/bar.go @@ -0,0 +1,135 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +import "fmt" + +// BarChart creates multiple bars in a widget: +/* + bc := termui.NewBarChart() + data := []int{3, 2, 5, 3, 9, 5} + bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"} + bc.Border.Label = "Bar Chart" + bc.Data = data + bc.Width = 26 + bc.Height = 10 + bc.DataLabels = bclabels + bc.TextColor = termui.ColorGreen + bc.BarColor = termui.ColorRed + bc.NumColor = termui.ColorYellow +*/ +type BarChart struct { + Block + BarColor Attribute + TextColor Attribute + NumColor Attribute + Data []int + DataLabels []string + BarWidth int + BarGap int + labels [][]rune + dataNum [][]rune + numBar int + scale float64 + max int +} + +// NewBarChart returns a new *BarChart with current theme. +func NewBarChart() *BarChart { + bc := &BarChart{Block: *NewBlock()} + bc.BarColor = theme.BarChartBar + bc.NumColor = theme.BarChartNum + bc.TextColor = theme.BarChartText + bc.BarGap = 1 + bc.BarWidth = 3 + return bc +} + +func (bc *BarChart) layout() { + bc.numBar = bc.innerWidth / (bc.BarGap + bc.BarWidth) + bc.labels = make([][]rune, bc.numBar) + bc.dataNum = make([][]rune, len(bc.Data)) + + for i := 0; i < bc.numBar && i < len(bc.DataLabels) && i < len(bc.Data); i++ { + bc.labels[i] = trimStr2Runes(bc.DataLabels[i], bc.BarWidth) + n := bc.Data[i] + s := fmt.Sprint(n) + bc.dataNum[i] = trimStr2Runes(s, bc.BarWidth) + } + + //bc.max = bc.Data[0] // what if Data is nil? Sometimes when bar graph is nill it produces panic with panic: runtime error: index out of range + // Asign a negative value to get maxvalue auto-populates + if bc.max == 0 { + bc.max = -1 + } + for i := 0; i < len(bc.Data); i++ { + if bc.max < bc.Data[i] { + bc.max = bc.Data[i] + } + } + bc.scale = float64(bc.max) / float64(bc.innerHeight-1) +} + +func (bc *BarChart) SetMax(max int) { + + if max > 0 { + bc.max = max + } +} + +// Buffer implements Bufferer interface. +func (bc *BarChart) Buffer() []Point { + ps := bc.Block.Buffer() + bc.layout() + + for i := 0; i < bc.numBar && i < len(bc.Data) && i < len(bc.DataLabels); i++ { + h := int(float64(bc.Data[i]) / bc.scale) + oftX := i * (bc.BarWidth + bc.BarGap) + // plot bar + for j := 0; j < bc.BarWidth; j++ { + for k := 0; k < h; k++ { + p := Point{} + p.Ch = ' ' + p.Bg = bc.BarColor + if bc.BarColor == ColorDefault { // when color is default, space char treated as transparent! + p.Bg |= AttrReverse + } + p.X = bc.innerX + i*(bc.BarWidth+bc.BarGap) + j + p.Y = bc.innerY + bc.innerHeight - 2 - k + ps = append(ps, p) + } + } + // plot text + for j, k := 0, 0; j < len(bc.labels[i]); j++ { + w := charWidth(bc.labels[i][j]) + p := Point{} + p.Ch = bc.labels[i][j] + p.Bg = bc.BgColor + p.Fg = bc.TextColor + p.Y = bc.innerY + bc.innerHeight - 1 + p.X = bc.innerX + oftX + k + ps = append(ps, p) + k += w + } + // plot num + for j := 0; j < len(bc.dataNum[i]); j++ { + p := Point{} + p.Ch = bc.dataNum[i][j] + p.Fg = bc.NumColor + p.Bg = bc.BarColor + if bc.BarColor == ColorDefault { // the same as above + p.Bg |= AttrReverse + } + if h == 0 { + p.Bg = bc.BgColor + } + p.X = bc.innerX + oftX + (bc.BarWidth-len(bc.dataNum[i]))/2 + j + p.Y = bc.innerY + bc.innerHeight - 2 + ps = append(ps, p) + } + } + + return bc.Block.chopOverflow(ps) +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/block.go b/Godeps/_workspace/src/github.com/gizak/termui/block.go new file mode 100644 index 0000000000..9531365966 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/block.go @@ -0,0 +1,142 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +// Block is a base struct for all other upper level widgets, +// consider it as css: display:block. +// Normally you do not need to create it manually. +type Block struct { + X int + Y int + Border labeledBorder + IsDisplay bool + HasBorder bool + BgColor Attribute + Width int + Height int + innerWidth int + innerHeight int + innerX int + innerY int + PaddingTop int + PaddingBottom int + PaddingLeft int + PaddingRight int +} + +// NewBlock returns a *Block which inherits styles from current theme. +func NewBlock() *Block { + d := Block{} + d.IsDisplay = true + d.HasBorder = theme.HasBorder + d.Border.BgColor = theme.BorderBg + d.Border.FgColor = theme.BorderFg + d.Border.LabelBgColor = theme.BorderLabelTextBg + d.Border.LabelFgColor = theme.BorderLabelTextFg + d.BgColor = theme.BlockBg + d.Width = 2 + d.Height = 2 + return &d +} + +// compute box model +func (d *Block) align() { + d.innerWidth = d.Width - d.PaddingLeft - d.PaddingRight + d.innerHeight = d.Height - d.PaddingTop - d.PaddingBottom + d.innerX = d.X + d.PaddingLeft + d.innerY = d.Y + d.PaddingTop + + if d.HasBorder { + d.innerHeight -= 2 + d.innerWidth -= 2 + d.Border.X = d.X + d.Border.Y = d.Y + d.Border.Width = d.Width + d.Border.Height = d.Height + d.innerX++ + d.innerY++ + } + + if d.innerHeight < 0 { + d.innerHeight = 0 + } + if d.innerWidth < 0 { + d.innerWidth = 0 + } + +} + +// InnerBounds returns the internal bounds of the block after aligning and +// calculating the padding and border, if any. +func (d *Block) InnerBounds() (x, y, width, height int) { + d.align() + return d.innerX, d.innerY, d.innerWidth, d.innerHeight +} + +// Buffer implements Bufferer interface. +// Draw background and border (if any). +func (d *Block) Buffer() []Point { + d.align() + + ps := []Point{} + if !d.IsDisplay { + return ps + } + + if d.HasBorder { + ps = d.Border.Buffer() + } + + for i := 0; i < d.innerWidth; i++ { + for j := 0; j < d.innerHeight; j++ { + p := Point{} + p.X = d.X + 1 + i + p.Y = d.Y + 1 + j + p.Ch = ' ' + p.Bg = d.BgColor + ps = append(ps, p) + } + } + return ps +} + +// GetHeight implements GridBufferer. +// It returns current height of the block. +func (d Block) GetHeight() int { + return d.Height +} + +// SetX implements GridBufferer interface, which sets block's x position. +func (d *Block) SetX(x int) { + d.X = x +} + +// SetY implements GridBufferer interface, it sets y position for block. +func (d *Block) SetY(y int) { + d.Y = y +} + +// SetWidth implements GridBuffer interface, it sets block's width. +func (d *Block) SetWidth(w int) { + d.Width = w +} + +// chop the overflow parts +func (d *Block) chopOverflow(ps []Point) []Point { + nps := make([]Point, 0, len(ps)) + x := d.X + y := d.Y + w := d.Width + h := d.Height + for _, v := range ps { + if v.X >= x && + v.X < x+w && + v.Y >= y && + v.Y < y+h { + nps = append(nps, v) + } + } + return nps +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/block_test.go b/Godeps/_workspace/src/github.com/gizak/termui/block_test.go new file mode 100644 index 0000000000..2de205b21f --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/block_test.go @@ -0,0 +1,46 @@ +package termui + +import "testing" + +func TestBlock_InnerBounds(t *testing.T) { + b := NewBlock() + b.X = 10 + b.Y = 11 + b.Width = 12 + b.Height = 13 + + assert := func(name string, x, y, w, h int) { + t.Log(name) + cx, cy, cw, ch := b.InnerBounds() + if cx != x { + t.Errorf("expected x to be %d but got %d", x, cx) + } + if cy != y { + t.Errorf("expected y to be %d but got %d", y, cy) + } + if cw != w { + t.Errorf("expected width to be %d but got %d", w, cw) + } + if ch != h { + t.Errorf("expected height to be %d but got %d", h, ch) + } + } + + b.HasBorder = false + assert("no border, no padding", 10, 11, 12, 13) + + b.HasBorder = true + assert("border, no padding", 11, 12, 10, 11) + + b.PaddingBottom = 2 + assert("border, 2b padding", 11, 12, 10, 9) + + b.PaddingTop = 3 + assert("border, 2b 3t padding", 11, 15, 10, 6) + + b.PaddingLeft = 4 + assert("border, 2b 3t 4l padding", 15, 15, 6, 6) + + b.PaddingRight = 5 + assert("border, 2b 3t 4l 5r padding", 15, 15, 1, 6) +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/box.go b/Godeps/_workspace/src/github.com/gizak/termui/box.go new file mode 100644 index 0000000000..1dcfd86925 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/box.go @@ -0,0 +1,117 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +type border struct { + X int + Y int + Width int + Height int + FgColor Attribute + BgColor Attribute +} + +type hline struct { + X int + Y int + Length int + FgColor Attribute + BgColor Attribute +} + +type vline struct { + X int + Y int + Length int + FgColor Attribute + BgColor Attribute +} + +// Draw a horizontal line. +func (l hline) Buffer() []Point { + pts := make([]Point, l.Length) + for i := 0; i < l.Length; i++ { + pts[i].X = l.X + i + pts[i].Y = l.Y + pts[i].Ch = HORIZONTAL_LINE + pts[i].Bg = l.BgColor + pts[i].Fg = l.FgColor + } + return pts +} + +// Draw a vertical line. +func (l vline) Buffer() []Point { + pts := make([]Point, l.Length) + for i := 0; i < l.Length; i++ { + pts[i].X = l.X + pts[i].Y = l.Y + i + pts[i].Ch = VERTICAL_LINE + pts[i].Bg = l.BgColor + pts[i].Fg = l.FgColor + } + return pts +} + +// Draw a box border. +func (b border) Buffer() []Point { + if b.Width < 2 || b.Height < 2 { + return nil + } + pts := make([]Point, 2*b.Width+2*b.Height-4) + + pts[0].X = b.X + pts[0].Y = b.Y + pts[0].Fg = b.FgColor + pts[0].Bg = b.BgColor + pts[0].Ch = TOP_LEFT + + pts[1].X = b.X + b.Width - 1 + pts[1].Y = b.Y + pts[1].Fg = b.FgColor + pts[1].Bg = b.BgColor + pts[1].Ch = TOP_RIGHT + + pts[2].X = b.X + pts[2].Y = b.Y + b.Height - 1 + pts[2].Fg = b.FgColor + pts[2].Bg = b.BgColor + pts[2].Ch = BOTTOM_LEFT + + pts[3].X = b.X + b.Width - 1 + pts[3].Y = b.Y + b.Height - 1 + pts[3].Fg = b.FgColor + pts[3].Bg = b.BgColor + pts[3].Ch = BOTTOM_RIGHT + + copy(pts[4:], (hline{b.X + 1, b.Y, b.Width - 2, b.FgColor, b.BgColor}).Buffer()) + copy(pts[4+b.Width-2:], (hline{b.X + 1, b.Y + b.Height - 1, b.Width - 2, b.FgColor, b.BgColor}).Buffer()) + copy(pts[4+2*b.Width-4:], (vline{b.X, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer()) + copy(pts[4+2*b.Width-4+b.Height-2:], (vline{b.X + b.Width - 1, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer()) + + return pts +} + +type labeledBorder struct { + border + Label string + LabelFgColor Attribute + LabelBgColor Attribute +} + +// Draw a box border with label. +func (lb labeledBorder) Buffer() []Point { + ps := lb.border.Buffer() + maxTxtW := lb.Width - 2 + rs := trimStr2Runes(lb.Label, maxTxtW) + + for i, j, w := 0, 0, 0; i < len(rs); i++ { + w = charWidth(rs[i]) + ps = append(ps, newPointWithAttrs(rs[i], lb.X+1+j, lb.Y, lb.LabelFgColor, lb.LabelBgColor)) + j += w + } + + return ps +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/box_others.go b/Godeps/_workspace/src/github.com/gizak/termui/box_others.go new file mode 100644 index 0000000000..bcc3d7ded9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/box_others.go @@ -0,0 +1,14 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build !windows + +package termui + +const TOP_RIGHT = 'â”' +const VERTICAL_LINE = '│' +const HORIZONTAL_LINE = '─' +const TOP_LEFT = '┌' +const BOTTOM_RIGHT = '┘' +const BOTTOM_LEFT = 'â””' diff --git a/Godeps/_workspace/src/github.com/gizak/termui/box_windows.go b/Godeps/_workspace/src/github.com/gizak/termui/box_windows.go new file mode 100644 index 0000000000..dd39019fe7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/box_windows.go @@ -0,0 +1,14 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build windows + +package termui + +const TOP_RIGHT = '+' +const VERTICAL_LINE = '|' +const HORIZONTAL_LINE = '-' +const TOP_LEFT = '+' +const BOTTOM_RIGHT = '+' +const BOTTOM_LEFT = '+' diff --git a/Godeps/_workspace/src/github.com/gizak/termui/canvas.go b/Godeps/_workspace/src/github.com/gizak/termui/canvas.go new file mode 100644 index 0000000000..614635ee4e --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/canvas.go @@ -0,0 +1,74 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +/* +dots: + ,___, + |1 4| + |2 5| + |3 6| + |7 8| + ````` +*/ + +var brailleBase = '\u2800' + +var brailleOftMap = [4][2]rune{ + {'\u0001', '\u0008'}, + {'\u0002', '\u0010'}, + {'\u0004', '\u0020'}, + {'\u0040', '\u0080'}} + +// Canvas contains drawing map: i,j -> rune +type Canvas map[[2]int]rune + +// NewCanvas returns an empty Canvas +func NewCanvas() Canvas { + return make(map[[2]int]rune) +} + +func chOft(x, y int) rune { + return brailleOftMap[y%4][x%2] +} + +func (c Canvas) rawCh(x, y int) rune { + if ch, ok := c[[2]int{x, y}]; ok { + return ch + } + return '\u0000' //brailleOffset +} + +// return coordinate in terminal +func chPos(x, y int) (int, int) { + return y / 4, x / 2 +} + +// Set sets a point (x,y) in the virtual coordinate +func (c Canvas) Set(x, y int) { + i, j := chPos(x, y) + ch := c.rawCh(i, j) + ch |= chOft(x, y) + c[[2]int{i, j}] = ch +} + +// Unset removes point (x,y) +func (c Canvas) Unset(x, y int) { + i, j := chPos(x, y) + ch := c.rawCh(i, j) + ch &= ^chOft(x, y) + c[[2]int{i, j}] = ch +} + +// Buffer returns un-styled points +func (c Canvas) Buffer() []Point { + ps := make([]Point, len(c)) + i := 0 + for k, v := range c { + ps[i] = newPoint(v+brailleBase, k[0], k[1]) + i++ + } + return ps +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/canvas_test.go b/Godeps/_workspace/src/github.com/gizak/termui/canvas_test.go new file mode 100644 index 0000000000..021949ced7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/canvas_test.go @@ -0,0 +1,55 @@ +package termui + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" +) + +func TestCanvasSet(t *testing.T) { + c := NewCanvas() + c.Set(0, 0) + c.Set(0, 1) + c.Set(0, 2) + c.Set(0, 3) + c.Set(1, 3) + c.Set(2, 3) + c.Set(3, 3) + c.Set(4, 3) + c.Set(5, 3) + spew.Dump(c) +} + +func TestCanvasUnset(t *testing.T) { + c := NewCanvas() + c.Set(0, 0) + c.Set(0, 1) + c.Set(0, 2) + c.Unset(0, 2) + spew.Dump(c) + c.Unset(0, 3) + spew.Dump(c) +} + +func TestCanvasBuffer(t *testing.T) { + c := NewCanvas() + c.Set(0, 0) + c.Set(0, 1) + c.Set(0, 2) + c.Set(0, 3) + c.Set(1, 3) + c.Set(2, 3) + c.Set(3, 3) + c.Set(4, 3) + c.Set(5, 3) + c.Set(6, 3) + c.Set(7, 2) + c.Set(8, 1) + c.Set(9, 0) + bufs := c.Buffer() + rs := make([]rune, len(bufs)) + for i, v := range bufs { + rs[i] = v.Ch + } + spew.Dump(string(rs)) +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/chart.go b/Godeps/_workspace/src/github.com/gizak/termui/chart.go new file mode 100644 index 0000000000..d6fb8bc7df --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/chart.go @@ -0,0 +1,336 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +import ( + "fmt" + "math" +) + +// only 16 possible combinations, why bother +var braillePatterns = map[[2]int]rune{ + [2]int{0, 0}: '⣀', + [2]int{0, 1}: 'â¡ ', + [2]int{0, 2}: 'â¡', + [2]int{0, 3}: '⡈', + + [2]int{1, 0}: '⢄', + [2]int{1, 1}: 'â ¤', + [2]int{1, 2}: 'â ”', + [2]int{1, 3}: 'â Œ', + + [2]int{2, 0}: '⢂', + [2]int{2, 1}: 'â ¢', + [2]int{2, 2}: 'â ’', + [2]int{2, 3}: 'â Š', + + [2]int{3, 0}: 'â¢', + [2]int{3, 1}: 'â ¡', + [2]int{3, 2}: 'â ‘', + [2]int{3, 3}: 'â ‰', +} + +var lSingleBraille = [4]rune{'\u2840', 'â „', 'â ‚', 'â '} +var rSingleBraille = [4]rune{'\u2880', 'â  ', 'â ', 'â ˆ'} + +// LineChart has two modes: braille(default) and dot. Using braille gives 2x capicity as dot mode, +// because one braille char can represent two data points. +/* + lc := termui.NewLineChart() + lc.Border.Label = "braille-mode Line Chart" + lc.Data = [1.2, 1.3, 1.5, 1.7, 1.5, 1.6, 1.8, 2.0] + lc.Width = 50 + lc.Height = 12 + lc.AxesColor = termui.ColorWhite + lc.LineColor = termui.ColorGreen | termui.AttrBold + // termui.Render(lc)... +*/ +type LineChart struct { + Block + Data []float64 + DataLabels []string // if unset, the data indices will be used + Mode string // braille | dot + DotStyle rune + LineColor Attribute + scale float64 // data span per cell on y-axis + AxesColor Attribute + drawingX int + drawingY int + axisYHeight int + axisXWidth int + axisYLebelGap int + axisXLebelGap int + topValue float64 + bottomValue float64 + labelX [][]rune + labelY [][]rune + labelYSpace int + maxY float64 + minY float64 +} + +// NewLineChart returns a new LineChart with current theme. +func NewLineChart() *LineChart { + lc := &LineChart{Block: *NewBlock()} + lc.AxesColor = theme.LineChartAxes + lc.LineColor = theme.LineChartLine + lc.Mode = "braille" + lc.DotStyle = '•' + lc.axisXLebelGap = 2 + lc.axisYLebelGap = 1 + lc.bottomValue = math.Inf(1) + lc.topValue = math.Inf(-1) + return lc +} + +// one cell contains two data points +// so the capicity is 2x as dot-mode +func (lc *LineChart) renderBraille() []Point { + ps := []Point{} + + // return: b -> which cell should the point be in + // m -> in the cell, divided into 4 equal height levels, which subcell? + getPos := func(d float64) (b, m int) { + cnt4 := int((d-lc.bottomValue)/(lc.scale/4) + 0.5) + b = cnt4 / 4 + m = cnt4 % 4 + return + } + // plot points + for i := 0; 2*i+1 < len(lc.Data) && i < lc.axisXWidth; i++ { + b0, m0 := getPos(lc.Data[2*i]) + b1, m1 := getPos(lc.Data[2*i+1]) + + if b0 == b1 { + p := Point{} + p.Ch = braillePatterns[[2]int{m0, m1}] + p.Bg = lc.BgColor + p.Fg = lc.LineColor + p.Y = lc.innerY + lc.innerHeight - 3 - b0 + p.X = lc.innerX + lc.labelYSpace + 1 + i + ps = append(ps, p) + } else { + p0 := newPointWithAttrs(lSingleBraille[m0], + lc.innerX+lc.labelYSpace+1+i, + lc.innerY+lc.innerHeight-3-b0, + lc.LineColor, + lc.BgColor) + p1 := newPointWithAttrs(rSingleBraille[m1], + lc.innerX+lc.labelYSpace+1+i, + lc.innerY+lc.innerHeight-3-b1, + lc.LineColor, + lc.BgColor) + ps = append(ps, p0, p1) + } + + } + return ps +} + +func (lc *LineChart) renderDot() []Point { + ps := []Point{} + for i := 0; i < len(lc.Data) && i < lc.axisXWidth; i++ { + p := Point{} + p.Ch = lc.DotStyle + p.Fg = lc.LineColor + p.Bg = lc.BgColor + p.X = lc.innerX + lc.labelYSpace + 1 + i + p.Y = lc.innerY + lc.innerHeight - 3 - int((lc.Data[i]-lc.bottomValue)/lc.scale+0.5) + ps = append(ps, p) + } + + return ps +} + +func (lc *LineChart) calcLabelX() { + lc.labelX = [][]rune{} + + for i, l := 0, 0; i < len(lc.DataLabels) && l < lc.axisXWidth; i++ { + if lc.Mode == "dot" { + if l >= len(lc.DataLabels) { + break + } + + s := str2runes(lc.DataLabels[l]) + w := strWidth(lc.DataLabels[l]) + if l+w <= lc.axisXWidth { + lc.labelX = append(lc.labelX, s) + } + l += w + lc.axisXLebelGap + } else { // braille + if 2*l >= len(lc.DataLabels) { + break + } + + s := str2runes(lc.DataLabels[2*l]) + w := strWidth(lc.DataLabels[2*l]) + if l+w <= lc.axisXWidth { + lc.labelX = append(lc.labelX, s) + } + l += w + lc.axisXLebelGap + + } + } +} + +func shortenFloatVal(x float64) string { + s := fmt.Sprintf("%.2f", x) + if len(s)-3 > 3 { + s = fmt.Sprintf("%.2e", x) + } + + if x < 0 { + s = fmt.Sprintf("%.2f", x) + } + return s +} + +func (lc *LineChart) calcLabelY() { + span := lc.topValue - lc.bottomValue + lc.scale = span / float64(lc.axisYHeight) + + n := (1 + lc.axisYHeight) / (lc.axisYLebelGap + 1) + lc.labelY = make([][]rune, n) + maxLen := 0 + for i := 0; i < n; i++ { + s := str2runes(shortenFloatVal(lc.bottomValue + float64(i)*span/float64(n))) + if len(s) > maxLen { + maxLen = len(s) + } + lc.labelY[i] = s + } + + lc.labelYSpace = maxLen +} + +func (lc *LineChart) calcLayout() { + // set datalabels if it is not provided + if lc.DataLabels == nil || len(lc.DataLabels) == 0 { + lc.DataLabels = make([]string, len(lc.Data)) + for i := range lc.Data { + lc.DataLabels[i] = fmt.Sprint(i) + } + } + + // lazy increase, to avoid y shaking frequently + // update bound Y when drawing is gonna overflow + lc.minY = lc.Data[0] + lc.maxY = lc.Data[0] + + // valid visible range + vrange := lc.innerWidth + if lc.Mode == "braille" { + vrange = 2 * lc.innerWidth + } + if vrange > len(lc.Data) { + vrange = len(lc.Data) + } + + for _, v := range lc.Data[:vrange] { + if v > lc.maxY { + lc.maxY = v + } + if v < lc.minY { + lc.minY = v + } + } + + span := lc.maxY - lc.minY + + if lc.minY < lc.bottomValue { + lc.bottomValue = lc.minY - 0.2*span + } + + if lc.maxY > lc.topValue { + lc.topValue = lc.maxY + 0.2*span + } + + lc.axisYHeight = lc.innerHeight - 2 + lc.calcLabelY() + + lc.axisXWidth = lc.innerWidth - 1 - lc.labelYSpace + lc.calcLabelX() + + lc.drawingX = lc.innerX + 1 + lc.labelYSpace + lc.drawingY = lc.innerY +} + +func (lc *LineChart) plotAxes() []Point { + origY := lc.innerY + lc.innerHeight - 2 + origX := lc.innerX + lc.labelYSpace + + ps := []Point{newPointWithAttrs(ORIGIN, origX, origY, lc.AxesColor, lc.BgColor)} + + for x := origX + 1; x < origX+lc.axisXWidth; x++ { + p := Point{} + p.X = x + p.Y = origY + p.Bg = lc.BgColor + p.Fg = lc.AxesColor + p.Ch = HDASH + ps = append(ps, p) + } + + for dy := 1; dy <= lc.axisYHeight; dy++ { + p := Point{} + p.X = origX + p.Y = origY - dy + p.Bg = lc.BgColor + p.Fg = lc.AxesColor + p.Ch = VDASH + ps = append(ps, p) + } + + // x label + oft := 0 + for _, rs := range lc.labelX { + if oft+len(rs) > lc.axisXWidth { + break + } + for j, r := range rs { + p := Point{} + p.Ch = r + p.Fg = lc.AxesColor + p.Bg = lc.BgColor + p.X = origX + oft + j + p.Y = lc.innerY + lc.innerHeight - 1 + ps = append(ps, p) + } + oft += len(rs) + lc.axisXLebelGap + } + + // y labels + for i, rs := range lc.labelY { + for j, r := range rs { + p := Point{} + p.Ch = r + p.Fg = lc.AxesColor + p.Bg = lc.BgColor + p.X = lc.innerX + j + p.Y = origY - i*(lc.axisYLebelGap+1) + ps = append(ps, p) + } + } + + return ps +} + +// Buffer implements Bufferer interface. +func (lc *LineChart) Buffer() []Point { + ps := lc.Block.Buffer() + if lc.Data == nil || len(lc.Data) == 0 { + return ps + } + lc.calcLayout() + ps = append(ps, lc.plotAxes()...) + + if lc.Mode == "dot" { + ps = append(ps, lc.renderDot()...) + } else { + ps = append(ps, lc.renderBraille()...) + } + + return lc.Block.chopOverflow(ps) +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/chart_others.go b/Godeps/_workspace/src/github.com/gizak/termui/chart_others.go new file mode 100644 index 0000000000..8911873b63 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/chart_others.go @@ -0,0 +1,11 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build !windows + +package termui + +const VDASH = '┊' +const HDASH = '┈' +const ORIGIN = 'â””' diff --git a/Godeps/_workspace/src/github.com/gizak/termui/chart_windows.go b/Godeps/_workspace/src/github.com/gizak/termui/chart_windows.go new file mode 100644 index 0000000000..9f9a5e96c0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/chart_windows.go @@ -0,0 +1,11 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build windows + +package termui + +const VDASH = '|' +const HDASH = '-' +const ORIGIN = '+' diff --git a/Godeps/_workspace/src/github.com/gizak/termui/doc.go b/Godeps/_workspace/src/github.com/gizak/termui/doc.go new file mode 100644 index 0000000000..43f886f552 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/doc.go @@ -0,0 +1,27 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +/* +Package termui is a library designed for creating command line UI. For more info, goto http://github.com/gizak/termui + +A simplest example: + package main + + import ui "github.com/gizak/termui" + + func main() { + if err:=ui.Init(); err != nil { + panic(err) + } + defer ui.Close() + + g := ui.NewGauge() + g.Percent = 50 + g.Width = 50 + g.Border.Label = "Gauge" + + ui.Render(g) + } +*/ +package termui diff --git a/Godeps/_workspace/src/github.com/gizak/termui/events.go b/Godeps/_workspace/src/github.com/gizak/termui/events.go new file mode 100644 index 0000000000..23a189b56a --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/events.go @@ -0,0 +1,219 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. +// +// Portions of this file uses [termbox-go](https://github.com/nsf/termbox-go/blob/54b74d087b7c397c402d0e3b66d2ccb6eaf5c2b4/api_common.go) +// by [authors](https://github.com/nsf/termbox-go/blob/master/AUTHORS) +// under [license](https://github.com/nsf/termbox-go/blob/master/LICENSE) + +package termui + +import "github.com/nsf/termbox-go" + +/***********************************termbox-go**************************************/ + +type ( + EventType uint8 + Modifier uint8 + Key uint16 +) + +// This type represents a termbox event. The 'Mod', 'Key' and 'Ch' fields are +// valid if 'Type' is EventKey. The 'Width' and 'Height' fields are valid if +// 'Type' is EventResize. The 'Err' field is valid if 'Type' is EventError. +type Event struct { + Type EventType // one of Event* constants + Mod Modifier // one of Mod* constants or 0 + Key Key // one of Key* constants, invalid if 'Ch' is not 0 + Ch rune // a unicode character + Width int // width of the screen + Height int // height of the screen + Err error // error in case if input failed + MouseX int // x coord of mouse + MouseY int // y coord of mouse + N int // number of bytes written when getting a raw event +} + +const ( + KeyF1 Key = 0xFFFF - iota + KeyF2 + KeyF3 + KeyF4 + KeyF5 + KeyF6 + KeyF7 + KeyF8 + KeyF9 + KeyF10 + KeyF11 + KeyF12 + KeyInsert + KeyDelete + KeyHome + KeyEnd + KeyPgup + KeyPgdn + KeyArrowUp + KeyArrowDown + KeyArrowLeft + KeyArrowRight + key_min // see terminfo + MouseLeft + MouseMiddle + MouseRight +) + +const ( + KeyCtrlTilde Key = 0x00 + KeyCtrl2 Key = 0x00 + KeyCtrlSpace Key = 0x00 + KeyCtrlA Key = 0x01 + KeyCtrlB Key = 0x02 + KeyCtrlC Key = 0x03 + KeyCtrlD Key = 0x04 + KeyCtrlE Key = 0x05 + KeyCtrlF Key = 0x06 + KeyCtrlG Key = 0x07 + KeyBackspace Key = 0x08 + KeyCtrlH Key = 0x08 + KeyTab Key = 0x09 + KeyCtrlI Key = 0x09 + KeyCtrlJ Key = 0x0A + KeyCtrlK Key = 0x0B + KeyCtrlL Key = 0x0C + KeyEnter Key = 0x0D + KeyCtrlM Key = 0x0D + KeyCtrlN Key = 0x0E + KeyCtrlO Key = 0x0F + KeyCtrlP Key = 0x10 + KeyCtrlQ Key = 0x11 + KeyCtrlR Key = 0x12 + KeyCtrlS Key = 0x13 + KeyCtrlT Key = 0x14 + KeyCtrlU Key = 0x15 + KeyCtrlV Key = 0x16 + KeyCtrlW Key = 0x17 + KeyCtrlX Key = 0x18 + KeyCtrlY Key = 0x19 + KeyCtrlZ Key = 0x1A + KeyEsc Key = 0x1B + KeyCtrlLsqBracket Key = 0x1B + KeyCtrl3 Key = 0x1B + KeyCtrl4 Key = 0x1C + KeyCtrlBackslash Key = 0x1C + KeyCtrl5 Key = 0x1D + KeyCtrlRsqBracket Key = 0x1D + KeyCtrl6 Key = 0x1E + KeyCtrl7 Key = 0x1F + KeyCtrlSlash Key = 0x1F + KeyCtrlUnderscore Key = 0x1F + KeySpace Key = 0x20 + KeyBackspace2 Key = 0x7F + KeyCtrl8 Key = 0x7F +) + +// Alt modifier constant, see Event.Mod field and SetInputMode function. +const ( + ModAlt Modifier = 0x01 +) + +// Event type. See Event.Type field. +const ( + EventKey EventType = iota + EventResize + EventMouse + EventError + EventInterrupt + EventRaw + EventNone +) + +/**************************************end**************************************/ + +// convert termbox.Event to termui.Event +func uiEvt(e termbox.Event) Event { + event := Event{} + event.Type = EventType(e.Type) + event.Mod = Modifier(e.Mod) + event.Key = Key(e.Key) + event.Ch = e.Ch + event.Width = e.Width + event.Height = e.Height + event.Err = e.Err + event.MouseX = e.MouseX + event.MouseY = e.MouseY + event.N = e.N + + return event +} + +var evtChs = make([]chan Event, 0) + +// EventCh returns an output-only event channel. +// This function can be called many times (multiplexer). +func EventCh() <-chan Event { + out := make(chan Event) + evtChs = append(evtChs, out) + return out +} + +// turn on event listener +func evtListen() { + go func() { + for { + e := termbox.PollEvent() + // dispatch + for _, c := range evtChs { + go func(ch chan Event) { + ch <- uiEvt(e) + }(c) + } + } + }() +} + +/* +// EventHandlers is a handler sequence +var EventHandlers []func(Event) + +var signalQuit = make(chan bool) + +// Quit sends quit signal to terminate termui +func Quit() { + signalQuit <- true +} + +// Wait listening to signalQuit, block operation. +func Wait() { + <-signalQuit +} + +// RegEvtHandler register function into TSEventHandler sequence. +func RegEvtHandler(fn func(Event)) { + EventHandlers = append(EventHandlers, fn) +} + +// EventLoop handles all events and +// redirects every event to callbacks in EventHandlers +func EventLoop() { + evt := make(chan termbox.Event) + + go func() { + for { + evt <- termbox.PollEvent() + } + }() + + for { + select { + case c := <-signalQuit: + defer func() { signalQuit <- c }() + return + case e := <-evt: + for _, fn := range EventHandlers { + fn(uiEvt(e)) + } + } + } +} +*/ diff --git a/Godeps/_workspace/src/github.com/gizak/termui/events_test.go b/Godeps/_workspace/src/github.com/gizak/termui/events_test.go new file mode 100644 index 0000000000..1137b1d260 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/events_test.go @@ -0,0 +1,28 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. +// +// Portions of this file uses [termbox-go](https://github.com/nsf/termbox-go/blob/54b74d087b7c397c402d0e3b66d2ccb6eaf5c2b4/api_common.go) +// by [authors](https://github.com/nsf/termbox-go/blob/master/AUTHORS) +// under [license](https://github.com/nsf/termbox-go/blob/master/LICENSE) + +package termui + +import ( + "errors" + "testing" + + termbox "github.com/nsf/termbox-go" + "github.com/stretchr/testify/assert" +) + +type boxEvent termbox.Event + +func TestUiEvt(t *testing.T) { + err := errors.New("This is a mock error") + event := boxEvent{3, 5, 2, 'H', 200, 500, err, 50, 30, 2} + expetced := Event{3, 5, 2, 'H', 200, 500, err, 50, 30, 2} + + // We need to do that ugly casting so that vet does not complain + assert.Equal(t, uiEvt(termbox.Event(event)), expetced) +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.go b/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.go new file mode 100644 index 0000000000..83947f580d --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.go @@ -0,0 +1,35 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build ignore + +package main + +import "github.com/gizak/termui" + +func main() { + err := termui.Init() + if err != nil { + panic(err) + } + defer termui.Close() + + termui.UseTheme("helloworld") + + bc := termui.NewBarChart() + data := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6} + bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"} + bc.Border.Label = "Bar Chart" + bc.Data = data + bc.Width = 26 + bc.Height = 10 + bc.DataLabels = bclabels + bc.TextColor = termui.ColorGreen + bc.BarColor = termui.ColorRed + bc.NumColor = termui.ColorYellow + + termui.Render(bc) + + <-termui.EventCh() +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.png b/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.png new file mode 100644 index 0000000000000000000000000000000000000000..a37912f7fd18a6b52683ae819335dee9eb017f3a GIT binary patch literal 15386 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

RmQ-mGO0(Bv==_=c|yZq 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

PIOw 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

a;0s!Db#1BCbzWcmup5=rWNje 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 P7eDJ(J. All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build ignore + +package main + +import ui "github.com/gizak/termui" +import "math" + +import "time" + +func main() { + err := ui.Init() + if err != nil { + panic(err) + } + defer ui.Close() + + p := ui.NewPar(":PRESS q TO QUIT DEMO") + p.Height = 3 + p.Width = 50 + p.TextFgColor = ui.ColorWhite + p.Border.Label = "Text Box" + p.Border.FgColor = ui.ColorCyan + + strs := []string{"[0] gizak/termui", "[1] editbox.go", "[2] iterrupt.go", "[3] keyboard.go", "[4] output.go", "[5] random_out.go", "[6] dashboard.go", "[7] nsf/termbox-go"} + list := ui.NewList() + list.Items = strs + list.ItemFgColor = ui.ColorYellow + list.Border.Label = "List" + list.Height = 7 + list.Width = 25 + list.Y = 4 + + g := ui.NewGauge() + g.Percent = 50 + g.Width = 50 + g.Height = 3 + g.Y = 11 + g.Border.Label = "Gauge" + g.BarColor = ui.ColorRed + g.Border.FgColor = ui.ColorWhite + g.Border.LabelFgColor = ui.ColorCyan + + spark := ui.Sparkline{} + spark.Height = 1 + spark.Title = "srv 0:" + spdata := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6} + spark.Data = spdata + spark.LineColor = ui.ColorCyan + spark.TitleColor = ui.ColorWhite + + spark1 := ui.Sparkline{} + spark1.Height = 1 + spark1.Title = "srv 1:" + spark1.Data = spdata + spark1.TitleColor = ui.ColorWhite + spark1.LineColor = ui.ColorRed + + sp := ui.NewSparklines(spark, spark1) + sp.Width = 25 + sp.Height = 7 + sp.Border.Label = "Sparkline" + sp.Y = 4 + sp.X = 25 + + sinps := (func() []float64 { + n := 220 + ps := make([]float64, n) + for i := range ps { + ps[i] = 1 + math.Sin(float64(i)/5) + } + return ps + })() + + lc := ui.NewLineChart() + lc.Border.Label = "dot-mode Line Chart" + lc.Data = sinps + lc.Width = 50 + lc.Height = 11 + lc.X = 0 + lc.Y = 14 + lc.AxesColor = ui.ColorWhite + lc.LineColor = ui.ColorRed | ui.AttrBold + lc.Mode = "dot" + + bc := ui.NewBarChart() + bcdata := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6} + bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"} + bc.Border.Label = "Bar Chart" + bc.Width = 26 + bc.Height = 10 + bc.X = 51 + bc.Y = 0 + bc.DataLabels = bclabels + bc.BarColor = ui.ColorGreen + bc.NumColor = ui.ColorBlack + + lc1 := ui.NewLineChart() + lc1.Border.Label = "braille-mode Line Chart" + lc1.Data = sinps + lc1.Width = 26 + lc1.Height = 11 + lc1.X = 51 + lc1.Y = 14 + lc1.AxesColor = ui.ColorWhite + lc1.LineColor = ui.ColorYellow | ui.AttrBold + + p1 := ui.NewPar("Hey!\nI am a borderless block!") + p1.HasBorder = false + p1.Width = 26 + p1.Height = 2 + p1.TextFgColor = ui.ColorMagenta + p1.X = 52 + p1.Y = 11 + + draw := func(t int) { + g.Percent = t % 101 + list.Items = strs[t%9:] + sp.Lines[0].Data = spdata[:30+t%50] + sp.Lines[1].Data = spdata[:35+t%50] + lc.Data = sinps[t/2:] + lc1.Data = sinps[2*t:] + bc.Data = bcdata[t/2%10:] + ui.Render(p, list, g, sp, lc, bc, lc1, p1) + } + + evt := ui.EventCh() + + i := 0 + for { + select { + case e := <-evt: + if e.Type == ui.EventKey && e.Ch == 'q' { + return + } + default: + draw(i) + i++ + if i == 102 { + return + } + time.Sleep(time.Second / 2) + } + } +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.go b/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.go new file mode 100644 index 0000000000..b7033580f0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.go @@ -0,0 +1,62 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build ignore + +package main + +import "github.com/gizak/termui" + +func main() { + err := termui.Init() + if err != nil { + panic(err) + } + defer termui.Close() + + termui.UseTheme("helloworld") + + g0 := termui.NewGauge() + g0.Percent = 40 + g0.Width = 50 + g0.Height = 3 + g0.Border.Label = "Slim Gauge" + g0.BarColor = termui.ColorRed + g0.Border.FgColor = termui.ColorWhite + g0.Border.LabelFgColor = termui.ColorCyan + + g2 := termui.NewGauge() + g2.Percent = 60 + g2.Width = 50 + g2.Height = 3 + g2.PercentColor = termui.ColorBlue + g2.Y = 3 + g2.Border.Label = "Slim Gauge" + g2.BarColor = termui.ColorYellow + g2.Border.FgColor = termui.ColorWhite + + g1 := termui.NewGauge() + g1.Percent = 30 + g1.Width = 50 + g1.Height = 5 + g1.Y = 6 + g1.Border.Label = "Big Gauge" + g1.PercentColor = termui.ColorYellow + g1.BarColor = termui.ColorGreen + g1.Border.FgColor = termui.ColorWhite + g1.Border.LabelFgColor = termui.ColorMagenta + + g3 := termui.NewGauge() + g3.Percent = 50 + g3.Width = 50 + g3.Height = 3 + g3.Y = 11 + g3.Border.Label = "Gauge with custom label" + g3.Label = "{{percent}}% (100MBs free)" + g3.LabelAlign = termui.AlignRight + + termui.Render(g0, g1, g2, g3) + + <-termui.EventCh() +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.png b/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.png new file mode 100644 index 0000000000000000000000000000000000000000..5c20e6e8ae37be1c08392a294b8fdc64db6bc216 GIT binary patch literal 32431 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 Ef=cVEssI20 literal 0 HcmV?d00001 diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/grid.gif b/Godeps/_workspace/src/github.com/gizak/termui/example/grid.gif new file mode 100644 index 0000000000000000000000000000000000000000..7490043dead4c2077cdeb58fc27a3c339980335d GIT binary patch literal 800288 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

8^T^_F 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 z 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

9DAr9V> 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 `ZPqwllgl;9&WzxFtk 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 z z^>+dH6QWX~WgGLh=kpuj3*TGhzS~AXRqzk#6Deo}F<~B`gw1VEvZg zR#mB7vFrlP2stgBzbX^Eyj)A^hwR|LGk#rk&C+w-Lw=q|3Xo|3iJbn~Y+*6R%5L!| zGQ#`;0WhiYDB|9zZ}(@ex95P-eL2{|33S#j?c-Yr0GlN>InIvqyiE_HiJM9)c> zg%lJ_ok{t?<$cWDQa7Y5!itY^m%5LG>iUmREJ9L?;upD#8b$vd$(co+j3km#DdBTX zzqPS=qXZ*s3RvX*$H`$Mn-y&;8BUlZ(pni3%TyI$s~az+6MsEn65#S>V(TDF%kph3 zjiz^6&SR?&D@uAWeX0cK2Ypxav659!-IemZHRQ$$IjR7M$sZ|fQ~7riY&O5(4Ggf= zDAJED$=O8;RLqn3o?x1gM4e6t${Z&KrOzMZZ|~PVdewl?Nt z9x}^%?)~|S%kpmK^GpUm?m}NOQvPZj1WFP?PXreDV8kJ(dqz7K0HDj66nliiOvnkp zG!Z13vgxn_0@GiTTt^0=TaSjB>8w!{2C|EuA`evyM46U1=^ryYNHb)gQvlj09`e8Oo z%R3)hr@PGDedm!`Z?%|7_afU;l*z*YP-=ys8C>~~l;Ip%0AA1^4>i!}X5${Cnr8{zK#cAKn1my(2R zihYa?O0Bd}!3jX%g*A3upwXK!<(Qm1VA`WGiWHsb%3d|Y=P#?81(tN%!hC8bfE8lG z2JAJq_S5^Uty=LZM5BhuM5z+`Eq;om8yFTVgAD(8w$TYEV%H~n3Fborns^qb8pwIG z1Cnw7dEeOfyCw!u&+de}IR2ialD8uD;t@)Z)`Oyzc&5W#xg~WUBx!*+ng|bf3-%Xp z?WjS<_+~;^Y)&iNoLlBDw-;6rnvpx8mcSs%@P`6k4l#tE-T~F?M(AKVEz{QahnYPV} z#A~iZjdJ;SM7#HKDxM-KgQ1fRb~V=?$8 zwMe2<{8R5QaeHIVE^o7QstpXe&2C)7d5GA~@gHGE>l#A21i$c**(s~Tr_3nxW3qN1 zN%#DCVs^Xs3(1U>B2(zJ`vNW*cv{(#mcc>unaEhs1fj@gK1fg;o_BiU!+%&t7OwU= zleD2SC$R|v5TDS;AJO!Xdy_?0*rE8-jT&4-IZV0iGqw%bg$PS#D5<|vRdL%@(?9+Z z#W+;LnlxC#FjJ%PclHsz^xL-&gxwNvmecvTBLxU5;RJ-Y**Tehz=;)fRbCO_dcVvG zXT-XvZ&xzY54y?lZV9Is+>3#3RW@n8`U+;zVS*KviT94B%CKzEGl=A%uyV>2&p!qf z^PKHK_z9gT%!jD>ie$<3`eB+-QAUCHkT*u62so!6hDp{E&p8G61|Krx=|0m$fHv@6 zAwP&7M~`-^H>m()ma!&7C4S?u+&}oL2POJylV-mR)zgQGz5<$>eUVl@T4>={=Xp=$ zy`uNM@NdjY#To|V_D;Xe zDh$KlkbqhDQt>i*>wyNp z!m!@*b|-Dyl-I5GKl2^>M5=@#oZxlp4w(l}CG#59cG@3#gvF!hJPE}C|MxK%%1R%O zy|$I`WMV^0;f~6Yh++Z-{O9@VI4|S%(cud9^NC*JUSnMAIcxNKFf+n~fp;x}k{1Lf z8N{PDFb7GXEpaaI+a%HBJH+3bJ5yXrEB1HovOuMbG}uK={j|{ZLzMClBIesvybERdK_Hz3{ zl4aXqS5r8R)hfl39z`rj^4e%Xq$p z5h3rd7cQT^B}k%&@6b5tTyu&ML{haiPJL(d1nXhnlzwxaOiwVRzH2JVm(dqS98w=Rc?kr{z@8L?#Jg7RNAHP+trhj&TA?2Ju()=2g+n6z z+wP2vhT`c}O2^JLD@!9Gl($HQ0+pUwv%v;=Xa^@_M1reVZ$qROy50vQhI8;Db`*K8 zCqoK?KxgyDsk6-2g&fig=lKYtS_*JD3^PXu)_iPjPSA%BX zjx6-|VnY9Ulf}(}^g`&;s<{_ry5JD;=J#}4y;t9X0wiQTV6LX{SA#{+o{qHqM&Hq| zF6rPCwNcs4&*qmEtcGL5N3}P&<;U$zsQdm`33K5Waq(#F@MHl}@>6)i z?O7ym8V~5M=c4ja2%2X7?VrF~dEsPcYaZWvg3=wgEBe<{PiV}kQYfvk52>*B0vTGmWHg@hHOGY$x)%lSrB5o zU|F`%E7hP+J|T-2q5C{RJW!;dOb8V;81FLdmsseTbjZ4N7#>PAvC+nd8xVM)@0)&K zyhWAH)<0a=wMzBrFGA`VFbk8k4HhE>5A*;+QbofC!7s%iK_!u~KSB3*Z4<;KoD;W$Pk>El6gfq-{UzXtic*n@_O=7;cR^g}D6dN#TmuBrM+=KalaEGw*+r2r zM61|Et5gCZ^eEEls0`nz#4%KyQFQ27l(!lX3`P0yqPRpO+)z=uGBI&>fQV>ps#;8$ zT}%Tn${Q7%pB?Kh6VqxJ6W1A+K_92G7?-OCWEr92eZhr`sAk^iNGP7uE-1ndMV=gA zb{Uhs8|MrKgb}EL-RR)O1msu(xlX)`Z#*f0N73kq9&yRl=ciItm{+k=3w6gGo5m;K z)8CC)(@Ub5!A4w3nLCPc`M81Y5RhRI@8vY1G{(^bo@^%yacw7yFNad+u+Vn7v4`pj z4f|<4u$u8?Kc+RIp|f%P$}NR_B00@L;%2Ati9?73EO|m;)Rv@A5Xt`|3D8%3LnWNE zEt-B#XaxmC5kb_P#t*L27^>2ZX5IK62p7JxvLJMQDW0SniqN#9BpxBXHcD&uOyf&Q za}0Ya&%mz5c{d3Scx6ICh*!6eDVngX$(eL+E<=%D#`)Aq>L?CFSxNTdjGn=a=X^3Z zmlT%cR`{ZiGO4rTs>D5wl_S4AX1}r>f0X)t&?#`q;r4)GB~SLB2iXTF{Lpfd6H)Wn z@$3q0mynXLwRGcSvvWUzOjSKTm9c4`{#%;bY!JuwnZ)sauOm0CVAf4<<11tKu1f!UKMllWG zUZP|aw4_A9pK-6nDku~Q{$WfRi7xsLE21I-D3Zaphn095%`_br@gBL4`48-pS=zY=CkyuMUiT(@T~0DMR36E`5Kfq2m%nG!Pt86z1N=T#&tO;2_ndEnXfh47R^{4%*H=zqc0y@ zomo}Qy;Y4q@t^k2Yngb`e9|mQRe-mYlA7#nR7|r<2*XWy5CbL2ZeoNRge*NQU(aEc z1K{;XE{b_l=8Iqnbkl3RHXnBTd+;{-6F`LthU0WxlPeGc?Z>eYO}FTH3a%_RFm|Rb zve_94DmVPmerD3<;f9NDA@a)+y#^Rq2OSpFBj zq_tleXhgPnja{=_S4*jD;vVk91DQ86c4IG~m6pV~{!Q8%s0)TL9?hCX0JE7UC(L3h z6M!`kQ{bjWE(k~l1_p=Yd%z)NNXDkn?rH)1J8bP2b~F=toykaYq)BHinw849yYWY4 zm1a-3J8bwsv?>p9LqK{QA)wE&mt!<*0lg#L9X(7bWsnSj}TR_#kd6Kp?K)?K-6+$*q+xmeIl=wlsnd zVq?Wp4y3{X1F>>zOeG69%#DHxS0Q^VAG{{lmx`b@1^{bET2nUQM*!@B4*n`be#5{( zk{pD(mQ|5rP#)8lDLR0q38VqgtmLJGscb!Yq66}5Z}TaJ=>vefy>F*X&41NAIAa2o z;LQ#85$fglzu9x}$Z`smB&MAB^U0>^@nRk?Cf%*!cr}S&`qcGkAJ)qg*zU+0;KuuQ z6vmJbr2>l;G`^-crEHktZ$ zlFu+RxxNQWW2-eyia#0qvI3d|d25y0a&A}p^F#8MMWeOG{z-c=@3eHvt0yNW@WxJ= zfGLvqC9xyN-2Q1j&Dm9?kbG!JjEK*q`_0()Qq{Xu6q^A1}qf78fe${Zz$#wqhBNF_nmirT)Jj*q$eKUn1QD{RlrfIxc@VXWU zPyI7uQ-Xui{AnH{#ljpQifr>_NWdRnr*{L@G?}+04Kzjz_Td6m4E{HN8dM1(`9_`5 zd#HS^D8>oqUGNW{^Xmkdx1E3a{T&X^F}!K;VVfJtt@Z4~$GJ*L+6yU|9{cMCCoE>+ ziTt7`l8|DWAio@nd_Nhdsmwu)$5}(dp7W-n<;{C|mvX{q`S+h5JXe`b|Ge1yxi(!~ z-+(ldzoYa<^yiv zGt8B3kqA7p{yZ@9UBE4Hee)kt#_hDc8{9y)%1jF|%_npufW4F{4^Lhwz( z2OC|mO^BT+^Fs>24g--hkm+! zDb-*MM0#2rj}0hw$T~JMyxlf}RoS+1p}r%$9sX+vG3l#69G}s!>pz_OK=~#SE{v;anWl0_ z+y9QdPt8*}ee^x7xP}D#{agR?p&hXoa?3dQe#_eT&7&iJ_wBD(?9s1a<(T>hn_;>P zuRhAhemOllreOE@fIS9>z^W1-CBsr_`oFibFf0JyDjL7GG^P+Cd*>aRTp51Q{x}Iw z{sC?NkwS5tj|Ldlf83wg7IFER4G^)i5`~EUj62CBcl{ySz=EEBCdLY@j;HV!>PG{;8a3L!|cUqbHsk4X5hsr@yXGPxwwB0!1n!r`q>DpFBA=UH5*(ic4nC zlpsasZ%&=Fip`SFO8=Q)x^X3YDPgIlbO8v>T z)6}Vk$Yoj51@2PU)#5aK{pxAR)$63ILW_&XZ_YDBPHh{`Tc=K|*3WK?&yyO!y%xXI z?_WeJoO?`NcpP6E-2eUl__}ocJZ0(v*R5mhid);bDHCaEu($|bzu0KFE_40!Y5lYv z&p}JSS!khR5^WUFO{tg?yzNPnivEc97)Zd5mfB%yIqvC{zMMR_gP~ow0iHT7W z32^~wX{jl3u{pW|*B%Nm>f5~8vi>Z7@Ven6#fXY+|SH&H2UU z)%EW`H`u=bc$<^5V!ALqkc$8CV>G!+R506l%x?78p;&qehtqFgN5Yd>pC<$A%~qqS zct5$+v$z!cZ(se4BF_b&thq;4a;0LZM0!@yWj#D(v{ye z&kk3MY@#{HYJ9i#iag0Xv~GW@w|>j53) zkBYO#8v1i+p-)r7}r@(i+il@Nkd~c@+NyxtzJ@s(3G>O7^h&wz?xNE00`4RtK!8zOXE>6X% zuFAwd+2=*4D`-S8C&yij0l?0xL>P^MFD3~OLNQuE$l~h;c;GKyYZ5Yhslsa;Cvrn; z`lqXFqSCl)4x0n9ASH0W=mvm4MbwP}RSl})5$1Ux2%)8u?Y9&4&ryg+i$eSF{tIORgdjFitq`Y{mF#9M*>AG2j z7WVtANYm9Av2tGrzbgDKP~dYa0zqMz@$}7p49rvNIG>5=5fAat{L*zg$1Vl(W00ec zZt<#&vYTiy$h9mqin$`p?#CtKqv zJ&IuhfI8WOnh9texOG`!h6hk@unuF1eL>VECyEx-NF+ZPAl#0=KSa3!qf^VF21McM z<4&Q_z%bki8XgQ=5`vG924K)P!#O7r^c*N9MQh%1?6YVOxZZ+D<$`?K7Zr0#fSfiJ zDOcAf05U?YohV|e$yyJg_-*8j^<1fXOiaJP!*nudvPweC) zpQ%8LJ8>73fHh4g=C7SW=!LoxQBt5X*WV66ZI;CSNiv9lW4w#VtQka;%m@=W5$8jv z+R*X>gu*d+#Q7CKZJ;t;>4t{-Q*>JHAFE)UJ1lsIquH1A+=|KeNpJYlU4NTq{Y^BymZ6Rjkr zB=y314h;2yh}q0@Xug7+v2tl~bLwv}lG@xm>G#!FD<-Xdye~d*vQ41EBQDQmq1%9Y zs17RURzv27#1Zt*>Rc2Ko_{AY?B1rS_p^3HEOi^)CZTQcEfBDz3s~qRrEPS7=43`% zvoOZkUZ3_{(1h~9sH-{y+Z>@#yCPb%*p8j6k9%Kh$ACM7mujyo8?H4s)imvysLp$1 zmtWznkJfp%DQ8ffukayeCP$nu>px%`V}iv|R})c7f^L(WrbJH%DOlLHWyWH6I2B8hI&66TT}zUt&Y zE7*jfGV@h_QVK+Bn0pZEAqQ`$Pu>s|##<})VL0(F?-P7zsE){Uh)#F}=T);DVn3=D zrlBVwx!3%*pmtEMM2y%`<|X}CWHgrzNs{MeCvzbpD$!MN(+KtAwtV}Dz#1OR_tPa+ z3+h1vgFA)R?pI3e8RokP^bVVcE=(zgqvBC;DDu*qjCJ3ua+i_lN%#vTPa~OC8Z(;q zit!(v<88_di6g7gEP{T-uRUuF=I-9#DJ?yR+x^-cTMcG|( z61o8ZyGq1&$5db>`Oz$a5n%bP^}qZvmKMIR=5n=OMa5|#%W?nnz=u`(A?}#k=4|V} za{}s42l9qy-vN!AB9L4RUe8JtUukiIg~Ke}#HN)13&Xg!IXJi7u3Th=o3yjyyR$>U z_Db2_ggG*mrWa)`mHuVIEMNP`-f(N#f3i7~2Hi5M9Rq)+oSuEtSWjv79ZaLpQvKk< zOyKs0eFIi+p!fU?FIMxy;=!!}yu+LbFn%pqBOn{H%>YUnJ+_35A-(ieA5w}6rd*)e z=ftP$!IGq1hSQz&X%wO0cr z#}Ihjokh-1p3`BOMxu~9P6{IWddwdzol=DXBJ^AZJ(>N!i;S}oNtnM*=$ue}tJG=e zC+7xX#}hb6KQ#iR_8Uby_4h>Q{*TT`PPsu}t`c6+2ahYnwa!4ge;WbD9cIE4q`4=# zl#l6O1VC@6)4sz@oQy|_2qg;(9IGHFb;HFkLN2o)KLB|F2dF80{%nNRm6J!m)&6@D zcB70Zu^1xXsf}6)`2u2lKCcYWx$S}cl)&7^rLu-@+NvC3qYFX2gozd&f zAP;zCAU({?F(eKR_M8S^AqaEkSs~mBs{R_V0>prjL@d? zH)=C~-o(Rft`apHP$>8z8x9i27uvF@w+od(gGrTxW>I0KGXIUS`wVI-ej7f2NCHV{ zi6Fg&UZf+vg$@FWpmZ=uZxVV{L+=`zbPT=sB25gv_YR^+QAAWMprXdj|K7cK@7d?s znSGg;nViX-^E=n|{XkT9LFVIJq>V>9vhjb${q|&0{kJ8{WwET$_{*LG2T5QuW!gscZgDR%EE$!J#y%0go| z5v@!fDmIZ)(IP*dOGACkAUArzVGHR4#3&1Q#EK$R?KE2m z2LuCFb;;)5cyQ7r;y=a?8X6mpxG@P)HltDn5`9|0lx&%c-C5zpoWK?^8D59#N<(dS zseD>Ma)n8_J%j+OxF9y2p`7A_O}>mH%2+&=3eiMzH%HPaFPxYS zeH&%-i^lCVuVjo29VEQKVziYDCgH%+x7W8!w`nmm84^xkVX@zQ4mt%T)Jt^H#}TYq3a$ zw)T-LlC5OVGgpDVf^{gt9eARHFN}mkBZ*YMv6!#ncX*S_2Cz?G5Tjy=r8)3QAVrF+ zo${Os;ucQjiLYFOC90d52O^=nFyMPw<#i7P`Fu$OPeNeBa)2#)2d|=yqsI_z`pSlk z`feFiwA^P4wjo+^5M3^;n-~vL&UD5F!z+?hYA*#OE1qTtnnBg1!Fq7TKW2HO@Js+* z`GNqjdO|D15$o2KtHJ=+FeE}38jOYpV5+Ow>MF;g7zqF=KAn8Fot$6y3rX8`K|`+j zYbTq`tkZzKOvIF`K`8_P_xNE7H2R{f`?#K%5}d8Veb43*-7ma4b%N8|01~~3&6D8`tHKuI-F52|QN{qp zJ@Pa?p&9a_+4M&cv99u`w4nz1wwgo$Lls(%YP0^E(P{HK1>CSj55=JCbuEkC=E~Bo zN9^2U)=8=5@vmx=_YUOJt=rMtWCs9&AZP$u_nT?}H}=Xul+Z*nq=U|}>P3icWC55v zRuN)YEEI&L3d^dT2(P-XY9X_oIaiCYJg&MR0?ze$)*p&yf`Yx^fFl8Rr?$u!t)aSG zwlsOi&{#39g;JiqgG8tix++Ajrr959OIJMlVAze14Es=k$TH;KE#)R3?0>yL(BZ&s zHJoBvCIh>mt_j48x*ig~N53ymg^==F8mxF)^=B8P)Y6l21)0#Nw3D2acvsSpwf0G1 z-%w<^j%q(?%$uydC?U+C!FfqXFt-I&?6~Ul$&CIL@-F&Ns07;R=Z|?L zb@jz&hN5U_Ak74VxW_dX5ICA~MKPDcaDuC7q5RtVhZN1%_?>Qx2bzz?-$I5Y7PGK#F^Fn)!w4j_)#o25{ zit;TQqn$vU-;&lAxFaBLZXgX0#XutMVfX(4{N=+o0qs*?8eX8l=GW?;T^s&qMwKYm z@n(XHdY3Ze1hK=2EMw<(YpFUXPUNc%zJ|3(g%|o0vhZn~X)m9S+wi~MGEHwUe@Roa zz>!hnL2>)L^hL#3JqW~P z2({W6C<8Y0;*5qZt4gGI%^#n&yp?H-0vyoL6cjW-+RM{(A;+952AQL41luuu(ujRx zbCI*C*o({GxM*4TQK7rjQ=k`~KY#=Bu0fyUC&fj(rBLf*2Wu54S%>_D!~H~lPw3Km zMMYF*5V7Lcx`H$sDtrhE_*-jE4Ja;T()WUr(levCwjb6YNEZ1e<;j`e@U5jIP^$X6 z&C4HF=5B8xj0X#E~Qi+5{!>DMnB>fZB(|ps2ZRA4U>XD~6 z01ijLm8CyqO-0oA=DE`!Y2W}8M+jLh)5Daui4LB(?4!*vY47s}2z$!N{rKzqv&9E5 z;koq6sFaN`P4~>AP_^0@w8ZlttGB+#sogK%EW|Rc?mm z9;BEX;Ij`;LJ_)IAo3CllOEukwv!upgY$M&N#OWc?yh?v`fUR87|*#W1eG2C0_DNiFX>n@Hp%$ldckJ7(~ef^b_?MfF&`Sgn*4SrWEePH2p z#0q!@`d!VBoPTi@AojD}fApmg^(a#CR(tr-f%4eC%GbLN;US=fQJpPyhb{GGrcNCy zvxqG{^1+qikYr>m)y%hw*QQAbnA~kkY0v=Ck(dQpyB_WMnR`RhoJ+B4*)LP(<2NsxF+FTG%o;7yRA+xGN1$d3^KKqppg)HqguSzL7{(efN$J z>bK1TWyr!6)A_GUu+rFp`IraW7Aa5tP%vLpzZ#RgLYuuN1a7 zyA6OCo;z9a&ofgP)X!;&UG?JTv1%{4oQj^aH;|x`BcnPQCGv7_QOA+V3{F5EOD9+L zgy{_<*g{ML4bV2fEPsA_WFp&DJtpG1J&<0=n5vo;xh!fk3_<)HU)=Mxk^$Go0>ba)G*K#_0hxHkKpwC3=V^(&Y`1 zp@ykUpf|spGX{}FI=OfS9$|+87_t-$aRgRjAh(S-!(i>ag*65wvi7#6!{HYuexV(i zL6ipO7mh~zbax`pwe40pTi^j<81U_UPgU|?q7FUG>43wyxM!Fqykb${l7)tHb#c03 z&KOvHb+Q^6>0?>L?RkL9rcp%e4}k%XI%2-XgF3-nJid~O)M$PEG^PcZ5gFw3ev5P~ zbt!;f&h(ajFUo$?jq>P8+^ev1Bb6BAdp*S>K#It7io_JLPrZCJ;*+z+sS1`aBmJZy zK5`EH+b<*aVuxQA#$5-2P_w|Elg!SG6WWFn00M&{rKw-W`bl5j-^Qt~(?(Isq$8ze zR8xJTn$hfJ>}HBh_3P*9gGYvevkJm1Bis^BF1n1W-x>_*0%l6%d-TCJll;ARwb$6G zX&II{RNpy`1MXefi5Z%QS_T=@Q~nl}$^8pwM&=*WlK82!RSec>iHjlY!2zo=wGnT5 z6X!f>kt_2pl9|K>iOT!8H--ASLe~t2b}}=t;_)QlCBs3E!C{<(#1DS=PrT2JF!LE> z(T{wdXRr9q-|Vb%9&|E*gn#_=kze~|$1OXFRydC0sl?Zzg~+r*!(9*IGJ}m8yB+g& z{ef2@CkEqB_P;INn4h?J3>yC=HhPIAwSRoknCA5(+LwMpR4&9fhEz%T2Qg`!$mpXy zRy6UKCGN>~IOyiX!X`O19Z7KeOfZD47k}si>WM zfTXdjYcpwoQeQ3NS=m(xTJ%169u6s|an-wJGT}?*JpW*DMNj}fBMi;e5SDV~-s99e zMJ&A2ITTD4Xv*tRF64UBq>0K%<}QQ485Rw>iqwiK5P zT^`WV>ua+vvOa3dIE$&2diZ`^4HOvB1bOw%O?JjbEHM9o4=s~FIc8(~Me*5)E6aYo zspA}|;N?k`;=}ioekm3yYMjDX%RR0i8(Ca_!5fcl>7MxH$(Z)Op<4a3kz`ON1cYIz z5=tR}O{Fm~@s$zUUPw2uINehcnC%F<8D@5!ob{mYG}UDr#Gz_3Bi^_irMrbcKk2-Z z`|8`C+OzkI*>ypcnMWeR5UhNiJPqK8DiXQ{)$4QBmXG*aAT))sAg!(_pl3aKsyz}E zuw}HRN_B=|y-AHeWi@U7qQbHRA0y)fbRr)ALp0nY7Fe;{Y3(lcX=94n&Gb%wHEIb^W2Hih z>s}Wp=k`f_xmSwuPApT886+4(0&)srU)M@~Jx?c1_fR{!;tH4g8k@M%jqNWPv-AYO z8lu0UMgHlB_Qp7CM^EcRm01HBFK9oaU5uuKH)WLy4$F*GKiKeG37@Q=xv4D24z0UX z%9HsM#+86yhe9ameI~Rn(c^F`5G|;PRC zuArhxNI*uIn!;A@@^p(mJ^iPj4nbx{5SOd4pn>JP4>BpA+@NIOQk-1=hCD-cM{S`r z8Lcj(HoJ76A4);5&G2L_;;_O<7z)~4jo8#)LCGM2R=292te`=Exq@oyeDSzUhJsZs|xm=m`x&Pf$7Ijdb6CxDl!Pi7{ zS7jucuHu#x+X;#pWT-F~BCVTYFX}bfQ9&2Qq037zljK&)G`KD}#MuQTj-Foqd7n}D z10W4nqZ>jd8tRVwy63BDV?4Uvr5Iu4?;l@Ly*jOT=2r5S;ftT<-w;qFhBS=$qil!< z77e5!--!>JI`rK4pDO%_{Q%p@rGySy1n=LsStQ@^iHDCH1W`QnZ(&U}iyD7N#nr{A zDGU2z@o+}?G9n4~$(_UPEIb1*sjc9m`^4DJ1zV^XBXJbd(+ZlS0e24SH$+3bk?4{tJsn~|68L(|OI{)6Y>pgrRjO__1}gY2n^LaDn}h7}CD znYJYqm$A`a;j*e6Oz_+8iU$6un%k^*c-d1h%-oi=#@#S6D-aCFw~#VmvA1u_{)|aOndSu> zf0D(fb%YoFNUp6($w$Q`<8NY5`E#Yg?R%hDl$UpamgcEgQ_6Lg446>$++`5NyN&DdWP>bxHi z%_oL$5mLi~g9oij%BTbu(*5r~y6OsD2)OfdLa-ztT}AH^(NOqJlE@=M0DjLRODC6BcQVCN`M{H*?J?pkY~qSFFn4E=4kHH9BGj|@IIs<>juYInP9ys{gI^`w z(9ngYh!Ucoq%}D(XISasf*CcgKg!bl1)D#Bk!S?rpf!d_9Txp?rLQc<~5!WlS5 z?j9cPVCH1)xyhh$s*n@w@VYGf4x@rSg_r7ZMiWf2$U?x^lg$GPRSCr0q)^DoQgF&w zyDM@#mS_tXg@j2%JDt_$+F>msfV-J|A0M@^+>=dLVYm14^8Spk_dqf2&IM*!5-@XK z`IJglDQKuUTC`|r)0yw4E}Pl)bOQMXK|7f|J9|?XF?xApL07&)H}kY8;}o=*3HuM8 za|&*b16Xup^abFvY;ZcWVgVUa$$D~0D!y2C=|(d4jtUSiX9yyAlt>6@D|S4c`UU&G z47>?1tn>%VTxB@=`Y2@qpq3`gDdt7 zNd|K~@KA5*ER?Nev!Fp7_Nijqog1xGGPbwxhn4p8rm#0K%1-l}k_Fmk?DMJhKjWUunP z7H}qzt(ja(F<$9NDW$n(=qXm^no=E3eaStgJmk3gN_y4F_rb5PlF8w z`mLiuBEV>Nb=k<(5E5Ra5Dh%3gRw2p31|WTfpRdw?<@-DGP<0I+B`f38^O=KqPqDQ zX|TWtiGy@{RZWh7RL-mWrp%+a!gCBvg=?}LBT~9sfLVVjUOepFLL;?>ZuFGS=oBV` zLd_PyH_^ZkB!`HzEYL!qf&#G&i;2(vZK+&TL7>Gd2%-5QB+Cb0Oc$m?Up@RB~YY@i6IKZG}Y3V&LDFg$f zC5rA6KLUuQr0s)Y`e1BGS!-ll3Xa#}3fwrdP2_i-av<8k3@Nn@IX`Yw0o`x?mY!lpeE>U!M}nB@L1A7CTigQhv&Oj z2A1>TKf(tTdaF)S;peHfr-ksdNRFS=@ZisOQ4#Jo|MxL z#5V0aTf}D!?>FheSL7rNH9|-gag0NJZs}YlB6wcHW-~ydwCpU5LrZVywvnKmx-Q5P zr_t$vTzh}Zv7FBW#0z~%{}d|Y4Gkec3^45yU!dF5&%4>ZRB&MB(-9RwNEtn6#8SR*J(U||svFrAumT6 z3CFji=`SaX(!hnBV}bTlPopL>PsY(mq7=+U`-$No?{r>njZ-IV*sLE>1Y33DwMK$w z@$@t&L+7#1=QVZa|Mbtp@6QA3^VP!(^b(7Z#!BS#c{F16%atL2Ydtx;IBk-i3Aj1;T2d9EME72z8+$_-gS2)*mwP2<3_^l zdMwvw=*JB#*LqCjdeF{Bw(rK1oz2*f>-p*%f$Cd@_t)dO*0VmYm3&+alh~~JyGHQc zs*u=hR^Mt--)i*Tj-}f+*#ni)ZFJLZf3MkYrQ7T&-YBKpE|plHZrrM$-7e?alEe`37DL=XfG8-+8BM!ZImt ztCW`4(MI3nP~_IcpVl6chV>mZ-WU)d*U@N+vJvl&xA{%)>pTqOwh9GS)s@n*GQ1qC z3-2D|_X>9VTsjW-An%(s_zERIv`f}#F;7bk>^KS>ci}nm3;LHBjk0u)&LJO0>E}Bh zolJgmCKlMN9h5`ts;9^*&h?M0O(u#q#&&`&3y#xpAF_(`>5b$k^O3!lleY<5rQp5~ z&!j(*4UNzAp9N%=hf+Q{x^@h*eI~myze_&b$eY^tmL~Ons+ssq>30gf@qu{!cCI8` z_Ei=P@#T`#7gg0|WgC|}XO%xSzHrQc;gTxy>pi8I-`UaV;r=fbCoA#e=A)QA_Y{Ho zPoh%aikMl+p1*KJbixaoBHQ(nwlomM9;$WBBqBik`GNskD=)K@1~!><1SzG zK%H4oeSJsje*b{T{_nfp{F#HFBm#A2-c0GbyVgHgC`I3+I{(3O{@nNTIe&)lU8ysb zh4*D)dRWreu0Q9I^FQv-!~A*9J@DXfkG@GZfA8M?k=*>#rx_eAbr$=2Pg0|UW!{h# zQIY!iS3cr<`W>o(8$U8`EPu}aAXam3-2AKh@rB6ipSH-Kv3?(TAODbk>QYNqaS&h9 zKmQDBE*IA{ANZwS>37j3^=Fvpb2raVC9|^=^Uvqk8*Fd8wLJ-;kvk6m0=R7mKmxUh%{9~s_}mX$G3 z+CyQV6|ZNSZC$;ofX$rZ-Q<-x&z3#EFEPxU$ zaTyq)jBfGjYOC8BNH||tcD5C=^ya@8%zNi97n`^doAeDf1#?vmEisjwiW;8W_SWQD zv#hZN$NyKY+4hDH#yHH`+|a?x+|K>~tTlVNx&;ITIygC&a`BgPsZ>f!lWWcOdJ5!P zb4r+7y*;K}$>je>t=YdS<^QQQb4DbwSG97LHHbF+FSX{3jN06!_MDXeyVjhL*I3j# zkXhYPU0L;?TJwv6uGYrV;?nm)P*FGu^k|WmX$dsk$f#Dv9Km{u&`4mGqa@T z=H(X@78RE~CH#+TIR?U#RnE+j$ib1>!QR}E+|*J8$!)7;W+p!Go0y!Mo|&DS7LMV* zwQ`H9(%dqc`}VE&ByRKh|Bf{0(cXGe{w9%a=QY4>@oD>o)=|?A0~E}@P!hNX3W1Vqi#T%>lm8}p7*>{2@CBWDO%Np-ccnAl zuJ)$w1U7?NH#gT>Ooo=eN$kylAObk$RA0c1~E} z5qq4Z@l)@s&f)s?8l9uatubRwLDf7)*_ z_2A7W=^Z=+EyTx@b@tw!I{W3$vum`fw}`y*7D%7~Rg*yp4{q;p<^&egVXT@@yJLM+J3y)=Q!R-`OWXbN1OsKV~~G;}X{q zURxHy$9wejA(fcu(>(S%PejQcn^$e+J(Z)nn7haCD;kzmys9D{**}y%PY=xCobNVgsj~w6H)wwAM~~sa-*|gha`-F$wqiH|Ex*iH|*#t@AFa^_u$92Ezu# za9ziX;HkL%Z!V|OgQ5ltH-T(-x=J}sQa;`qM-Y7j=vk(1vwvO?hHP~>;-8tKE ztL9SJ^4cEk+Vp!Sq4?5s{BOw1z^BE}w!-=vf2@amRu6scRE?XUu@9xNu$0$=+9duK z>;B#)ebegAWeXRA7Sp2dt@xGO?KIPxudZt^QeM05-#L(YRXl0MrSrq1!@7qW(oBsK z8;>44eaS-%B>{p-NS7a`N;`J1C4PRLQT+U8cRu!h)V2?g=JT}#KL#BLJ?iU?MN+_C zQ_jgB0VJ2+n3j6_r}&&t=8)5Io@n~72FO_Y@AG~SNnc*y`S(Y-hUedI;){QaQn=G^ zPybMN6DhV3(KOkw|8hstoN+H1;!!Y_q9867%3Y-L1b-95|`c3f%g_7`^ z)D_JFOw>C%QB%rPj`>Ljt3oRbOM@SRJ}t+6IBDhl>U5KF)X7Z4F-9efm)2{@d+J{b zt0u|!agvJR9tp$x;_@0c7PUe_|4vw!M`bA~e&+Rg$i}$7wrsS#Nd=OTlx)cD)$%|z z`wb|1!r~v=PVhM6tD3ZO$vh zQh?HMLL(*CgzkV|VIi&R>dse?Mn419b=^rBmbb>0$i`e|EvxHQdd7E>T)~qKNfJ-l zdOTOJI51I|`Lp6VY&G(@p+BN7t=4Rq|oW6Za1-D z>wAq99F-F_Q_0>z7<=wWjz^o9bMGP(6^S6=IIXHyv{Tpkxj!lSsUu~jC}qv9@`z+m zHdX1k^44wbi;Nz0P?d*iJzq=sqA@C7cSMa|_L5dw08&TLYqs9;hwY*dcUcur_89myn18O75ng;#{G3eEtJ>>K5;&qUfKBOyxEgC*t+M&Xw!BAU86@%bhr0Ka7T@4 zqgNJ%wW+T2B}n(Em%H)ymQYzIAkyd?I=%f$`%6cDSiN7O@yi8E3rdB<6G_LG#4hF^ zJqr%wrp5IzF5Mr!8wghf!}E<5{9#BMZZZwkey%^rQBeQ=g1#iM6J>o7@2pZ(OEU8UlOFIPa_c zWN7}_ieK*A;i(>?3_=g$bBopyceMFT9(@h|U4NI#%4W(sAw7$Q;!r%&W`y|MUv%U5 zq3nx1#Su#Ok+{3rm=G@quQieI+Xu|I#Xw_X*u#oizsPUe~K*R%)0#pElNJ7K*X4 zJyhsyaPoE0yWBfdd;P4zG{gH=;n0|s24#7u>4_Ohmwn~AWN@oqhL3Aj%zP=HNFPHB zz>m;F4;#QwB3&7sTuf*Tn;jsQx#w&m%3D7G0%YV`x!` zU#wH8PqM7Bz!>U>APjR)E=ld+YRw6s&x{QvdD|lrI~>M<0;{$RQaJ6#A{bhrN=1Yn z6cU2tpQDDk@X|KAK?DTH-G*y_; zvcJ?O{hT(q_laZU?<}k9Bju9U=`4uukOP+HpmI&-6qBY zRtU=qg@@Tnh$svhgG3R&xxD}LP6uTROT&FHLJWe@2pn?<;bXo$n#N4(Vl$C+R>q`$ zWbxvng2nM$A};drAt@kJQS~%XSnXM|RKUKX-Raaj$gGqKbWDnmA^;bA=`B7Hj+CNw z>W<~=N5M=O1t0^TAs^1XK=J?hAfM(N;7d2`=Ek2ge*4^2_L=jL9alu_jHUvKgw3sc zPy7gwvGQRXjN-Mz^@QL86>$`-_n)mg@N|XcBdP4<{B$r-eIiuT40-?s=r9l{f%@)x za4|aABiB-V0xk-RlqCHO?s5g0uftiC;f0E1ZAMm3ea3OR=WN^ag(1%eu z34NpCCgbo1;lQ5J*f?faTElqyJnvf@QI}agB3a|^=XpI835d?~Z4QcFgOc;HP)!s} z4+9lJ0SfOZO|zkhg+Q&qMAsU4ts54V;Bi zDm=_1))3bjmXw?qo?2rsi-QCLP#v6a04^L@(6vWWV1TRCEzk%8_)CKCTSaQAnmg+v z7BVnu(sq*N=0v)pQs67*sHPN8YF!0L@Dgilhi<~q?+?bdP$E=YC@Mo zVV*>J{;;&-Jm5=}{5`avN1$H}9#Cs>u9o(Pyv2Jmf!Gog7?mvqcT)%$|2(tw+}&7V zp~vmkRNqCskUtZj=eeUcqu!oBT6mXSc$S=m@?8<~y?C4X0iY0<2Fb<);tQaDJwO}{ zlKlxsi)L@gd$fAo75$aS_x{mISY}XHHcBy5U@~(u*Ul*+v8=^^9uq4Dvk*i+>bwo8 zSX00LX>TtITM4;~_Q>ft%BFzfv|u@bLOCDFWl_=GI4fJRj3?#N9y9+l9kWkF8T}yO(;`4nYJG&>}4b5Eg*0UZc5K}CWOHA|*zgv`F zP#d0Kw^<JJw-7{@5S1jQoLUU1|(r^$GMw8XOl5fmC*oXJk%@d>A4ejRqcBGt+8Tpk*9a3(slJ7D|BRN*(>vazuVQOFJFHsP| z#BNKEteR*^DWs~Iz?Lf1!cn~#K9y>TP%6+yjXOG*<_X|io0%eZZzvq5-Aj!NhZ&^U z8u!u^dwG52YkQvfa`Y^B|i>Z2Rt|&V@2YV zw)5k?vaksNYd3rZ49Rv6oM3HCB?1gv&T(EIZBP)8H+7#~9?SM-^d-pmUlD7M7sU2-<;HE2-09uXb zCpc0%29AMfs4{$;LcZp>8>ea;%iQ`arzzt@^TlX?TV#9^@_8Pn(+A6S=ZG?wwK(9k zQt%7ehyeavaS7P48}%-U!S>^-2Y!tXT-)wqx!v~&mYj$JN9|IP4Py{K8HyS#?)HzF za)Iww(=QHcKk3cK4D4*xr1y4Fk?ivq*1I=@!2!Pl8b0(}|I!^)N;Aay-p8fMv_Qi# z5M3MufeF+PeRlZH_s#ZQBYS$$B-ckqcc}Y^&ODlaGmR=v6aO4Nj#+?4EhLW&D`)_K z@%g=s#d_50 z_o5i4m&gqLl}_ulV_c!_j$P)|szZ9~osV-L zROT97=e#6fVx}a9#tFBBUu)0Lx&uw~M{k2g)Nn@kJEFwb@^*V7Kf+m_(`W6tY>RF5 zyN<>edmDs3GE%ZDP@fbqt>59;B%naAlo=o&on2We@_g-Rfa$`WUKDgWN^m$fXa-@a`$TA!1u@Nr-|*!EW9jJLv$wq^55I=vGIg_rks zncl`!dhTsQyYA<6bJL*_v(wE%KxLylk~k%okjFH8=Kv1mu+4Qcy&|$L7pfOuTxqMu zge&=Og;VXmc6%M>BZ{vFlfj$biD{4fG01@fORp+!RW(}`V{M}L46JMIrphA z-_LXPynHL&<9b}zBH=+l^PNbH`RnM5xwjnnOSA>>SKM#E&pS=&<1&MX!z* z)~AuBYQ?tVJItIZkp{190v_1}Ilh~Xcy~==Zb%e(%|iZviAhDP1rg-!f#d6ORH4Ma ztZC1pA4iPLAA~aY;G~^^#`i(KZ|Ltm;985;$3S_NVv^Bnehc6)Zy{?}PByQ=1UFuh zvO?Zo$WMLSnevZ%AC>dI_qtbD;$vn!@Pn3v^J8f0{eGmwiy!qcZB!6|P0oTPRFt#^ zV-K^LiNee)F4^zH$o~Bt92s;pO}ixTy*rB2hfzFJ9~VaCCgpv+Wc^9*^DT}!|WBf5zJ?!c$jCh7D7vwU0k99uP&PZg!cRU2vV|BTR2l|1Lh67o@x3|1w=`mM0yb z$CdyHD_!o}$@pDTDc1?qxc$zR@)AIpnrakJxbAh-{tmSKIqJ51uuz;|ppII~9_#H)~{SVSV59_J`jz z{dW3hcC@x~Pa4!LnNR-E(%HjeBMghZUba}?efjY(9sO2DPUkLMtAuT!B&nowj(Z+9 zocNJ-kXqt}AIHak2x&|U2ZZKT3m$jp8OL0a%uz9wS~cR&#soSQ z`4kq1f-eCj?VmW(9dMTzH0n>5d)JgO>9Ha(ihrk5tXs|$P`bDd26r%vspy6i&G=jPvD!uN9(@_dmSD%#z zEij!~#+jz>pBYkBDFk31^jAZKxuj%k?Vbz&{KOL9ef)crJ1_NA&)d7$Pady@iFRM< zbcj)+5P8kJsa&z^@Y+GZQ6@@$0_MV&X~B~aSGjEH#BIyB$0xX!aQR`%#P`=8>oU5# zvM_x^el%^wPmHYGTGDdd8cxv|q{b=D$1h}ZI+3Ag&X>Y(Dw%AD)!%z&=PxsRFq1xT zI6?c^kyP#)TeEm3cvC~{&_TjdI~+zKj>iHt;-nrU?L;39Z5)Mo8UPggcVXs=p9m0y zpVIb+190(4D<}ROWu0PKicbnvA+CCVuK5@-{ueqU#%;*FCG^Q^CMZD%2gUMB{2T>W#_IE4^v8OHZQ3 zI<7iFIMl^5%^L_%Oqcno6;RUxYIJD)J?Ly|~x!=Lr!T~=4|5U|;UFyXnJz4hFjnLnS<+^JW z2c2qyMokD_3fVL!*=}V*qtG$pzCB=7)+|`pNTswNn+ZQ4m)qF^mZ{w|vEg1W*vft@ z;ks$;60=;WdQ>T1{fp>xVP4ek@>a37XZl`5dT#sGq1C4RxzKxACG#V$8sQ73!AlHJ zrqrsrrh2a5w_MJD_5Gc8x#+^3f%e=l-z!g$z4IPZ^n|m98m;#|rjM2a%J*HW6@C%T znlCNq(MZ&&h9^U8=h`b4PCQIqBbL3Iu2xVsx_-FaI-xBvn=w6jO+cBg<>CwZ6{p_u zG*P%@{qPNiERhRXz(IM6=IAXN>ljPcS5^O91}=$sL#`7QD0GPwGD*NTZOa-fK_2Ag zT2H^kP5~x$Fg5!WU)kPBLG(7sgF^}YAY(2^Je!$aXWAC zjiI%iu7Quf-p&}?8S2oMW_d~bn>6-glDVyuuJ=G!X&eTo&bwumCB4sjZ9iVOYAXnC z^mq|zJzo;i(dFuAe*^2V-4uL@#Y^`TV*VmKsHXP%{k7ABMRBgPA1w7TG}h!3Ky~Rk z|9}=R5Hm}nDq(jp)cW*yMB*D-Md2ENwN7&@Gj=-3TJ9@RfbObjf(4zm-9Oj56ssAU zB~ua=wC#5RFT2_r+lDN8nZ=HKtnLkpCSQ)z?UHWAnPCX_{iyW7tp}Pzg0fe`S!Azg z%`)`B;3vQ|%g9&!3tG22?8dN!c3Z_kt4oPt_*AY}Yi9n8n~n4hSp%B(;?MnWROA94 z@F;xC-@ml$J=$Y(&k_0%>Y#WkNIRc)FX#dK2`vBRI_4|-Dlq7zX1u>A|0pv36DQrV zS+$E(+NqAsFZ;_6JZ!@iY=Wf?t?t}p*&71F9yRzqzhuZigm|z^QRiyuY4uR@%FvUs zqBFO&;&3(wYSz1b8W{jr5}skPq>H!79`5kUk-X7MhC?I@ z29F;--i;rx!Hl4vsc>zF&ttJHeE3&Sbo>5&WCfj~pI$sGy*NV8O$0@8>ydpSAWnZy=iSHdVEuk-t4p_e%+Q$u9>PFkz#ufy*WmUx*2!jJGH? zVS@*YxXoGaFP!Y9IUJ;~gA>#AgH;yhQWmBFDeR9LZD5FfVZp?)S=+h7hLTrblXboQ zcq#9pyv}P0td|nJXqt(H9S%5h?Nt!xv0!k zlS$-u2xCm)x|FU6rqSU`h_G9=}fk#(I3oINIhk76E;0dT29pm7(8Z5_9H;kO8=yJvDrICy9 z+WV*^{Mm=p{Fm-I#aN(pEnz(rWD?Lfh76v^>2<&jgxrf;=@I#u!Ui7safWjtAk>vy z_*nW-t0Q&?hQ67B?Yrxo!%EgeX*Slc+6w-jCjUFdg(JIhy@jLz1 zMd*sij|JN^WprUcw!KWh45rX(DLW6sY1xRffDWE=q2^%u0+4f`asC`nEoX0V^YkGA zlWqPzrHXFV4L{GuPX)+Um2@QAl!m1R`gY3U$Hxtt)Y0Bgk%e2jo?{xJlTgk}Q!ZaVB3|}c{rQM4sw_*& z(y2HX9N(LL*+WL`Q^+G|Q!q_0UbD_{8kJ-Z@trIEtz%G5=Df-Jqno&J>M){2k^c&}#JwG`0fTE0H$gC~oCuXGHwBK~yxk#U?Dlhb`Xqsf$54 z`lvmsp}H}#w=vumTXe5|{#cWwXA@78Qi)ZEj54t-wQ0(n9c)GM;7cFmW$|F>SHS|?thobK+Q?*G+!DZI1Y6T;m}ygsS*5XC0!dA>=Jr}`d)lf9$t zx_H40Mn;}$O)BoosDBmt^rM1{gu%8V8q##os`H1H)*>i-Mk7oYrXk;*Priz%0W4NE zq8XJ6>`4ou=S)!-DmS}#?tzLgbz@LTtYNbLBy!{G)j&$lm1P8o>APauSB~dA$&xT; z#94au>F}L%I1@N~9gHJsq|n%oMqDkywCP(Ic)!;;(Q?h>I2(8d&c@EetJll-n}Inj zp3pUzbR+y&@abB5(4z&AlMef9&c;z2WPly2panJR;c&ZzIHo7Ym6$zN zi5t(iH&k2~-PaWxYaxvv>jqW3(Z`G9KFo|AyME%tpOi=^BYlPu(c8%6$K9aFiD!o< zg7qf?x+jRQV170ee#P*Z$Zk@%aZKby*!o1QzG>>KiR4!kA>ES`Y*WhP69PFCLEck- zH>ZkNk{J9@! zGu5l|;KH8=XD>{5N8Z1jHvK~7-h&Gd^Zwi)eK1{l^WJlgdoONIm#RF<)PGcL(-Z0a zaKq-&MVrTiY5R|^-hB8(Y&?gOD$}o3rhYzv zaih^Z*fxQvS)r0yk%yN^ZL{JVvyz-o4n3R|F?fRYc_J$QM5*V=;fGJ$pFTOd@dT&( z^h*2_b%UppK2IOUJ=J^o)ZlNN;D(0A##0m9XHu%q%u1dTdY)PP%vwav_F1|s;JrGn z=7JMkbAsk_T3{ZkZmz0xUQu&2FIUHOSFfJVAUU@vjroFvxnRV6@ZEXGC08HS=Z@*n zPTlA6oX>-AJ&*QrjY*#)_sn_t40-!3WR}cjs4h?p<_k9Fy*L+QZ0GZ%Tu*JxSC`D6 zN`KDFocAwT^xLnWixQvDDR~}}>s_t-JX`#EiRwar`h3{NVx#JU0x%zQYoYSt!a3EK zHLCMf8w(j5F9#pKj9GH+@0mZJ{+whxuSRMT#w2)})Rlc+^D*j?7ec{^QSHrem zw@Vg0N|qLuUc6U*(Y5i?KmDce#?tBS#gF1IU6&Tqqn6e1$-r8yt* zh1VNP(|=z#N4^+Lk#|S+(JG}NE}BF0HIKUQUC%$9+OI*uSEEKp zmQC!I2V!rVl`ijFUS75y;l@8&KFPJ>aAbwgV8tbR#f@vlqIBgh4es-0#gFTQ|B(-Y zb{~SGKZKNi2pCz3c=Vx}wH(F87ItJc&Tciqca>DSnz9e_Z1&3Ixwf)EBpHy5MvIep zO#{&K4kQ#tyBfO&9uzSHLMW1`9EsQCj6&k&k9Che#$|xzkD{u({1HsxCt6sL0ZGkR z0fiJi=!jDg6>>C~VaMf3Uc1PEdeIOi5@-$@Vz3wLfn#&Sa}7j;qZ#Yhk9;nf`EL}&EMiRRBa21rMD?~_&@Spvea^geoOs*Fict2d8 zhOJbxcOgK#ZoJ=6kAXPTA%H#LxVa$#0208S(n*9600`RemF%Ac9PJOT(3eu~J!jT8 zA>1#eli%wbAa6##IBjkea|5p*{cnUj0Jk4>+>RF{LYWZhYWco~W}h!0s%<;p`}Q$XQ6jaa_d75$^0FDsr9a zIO8k`INlKw0XRfmT!n<-0K$3S`H-j+;36a_F^>>*bQKj{etkb1?&u^qE757uo#r6-Nk<@wr=3h~rjL1T`qIfQ3Y z?4XfX4T*s!;{|z-NG*7m-8HJ_Svkd4sKbYUSO>pG1BgshP~e#Dsq+9a#0fa;oA_Ht z(-eKtm&a#sIve3;npy744@<@&yPU80tpR~1nb}atl#NnQGP2wah+b~{Euto=HB{h?@5cyB|Yw~ z=g%t!4foUk{`fK0H+fdvaCh(f#&e0p*F7N@Grz2~HKe?DnXEsvyfpdd42+kslmk_! zHfB9H2$g_dWvElFPcOxTkdx?g1fPZjnUBvii}6mt2In&GsIOC%TLdhhVhVah_PTMqt6I7~_KGN~*ykBmv(ubPtEdNO!)Ag-9?hE=5 zCP$(^4@xq!8zLg)cYrhlNAbZZNk4ZPD!<6GBSPEd6irNEhY$-9KveGBkLrQY?(4h) zpLkX64{pfh9(Re?H515_MKPPppe%OWxEdBAm@%RJxtnHS{<&x9L+9tqgD(oZuJpfP z>%KhpEquMVS1=;7m#O*kbKijU;f?-ht}hEzbTL=m%v>eP-`UArs$muyhxN`2%8bWX zRB1L%Rh*Q4cIuL?881!H+e819Oodm1#yP1o;>L2Nwi-GFzXICOYVaw|_02K=sb3SA zD+jHT6291205}~#idJFI_jYW+U%-r_vOVoNI&)M~N0AJk9Ih@nLze&n1VVCS#+57( z@M}JswAdD_x8ILkU3}2V#iPE_KW%4$8AGd?0ts*%3vrWqyOZJr&wMS?2cCLs^_c80 zI-XTcSk%o~(s<#XDgN_$_+#6|CDQ8OftR-5Z|yt}x&LrrItzAW_ibK;YQnoypL;Z3 zc*#g;EQbs2_rLdXQcaw<{~eV8*WN5Mre=#_@AyhbrpZWq4jfF@!SQi8)HDk-=Zeo} z#FQF@JKTX>eH#7LLk7#twlOXv-gE@TNPi&A@8gy0Vq!7UOh-0o)^`v52|}fu4Ut(m zlTS*Q!sL*Dc}bu7vH5$GI}bNW2mMh(JT)K3v8PE!YEv8REY)A?y4H>Fp$*bxon!U@ z7|IkjKRgjZ9%Y7l@czVS68N9&LzTTBa$fk6g0h7nc z*InCWRD6^Qpjf6S;}U-p)kr=ded>V-lt6)hLT5lwuJ7(K?%%eC^mM)Bg0ctq8JFAg^ z=<03>mTgn%$-)Dt)m`Vu?kS}{{l}^f$n2P4!nE(NZ|9gCt>&O&5g!LRf$)b-72MP_ zS#K3Y){sBJN3+7%?f`N_xe$;D$e*6@eaF}O8?>}Dmftsq>S-HUjqjNR9Ffj_tUrqs zasW8S;{=sdKnRYeocQZ|1HjqNwbVgHPzm(9*y*i)Ja5hi#sy4CgUR9^RNC%GlkmfK zb1hwb(UEs_F;x)d$;{>v#$JLJw_AzlJ+ZvQY*sx8+lE*&$~y?Q}eM?^&_LK!<%vr!ytlDbjYk)BRyM(ACLZ21+SP*mpY9yxI$|KY*DAoM8o0N}!YATyBG-VroQtKt3I32nGp3Ts|ec(;F9lJFA8C*~U?nhj<-NHryk*!umLHn@E2iV)XT);83A7+a0txI6$- z@^;4+&6SLv-(%_N8-b@;l%lVx;GSXPcnThR=(1dv)HsCePn-!ijjUkmtZrxGPJz3Q z!u0m=T;*``Uto>3y-%DxaB2aG@i^9OdN#^b@tAZTDMxqB=yG8RANLH4GRAD2PP8{l z3t{)yz5NUoHbe;@Nhp|Gk1E{#Pd6b`_Q{rW*G|@ z?hj5E)NS9~`1xKb_X)Bqb~5zO|oK09m7_*S4>S*9Ux%Hm-lgH8_;H z`vlr)G?6Hm1Ixpq3~x&DoKNg-m1GA_vNwTe-;Oa#BJ;5vcl!C<$xsX|PaiYNZb{@$+^185_zve7sFbreYgF9kYy|YyzrINXlY6<#!@`b=f3 zli5uD-rqmH^qzM?6~jx)xgWBR(MyJMClcFAM2$KBR^xe6SuZsS#K}!LX2262lBOwE zz=*tm?cOMUW8%ul_HCgXESPni$)EIJ3y%%QC{|RE08opFf9Ay>_qwl)Leh7i{$=^Z z8#xQ#25Kl0g0v6`sq0%&7h$Kq;9h3^o@V!zhVLOW^JjqHRjBSDPn;GA4Mov0VXWK` z5)Ft$Ayp<(H_VTrnM9gH_=}%z1+E}#Crh>_U20d3hXa$t6P5@_U}V^tG3_cJSaAV(@On?g#rch9|w17Hkb zRKP`MBHeX2_ugF25-M-M-!V8juY~RrK*);(-A7h(^YOVJ1G!eYd5OaN4&li;QA7Dy zLV#p~&4Jh_M^ARTWRph*Ky0|gEF{U_b^s4Zu?Rl?RD=|OAp%GmmBNHPAETBfvu7(7 zKojyWC8Mn|2y0qlDF$Ib123V&%V_x|cXnPn6(CXoBJ77I$VL+Zs{nIszSMEJNgFu0 zLXC5A!-c}almcBjB4k zdo0T*UmY#<=fHJ98*FWFll0zO}4O7tMg)TUs1B~ ztCS93!{*RCOQ3Te$RtN_Wosd^`)F5e_WSo`|x?RVR|G9f&Av8r%w7W402N z{4@G07Uh_aGO#D{W8u|reOm9Lss|#>h_UgTzEC18cOZ<&%uFGPFlPM!Re_w0z%+Z5 z5SST&=<*eoP;Xyhlzzo z0pyr(i{%eB{nS3eMuI$&a2}f<;=c^DolR*{3ipW3HYrwu9aaX8kWj1^HbbI(k!eD$ z0w}Bu>V;oa{UyAx4TIt@(Pk0vrjz;zl=L5h1dmetGCn&c=;U#TS9zTWNl-IZUmA}a z`M9s=nSuzOg=$La$>C(3A<#*ROiXRtL0D{uaKZf!+>6AA#6U9-)ycoBl*98A8bQ-h zLqMS38%?8?p%yz1nDCBN8p>)0Noz#e6Fn4XT8uT^BV62T)Y#92dHMnoFf4>XPR^!# zMlxZ)Q1I*bx)L{G`D&p&d~hBnY*75Vf&hURZ*Dg6e8*} zq0>N%*3emPP0y44AY8sf@ZW^{li(4|rd%L`rx_KtiDWN}SM^le`3`GEuwMY+CiIwu z0Th)#Gi?uTz&a;L5zb|}4$Cvr7$>w+7}3UAzT_Bhd$$Azsi8G02Zws?a(t*Y0(P!U zY%DX1gxNWM-JF4nBn_SXc_l&1Yfg|&xT0BJX{h%%W8WqGMgsHP&!6rCXW-_vn=)$f z6msdg^B{eKGE-Q-Tiuy^Bcvqa`t(3vHpw2vkmgitoj5O}`|_v`yNm}JdfZXQx?ILp z`smSbGDc8Y(PYrwR3C->@TFt3L*Gp-57|7RB(m;f|t%UpOkw4f_h6* zeI^}MHd+m8@w&UX{IE#)hy?x?TuQ>mk_lj|3ra7qiGm#pKF#N3;h)HoE{Kpn5S@74 zPR)6>WM;?a<4l7FPkqyg<(@dtAp}SD3Tvwz+=kshk+GX?eylEZm)_GP%^6Ph z_c77+K&*R6Oe^9+LD!8P7`%0xlKuhHKiHE^O1!xl&!BtaXKvj59NRd9YK%Z>Mu7UL zV{^YxkWlc0^Y2B?gt68e+`T}4oi8=WwQ)7(wYP(0$S`#?F$akF^Bvh(A$;B1=W=4q zhe&Y8>l*%V9g-Y8Uo5Ve1b<-?0OFXjx?pRGLL7eb6eqsp~MllUn zZm<0#pu=N0N@)v@<-gAdovwIV_`qPMPfrSGXoGJ*=qy-!|8)KM)7dfj%JB<(1X&sJ z(SgW(f063yyM-xqS|$zU%K~4f)SrCeoRbg#rp11=3I%0&bq8t8-c#?qi|7#Q_M1fN z&UF3pgd8KmHwAhQ(xH2ZboWFMN@F`gKVyJbGr~N7ljb3B5#L6SjkDEAO$WP^QnGwv z;9W2z@x(;uJU~8EaO=zunJY%P=K>g**(NOJFVL9;3cW}2FaqB^K&9G44kb~BUcx@9 zYeYTdZNLKlG}L~ltwNg*{BAPtVJft&{`tY195-iAA`@0?yEt<$1&)Q3wV^`3&&O`S zOvBUEaEpo`Xp7%WL-?5*4$mUl%pBv*nJH#&{d)DFncojSe|2+Ddvn62+X!z9C4<|? z)y(!v?kzrjlMrw5!=P?D9@KNN_@rv%l%D_mqe8tEjrJD#W)ZXpd^2&t=uPj`(2_-t zTftCvf$NztOju^Q`>uJy?VuCauErk2G%B$&#R>FZD3QIN!qsnK797nZce5f%HjVEU zZcN0AEsPG|%Tk&FHa@)T7I>~}_<{|GdRhc?ywH1EG>ZykjdZcS4Jt~HjHNRg>U4ol zQMO-6`@j^3$kER;7`GFaBe6Sy9cs+w%KBw9!N81il+sA%vI0CVW6JMEx{^1T8_ND_ z*+4qWcHY@`jn8go99WVaaOzrfx(_Ko;>44Y-v%N?UW484_5W(%;Z%Btnx|LA9j=2y z*_niEnkfNx6w@J4Z#M#pqaYeTAFKfB;g%-u9!%zQEVUbTaqEbk&xJ#j>|u>Mt(2-E zkZW z)4zcJU-fgxZ|8jVTbR`xbe6dbRmFbEn)`zM_vJ)CEcpz4ZY1f&RKAqiYm8rZ{{F>) z80{@#ZqH>yP^M<<>Eu^)@TO11NXX-2H6B^DS?kw2O~9XLSYi%;!x& zi*d0cvsL#f_`PFtTZy-S$-PO^#UP!pgHH1pwzYSP3_w!Z5=|%29Gdo_tY+WA2JP?@ zJkQI&nE4&u^!<{8a{km*T}7rDp}^}v(nt%G(fIou@r{5lmF|}zZMm$`6oUhPP5a40 zkR0-X?HQLMfLNbM*g}HmUe#~e2brkOzsInDxEslQ7K=ar$&>9vLMD;K1 zU22?`JBUg78NBA0ueBEBu1;`U4crYt#S6=XK9}1BH;<(Xf0l_)N^u{bv`AtD!Yz_4 zlx4IQ5P<7sNK)N5HgQ!0Tc4BY+mWR&o8ximn15$EMFP|w=N+K@J zzzVA%2}mW{tK)f5rBY>4go{mK-z_M*q|`JHX@9DiHi3o(ux;3Kjago4|Fs$C<`&)^ z{y%72;*%ze_qIMx+ocwUMi=a!$`vy-Zw)U2JtD8D_gAk z^@!GM4o}te2EQ!bJo9^>Q-6qb@1-H{w_YNoRKfpxPRi-=xx>W7S7JE+Nls}bp*RiR zL_Ditdiu*V|MzVCLNew%Ly+8nmT8Od*Hf(TGW#|Xu)HUV`*Y=KhD?Pw+$IaX$TJE3 zS@nteYj+#ex#E9{2fgnZpG-AZQM65@j>k0~@y5(vOyr`uO964XP|*6&{FX0SWp*TBy|ties}*#4I=C)+1RZkWYW<>Qp!s+;hxi@v;7#Dk_>6tI^7Y=w{%7DO zC`s0q)S6T}2QsVAX?sP&kD=nlBWa+>6irXRDh9{N2SVA?o&V9S6z+ zf}B5$GyZ&-7i?0-SO_VpZ5<3W`NyNy{@SrFDI>qmG?~B>#DRS4i)m0P}g%5 zX@|wbQ9@8c{?z3}_j^jx#$vTn(w>faR{Hq<&d#Qm1-%W%xbgdsJdG1Z(~VXR$*?enj=ICK9_&HI>CFrj+gqZSM3oUD~ATNkC(eYW7e zaigm^Kes5)I4Or)I#y~_It0eLBk@h_S20|7w`~ml zQ|dN#E3v;37S`lKH{q#hDYIBd%G%$AON#g&BTWD1JxOcqb%1PD7*$M&fAC5_`gf;q zIp^nWZrX<%Cq?auw?CsXhx+@Llx8Mj+lVy*W8yRD=hHb71e~E76|!fCfu!th7)CA_ zS+11>)!TF^(v-!s{FA!bZ;E+L9sTix4ii_jPdTQ2@@MongWuZ<-1=DFwM$vUVXO~S zo5&`<22fYHm}~z~ZS%wn;n6&>BLJglkGHIS+l5SA_uY?*( zq=s9*TrE@eq39jg1|%`ScV%F`q<+aWTuI)Uo+nHm1snWQDM0Mwsm)#Ngp9K>4Pa zzyFMmI>F78MPd7KA&(G(ZyvP|FaF*%PXZuZGu%5L$Ld!YQfCjb$f)I~7!F*!R%4lI z)<}G-dQXRKTW@cjZy;B^` zfzVu+L;%XdeT=8HX)gTqTo)1X$o(u!p(l8ohrK4;{mriu*{Ouf@jYEWUkjh#{FHDd zZKKQYAKSt$%~=FjR+m3_(SpvF5n`Sc5g>Vn%Ct(nTG`X>S4CXBtr^=x+vpBCaifN0 z{2rbm&4gRoyYd~Zw@cNSdvI<#o5W+`QbVQM2V3Y@52_bGxC2m*gX0|9XP{@lN;N9# zcL|JMU3Wg}a$LhMJwq!nro0guIMIyGxpb*qTSXDW(okQ$W!oC*5HQ~RrS|hO3+CE(V3YTZIDP7 zl!QXJ4$2Ms?V&uCSbq_~ulsMo4g`ZO?P3|h_j zVT7^lHj1O^8bJVGyYTd;%NG2B*G7cJ`w=h2Bs4%IADodq_ENlDKWLxr^H1lHyn9yG zZ>4a@&w71N24G^sPxE9I-*Tmpp`*?CP5m_pTPnjOG4SEI*YA}>(_wrLi-lY9<2wSP z2i3cNTU*7HBg;}}%_nciZk0Q|U!J!gK9TUAZOipNJbx&AKg$v;?sxm$Ep;z^eIJ9h z7o9r8MCt-!*lf&{$0LCFH3OZte&Vy+fO_1op*|*5kVc;Rg!R;KJyYNRquod`Low4+UL_C_cYKmLBD2&HkuV`$X+4D+dw6$rEzlYmVOfc=GY?(};}k8H4)o5N}eR z2#rviR&TuJJbmVw(AM{|2K{xXE5GMpw|{hH7H%3zrY)Yy*cTkaI_}!fbJdgq(l~izb3qV21&eT@M6HD z7|51V%$6B4mnCEmp2}8g&pterEl1u1HZl*7B(ICsi9^@Ftvik@(`))Yl^mtruL zZ77^mjLC?&CeEE4N!kI|%}!+m`+k>?KZqh&)nowpC_6=9uPxrgKH=A3^!}u${_}Xt zJkZIVTzf4ikCX|v=Ge<-#V)w+Lg50(Yq<}7Czw6VJM^Hk)VY`)TYw}dsM?M#sGJo3nNct9d53P7Z6k{$)Q zAIW#u*WohMQNt^7?uVch3=h;EQsrot=z0tBG9LIER7Rcg>$(evF*DMyA*etYK=)i* zVFQ9gdo-%L<~)H!U#=P7gK{gRdHKWEyoZUtT~)4Li;(o4JWr8xCCDu0>2vW21bG<= zoy=m!C;190OSnfAbkr1eh^k@5?^Su8vgG_6`(*V6%an1M6oeRM>8xF>1`3+jd~xk}BrzJOwy7SP=4$~SYhcNfoH zFSsz>ap5f9;iJ7*#2tt#6RK+OIuv%{xl;c9j{29=H8-d0-=M`{j9Q7GV7zH1tKj0t zu;AAn`xiI%xK_i!cONf)w``D^xVT-=u-DP>`~1a+(+&U7bciy2Ah7`!PDd5e(cw;r zPCDl&IyYOR(EA1+t44wFMj1OKdyV3s8W(;vN+~zVC^sFlYEmd{QtG_OLr)G5 zXi{ctR#R>+?0^;Li>l$8bvm2%YHPTFWb#iy`(Cq&)g?1F4;~u< zWvgk~yO&(TTiouM@?z4h3R`?WwfOzQId~>Jv$Y0=w}#vk^}L>@$AEbkw#Klv#d>lP zJ|$&aw4OddnmgO53?TeoTJ-g{Eamo4<<@J1uq55~g3fl=LoJULlF8TG%al9xU$jxv z6jErq9p^hcl&sn)`R#RVosBOVdFjbnt7$dLogJN>+@IR6DL~W*JA0M8K+pDTKRfyg zyM{d*20o<>c6Qxn>wZ;mskY6?`cU^|VYkdgmp-d&`cwDg)Zl>59GGP7>2|44r-Bvfvf|;P*ha(#EBE8rlwHQoS5wPx_x3? zoC|W)K<~+`FqUGOU%|ykG)@E{wFieE`)~bF5^#q-0sf;O{x^LnA}cPYC9WXW8^O=Pp$?QdH6vayq)& z+LJC{`A;HiaA^4Yje}3V&7`)pjNYA?tQ))3r`p-wJMi%8)c-4aUbuH|>FqoEn;HOY ze3J8t0xRLu*U9125&Zn<{ob$NfBx?Oqw@2OHT@WUIP04}3m!$mah1GuFW8xi^kym2N0)sJ}U2law&48&YTSz|b1sGBOUC{6(AR zS@vUfTi8Ku*yiX#DS9P3k%lw1Z# z`qIas67s}V$zr`~i)NX{#+>)vMZE7GK_wSHQOU#mVIM0hT#u=EjDCZM((fKRv))od zoNmI3@*Zr18iI~+^|n-pCJF9w4RN5y)Y$Lpl?xFslFO&GMAPHV?{pQfo$gyN3sUzA zqw~+de0-~%>z7J@G4Z?<2VrUp$-4t!^W(ECr_A8Q{U2N7J}DasS$=h27Ta#uE`-%y ztme_In>tU!ADWuPVaGV~N5nq%J*@5hTK4zq1#Tvi?N4{(F@0r9Q+~Xd!=a=fvlboM z`uaxz-{57Wg_@#|#Q_UG>L9D|aozIy)pU%4?C~m;F;VI4h6YYwvM$CQwt6#BE9%7g z8K$*h&%N9g^JAl2ob2!L+*uWMZ;xQ8nCuWtJ41U4){Zs4xnOCx_o`;qaj-?Bjwk8E z`$(?2rR1}6TAojjB>Cv(e>VQ+dZpPK@b_Xj*IOHUFReRrN%BnUmpP7)iCnuBWR}nDyozZs!0j*PA2rm@$3L^^;@+;m{Oir&*Ztq4 z#YZ!DH@_bH_ZKY}Af@skGdu0yHv7S3vj+V~#9jp6e-|P|Fue7*HKEbo2dY3AWs}Ix z5>}@mPL>%VKOIfLz!5~TM*hrLeAGq7x5$pIa*y^?xin!sN(eOBcsN5Yuzv&WyA_pH z=J1HRi(I$gDOi}p37fCOdCu;N3of*3)ZcikRkOya^!jLU&!`b6|D4)Ry>UuDNoe_5 z+^{X9sPHZ(P?1TIRA+nV>(DQ)_DT`0^C-qL(SG8qNb1p*6-FPZTc?JJJk$g`K0uKSAUdw>dt_cR(gBqfZ7EbO}3 z(npyBN)ZkOW3JQH!=8d7ydqZKY{ton)eyJ;7N7WWxO`m8G0mlb`q>9?eUn~Gc3-Cp!{=#I zS!e-YRl&BfS0z&`Nkmu8=zRp-uV z+tSTizP)k8jfYOH^UKi8rT6*f8o7hn)-+BnaeC-&H*qCg%=rS$OX#PwKwj(t@tPl?fZ>{j%mRsdKkcW5x)TeNgQ1i-iW*DefwHR;+js7b7-3-eJqhtg)@tzD*S17_K&xcuBIdKd=AgzwT(G8hP& zhgswMV{^>*;X*~jk%?Mr>e2utWs)Mu>PRSBbCubU2|n#PZdhI>8K1*#J@!JU-<;Zn z5g1&g_Z-cwA9mRn(w_V372J3`^0m9SVtWz20tQU7F$KpU9Dl$_#9ckZIq7_^-SXCJxfq2niO2P4mc?Gw7@~^_z zvKy~xiYHh<0}Rcc*_zzxBkbN!va_mvAM?Sm;r)Jl-|3UgYR1(TB*=g7I}wqdfzQ0I zgSoJ1LpaB1G50R1`x4*rb9>o0W=Gxl$dhV|I3QIMd2`733gapFy1&-YqFiHK)cBgP zQ}7K{Ep{7ao_(hGnA#2dy8g%r*^H!irGgIA6@ ztoSY8+M;hd`15$AWW!&7HvMNi3-d~zIU&9Af_&?*%UBO9{*)|E;D4Cl|o>DYyWt+kr9>aKuxzZeZ4U?@$~1C!7e2t z80#jWf z5#=(4fY?hbkfg5aygF7y*l+@>M?oX}2_VPU$mxG5lT3BLYSPbKI!U4EE0Sqd?!0<<_Q>d@MYj zrW)}UVeP6s9wc9PE^vZi#;(M*?k=(Yvy^l^b7SGSqI(9{mJ;h&h~ z(5w%(Zs~wah5B`QG2TheKw&m+ROFg*99j{%VNw&_R$E+FBfMH`=YgBH7$1CSXJ zJdz&6b^b(aufd&C$k#rO{%B5Nro zpFY;FoXeP8zPMEo^nF@*TgQasYQ5*gMdnYm+w*w;8g$aI0B350zmzECg;DEhZJ=dI z|7QNtkeI;^JFh{0M>KuG;}Bo1k>@E<(`J?HQsm;@=x6&{?BZ0v(B~;-INPeX66bPd z{tXMr-NV0K<(~K$hdgxgm&v6$d~@+;O2!jfOIGo>(?O`W2EI~F2C4XQB^ANNrkd?Y z^VEa-&Oj7TlN6g|9~$GF66jEiDLr=9B(TuKwFMd9@(XiGeYJK|1ij{#|BrsDfK@(x z?C7u2OGRY=Fx@f-NVPSj4f&(_FR@W54EJXkME&A!qJrdmSjQd6--IL4zm5=Ia5b>i z8pgF7PH+yp$&y>!cV*i2#;T5m(v#TG6`#1D&)JEyHAz~5f%o_uu64a&`ezlia5r^+ zA8Y@EZ&Mqr=(D$f+QA(#21+o~SJa@}31I3pcK>;;g3Zs?6=vrmxtsK<=NN<<-bvT^ubictAb+J@$W?9ONh?d7t^r`?_89^x0ptOS}<5e;^HBp$^`7W7O{qSs?WcH$)Y@ z}3!KC&BKAJmjh8jay+^vS9xYKg%30lHOe#am1F zAuMQ!Hwg$M0-`1ynnE6}E*`z=HEKZ}ZJrpt)-l?)IT}xeREL*bu^DUJEYPQn*_n^s zWDN>a##+On-J)X_jM2`4@p%0B;Kca#_hao7<4ql758osD!$-RZ#+XCz$7fO|ZWTkT zi^KZE$7sc4Ce(?J_b)p-AWbPHw3Nva!^y_*l10O@jm?Q^j^! zl5A+6aL7gvO*Y?P6BYv1=&HV{P!TKViPlk!$0I)XOaTnA00XQ?g0Nv&2`~_A&C*Z> z1ftLA-v-neGbTo}cB!)#7iJw)KsMfBBkx%*2ACHBoKjz({5FHX&5HZY!sxT7OIRV? z8MnW)!6)Wy|AM`}=gd{+B2wpYf5B>mIX=={tkGO`Aaj-r1M>bb>-_TdsSC4ZE3eP} zowHJT9cuI@|J!`@?fH}wZ@91^0V3dJ1UTM)eNOC+kJ#(_m-As_^SP;WYPk854{yT6 zUfZ8o;HA!&555Ud0l8i9u=Rdx@nP=D?S(71->~AiJ-6T9y}-)lF2voQH@#3Q`qxJK zwt@DMX|dV&P59~7-?>sD2xE`Fo{JxZo`h5s^+{d3(cfVEQG_kKUE~bER@!@Z4s@9& zU0xR$pbg$?`pQ20p*}BVB=tb+otR>Kj&`b2&KINP)t5bk=*Aqcd*UVROAqgQCS_$~ zb#r2nB{#E5^gctFnei#g`Tgu_2A_--KadHZ25vkOVx}z?;^~jRJiNj9j7h_ho_Y@B z7JucHYZWa@_O@xiVORU;(M!Hu)^3h3`f^3ddWb|fnsk4_Se!et)EVD?vGK|y(o)Ki zvuw~sIdAqbb`+8dF`7q_WIa4SBS~??JRc$Y^GN^B_nEZXp8$%T1Ti3IAt?|e1|hA| zJ&_Z|fnVUJXRV?=SS?M4`Kz8xWZXx{JqWifp#g~o@iBmMN4bk1J1#h0$iadVwvcLM zNWR-j_$2CxF}LX&%F1~83s;>a%?}DD^eMbTx^_WMNdV)+FmC+OQY`318Pq2l?0FSpL8u*%+Ky+G zTVCDCrSo`WK|W`}qtBSTm)dtzX#$Zye$sY7@RHRz)hwkPktJsRd|juTu>D<8KVDzZ zJzn#$JOR@C(r~a_alw>p@{sY2;-Y6y< zj`4&%@I5Fc1MggTm3X1&KKgw4w;ySG=!hxcV2svrqoQN?hE2Z|nHbNgd@4>(H;()A ze$8*|>sCAoK_tY#kOll$H(^LDdbPR@eKEetrcN+KDmFgzbo}Zm6dUna0mdyz%k8*O zy-jR@+iz?vvqo;@2(>UFCP-=(Nl9L82x}uz<=l@}>Gsz**anG^`aFVu+cp-+c_-Cx zIB?)*R-xq7pckiY8cBt>LMIJGePUNZz?Veis7Ts;aK5md6WG9i`^HG|;~WkV{ggGz zL~Q~8ixELA;NL2IM4>tZsnIf0E@NMBSfJ5rcPU_`I7-hs_qnC0LFs<4#*N9#hW5gt zO(^FgW4ZIj56>-4avLK&SP0m;S&i%xG^Qu&#<+uI>J^|Z-a^5((kepu59Gr z8m7&(x`poQ{y=Efd7wx8{ax+sm-(IiFQ^)@NGiYU-&0OM?~SCUd1)55$=MX>M9u1! z4w!brN6N<0=eDmi)@R#2hr~7d9ZpY_kGFw79CO@U8s9z?+M&^|QB4DX#uoP+7#IVX zy;Korj(ff6=W8?1J?dsZTc$9FbJ#EVd|SO_wR=diO@;IF74X^2vjVPu@BJku2(zo) zs+v3MuhXOU`6L0<<}sU$bIX~yW4N}27kmb>FozQ4?lUXg&dq#ZRd*Hlb23htVe4Eb zvD-sT7wos_A^dDAw~XPf$?l~zcB4FTDx}8#gzxE-&l6TI7o4x3<8k8=dZ*GeRV&7< zyLtZd#rh2KJnZ6Ky{(umKRY=@^3TtvN)3`a`*mjt|ZYI+s4r*;Cheo}z6mXv(6p9r{tKYK)AZBVJKFrbYv7`xe|xy^bIA z>Jjdg&nJ4tuq=OsG7m~`Zn%9zZT7aId?bXD@ik2v^Qzf?MaKzL&YGO|%hW{39{6L1__x>kt_ zk;~Pu>?yPuT+jEuIXLMpj-hu-VkIDP}6?8UQzc|l-jQ^KT8gIS$pD4=ER=F zSNRQ}4*9nJ;nQ6W7cLg*-A>{)P><=T*4l}=ajNv&!{!7-kDxj#ojcxfF${4)G7NRWZTG+8q?zKfFIa^f=fTt0&#=}fb`Ztqg)w8u_bDj zRTPfvBE#5Zfs&O+z@fA?h+=<3p%PLSanf(hdUeaN}k4t(eQ3;WrFEp`46E zw;O+S+%Wn+%I13C`D#oD)TDX;RS0|s4cT=y{j4>bDbC*ng~5!te~cTcp5)=nIcLdZ zYM16SD&agPeGdK0;YJO_pl76=C zyW4;A`uW#gg)iGZcE@I#HGZ|H{=GGmv~f3yTq$}XRnaA$G~X*c*RIET`&7-J)3@L5 zw3CcFJnGKOHe3_9UE|FXu$LS*q_#0tfEmEfapHsg%q}I>RJ+DT5`5S)r^O)Dw=}YZ3 zVz(VL@;)7IxDBP^W($n#(W0w|8?)3r{l=q=?^M4$T+yznoAkRFQ~hip@c4s;N!hiY#;(IW3Xx)$;mi7gSB5TOENW zZ|bJPuHS1@xEx}4&^J@-xLYUvVND5=JX`lXx@9+I)3~93b}(X_eU2lXz1L%6^!fIk zH(qP!D*Gp%F}3b|3SaYSNPK&~`d3?t(W;XtoeA=|xP8ZiGfa0?_+1b@?(#R4)m!kf*ZzI~9eZwI0`Xh7TS-;v?-xA}0v? zuO7ZChW9 z2)$x^Wa7h9*+pIqT1+^5-k85;=-jHF#J)9$u_*JZT<(&&)Begu+_rUkT@9Er!boTVUr)rOWl$9MWDW&gEL_X4XT02~`PyaL9b)L7g z?C)k+`oa6}kA4qvGZ{tchp*L!_AmdN+P05A+>9JL_{9D1o4N1bovw7Fh9D%bABbH7 zX$fNbnu;<&5`F+x9gtuc!wKA++v#XJfS_2wY3aEbq70rmcQjq7Eki^w&7J~1LC>(o zCigu6nq(ZHWYDi0nG`5UkqC1mAYl~HA%abmlI~7{kw42RP+(fY{Ookr)DP@V(mzGW zQcFOZ*Jc~-fwo_;spMxrc$(pAlfx8ggZ{mTkg|c`w%Pe8@Gw7c=Wj=0EG*Cl2BlgH zkw8{WxrHQ<3nepZ&lX9B=_0f8fNVY+)SshZ8GN4pyf`}vmNeoFkn-~U0BMpw%j>}a zU}+pE4*+3^&h8ZAXI!2;85SRGe`>AZs&1Mc;XhkTtnjQYfn$!2Y^B1($cVicjsf$a z09{ycoApT?Op^!b?M=$V0fLyk;SpOIJiyX&@`3D{HsqgpZZwe<&t-*kVFyRSP``qN zT9`Z;rkW3PAm*6{195xBxzv&`teV4o*vx#k2pQ%<$jcnb|6r4G@Brq?n&P&?KIS7u zNUZmn#g7ED(X=dg4A?OkDUL7p#N_rs3pv+GZ{-T{XxMxnV8H-F=|~g}fg^DrB?5eC zrvPLz6blmr04N3)*qa;ao*NikA+HB>q2xj^u#>DnD^Tf5D!MCJ=>il(urMKfF2M$- zAXEjAK~{AY!8W-rEG;M#WEE0@3#l}%OM9GusR<8j49+)gL$WqVgUVqJSm2v3Sk(r^ z+5yY+%fe97G4xFKg#6szf}`jffC7^sR96R=IAFn6^XV`KNHrLV%ZCvPU`J^+7@+o& zU$z^*>^C0BFDN$F1-6i2b7Tpba;bNRbajE`Rx5zVWag6P+nE|VHhA`mW=AA0H#i?S zEmSFpsk-Y?VOmhcj%~Piv%%G`f$ClbzzK_aMhxa&5dB9rp&Rl-D& zkaMHuzUjmDhW_JHBfR}AH?#oqB^L#HLoT^e5M3om1L^PQ z_S-hNU@CImEBgC#Wl)W;6zm4_^Q>+0OkoZKg$I;MT{_Oge;F%iPTLil^ zgW5M+&)m=_A}{Zk{O&D#<6iCHmvywh?9YvK2Qt`!kRPL0qtlk zvFbcj(<|Mq-$dZtdaq{0XzD{>bJ6YeZO?G_>r@U!n&UL0X|RWAoiAGarldfVKbJi>y7DkpJBp1K z_070CkX>lYsicZ~iIl#*mb9;3kg(RwqE>=#w^uy~MrxK>0O`tw=pMfykrgz!5)@nA zN4R+5*RejW)eDwEu~p26eV=qfTZ{V17b7I%`$!l2Lf`bc-S6vah#9(0cx82gd@<&h z{lkfi1eLtdztr(M60cYi?OO;n{p|L(8;_vevp z?l4cFK=@1+bRRT>%=nN1DESqDZrzJRf^qG6`^W+qtprVeB#s5YN&uqzuHxs@S<--N zFaQUJQf)!1@^=9GtqMV^I~sHp3H-DNL9x|G01)&H3Qn!{1i+pmoqp_(zZ`}6uml1; z`w29Fr9xt8>XtGHClV@5$&uSKSBO+~FTVwf19Tc&T`{dLq$dOWy?SGf1`gc-`f@Jy z!I`8MrcNJas*XqBt4hD4;UpF?GpsOfOrXVH;>@~|yz>mBoqc?*L}TsJmhJPSZRrO$ z%B%zdRe4}gKVP#b3!pszAP7MGve#|0&UKWsrDVGkfJyxqVTL7?P~_`+BqTBGE3p(i z0$L0%EyO+#e_tS3Jo?G4Gn0()!DQZbkP&VKEK$(prQ9R-}L_f=*DCsdo>Od0J`z(GN>bpi`YX zTK=OSN?vdPp=rNbCZ$ULqaVtrP9r}9tPvd_8iaibSfN4JEg&YeXVh-M0^7`~2^_Do z{3Z#t@`DOcW|Ua^VaXKtYwg5TRbvfUIG zSp*Qh@K^4t4~ z)mbha6wCJH9T{QGm?ye;x^wC z)_CUQZ4?s6YT<)4hQu%s0+)SBJxD`vTTFY!4t+5#a$|_ z1j`@CfYe6`KB7VZ=6gxi#V0SUUR`4y@67bjsCsYIJ26uq(C0k->pTns@BF3;;Je9IK*CFUtOVYw<)|X3*(v=ih z!W~H;GTiIzs-cfEAB8iP_+HZmnnF`d;bOBiN8OS+UPpZCc^1hlZmN0B4o6#7Vm-V7 zhe0_0R!3dr!Xa!q{_ceo$J&L8>P`J*gVnwO$T z=0d!{ZX{EdpGgVolYV|z{ciMqd(7f{9u|ZV;_7Fv4@@rgHzT-+9OYbWs(y&GFJ(qK zS#iUq5Jq9DkA(Y60RQBj?$w1qIMkf<`pF&bOuWP{hBFTjeZU1MeMD(EZTtCc4^FNB zE;ljh`klb7#z?7fd=4HM>F5 z=>6`e2aC$(_qZJ&eCOsSNAl4mwCHb!&7ck3_S!1{Dz%_DOSE-9SeX-`)|Zh60L$RX zveD0C>4yboR@OX)g?v_40;K91t;_-rtFoH^X&S$Z_Hb{P%7TcvOVo(AyL?+d;j6%C;I2b56pO z9yUJ`)ASiR#mjCG&)5^pK7Y2etU#QLW^?EIOM7%J5laTM=bKWmm|i;qe%cLr4Tox; z!rjCpP1;Y5YFyjMH-}#Xdn+ogI`X(1zQ3#2*|BgZcuH}&SC@>=q`kxRObeU$($ZNG{h~-wJep7so=)Q z?Uq1#2C^QOBaT=8?B|7-|KaErk8_^nwUZy_%n;4ZbUs_KM0qaKy!RQ#5q1bX7dwLV zw-%G(a=NRYwpfo&p!0kQ6_6~Dt0ROiAS?_wgaG!q+UD!r%%IRvM1Em$$Ye#nVv-F>`~1mu zG4GVQ&+UVpuEQ8;aS%$yIb`@L;1RBF<|H0GHI{088_c2{j5LV?Cneh-BcwULn1V)& z=^Ow|)LsJXzY7I}Mu`L!nHS;1PX*2fzT=akD~@j>m9U60Y%ev*E^}|CU5!7!quE+y zVQI>dH*u}$g*bk*$(rxo{8t7>8PFMlTFMALm5=J}zIHSSjs@{X2|@vmRLbxZQE>T0 zE|)xH7?2<^&{ifAuUI>}HW=9#BKnx_=dvLKH_Zi2Ft|J(eR77NRUEoWt1X|=oX2hV zFa;rM{`;J*rO`jH?U#BYe<9pX5MnM<+=(>kVyRxGOdXFLdCxt1VTYz6BX~QT2mO22 zbXUyyFe}~~ND=)hdHDl*>D@(!sFj4HmxeH;BuESjHkTKJ^771z#!PxX9ER|!3UMKD zvhP&T%kHmIemtRsLB}aWgiA=3qa4?iRL=fT%w&1BER668zTNxbDA!{H!0w(4fRac- zvq$j{@D|Z0W;?y{cj+1!nSnM;+8_{c^)TL@Rc_b`zAj;)@aMVOKaWGHL+hORS#<($ zdcdt05*%Uk2l_il(Jvji75?OLUZKIXM29mn%`F5sNV&$FlAJ}Ewj@$xr7+(ao#T-GGd!|M`@M=1YnYl)!)jD>T`JlJn1#Rk)U; zX84p%C<`i0$AT`_O4`t#=B7i}v#s*aA|W`lffH;1vd`L|EdMMEU5dFOk}az745suE zRCIBEg3cQ)sDsWxM$b?9E24qnmrXh~xU*8zq~}6)bMHck>{p+nY5|;&{^R-BI$m3uN`_$m`$6Q-3Y(W3K$FGsyr?sH6pe_D=;O3xMRuY zVrvXINS=8OnM8Ra>>_1Z+hLSA~l4Z}#M@rJ#xG!uly#GFl)8nuW#TsDcpx_vC3mqstnqx%PL{m>Wk z$;=bCl?ImlN{zDbTA?qA(gzA=%DK#t+ZIoG)iR`sNfrT0V;?w=$-3xU?9}7$S+JTW zEZpX~c*YGTe^x((x`#K(oe6eSBeLc~!HCqe&Nu-J(%40wpwpj}B-EpYs!l!z8yC_Z zr=iO;2kTGObjMygxqIey+p)#kd`o5iKfuwxlbWbM53RB)@RDgN!}Ym?qeef~^TiB1 zncS@M69==VUgKIoRuo2rf2W$x1CrSQ;T!x&Q=Nr8&Z0ZRf@3^EaKSJj62J#bZSm+q zYlH8T0jY>U2(jtc#Q<=I)KTcWy2|sYKEqRrc8FmhmkWc@Q|=TU)Ah>batY8(g>e2M zc+VArrMsSV`fm~6tf+4ABB?5EryC3w`j6iM94!=UAz)sNYz;{eaBj)Uf#8c!2-0Z< zH9|3aO0+`1FbGBjeNIRu$|KfB5!rHJWWM_)o;6!22jMd}u?RKPe`~8MBOk$lvcs`d zNezdLGwQ4T1AK(XkL zh>c);;N9w9?BRcB3`kD*;xKXk+&|XwtG{4jAI-Ux(OJiz>jhfQYTbL-=)ssZ6M*Hn zOKlFq#2{p&^#g<&K&ynLOrKt3e>D^)nF)*p9kFCqhp9ZBzI;a4ucKQKmt5-XYjHB; zd0yL|;zS)`n}8G65C>@#&IBHNnBp68>%92;*gO-zEZ=|c(1Rh1Pxy*;cz6Y2{3<f8Qpx& zw+1QSuW(I`s(qAj=~}hJnX5PTa${GX@EPCtcyla=@DO%w}$Oa{6@&phrpDW`K?8=_DfYmpYQQ7& z_HqgHXeGhCYIexr)%$X#lFgCEosQE+9ifV@|5h|lVy#JOm@fTAYtA(SWhNf}OV{9@9FD=wX35U^xzk?z)AX01w1Dz{U0_ z^fc2#TJu4eD*d=ZAi|g~g^gBR!6AIJ6&G3GVcaqApQIIrRL^kv3Wj91e2fsy8%B&< z)~c)qqf!=+C9vWtAzTDBpoObksg29YP>g3t75o4jnF&Tf&%C=Q=DH}IMXrpeR$>GZ zbw7{Q5M@^IB8o!Nr_XZvpewYm@n+ErwQ#N-izzC86;IZVUl^^pse#s&ax}<9Xt`7d zoV^6^t1Vur9aPT&=)jQ~L=pj7fG<0C?}RlC!j}cr$b zMt#x$?WYl6iA1v2p%7teqUWfUcaqK^b za6mKq$wjC(R7X?arn}Jz3!U_ko(j>j!Rh4lH0nJ8;%W6UPa3*IJj48;Q^83`)b&ly zU5I5|4uqh->p{I~b$Jjgi%h89Ik3zZxB0Ey)*`69G1iERny?f^IRj>;hnP z!&+n_pw`Zvb1u*xz( z4|()d&1M|Z9KctStjiZHbf2~oV+9??ShozGoq;HctZPE1%*NU%6o=n+Z#~xtGDOJE zChn%WA5=GYDN#%^#G?=qa1(ACiZDNeuvFBDP()|lYKhcpj*4yGm~X1@zu7oOyp8}u z3ECe5jun_85&-FYHApqACPCvQEXTF7$GL!5QxSB`X!+##r7G{lW7b637@DJc#Yq6~ zq@Dv~%)2jPH7g-2# zj3bkGlB8Kx4?U~`gB@S9Bh6e7yhsc$agjE(q;Czbq*LD4@Es4AlJr(!Pb$sVd%^RQ zP3dma9p2a7iNg2vkW%^8Ru40Hv<>d$*u~*Q6cr>LRolv>IG$AT{(rm3q~d zgyZjDP+0GOSPTEG(+iq{-?7(tWz)xWO%9Dd9l?zWeG%4sK4D^@o%7d*%?24IbT!L)=h$@GE&JEuTcw zXOsDI%!kO2M8~iAfqiR^{bv2A*2D`8$0rlgL^Dww!_NW-6eE?cIGaLZ*$RY>vbgBZYN|HKftJ0Z3zGGBHK4Wkm4k+Q>B` zF^?d`4TxYg0RFY-J%;0v^D&$mb$5;?vHudyRw?7Qjfp<+H&!6n zwc@6?o@5KEOcq(jxa!2vTDUHdQ}cJH!jz|NQj4M9Q%25ej_T~n4^G!GrdzN840qaH zGG&$m^8mo7OpQHE&5?3!_NnJSU7RxbmTeEf!i{21kfBw2)%?@&(Vb|Czc+0!zZp$% z;~j}MACB(t0S5RnYJ;E`Bv{aEzJ(_HTYfWpO%k0nrFPb^Zum9wwn6f#XsuYWX@-3@ zImNPeZmAKG3`p8j5Unal1)>o(ucs{k<|W*I)5BRHLjmtc`JGHPsC{afQ3Cresj_+p zU?#;WKg&>6Ujd08Qys(s5`dxSXTFavz?#2`1{`pmvhSq;;`H}(P0EA3DnHF^B?$cb zDsP?Kxd<7Y;26%)Sv5R;u0T6km1WV(wO;r8)Rg~eU@Gg+Z(seRMaQ-Hv(V$eIh^ff%x)N7OH7#!D9BOXi&r^N1zGQYeo3 z#guv3&RE~7bjd7Y$+&dM>LbM1amht|$?oHl#nu-C%CeW^GLE_AQMzLIk-6mXammzi z*>ds=!Dl&`x#B#zoS?d7!?n!vC*vnq!a7$ICm{ho%UP2U0@sR3>1x2%szvFtb=qqF zqm{U=<>tz@jI^b!t>sUNYX;cWAY=V2K1+pHR;$z2%s;Lq_-vFtT5~jBHH%38eEFUG zDN#1MJ(@`$#<92AoGSUo5eZANpRyA~*x%`~Q@pb980)rr$9`~Wp%5n;WSOnT%oLJ( zGtY2%LsEz!m}ox;h(8gtXuS1BJXytIYsGPEqjPKh(bg7oiy{6!VtQ-K@%zuT?~4)N zzjl7#`}ln`ZEKskb-4BYpAQ3?&OnwiASPP{fNIbY{#w-Ai6;IaX6x6W)@WW;uwov2 zyM+-O@D_W*?dX=#Yoj9%o^B!qHk%o4sy^RdKftWt{s__Z_}3ix!zh`Tw7pofolw24 zN7}}vXC(Xr>kma3cZKNTSlhLrgkRg{Wji?E9h}LINmqyfY3G#0?x{~Z1`@lY0=r&n zAX&_=FZZrtS%huZwpUru$?v<1Z+2YDBHUhuTbS&4NA51x?4IY|iC6oz==R&xX@{5g z%f4&J)@gTQW!J1MBH;UW>ecX5zN}`O-AJ|Hm(+ff)b>n=_D6s1_)F|0ecEvv`rT-< z7d*6cvFmrszx}NA4CnMe38%rfzF;TrgKCps^{4kjBL8$c?K4BV4)R{@9TnWSi4;|$ z&fYPebFJrqV>u+r{JO`!b&{1Z6#r2GBo04IH9HF3uSB8AKtS@+`h*$=RnpA^1U&ELf~PkTHJdYwz1X^}>+_HolSRWmmh> z1zUd~Z(DkG*&u1_kPn(eA5P_1)=NREUwc}>uXJXhF#iX?9ssuzb#J*{-vXBAkY8LL zrsmqpoKSu12h2$!MFM;j0XkK&yagWn6g7I|MKPC{q zCKVigSbXY!KDFZ6vAOPw`g)@xo!f6^0^aqfvLEl1hMir0`%H_THC`-ox(x~1iFkJ} zn_WalS+{%fS+V(ra0e~)f8icN|BZV9z-B&89>TJsqPk*ovLagQqC!IQ zLP9!{LXtvCQo_m_|0{bK85yZ-sQ)+XVQ0W9{S_BGEh=pz`v1xvj#5HVlCsg#{|EQ5 z7Z33eO$ZgUw#C?J(!iLqD@4HoNh`+r#vFaK+LHX`+6Vuk;aJ%r07F-77m+{3Yvz>+=6 z^Tmrw{txSMqcAf2`Z)m44I{rVbN5Oxw9;KzXs|z0dujx^H`#+|~ z^}DStE&mOA-0!~KQh)6~phx%R{{=lpM@Q%9=hxQO{`~oKi%|4`!#yf0S-3|{?f>8& zP1l-RTCd+|yV-`0Nli&f?e6JGOTG7?H|@W0kB7I0A3u4@!aYVt$HpgKPQIdzqLV3i z=I-B{AA0wGaOyu74quj*S60{7Hzv`E-Cb|)^xyCP@as_)`;jBH0s=Wgheza3e*V;- zh2&GrwxB-7*})KjR5}4aT-YScn_%JB+>~GU>q7V*p=q>IUhH!%q^rI?X@2AL^u?|Q z42Mg!nYtg!uF6dGx{bPSepXeLO{HS$eZOE?E_@-IY$2#{27jVJ)eHlBBH3IkfP5Ju zsU*uKR(;F6XcMOG##Fr>*kI7LVgwxN7ic36OUqu(o#1^texLIB$>p9uB^J7$PMJc* z<2U4co!^+3s92V}Gy%`XiUc6}X0Yz{nal3OXa4?tJK?4AEomIn%1Yp!8!WxAD60a1 z@we;>*ji&j)CUqXR^oaO$Y1nQo3A*EDQq?NXM7QTWYACMz!&m?z59sUUHZ3~;|-Nr z7b9O!sXKnxe zDa6&gXW{7;*rCjEe#b+La*%Ih!H6l`S)T6d13rD92y?cOy#}*7MFIF-z5GtX`EOmL zhJZPQWaLh8G6QE*=BISu7RZ2EPvJVk@^yaYQTLZ5#cWJP;I8=YFZ_JAQKqiWYsXK< z90^af$$<9+pL4~#WpU~{CXFoTTd&ag{T}61iRbXmP0yb1NnKn z5i<6R_g%*$RFRj?1KyZ}uHIkA1|S3MChu<#jcgRM+M0MD9;c)mc@QsnqC$l)mx z{Rvjo&_x%J7EK%kYli84%yR003?N!u!1f*8D{ob_LN>-l9Sno`;hFnY0VR$Z&qest z`q;vv|4rz>=Px*;{^C3JRkt;R%I%c$BT>{ThXZm+bsjxt4HiF2Lq7FYxJtQJH>S`O+@-VM06_N65hr4@`_+F{HjlpY5QyL< ziNEzWhC4UEC#+Ta3e-F>k>@29tUi=D=&!M0%Bpd@i8k-tU$wx3zZ2UMhI8a)^%K3= zTw688pbk3uoeVsBSfQ!vtXv&~8jLm#uZKnDJvK$NnyHGH*zM4^Hjl^^Bvw%lmg$js z!j2bF)v+X_e$&>$j9OWpjgvRAwG;K4u291T%DAC2?8kblWfNLuo%=>@fBl3}TLM)A zQ4^lec`ILZ1jv;q+Ml|wQ8CDW{aBoyLqL6W)g`E`rmM#ZZ^w%IxBRWjF$H#hS1PLK z1D54tMr~a>r>i^p<@8S^+Bv-r#9q>qu6em3b#?VcF%uSZ?*)en5K z7GE(j(GuW21>?U{wigkSS5DauOLHr7My`bkbR>p4mD^D=oqoJx^6kL}2{PzN#FxrT2dg*n4{r@xcx93p=##dc0PrE@w#_q_?bHg zAD5o%+}9f>YT4pe|znNmpSXR->I6HC6&7}*G|Z=)+Q_a=cahJ@f;6Vwv2v}n+A4!oNPXs ztj3AniuiTkp!utnwf;-*zr6Ot(1nN8*`5!Rzn|clMjsTvKcts~emn6Su4{K04BB!P z4;vUO7zZUEWBa!^R(5UeY657Q`^w(b=fm~*?twMFX|Q3+k?l)3B2SO;pSjA+pEsMH zye}wOPaJPPO8%7lH9noI0FlNwyfVnp&iLafn!1H_>aFyxJn-fCxBm(Ea7i7Myyj`b z^KA9$j}WK$XWae!O+%0NP+idiErWcmSDAZneDgOV7a1e}V#JoG8G}QO9D6VR3I2SQ zu0i?4^Yj#vJ5)r+y`? z_of}MMag2~xoZg*-O~BjqBV7i=D|p({B*Il=vgaB1QroSM*0GVp;!PwLnbQqGii~> zFeqtalne%xNy-IqU_PuE2Av1cbHnCy1>M95`FW8xc@g=-5xU@T_dE@o)6Mu5pviooQefwiI=rr<}&;=u&iP;XIezOV?s_+divXabCN zn@Q~jPYM=~%%kA$Axs;aWR#MRgn`H>a#1^$$DCwYiA9ya2xHmVM1H z)eJ86XB5nw&oQ}?1gFE>5|COXgb4;f?LZE8ARHJ(+ZQLZHYD`F*7te$MR*f|BZAvm0_mfbEC+!A;RK*)g(#DFxzS|y+rQyxDT}{AFbJAe&oNWL}+8+XNhH(Un%oRMjP2curzQrVu;>Rl6UI5_d-u(3f)k;64d}ITm3-LKx96WfB1k zI#7ZuUYJKxbxUl2)R)kTZ+i&#B+A?!ttcck_@AyJ;|aQnnGQPX+my^N?ibSa>dN$T z_7Wi9MoP7TvNCJnr%l-wvdSr;c1*9}j}2MJ z|2`;W0V%W~zbhpCvp|py2aZXU;aRUPre3Y5Mc?qt{MZ{?|4aDAdU)y0#&U(accYi9 z-;gW!$$yVF@v>#=2qrA9^PI;c3^B;2#9Sm1;pGQO_Cv5Ph6Ci!M=`Aca8eldX2Y>= z;P*Q6-%WwzV`wFSTtUCqPN@8Wh!*b2e2$7+wrbk5shucj`mmm0S9sYezo};bd>JM+ zivhM`z{AnddwXzBTZU8;juj_~Fe>k`I z?K~fk$LoIQ#-x)-#ilGZnb;azwCg8Z6il*&0P@NojAt74mc~F7F_2Vy2p;!{qbPdy zajAtyh?VF4%%W)P-ICPR`|~S^=nDup(#2WP1dG`i>Z;HE~I9k)p3-#%;!LfE`qTK$&3L@kyx3@U_mk-N(Kwz9%fU3AHThl zlaa5FiTd0zfdlz{v)(VBl#0omr&3r}n<8u}xgiwU+NRgLZAnBQXlhjCE|MGDAU4-d z9|UMSAen*UT3DIpYu|yC#+Y5_kQ(oeV=uXarfYVcvOR&+r3c_ZN{6^z)i+Vf%t#NJKH=*5Clz}=HExe{ z@V-=2M0hP;c>Q5M03Py;eEJ00sewEVLq?-&J5^)io{-5Ztimi!RSuo04t+_Jal!*} zpWWgj!jXSn8vtT!R%}fkzUEcZ(<1y+^snwG;f>8f9xMg^B@aBM@ufeL`;x=^c6qvg zjMcr#D=Y_^6Y$v-O~F4NtvUFI$Gzb&BKU6|l4Yg&QtFf9*_LnJ0cOemVp5)_rhT7# zWA=Fl?0a)nCoQ6~ddq(Im11&Uj6Nfi9(KBR)q(o)ZsDS@b1G;@RCeBOwza`x_kqNN zx-w!B3m&!R6}mc!)J*q--HZ)3sj7S#pnicO8tf^4T7YI4`lb4q+o*KbB-3na_~gRS z=i?soL0Om?N?tO;cLynS(>X14KzSVLt{MLQ$mgf)aNWqDwRfl7`A7fV>{QxoQ%a9I z*fD060Pd!99+{!AuDE5_Ss;5JS?t?>hjnBM>GlD&twVs>bEF>ZeRJ?rdX^l!d zqy#av@|ri2=mGVq^Z;(uL+Oy32;{{^#9J?9Z$pHpN&nF&>ec#j#fG+?i19Ix`%+$$ zx+w+U_WE3;kq9!RULE0HhwtP;xkyAjn|R*tb+7#9Ak8eCEZ)~BlH`d(kN5Y*1o9FJ z*QP-y(@7CehIo;$lTnO7OOtBLPfygB2+yXQNQ88Bg@15inz*ga91|JneD1wKPr-{MfU&$VfvXh!9P}klIPyW%X%KnK17+b1@F#8EP>; zuk*7KmqOo+c5R89%dA)<7Ap#Z>}nHIaQ0J>hC3&k6wfqTm;a=6NK*r3rv>M!OOk+?C5pB{DoWB0ho<57-av7yVR-%*@BPB_BzBRbjFNmVcXi zVS0R$2!T~d8~_QWz|8wC0w|S7jC094D_k2}qrfM*{CCS2cAC8h%_qn1sxBc_AbB@; z^JP{Te7qcJpDYX77hn)W0DkNDBd6cs5IkHT4>eo|D7DqL$apcDpUHjHl8@iQ>)Dpe zFDz-E!Og+<_u({r*KT9kZl}uo8rc5^ZZ{Gdj{x-V40lm-`I5YO{%_6oP9uO}a-5f+m^hxjoe`DJ>(icZ?x zb9OCXx*kP4cK*66C4jVhcVvHjoOv*zD^pu__jTZH=P--zji)EJdu6Vr_ad23VvmpF zS`HCLUnNS`9k)*W9FEGEx9xr-|8_mm>s}q9e963Ua-aGJW&Zlt)UP0c-)_vmJN|uL zelSyp_jQmCkiWz*BpcB94uM9$7WkXt$#C0{Pon$Z>(F<9GQtlo*Bv#Q|9xM*Ge*eH zQ~i@p4s|yVCewP?|GLZyY`nNlEByRHqNQEt9nzbhLFme_vIpfa2oKkuA&SnIKxg*f zW}Kwl<|C4^Y+{C-hH8e@|6kv*gCPEYeS@i~XJ~3sy++DPc5t@ItO5=0;5mu=fbX58 zKOh7u&uLEm;xSJzY3!R?+t=y?Ngu3vOP8oSnEk!M+I`G8b3uD%$?e{kq__F~{a=om z1mu{X-TLp}4gcEcf}Y)f%(L@PW1yGmw301tr0k3A`szn@@2A9e8Ap&$c7_bnc{RiS zi0?uWq$=rq6R%iwOVrnoNPE|s*B<-tY_0ThWma9e`s?VM8A3_CzEnS4a8^XA?y5o) z{~do*naZxpv%X=`8TWqi3Y~VyGU`agI#tr)yRV7t)>NVL+*ALgYmUp67b6pIq}uKj zJa%wPX1TT{w=VzpJNI=2b*SiozkPgv%r)+?@94E!F?CCAkG_%VS8!b>|sYC627 zLm6=rIWp68)fSg7)P|K8ym>ll(Z*vqavZ)9SRDPXR^p&;#twTkQ-BL}P6+$yU*>q! zUzZ>vN^mScTh+DVoPCg2o*47ZH@`sZDvx*c_#?Qp6{Nj^F=}fhvwZF9N{@ZyCjv0n+mcy7J^^$#zeUI`3ub%O=VX^ z{`<~ykb8g18}>1ad13jZKl3nWAq-YBW~EwI`td4>sY}l}OO=*TI3+A{{jp%_@LGzS z*X4@Y*+?ss8n=o>etS}+{o6y`K-s^`>%~5;!ZlgR4+h=JFFV?&R&!UT;P1xznR?b$ zueJ#pN>0zcck`$dwZEJ<FCykGofTcUPQmYeX|MLvH*4vdxS6WtO-!reU++rZ z;Vks?b{VlOE?BOWTE&hsGxT_U6;pENi;)HJfA#c(mZf}bnB5JmAc7H{iXiS^`CK5W zMqKa+ig{SLlK~bg^T=2Bme=#&=F=Z$l0SX?rUwOd(zpV~1`ICfOl@TF*&_(Qkl8Qh zpknG^zQQ#^j`l2A=%cEJ5qhC@yr&pgTz|>j%f8atd z;PwYbm~K1Y`tvQsnhB6)A=8$fzuo!oMaJHv%a#wDp44;9`%223VO2BEYei7zU=DOi zLR9K0Wx6{2RIgA|K#cUVA`vQ*$%Y$?V+JrZoa`St;>#f@{Wf0VOH2YFqE-s6)6t>V zhDSgo%;ucWbAQ%nh4xijCY;P$RGw>?^JVz9&rgLI1^8 zGeVUxaHT^i#LqJJ9SCz{a^k8hw`BrE;vr7TJ&X7~NXM~{4aeJObnX_NMAAhD{+mjd z6?&E86rhIW7#(J(`W5(w3t2fZby9< zCCpO(G=MYq}{Mr3UYitK+@Gl8tdc-zEXh>Nw(GG0a_6D+&KvNETVW69oUx3 zm*8Btp|hvI%iE#n@f+>1I1-iGTKVRkYp!W}p-q>h$o6?TLmXCofFmpXc_Y>Zu2%a* zw7v!;lWTffCVwJ}lP(e?(0#Y#T@2zpdGgUS_^OoyL$<-oKn~CHfdwNc`EGO^Tl~FG zuZ8(k6OO{)L4Y3y`S)#EJsG?dnorkaoas`#NU!1RzXW>UsNQ@Q@b&6B{icV$!J2=x zss#{eN3JH@bouE_`t$odB?^GSX19{vRNb)|A&}uuXXnxt-Ef&F(m^0z z{C+(8&OX5_3&8Q8ys?NnH}TDhJ6*sv>;}u{gfSkWkYdKKl|zWrgNn62dbRfC(aEtd zYO@M>aQCtjB53&c_1~rPpXjFc3ahVw*66z=d$;C=(;ac^C4K!BRrVYen@5*?cUa_> zxIAyMxqp{#IQQQf+;Ra<7JPqx0I@}m#fTl7@j!^`H4l` z62~7-JuK?)RBZF=$Yw3*wvB>TC@St<7x=KaQ)k)X|ED2YTMuL?Uhf=@rYLG#!`uZ+b@vkItSlp~3(?%b1ZTlAz0>I+26@ zk^fLlaSBIwIRFNBW4(u+rfq;my}#%sucZ-$MvIQVo6C>O?O8%%d6%w8U9}ir_?7sp z!i)*&`A=Oz=GNu$q~L>F&b$h@!9f>jm?{*|Arg+7JTN9IbmT3p{!b;R*KiE za&&*t?#n%enpmV?dH?sNg1q-rqsu3sBBDC73M1o#wd(PKIcz9Ak)p)X=r_puvs#We zGcv>AtSbE?Jo@jj^tZ38ulsGw%A+E5FHLAszq4)E=Yu~O$jzqAZ;i-Z+DU$wwiL?! zVuGV0uiOIZ*>dy3)5-XslW|3-x1&d|m{2F*Cc72_`rZH$f*{hlMIkvYwnynFjwOxn zn!^kQ9~^jV4uC(>@z~ZxC$n&IC;L=ZjH$!-eOE+N8LXq{QuHO-fSIc2dT6lIB5Dl6Xq2 zT}lq;nL{b%LC@uwkmPjZl&bCIgt3&@(A3hN)PkPW=8%+!+sPTmDJ0|Mp5)}#+O&A% z6ee;~P)}M>ZCX7d{c%rf#B#FXLGrj=dRcPHT+ijPkhJ=Ow94d^%I&ne<<#-{3`$5^ zadOgYwY1o=^ycKGV!MoIwHYLYGx8ASV$3LX4v*UmSoMoL$d40pJEtX1OGNly%5gT) z@Qty*4&hh3>vE*lI7o-A(rSe2n-{UlG~yqtiFVJN#BYx`T#th0zm;FFaUxbfYH>F8D#0? zO34c(NEBO&o(1H{rAx@t`Nz_0T%}VUz#0;?i7aI#m7xy6Gb_MATj`g&(yzZtulF;4cz@+-&*l8>O7~S@HoA^eVLMoJPgcO6gB7vM9Q8+oW<$qFh{~62e_}xKqloONJCxa!Z!&BTL_f zmMKdL+!gmbC|V&N86H3cFh)n4(L#4&q7Vfke;6S^ z{N1s1x@v-re9q@nh8$srHdOw~YtG8Ns`@Y%PgRBJ>Ixhb#M zx3G9wrv9%1x0j-(bp5LkP zC=7HO#?EimR;GYfpG0(XM!E-gpDDnV?RPSu=Hr3}WTH!V#Qk^<# z9PGtN)GY9(b6uCpeJ-jn{$WKxl(^yobO9aMy_ z0qWZh5RwMSVN&`myBSHyImsS%psQfLYr`6K21Cs}?a7nx>8140I6!B4Br&|}4o}Yn z!cBWS-psineQP+aIs*ck+l$>VnW3tn4TXEM{y6w+ zMU)aw!HbB*k|Tdl)K>x!KXjA>seU8BuL9rakCU6B2cjoT3+PctS+dm&vcG@#_F|!D zg;WvIXxI#e%asiV0M&)Qt^=^2NC|`pJmGm-aqzUCNAATT<4y9@a)SCslHMSh~R9ye2fkC>MfurHp)#`+nZYB_J(46P|CJK!* zLp>9|(#{hyNgc!{BD?5gd!$e}sA9Y%O8lXM8XlUAx{Lb|zisxvaoeoXLo~!NeV9gE zH4K$RDOtiNSQSSaV2lS^a3vIjC3J*UQT8reiwKdvOD~NnWaI^{E>Ts};U0t}O#m=x zgvgPGHUGeZ@Y0v2483QE7k7~;l7f^la6SFGKlyp(de<4jBH9y7OdnOlKym59ANGJ3 zkdnpsvR=HX$8~f})GH6d4bo;A=sYed;D*u@i4#QSi{yS$1nTx7#EGrj5D(lVkJmYm^%0e|$g#E7 zDAIe#ZGW6BNqJcdu63Y%k=WgZoBnT>>PCTuSx%RefY2W$tvs}nBwo}f2GE_HDF=U* zDqv=ocNC^Heu+v?Ai%-vQ{c-e?W&tcZ8P8Yk?(tX+wrrY&Dn=UVBUQCVy-d+Io_NQ zD|KQUf*(2w3pRWh{PrVLqr;?FdT3AMU?m2^a5`!AQf6$u`5&U??;(Tn30;6?)b0m==tU``7Gm%Ukf7(PEtwO-tmY=^YhstFGZ7 zc^a=Vmcn11Qa#sw&LlryVi!i9LdGtm9ImN*lmh>e>7dvZ?pshpG}P2sk@S8o>LPsl zQ0o#w-GBu58%rdwzj@IvyEMIANjU2*8QwC!Wtx&icmtbFHLP!tx9<*%=v_n*m0vZ? zY=^7M)V<@1(t7!Zp6avO9r%PRO&hxbZ@x9D%oB*z@p+(O(w$fUs|6=eAp;IpbMqE6&!-le4uhedc6nAN1Goknbb}B^?%HhuJf;blm-r` z=wU8FfVzvGTr?!Qd2YY9m~#cGe#w6y$W^Iiuu;542m#I z-QIlGiZ8ojxaDzy&NZeo~z+@UX_z%C=-RxPqjR(a-gzL79u~Q8rs)kOA zf9T0US%7yeM5E(9q{=MRs04OH80Uos{hX%vD1GVkX7(}#qHg)zs%6ZO8FiZ(WPsT| zEBP<)FO&iLs$bt7WE`?fqufce1*GH1@-_188XDU#TJZKE2C6}V1Z#m@T9644eTH{nXF@+R{u{mX29y-966mfoyzwHs2EIZ~6BTn$Nq3_QB!c!XecQ zK(GRFz<-|c$tlTa;@qGMfR2Aoj&^E(oLjE{O_Y3S#^tzj|Dei(+EkfPQeAUPKHAqm zyt6Z+=W%3DU|`otuBTu;}#v;2x`Y?k@iC)|U1^W81y` z&s%Q~zO8P2`FV7F@-t4xzv;A*0v7Wm#l_-u>4S3B#wZ(PggUR9HFR!W2dpL}bcal+ zG}31zY`Y(@INeW(*R|I&Mt{`f6*gt^97ltO3q)D^mMd^#)i6yVO#OCF`K5A->F|o4 z7qdXkoNaBB*@VRyLKdx_1J25wKdpD0>#XbSe?G6V-~$2+A|n%3?%j}o zLw!^1)vdfL-*_u0+>2Y*d!@(!;ZWL`{D*hcGZEjFzMgOIYk$D`=7yQhNn;5_ow&2 zFWAh?x}Cv2#A?amN1)mDShS(|Mm#&JYAv!|saqg=&gP>aks1KIlOXcIeKX}y`2>?H z-L<`$7Tt*%y_>qRRC3Mo)`(N!vmYk{$-;x;A4vKfq2mcmM|VGDo2z&TWs_Dy()=G7 z7^P?8Tz5V^xEUl-o@yEDUjD&&%D8LZL1{U)eUy3H%;!J$|8N$uDy+3#AQ9pgpQni6~<2c8tlx zkgA#So!f=Yrgavv@`axDaOK_l1R_oBW3E@*&SXHUYhfIVCVRtB>)0+{x>b|+wRHQ8 zm{b#!y1toD`}6C2`%J5nJTk2>!y3FhrzIU^+g8MS8(a6d!=*burJmkv{TAjR+wt8# z?Z3VsyLkQn&F?(2U90oq_n7`X2*n5_9#pJ$ZM4MQN5r0UR*Kz(zSO*^K;wl zFX5j@RarH^PAYy4|NczznWkv?lagIuCe#JBmR%*f9xZY_U*ZPr}s`}M}C zrSJFq!?Ek6Tq4MhB7dk13{zqn0nItUY7)8A$~jD6%TZuBDS zekP*oiJA@oMo=-Qfm zrDK!h*_gg`kX5o9!zO3U@^ftLw{$hkUG&FVL+MoCbdP|C=erRxN{%ck5kDScp1VKS z`ks|}{m)%4P@%C5$M>xCbZ6l?V`D?ptZclNv*=TIV?k~VOB#dAxpxS|i}(F9P1r@* zr?2#ExR#$Qt8D%nQJ)d>I zcTH4DxzOCB>>FLRcQtoQoxbZ#R-u*B9oZUVbH_y5RbbHRN>uGa`R!Xsvj&IU^5KAn zP>uNOM^iQ0w|+=a*K^SSlt>!B3sO>lCChYHYjn?_t!_1bR0OV`%M0ibcG^dmArfj0 zRVU`|hy8f?bwH;mNfH6gn?Xx zW30DKQJkGWw;S-~2eWCMvNapuMxA9wy>*T0V!i#(db{cR>)ob{)nPvy@TCaoE@4Qy z^IDR`^DA~2h8Me@{A?m*c-bzQE_SZU5BLHZC`;3|QxP%WP_ zAPNoa+*_MLeE_KEnqy7P-hLlBhb->Vv;K!oQs&*DyJrlcv!ASCFb1Kn7U+VahCmEz zRnJn_iR|~x@N%E)71*A7WKyaM7a0d1+o8W=D)(*~u&Y8v2w(1A(sj}w?vewx4=_wb zwoEh`We3Eh=F=0;&L@_+rbZkZa6$@?^{LIsU!UuRT{z*aH^xtJlK{AK)c{lU#~ko} zS`5Q_u#KF70ekH_A7CCcK})H{(V?bXE}ZME($u|mn~wot<;2mcaC{R@-2;JcuA>Cq z<%9GnMCrZ|G~L)Byct-N5(f#|l6=!zc-(*=zfeL4((xG$pg|fJ0390)6v((Kz0AcX zekC3z;`1JCd<-mIRuY>^-=f<&S*VSY3@ar;>s~oAem02Z4FTfR%>h7n!9!OI{Geg!}lo&_EE{T zA=wKs1LsG=%CJ*9xHr0YD;M5h?wp-Yduy^hfV2pV<$HjGAD6{2h2rDToK9fvTf`** z2T+iNcPKm##ewZ2%41!cEe621Td3eK#URje80s3iDf&DqMglhg<~o>Mjqw3_UK;>A z=IhcS@Sq+CDmd%~vEwxR9o3e&5`3OON1I0fhAB@ZSIBMMmY1-)!OvEn)EJ&yDHi^< zYv8HP4u+_`LA+4e6H9JoUFN+boeWG%9RqGNFTi1LiL-4uVa&bR6Df(s-Xo|xd4+rK{LXxpA$(BTZj-VqO2Y^aU!F$J1 zqa9R;UT#FbS?O4as^m*0`Ma{tFXhm23cGhyU2-5oJ@Pnz885xq#qV-xMFok6>almF zMaR^2{gr0tl|E!+4;9oeT~j@}8poXzzXn#9IE=~BlUvn|OMj`brmHfnppus(L&t`_ zcBpV8Io`!T!S$MwOpn@Kah6H>tB+m^oEY-eLx+gtsg!oy!BH>)BLB#%@In3NnD8%UR34Q9+o z6%=6J+onGH2=!ZsMpNM0D)8WSXdo8uiHBv7=>i793oq&HREbB*E|yq2PJ9ghlk-vM zZGaL8KZyoNK9=jZ;|MO;AR=4hZEGyuyfNLbA%a8g-c<_lD+x5w6LcM?`|`au&oKMD zocld-Ity_+@;@~9#dY@V?tkRWWOUY&62Y+qXtw+7zImwu6l(t}&>4f^4qoao=+loL z-p?Rv+T4OnMTW?x@pc6mfrCoNfZOla%k4kj-BN{{ zp=~Y)L*ox}aU}RPb+Mjhl=(=sB_5!&1L%msBO`$!aJnfDI_N-(g1Z}JO-0YNgs)7n~ zG7S-TQ*XuCcmRY)%LcThRhufW`tm=8H8vliPvQcs^59=wQg9f!KLO>k3I03~JFdp)#lvMgf*X+Lq&H>_cFi4X`93M*6*gpxgb~ex?*S8 z+2%m>+mm+fa3KW;&WA%%-S`GRKhbl)+D&^!bWTwW>i`S7lVu%Xz(LUjq|z+p`2e7c zjTVRj)X?k-AgDeL>e$=iKi^KY(o?M`0^eq%u@5LKGCK~xXr?z z4=_K#uz7b+j_@)9-NA_t)Pb#prK?sjadkm(jyXs z&}8X}NCVh4S!{YC=yllD8>|i3o_tL)&(rfKg5uTPl&{uV^{T!7^n$XOV!Rj3dmTm# zq(G!K5&IRLOxf^uDstNy5`ckw;}G(=+O}lW*`nNopzFPkJWz!jtb^MP5r3$V`t`mX zG98!*G;1PjFi&#`h-P%L7CP+g)W4t)w{e4ntRoU7dnO$EUr$0DvB;O2@Jp1Ztv&FY zSky)@>>0h_{oeCGuU{2OyYAN@&bBsyyd%JfhWe4<0khCJdz1m8E7>ydA0DoaOCzB{ zhU>6k9O6F;Oy+J{0R@%d3H3mOLT6zbB$z)H;zxzX15kfl`KcvJ3m8J6;ltpe1mci( zItq&apRh0h*O-ilh0j9O@i1*Fzc+T+X&xMc?U9!5DI(Jp?a$Cr6jZ=0q{A-oKPpTn z2gd(rps<)z&*8ewpfI&<0GJ<5{v-PN8y%SpJ2peyHLv{9-O5yA{Z@XAJIY zY=%@safC?M+VJ?zap0gk9t-`a3GZ*5xkMWF#~`RvbdGp9e2R{MnMgtRGPR8`5aIr4 zc>CE)-q#VK4P-PkpJ;NQXxtNSjL|*&70%U%d>@+L-Cf;`X%IOpVj2bYTOQF0NTw?}f7Hg>dEYm0sEMSp^cTXr*YY>epUH-Yz7Dw&$CBS=cLO+)9>Obv) z{?&6Mz|}0l2urAr)ug#k|6XHX8z-o93L<^*OpG{NBSejD7`}uCHSa-6OCi-y;pSQh zmGu>M+^~HH0!&8IE}}ttRLCDPth$N%K>X}|4n!1~@&Z8m`w;%8BaQ@kv(IEHAA4le z@4@R#A zStdJV^tVm|>G;JihAGCnp;Qv2<=PAOZ~X=gfX4gTlQl=+fX*BgsI@-lM_3A-UNrbK z*EF=gJw4w@o{!K8dz7z7@3owCvHODdd*iwJ=vKBIMtUd?Z7aoAScp(7L*W}(ngNhH z_DN4QWTXg%B|;>bKB$ogm6&){99fmwv)ByY>Uh4r_QkUC;{}_U^KVx_cAeYe*J-GB zyQ*=H*3D$L#V86q@x0*rWh>?4C#D$N8DDGmaXo_ZCxFmOyys{*$j`I)>6T+}#6TAd z^5yF(%2Su^X#VYNZF|EzpGaS(lkW`(C(z%B>d57>h&H(MajKziwsBz}%{^=9D2>iK z*H|LT1|!*}EZXNj%BuguC(^b1Lw@H^A@s@t^jZS6US;3MW+(kKn&p6RzqB*evhymF z00Q4NrXvl`0t^rK*>t+D7bBD~y*i|E1`xD8{WG)tuGS6iG9*|UOA%-ir=!R=f>z>^$GN#8@@}U zvuW6Nv^cYNpvli2MGB*k0}YEx*wq8A*)I(AuK3LX9YB^c5}x&)u>#J@ix&QSKBX7l zR*Ve759LIlRm%_aEqek;^mPstzeUwP^G9WVvJs}grTU7ZLI zoNTe6R^?_O^EnKcBOK%=7E~^bEsb9XT$u?!xE!qi`$=6q>Sg-&DA}>42O1RyHN(;C z8N#Cp@SyeUc}&Y7&{Sd=xd{i+Tz5hdra&7oMGM~8UZ6~f?cVHR0WK849BSMHNYBn2 zUPh$;!ZGPatESLrqij$MD?rn&^B3fUglF0M|1 zcO(F+$72`XDbAPb-S!?P7u>F%Hqui_DjM|U?jY0Az&{VX_X}(&MPcd!}VYR5HiUIHkJzM`m%4dW2%; zVx znEoO7#(ZKP_FS4{{qd2cRW@DxZK|#P<)(U>w9T5xYucrjiXHCPjZBNRGc-DP7aJXV zqZl1JbJTw;n+mzY5L&xY z%6sfFHkiI8!EUabbE1~cr$q(7xcF-y0z_`KvXat0#R(f3q1c%DteMacl@SO_H8`7& z8m>H2ScNLcqX7jm0Ph~p!Gw1{6C9ZtrUncXzl$chm4!VKd08g)hTZIn7IOERr5;zH zwScL_g!My{&dPyv&L(+uuAd9?&H)ZiyAP@)ovnb|wp>(O*Fwh;L=6` z4bIg)vS>AU<v|&5X%;FE1Qcr7H~J_O1M%dulZ*Wy)seqM2pUi1sNP z(@4VLsh|(Tw90Mi4Q(@3A9-O$=E>w25<64=QV7*H!h$xC1z&X@oeX{_U$?C)rMlC> zW_gJ#tkx=BVYl{SBkwHDdu|mQ^ung_p7P*1vLI#AMqJ4ufwh)Dyz$1+Jr|sl9sAaR z4f!HY9e92vFR!`iaFs*R2JefOdfsLL28}sp8GJLXC9-}n{lS0YzN*a}`D1B!3wkez zP|?iR{^lE$FT4@-g}<9?DdN}EhnKwEtSmYp;fh%nBi;jMs=45QRf1V#w|Xxn!MRK} z6V!<#Fd$z4&n8K%TX~bk-K0WceWQ_2k2J*pJ&5!eM5PZMGi5khk7G`xFj*;;^K2w&A8ue+ z;~}ON@v&-^;wY;OFJ57MQbJGb^Q%)>K9JD4SYwk!z#+w&V=y}boqpf%+D`fnjubl4 zeN>RZvQ0~}Xu-J6^PrB2TT+}{rZv_hc8|cs9e~=0=fx?uM!YwxN}9a6>!-4)7kjcx zNwSlkLw*rj@=iVEc6cIxKb;DamYstb+QCItLWYqCvyX(u8d=%V0CUCBw0g&jb0}v6 zrk=SHya>)K9fKP(*Wu4?9Wwn?%sTahN_Vdf3i{N@1F$bs3Wxnmf4}Br%AOojPLhj_{ z4H}cNn1ZTDsj6UPfB_O7G6A1r1w-OLLMUtlpjW92a9%@52b-uPho13uG(LDBgzC^j z0RFm*%CWlR+L;cB>>)V6M&sRcma`fIn;oK08XH}@7mG!R4Pn(4L)=$}WZz(3D(5ir zDmGjz7ik{W0TYIJD}TkFFBxD`69+MT=K!fL55#&>LA*bF9h5EC=?rMeTLb$P2=AHH z#9%oFvUxW(h`gc0!a0cK9*IBSbG_`+W>K-b9!PyvUS# zNZX!rv3r?D5^Yw6o2DJ&k0oKr*434%9BofNN?NImI0BS>5V>B;;w^DEF^Pi(fp2ji z7_={|bbc((B~!&Mdbf7!$w<{zDX;!Pg{jSRj^|)97Kt?L(!(e3gKh@R#yc{0`+Z+| z`D06|y>RFxo69|fQMhy<8E1y$xDOOLW6Q~)%_h}T-=F+irMmX-20)7s^b8*-Cuzk)5X&9$zH#^@?S?0O zjVfKNGQMdR!9{#OU?&vejDy?`fI0Vw$09CbR11|irhn1z>h=HbaM%g44Ruh&1YqofDCc!bA8Y4Vn@y zfx!PD;m)37OuC9r8z!RgiOb{k+0CrH>%>sGWu2E_2Z+3!rRUhRH2`;P5P-1STM!~H zTg+tBS@L~Re*9#@eKE~rABQ^|MT@k@+UmkwJVv^QE5*7%=n!^WSZ$3(SmPU$1`_|B!NM^{vw= z^~e8;^e%1uO8#>4B9r!`AzDejUi%%*6lXN}+Uls?BI2r~nHshENaAE}uNP`GTw_!6RI7-b$&@ZwoQM?#1 zP$9b*@wtcxU3ZlT1St@dJubF#BX$ZME3vKj<-A;+k$9qBbSfmKD=ALTINm@_W?S*9 zQU&ns8zPa4aGf=js< ztD19%QF!`NQg?FNV>OSdgR5z{F!4ETlz@uu(C`Q-xAQEFA3AU^chX9Z*OXki6 zgDOkZ7ZPl)0$^YjG5Mq`N1#6m(9q1I+CJFC?;O-0j0VGj#w3rW8$aK`|1cdoa%tNsX z4w2|}vB_UrA>8v!Ha9MafJ0K$lkF-6#e|>^g>Z3F%%2zmCbZ~{?+_uC{P@B=hdLop zjDQtFF%X-_GS8%OC~%Jjq)QchX8=dH!Nmy5%t8F8I187Rg7AZT^CIvSA~1ju>PChH zJw6-bJ$UvJ!a#z%ey0n?3jAz^MTbT;smaLA=EQ>25>?ZJPl%x*xjS`b;4zx{&q`Pk z0Q~w+=WsyxJ2vwL1@_yDUQJKIz!Lf!tE4WBGKo{Y{8GpAC3ZFO>@KtbwKKRKupoA^ zfkS$%iYnb>Jmy%{|{$( z85L#xw~PLs8JHp*LZn0#K}uR$9YPuzKuH4->F$>9?q=xjP6z4k20^5xK}A3v&;0jZ zXFt!`=e#)Qyk*wn^}W8o>$*Nz^g|_n!F##O!N9s<-r?k3k_{RIm{4)^oxdPgqeRpT zhev@J5yU@kS~ayv44R=A#QX*W%d}D zevPyX>Zuu#AYFQi74Xbh2wmJP9UzXFKDD^ybMG zO38>|*DP}4PRMH%x--4>Wg^;WINX??*O8hX^&mn@-PrR*L=(LD1X(@hs^{&2kccP~lwwBF=uQKe10bW{1|tiSdo^6JLy$KMfxpJJ zD>@=)#_>;TNHIO|;a|lTgS9jf@YCM6zm-JR8lv8BsaDUC|J|?U`>uhfCJn;Y@$MyZ z82RAe#>#4KvWV@o9m|O@l-E$^>dURXQG9_IrGH+8dM?<4-QUgf5fJtJ1bdoRUV!W$ah5w@ zC{fY#MJI3;A60FTtSA6#E+lqtHH68h|{jxnW=aii_rscR$ib>}^x}4KcYl zqVopzg?^Hb_cfXgeIs5wue|YSbrv>x6HU@Sx{>T$Qa|Z8SO%LMS@V3uG*5!oU%qr7g| zP2R32roUJ;2k%;(ZomtmH$+I4e+&C)w?B{!^`;!~{vMJ2tGwURO8GE@QClRSrWa{- zi}dv`=Rh%6V{PZbDQDOe@PQFCuC9Nd1VH&Zb4U$vbOU;?Ka;mqn?Pd;yLxUxw?4j6 zHeNi0{g5F$ndN2k$WJ(qpHE3;~$k43t>`FEoZ^nN;MLi;AN$CA&*G-czZlVPoa-tO4r;!RLfTVP zDsy3#BQ)NOPm6rfVQ!(6)9wnu9h8INUAnwL%FH}K-;dInnCcVcC0i7uCqI}409!c% zX^$0n)t6Gn9KIAU$Yl{Ned{@uNx( z$0F11O6}UOI`Nb?8oS1uA}bzIL{7du1hvm{@}UABZ22AR7`!Uzy4dr2m8>g!;355t zWcJdn=@pnCdnY)^&mQw~KBD2K?H7>A+;UbPtvv|fG+1&0Nf6F{p6WNrPCo8W z>43vcc04G1jW(!O^15@2ij1)^jwpJ5-S02#v*TmL8?%tV5JFB=uN5Lrh?!y`omB^| z(RVt@54%1ehyjP~U6A(YheJMxtu}|v*@qKdhaan$TeA!a zKmKHM)XQ_&WpmiZbht2nu;X(m7JIy7bBI?bWNHt0@CTO^M+-j3`=3vGs*Zt)6FJn$ z82$wRTV`TLK^^KG1=Y(_@eBF{O#<;lrq9K>d5LnmT#k2509I^^DMQtc_a567k{ zEa2CEbY6u^E$>20^1mu=ivxg|_1bb1gg&Q0qOeLSSxQV>UGgO#4X5FcBAWuc}O71t*v8)z`&uuOnhE z^X-0xKK)(4e(lfu+jaf>yH~qEtR|$_t6E2qxeh->$B}UY++OO6di)$CF%r6dK)e7K z7%dTP!qJn~0MMZ=C!$Km%gGB?Q10sTA<5E)+A~J)sQ=%h- zd2=J83WJg&%KcGMS?S5uDe1g5W!RRoy7ubu(!7x7f{*pMw1MQVhWg=(@%UtHW!XUI zY#k~a+gQ|HoRyS1Jzg=}#+tpI)c^%f&(6R9_<8Z2m5|x}0$`LQo(xIKQ-iIM>~chb`w{J_m3qkr&`v_#=oYX}`W#*QmwaH4Cf9E7lK)ArXm z1-8=vgl)eW`=Mqj=%41tx#(GtaOE^O(>H-jmg>ft6_xI!Tcmy4$*}9^ z*v)j}fqr@N;u?YpD$H`ZD}%JAQ-4q51sM6$dts&F0`sl+Gh*d9%?+cqEWQ<{nv|6q zy9R5q2Kn48C@k?OZ~InSGQFfzR?)P-UtZI%H*czW%n@r2V=cg73)49Xo3>D{!B~ zxq4jomi3P*g^>5XH0HFR2~)Ry#My|Ckz$>UqG{#N`B(2=$8~w|E4SqkreYAxQ;kn*ReEH-TIcmr6S0&ofr}0j~0MGBkhJkvSFXmYMo2J=Q zt*rFPuk$>APJ91FL5|x#9-Qxd=<33pP0I6nPc`djA3h!7W4aqW7*tw9{L z&BE8bCa1V=pu^62!jpUy3l*U){yJt&LM+5wKgrfWQWqS+u9A!NChET30XR|)XI#kc zv~^XU28)j7n&`Q8{-}NaA>V=N&`F{99z8!lgxjBd5?0e!%I1fZ%%d(=c;>bRxGD!4 zQjt;Cb)Hpgza-74wIA$h|At^DN;5>MhIaF}okfubV#(ha^dD~9dX7I0*ZsFKIPm1t zM1c7u7_@dXcKeDa^ld}xom)eLd!2x*OU4FG_gn|N@OgY{;@ZL|VPW{>-QaXcIujK~ z2^#pX-Sr>{0K5YzKmml&b;9&IJ3IT+r%$D%q%<`(4Gj(5+}t7~BQr8G3JMCEo16dF zRQS)IKZ)>sgNo&yqLz9UjL{-WT+US4j0@>>v9Vj_{|Ao1CD zsKbd~HZLqtr6^tJkko=9sYpx9<&P(M>+4MZ)qCx4)k+#dCF<7Q$fHJzcMlca{b}^Q z?m8M+8U{pC202K_iTG+oMaG20`&ivb4oHo4e9N9_lb0_^k+IC_5AMhoG=E4<*F(L4BvI;Yb zV18pfiYzN5-tyT%#E*MQ)C$iQhHlZevNCLju$TDTW ztV8>jHqYA2uiAE5oVR>Pm+3oNEp=D&!^T;^PD^Cu%`0Cu`wtZPc{6lgI2@?NdsDd_ z&L8MD5JhRruL@ebe1a?|KRS3}Z-45;axGq;*}6DBcjgoDu>JI+th=W2$rB$})$X6K z@xcq`A}uL5z0S^Nv;5S>OxG-d;r?Z%3{>&5?WXbbjem4|3mz zPz*)VJH>yaG4NB>dTZLinwXXvavsK_7kRA6;QnF1cnv#$Gkh~O<#S`9wWlI-lk;sM ziWq@d9|y4)gUDEs%<4=tUpnWk(|h}kDtk%(=@hO`7nTWm7HCK{8|OT#c< zX%}=AaAZt5-_Wk8=>`=l*Y*9`6jSQlnHJCQA=*to$X_#8@dLPGEF!Eud>9|9&v-QF zhfDX+v!$<$Uu#QSmof6!t}1FZG`^T3XxG1i2M<4K$=`f4^TM{FVV1G|V0h%@NV0a> zGR5l-JudFP9dgHs`kEx~a4e z0U8qJLx<%UX*O{k6UN^VUMK?bP*;gb$`=F$wGVy@4m^M_XPeoVPXR9{>Qg0kMK(8lIl=36Ur> z04y?n#k@>7dA1FrG4=%kzP?Z|Gc)d~DIyXLFo>G)7dQ^m`;7C@4aGqQ=mGSE{aQwr zC#Cn+>V5Ni0A@4@gz^2&{^Nn^?O`~n0WETc1()I^r~6qCgMUJv1aJ%RtBJhO`5DaC z-6my;xpy#jFv~B2q$_uDkzue!H%fCD)^a&YYSKamL@uMoT}%>g)yr*i6Iby#$$rn; zW`8yy?(r>}mg-)|rUIAZ{qaa6YCROIId8+*pi;*E*5A545p=vl>^-S5`o6QmDW%z^n2b2jb++}n68=q&44J^9V%g%d$2`$GZ=JGP)}0z`o@=JOk={0U zxEi%vCUtDASmJKf5>*HB3-%VU32g-Ox{qt>P}Vci;&Wh$OW%-*ea0)GF9K;!Pz?vu z?jQ+8rvaBMb)mu<)}zn47^A`SJh5SR*8HLD)XjwK;tZpGy|xI3M}!6W``-%slRswA z5Gk@-(Wt%a#$1ht<%!a1rMWGr^CTnmZ3QhB@3TFmH-E`Q^OplFr>B10suA_}eg2T! z&LlSZrlw$b85NlYef4%wh4ALgYWVeJ&CpmW+S&5O4OqD{az30*=Jr~wvs?y+Et$~D zM0kI&YMO9UiqI!6BS*a+&x@NC9^RBC8hQ_69fYt9p499~iVK#>$moYPI_(=S}&|T7ry}!ZA@$}wWwJXr;(Sdi@))SU)n_o{9m6g zgfA8X3H<+$jN$t)GKS~>6B$GBVqU0l{BK?iEsqKvpBkO8#((o-v>8?32qZt+5dMkhVUI&<{bL}nv4lS7MGP*R7Rpay}i5}8XJ9DynWhQI=enrbr+R> z>ichG%+z!R%CWw#X^B9__{{uwGUgy@ZozAzp|!nZZ8egJAjZ(q1<}!PQ?tM52Dkr* zjG>lA8x$h(L?9=2{tdJ`H3J2+T?w`bd=o0%(Na?|lrX8F(~~?lUzKv<%dyE^SVRp; zLZQPn;1FsKD8k;?zpi8|znccA+;WVaDD>x3@k1(^Ps(ZV*>MX|&-k+oKh!A<1VN_j z&1UEwLLO!-yW{zrDUfJBE``cu7kUkP``9Oqz7P@{p=1reE&xfQaTo@CeWpv$4Z;wI zL155;O%Qbu(swLCCW2?zW?sVje53zoGJ8OxcK{7KSA&XIhXXUpHvTtZ&k7)R;4Rvx zA5QF(up~iNc{P0B-AjBP^+(K7HLtl;`_f%fc&_(Fnx=>l^)I!6m5laefjO+(T1Y?1 za@8-#^9sgw7Eb23->lb`h@Sz}LSK@*)d;Z7ZSh`iGfMrU+8^^40(Uh)HZ-`RL~6Q8 zClH`+9O_4X$0k$?DtXjO>O?yCM~q#;)Se5A7&rM`8!#w>1fvyWOtdg_ZMUU!lyN$Xf4)C;G3x@Cus(($vx zB)W%MhFUAIgaImsQcxRu_j@-(RC9}ovF?<{F`;aF^pZBY&>4#$W?u-o_{N4Wv9Nt< zqD|Z*W2v|dN^qYVchlg@$c?nVw`g5rA${_seGCV=*sNYTxfr!nX+_iVuq8#yXHM>l zrcDd0s=EGgtGaIbk@Cvk9pphRPL8Cq2FIpvRlgwpo4e{6>bF%x_wxhm))5QK!s$s{hV4O=X4WOSPr(Y%pQt!}1E3|ayM`=ml&ta;(-M)rtkUHHh z=hHvc_d2DReo?jo8Y?pmHqbLQF82vO*I>ONKs-aS`um{j^A6g)a)~^`zGwTKgumr7 zSe2*i3|wp1wsyf_x3H(N!qaE65M|T&^;}$JW%P+kMW2~q##z@md1g&pNWhUum+RYz za!78g0hy%rqic=Fc{`-5XIpOnf_}%(He-ZThqX|zoW}-dW zX5x~Hac6Bhl&9XUo9t;8D0K)>6v=v@+(C_%b1EmdQ?iq;gNN zcgn^%Hba#!kT(&Yts^Icpf}~9YoMR;Ic;A*f=nkhXC8y4al|m5=C`7zb7<0?QrwEkC>WJrltuMJuKx=w#cqaEHd7CV5m5(?&Fvc>BYtwK{u+P zSC{%IRfe7zBrYMn0h*m6x#O(kJA`@vo)i=g=s+PWj~bDS=y|40|E9WWMxBo6`EG>LPY{ zw@n})a%Bn<8bZrUNi5Df0JXt7uh9aN_b2-~YUm2%4Fv;3FAU_k>H4U1CG{1&sg-WW z{*`mO#lPmPBP=9>I?x$eru2|3V{jamq3`R_9#{;l&PjWIKr1Lzvr&M3q&VeXh#RP7 zWao|>tM-wQ(j^YpmOJajdRNs`6D=8Y9T?JkE!A(}(^D1S*FwT4h0LhdsP`nvx~9!0 z4l=Hg^UMeKeD`ShvXsX9cCK@R>dBc4j*fJTyhyw#r(!#n5*~+2&dL`gjJ_4!vUdF5$ zx;MEmPYek8WZ|Z%sI?>FT}~n02Y2p;nvU0J$8;M51y|*sY=0#x;zQbgW_cT+==$nAHJNT6Wroq&v$MfR4_D<+8xpDwFmlmhTn@}i_W=EYpskWB-Hz~B1lk=Eev?m zr$m#L%PjvM+N`9{uRw$JT91w#NZ4lj;DQ{V+CnT=bflM}72Srck3DX*O?-tCL#ELn zPvzzHXHu?uuTU^yt@ekufnQ6#`QZvHbQ`F3$9fRj(pleV{cm(jKZNJ=s}!Qyqu_z= zM+;{1R17zMd~O-0n%gzAG}`1E2po9#`CH;0;;nmkxRjO15`yv@$AybqC!Y!0+kMC* zu48JO?gKeCu3|UtstHZJ6tu$f{@tHQ6P*rt9!5m!=b&@rw@~_%Q(*?Lb~`P%j`y2l z`KF&Xjbc0n*?8=r}i?1 ztrAO}y1=q4y0tv#K(Utto_J=PUyd<-e^0gG2Io2JZfg@@H`k9WOflzTJjki5*_F?X ziEE?#yneonj2jm?*t4xT4R>|<+ee67F1$NB*EJJfH+^pSuq3W|slIr1y*MG;l|u1X z^Tp@$%l*Fetqw8wGEpr{`WW9?&D1Eu}9$dSD%AIKH?+%zU^B+{r3Bo zZ(xmgj@*YlHa98_hY~p}M_*UG927Jnb#MLrymIP!_`YX#p{`l&v-Bp zG8u>xg}yR_TM?!NbabD~0fHM)#~Nt30rXQolyIx$V}^C~5C!z zSnyNx1kTumJEwGik~ zHYHFzIO6(6FX5|%m{U-aP6GUHTC_nzf^HJCT_X8;YHUqfE)eW{H@JN!+}4G@xkfC* zHP%xOV#Ew3q06wPgLYgd-)X(+py-J0rf^D&aQWt6kI4A+EiTK~e3O{o&MrR00GjtT zgy$QCw>8y&!`VO{{^K$_8XbKeO1ZoQUr>KRN zS}Z!nGMXY7lr55RVP=>8~ajP8`@o62Dsdl{5}!@HdaNI}yo>^GUAsFrn~jqf+0M z4Y7pxwR|Quvf>poN(Il;^B#+v2}DG^!&V?NBJ6b$Hu3-)L*>u1D&5mEgkKrC25{+y zs2Dc?rs&U3;xj1k&>UX=EW=oWqyRorAj0K}7q9ofu79@db3>#tH8vm?3;L){$#VKe z(gCpbL=d5y2bvn6`4x+aIHZ~0I1|I0*^9OWO0+0zw}fW2D1|n?eI`%7hw!-$?k;X- zmrB=K$u5a&^y4xMUug~XY{_P5vvNbsHs{Bn8~C_dON*Oa^z3nC=;v+1@_R6{7U3V|*nd2?$E$Lafm0 z9<(9uoL23KfIpWbHk7Ly%2CNH;nJ7Q+!CIn8K#U>Z0E zwqcZwiMWQP2e>o<7iXZ0D<|J&a1iE9_9X$VQ`#i!z>w?MCgqQ+q918jTW?Cn?d`Tx zk|M|$XwAzIVv5B}rhqCQ5y^=vRvZ3!Lm(JNo1Cs0c&Kc3w}V;1qnqK-pMJF`)G{Mx z(n0JHuAhPn!GKwiUa54*s7^jZ)kTU z_ySUxtV{zOr*_-|M{_0`mqF9VDg~|@$xdyqYi?^*XzDS@Y+-nSg$(z6P=Ok~D%dM_ zekSS7h>XN?crz{2vU-resh~(f50FUNaYVGTizZ*DXz?8~OQ;Nf=&<*BH5ka%D_3D* zQehbpN%>$j|KYy7ni#T{v9j6=Vl>X(+~(a# z{n2V*NJq(xcK_y|l&*!e@7D+-RCP0K5{nJ}!iA_6w;PD4&XT;FQ9Legg)Qjl3sK43 zb{YQel`=I7*E1bE8<>j00QV+q30~G6hPsRz;LeD-RRm@FtML=4?Fh;6HUq5y2KpX5 zDneER^PCb$otiM2l8nNhbQoVs&d?L`D!{nMZj^3KR^G;#N$?P|c0^0R{KLwmLM6@X z@(3xiOqnC={M9)sor%#%ID_?U1oK=hs<|noxp-qfU2g0meKO@%d-iIvZY51W_q@Fs z-q!2k$Iu$TE5^lu#~nJmlbWgvWQXhr2V~z~Eh?NXv>zoTz}GU@s9vn9ZA+8?u&?2Rb9ty}T1EzF?vZij*xwx0s007+fQigM=irrc5q zE~u%w_`VRT5Yy!ti#>wz09 zX0oWJ^Pbo0mR%Q2beY7Pq)r=dahrC0t#xG0;_OwvS$Gwg^qp0@jYVyi{+UZE z0??IPitsf&nHf(u9LX2O1Q4AYL!Dw_^A=yzPY0)%cbG+o5{1`4;Z}1WuG$7$d%jA} z$fCh8g&2>St3BD}U0i3wdY%VnLTuo&1e<0fUIvvl9}c`7SPeD!(v902p!s4tKYYVs zV2~l1T*ZfnVJpv%5U$AxKW2P79Gl6s&H0A#%D)`~R9Wz0c*J0@CJPf-VI_}|VqK(- z9rn#$JKkL;?@H>j4!^XNeKP}P=YLLqqH6B?=5W#zKCK6TAr8lz+ZD3?1iNp9EYqvG zYyd{$31&9ttR1Ap20L7)fVyJ8eHHor*vX@;ft2XE-8Ym~X`|J2Q$N?@-rqL6@{Sme z_8aCtxwCZWe_CQU34Io8?_p5tj{-UH!Jc4U z9&aB$HUzmE;{AObpG5v0k@2|wMB3v}+;fxr?XHul=`5%Ce0Zf`X<_FKWaTkz`EgbA zZF_Jh>E90f?X1siAIJswr<;^w$)dh|AtM`lbLiX!&#|FK#-9AhUKRN0bEN{1`9i2k zb^=j9gY5u1edBoF+6Q*d_sQypPcKYjNY}c^T_g!XNBozQRu{8If5jYBPsa>*PKipk z>7%t1;mVmVu}kIaaUdqUBdct)gtSWh*XNxEosHQ(->dYeF3e2iJm_ypZ%DNM;LLws zvFAhp?LTW@|EyFj5Ffh?tgaFK_luB0h{Vm0Y&7W*_G~gpyWWyJ#~gRQ>04!OHy-k> zC%;|6`+FqYc${}7Z=r=Yda<+8H2L3$mJje($$ztJcAUu~qO1d(W7x+|{+QDI&0R4r z>iSFb;jhszJY3y9gWFByVn?*&?;#dHVQum!rrj67#hZc+*hRJ7{zJwrik4i8{_jNn zumXXo_n=K1Ufx&GXnxR+ACMn$9a%_O8CY4_{dMp_l6!P9elNY^kHY-nAJW?oAFIB$ z_Ktek*)jGy?JpS<50A~De}&TCaIDy7CpfaG{>&%FD^h++lrhL&rD^NBYrB=?A9{%V+Namqix}!&U!CdVy zjo0O598R~+D#wL*g=P+ittaQ?zCI|CF^cT!A1i)jxA9Swm?2wS!$?!x7UY2@LG{9X z0=e|N3g&w>-P5`7w*x${sEGWft=HPx`A$BEL}&#)DMSaS^3|J1&^e0!8d#um{@p(~ zSH7u9L`h_ijR91-g?~P@9hbP?PSJt>@H%#HaeAKrZJxF4)U0~0kCcB6;nB`UZ@Aok zLlFAwhF;usHug^&HZ|*# zrVoOXaWJ`8;BVJ`O^;-**$UBm6ShvvKY40OD$t7qQd|V$2`fV9iaFtW_Y{#}F=kh@ z!ZcqT_T_h43-brgTKg=qMY?W=ab)JHOzB}=10|skThAZT;>on$dh}#1P#5aa*al zF~0@Q`y9rIv6sI!PzdUeDbP1}bp|0S)jdEe53??pznxanF-!|2176GijHUi{$0On= zR=VT(tEMZfpwe6~PED4|4wKQy{R$@^lqtf7-RDfjdCuOQPGIuSxxjr52c(MCjJCkT z3okWZ7X^rDgA4*Jy2n>>mtqekWl5J9u(((hvfBZi#QA9qjd{`6={I+HnG;&3~uA_4(_pW#47lXw38xrJw3 zdYBI)*MoxSQDE@jKKov=h|Wc6U#gM~{|fBJdv=!+zdxbulk|*nT3@?(yC;0UpD~Z< zh|&(_9>Kyydv0&xh~?pin*S7IQ~k(Atr+L+j2lOBRRMQ!1D5w^Qrf+TbfNsJ zZhsy*a7JU>yWHjlj@AX%xkQ)gxeqwa<4Pg}a54Ilkqq|t>7wMlu zA!xy%hdolX>btL%@Aomw$UNb>N2YYI{GOZB-OB1*%Q!|O9ePKZ02PaP=*>$?5N(a3 zYVcV+PD)m>=px|ps2|Bd0t<`TAOyG%ga{P`(CZD!iwRZ7o(@KmxQC_T={n_@DDP*3 z-wNFodF*ia4awsD81tN)@dA9SM)9BG?~j@L2XggEgy0W1eBb?NZQ{*7g=Rg9!Dx2sC$bOAe2hgOfpG?oC--L<&QCu&`rD9O z(9Z92F9gac48P+xU*i=yYl|Fu=RB1LJ9KDcqu_K*E4%t8^{$ys65m-?`kX98W*wqV zOV(I@ON^oKUQLsd&<6CrXdsv{0G*~@$3(=3MoROALtb5=`!|<#`D=X*Sd;jQCb>-z zrxP+qLUxZIEx9>}6!)UP3ka|W&<^|RuN)^;2ln;9U87p0>f^lZ?S(WdT+qA#>ZAKTYug z8;`PDvJ0U^ep^MhWwtDu4hi_Tbl+5U$l_Y4fv+r5o)9T|@SaX?8AJ`zygr{BGQNuV zLi+ZTSLAHEYmigB=+dM2rd;ZQX9*2dx8_r6-;V}8BK=Csf`6`6zO6kp51Xa?uFz)^ zz!x(FdYRE`gcIPYi%VgU#?BeNcoL-`O|SaM=l(G==e?M6r?@8g4$oPvLs#XWuZX>YHQb@eu?esz%IPXkpchy8b%x%vsQ=9X@;St~AK z_ug3ny$@)gH=G=geK-dchGd?nhAq>Lr&oET!=;WqFb_UPW23W%U)#|7dACt)PHWdy zWgCm1t5yX)3L7B-3bf_+RTtn*?lQmHSbi;FX)X0TRKjl5+*CDx-TnqByN>{`tkE9IrH}Jl1p8an0SnW521j@8PWOJ%-iKE=q%Uu9jj~ zS-D+}#U9XVE+)*r0&xRuYXj1KavR>~G3LLD(v|e?)?P9K;X?pSjU66SJfVB zp9ZBNjZ+^CWIY6axaHwI#cKI4-@|{ia^0TsrKK{U>+uCn0m?z==wfdQN(_q(CN}UL z`n}UGmMo?A!(%y`2bV9H9euHrHVl{M{0fgA!dY(*YHsvB(Jgr9Mhvi;(P5y@Uyh^i^OV}_^LwN}71@6}d8sxcD6q(@JSiIWq89$~a%LN6>wit2j1+lig`qvAH z)Vz;EflON9v2#Xhd%+!vzI+ZQ;KoPVMAqM3g~FN1R2Od;n$cQ+3DGZ6D3*oa%ms4l zVeTlc7`~SVtW-&kVi`LQwhCb(lp(wt29_}YiK2k$iyKoIRj`@EbpsHI3gssXE>^I! zTW|=*JhrlfjC{2Nu1vOxR1R26|sGJD@Es?Fs-fhyU5!M;d+;( zcsA%n%8g9*ImEb|z=dRqJcMFHCgnT<`B$;>k{H?E9wO0L z$TPyV3oA@+kRY}MBupoWBND|<6P^wwJR?{;VGv2hMDbFH%C`h%x~_1e@06x4Mbu?kR5-Q@s>Le9|DH?^89x5)Ir_d^i&2 z6;mUxQtZQ$9KI#E;9JuYTN6aY(t{C+&R^l`ZcpM&4Kf$Q4D#dVdqYYLVwlCq$8|u8 zIybO^w&^e8*NWgmiLeTxglc243TpXAC*|@)+T?d);(RbEK9~$)w+jn#M-jR65n;b) zeW4>-3xh1RW@RKmmJr!%VOh&VS)UQvn~0pBV%d(dkd3q~0!sW{H~T~}=e$+yj3XO6 zll>(v2PB?@Xv>ChVz*nfesScirD0+FS;q+MpVnODehw2dSBe?tiNj(8Ab&XWu1j;N z+p@N>dO`CYx?Q*Byu5yUG(@&JzyLB~Q;|Mdp%R=Nx{^mTJp$x6367&)ZVW zzZ0H|2YF;m4rhs$Wk0gO%3!dUh$ivfzxZyDLeMW?tT zDYJMz;^)Udo|Hq+UYy*5B3-A~a_Vr4` zkRb462@e1Yw*WG(OEQrJZl?si0WR1t$)GRGMwaH%gQ7hkkxD>Xcv+D}N#;J73;>lc zml9MS9-u5vygdH8G$Oq;Dygg`yeuocBCf2WC%m+_tt@rFq-(gWxU8h8th9-~bSk}c zwyiuASw<9FIe-KuFIUv-RV>h#ZM0Rjw3XE^m+tMCwC$JkV5--LEA#g8mEY3KHp|MR z(#yk#OY+3aEA^`2b`|O3HNfxcO^edhw#xnes#?yy)Jl|0X!QE@U!bH_%FXI7>tp>hj{x476AwDCcU(44}Du0iYaeCq>Q784{OF5bFGAhI5G{v$sn}#$Fb~r zdmkpMztyq!r|q6srQlh|UNJ6v!$ zw8giusd|Jn#*@Olyrp-$1)^=2aM{|a%>9?Y{=*koRFc`*g&$nbwj!cv4CBzWf+Q8> zY0z(vE5E_M&@x-n!MfAF5~2Bk;Wo~onhEM9v!G&|68CnGe0oH5IF_t+#CFNEXmx}~ zZKb`05F0}gd1Hvov?Qzs%!Wq73xAOBd)^yCEc^P|CH-x!WN-PEuwh3=T=X6Z_ zdS7#E>2x4MoguIMdoxbKYPu9^q&<1KVB@@24XVf~DS(O*klKL74@BSEj2@1l==Mag zsN8vHfMe-suk>wxyUdbN56enG2-ZkiPKq8IXE|6Rcx%M4j?D>~i1N~~W9 z4cwx0uX(9&08j4`EAT?R;e*9`!K+9|QtTw>-C+Q8NqQ!N2mLbgk63C2qN8J&Fg@o8 zi04Nlgp9N9ZG&$~!XhIPxmIF>R`9wCgex_*A!~{Lv!UdT!D=sfY)RBdZjD@Y0HX$l zlS;Si>c`59k6Ti2K$7HY4LCPnxj zr`Lcp1V;!WhCAO#vYn(kb1I>ncbjbLmhj}m+e8pP<)QipjXzN7N?-sBCBuwa?Ns5!jifdBIhr(#tQfkvjZ$A z*h#7Ypo$8hCJ>RjR_4+6lyowy`Uox<3#+$=gN&ysx>sW`6omIfBnmBoU5ff6S7i-v z^Il1-k@+!s^X+hy#_Cc|)av8Or#kP^2y}BUstr@O;8j_trPH;e?En3+fEGj&Y zPX|W&(RB>*&n=cq4DmD;_V|ZP1^~l$Y6OHJTwj2R#bif@5Pg{u6M{q|@4h6Vh-8^z z1hZ6VR^}D@+R*yo|QDr$iyKea^p)XGm*=rj0H3Bk2ZGJ9YOvahOH-_g~0IE zd_;?#Q_&c)R88fXKMmTdFe%*h(Z(j94??;IcC_(4k-H%S_j&ie>@CuSFw_=l7vkq_ zq)#U4uh#=Ur-mXIdN$1gq~8Q$;>3Qyttjb zNEPDUc>I%IL@BkFlu))n=}sbAri2tQF@Viv`XvD{!ieb81{tf3z2Ehw&xAhL2M!DJ z^vU8NQYekpnQv*6dwqwH(k;34>`_O;f+%J*HDK)3`?o2l#Pno3jlX%R0^Y4DaB{v%(PN9zu49pqNTTY9$b|c-HpjypB36w~M$w z@VvSKMs`R3&i}#Kdj>TXH+r`_J)wqPq=eovH0cnU6e*!MrHOPg6zNK6p$Hgy5im6A z2#A7+8k%$jR6s=yN*5JDK~VALIp@7)&VBF9{lE-EJ}}HM+5halervG;A~v7GDR8MW zgyd7xX2Bj4;huI&C|!FR;$=O-qGeJw&U1RbL%^8tX~hInrT(|zus@IKmsU13pgD_< z@W_)twe)=^@$P4-VzTt~Erq|_V&q2R`$Pb*2YfNvM?pphPK<0n74yH~N zRebqo_$%4%U5?lI%Re`}>UPUdFxHz60#;X0a+fqIL-3K1O1hl20s~2rZG4%HikJOy ze%A`&)o}OrW_jXzLG^d7CqFDc>~6fLy?$X4&ADAX1TXIxzJIzg_XCRUu6`u`*N0zI zbEnm|PWU-0;E^E%VK}-M_B4M5r*XvTIE}|$!Kdtf+$~Hc)^8ui-Q}8WIQedKZT;I) z_#4i`B%133TZ2ivV#;y|Ko6fr=mDhkjLg#}S3*oUPlre885po+mZs;WnwYR5!!N6c zMo5&EosKQ2oUazcScy=zkekdnel8mQ^QzYt4@L~royCT zl7xCHo??lLi&poqUwZxYgza5>hhhBC8i^1EAyI-kJyXBw-`%`79{i07H2(A1Oe!)z zA+paYl&#{7fwVZ8L-Eb9w)pa@65B54jT}LvECF-&yxXeR4xp&rdR9Trh=biS&3ml3 z^)&wem>Yj_^Z9K(W*D~Hhs6}|&6m9}(H&UYfUmWvJa%Au)q)>YeK&ExW$~`p(0^8} zt*`G{j(WBAJ@{hZ7C>LIp6hA1GZMb}5$4*(ovjn=heB@3O7cKJ&!JT+>5S-S|#3m!N*U-)tjr!mG|HiSkY=r|Y^BL5Y#?FQzX%d6ECKt?IBRqF~^g zuaeV6oWbTw{iIC5iP8FP=4<}_vQ!v2q+1HbrZ;zZ$ z(~~i#$15BnV^!7HeI^QB_wQI$XnujdBxbf!ozI6#G6}__nGa@+8s^AR^5Fwi>>+$ zOiEzZiRQDzwL6prI|*pyFbF4beW%m&*1v(K0%8O_EhEXaI<0|{oNKUI-G4A4*B+AQ zUF2xDwcSE`HgP}r0twq7?OA>H|D3Td&S!n;M%S&_TQtv$D^>s}P`RXgGhu_Z#i5_S zKHAM)J^v_k_SCn>5^b3DczFAbZ%+Y){4N#XSrZ!2ih5+)6q%|W+OoFJ*^%^^Es)Q6b=DyLdPtYWSL=-#*Np+$jn@4cou`Z7ZVcqz z{w#gP8aZ+HBG^E%Chc=aqMC_(!}Qk2iXZgjjMeT)X3&?Pi(XG}bT5bxgZ59#FHZ>g zPj3n-M=cRX71T@N?#BnqF&k~sno#+ms|$*yZQCzepKNWv#J%f3{Ftqtn>irF@a5NP zVfvToMmbnvIE1j4fF&fJZG|1F{ZGawTsb-a%8rB6;yK=|ui=e?M` zdkxv{5K@2M`*0MsOJ&TTCCM6BvwD^q!1U19IYK-^DPY<6@WZ z7nLiiQ$AgMrI(+mRBaSWX>@M!1wB!z{E*Oq`))parTre|mq4S=2A@sZ_PyIL>LhWH zteJ1dKdRW%qzzf!X5*^P+CoPH%$Q~EBBSoqAswYn)ykh2>#0^8{IFD)I-Z}1w6BxB z)L=e8h>dRKUX#9nxwI2pB=^G zXKmQz`_~$ax64G@FPkS5-L6m;9?%Kp%NOL_KUp~6&-ZE%8~NiI!-X=LwJTc*{{MNoY0Gcb48)yf?=)?15H3$IQ(i>E*PUZA@41wH5v zeI<`_l6&*Kuec-iLTiZU4cD3WSNEmRyXTDwh z#1Pfp=olOs5${eLJm`D+MLsI+ocq>H(Y-l|wum10cRO)CkJgHU2~907AHF*EJ-XlK z;~#wC3x7}hUcG$W+gr}ZZ%Q8hHMtT7+F5vhTtY=!-%UQc_2wtHvzFK1y9eM!)$W{0 z0(fFqMQ+qP#B3?}mG(%w&A|#=^sixQ>#*9chN)5m<{_OUfl7yjHuQ^M&opK_bE8{3 zyJQODgCdHu{ii;Oo;n(%v$py1XT7IgHG;50U9H8IYk9AGCr(^ux{AvxrY=2ejj+4L zTPgcsP5D!cnxFN(^2I47?xCp>^-TWh^?vU&x2KRXblCQAYD4e$(Q_glwnbP47`{E4 zrPq?~PdKeOj_?ifbKk2mciOaYKb|k0>8_TV-m;F@GLer8KcwzVxp>zwxKhF893Zf~ z*9xRrg$lwfm#`(!Ad4szh;S_fkwBws4ydinzzQOUhUV|R+8%#r%TN3F>%_Ck-FXD4 zj*a`9>!HhFZm*Bgj#Th%kG&$zFYD76dduu2_e8qMsjC4Pn9JCp2oojA`9=(+{aG@% zBvptrVBo!&D?kMi!Lj!m7>;reMexM5w12-B1y3}Aer7#vfcu}1WqN};-@KqwQzRwp z81Siu-BcZw8L*vMEGGj_h9%NVTyYeNs6&4(Z*gsXo1)V6G(L&;|VAKzOsHyNT?UPDa79-QA0GoJHcg#`9l@%h+_k&9&}eA$Zj`**!1@| zZS>x=N=mAp{VFovWsqYhG*t}y^;-^)PA?-J%eqLPkP?$mKC^yhcM+v7zMWAkNkNit`2d<0|E4^UvMRX}K+s#jV;+N3ezM7t75UZHK>b?SpkspZ?o8bkMmrnI5 zK`I9zUC2;nGXN|FUT%mNrV?Nsq+UcE37xxv1ngsi=@@R?`qiHYaWMZhQ6Q@>{mQXf zoM#41hCntjBQQrJd(*Fo5`uT0kz8l9=fLUQfnkZ*XgYwimhPX3MVOt;UXL?9b)E=) z{!0ysG1Hs{m2C>xp<&YLAZ|jEEj9uM5RarX$~TF;UYUo{1++VfT(gR`F_EMI87Q_u z8WGBo5tB&-J^U4|9hjkqiYNN(DR!UhsynB~X}G?xSN+3~{IbZM)A(TDG@jGAs<3Fk z)NO63DG5K2f$@1E8M2T^{>VfG1&^W7{4$-< zjzV#^&Fpw}NBrk*D|Iz{$2A-2G{;R}E1r=Wg>5^POExNw_G`m6;H!?OkL?xG9DWQt z3cK0bzp}<^)hWf*X>Hq>23eY?SX!?K$o$eZdXSviQT~1@fo4WV5N@s@0T>=h^sU zZt!Cif!UnwAq)NmkJ^?d&z3|o`4bOFCy__UYc6rf#$r^MY~%vpO&9#FrP)d@L{(~e zpbZ(ZxQxFQvG*nu!76+RY+S zVi+e10ZJ3Dtl8SU`XREpudy0h4muj~$dT|=p1+WO)r(lvQdaNERO~gulQj z$&ps(vmRLzo{+N_Uc|Ky%DN`kw_Y=8d)?fET4(_|c|OzfSij`_S0#EA=Zt zTgq>{I7b@^&=K%PIM^T~-r}%ch!*)}Db!UX(gg$h2M1p&k2GGq3P)dolhe-iT)TTG zUKHqjdH}GicOcML7an$)pJ2gGyFpTA4H;gYyHNlFBZHCy{gVYDh~RvSyBNYqKQJrBuc?30U0nnAb^5|wSzM#%zE`)mk@pq2Z`iu# zZeQ~F0O5!`5{kdlmWlkyeQjJM;Ztdj3kKLd159cXPT`^kczVHJ08%~SDZG~z0hHak z;=T<6qpuDwJ}mQ!%-DU{zQ8}o6WLsHCEo%d-bzS`yZ7L&e-=N-%`E?@F@I}Hx-}u+ z<6^h@@B9-+uWFg-O!mzt_Ka{Cvd85S@z9_6uOYLTw|Vg}@sH_arryl)Tj6cx{fFuI z)iWPQ#y`nQ(GAJqjj4E%s74#(**>;e#<^_oDMlSNOGgCkhqX4I9B)zgk$z;w@ zqC$ctQsh7|9p#?i)C3aLrUNSC8Zg+RR${~i#e-l(ZAR+ABp&FHX3yp!VEUC(P4hNy zDe(!MnOka~68GKZznh?<>O_HYL=VJ626UD~w6fI{`Ueen)bx$IO~lHrBSO9Wa(1=V z`6*x-G?;l=L-+hh2}wO#W!P<5Wig`X!aCOXQmkz6h`7c`+>n}Y#WUTMXP)+<*z6My zAAvwzQclqMQQj$O6P4_!gn*D8wd^~>0iS&Q9CNNd7$sGxx}IlYMuW1K$Bh$0#C% zmWQGjPUiO5R#qfF9bG(uIyX+wZBo^R^rNFPsAvXKd>Dt|n)I%8Ys=?sUv2eLodH05SeP2T)FH6Imm6*;6T} zk<&2Ez1hl@`QJL&3ruIq3WncZjJ;#7cJ9I}{uhHxXei;oLO_hV^zj5V?>r;y-3zY^ z&_`4@*DvtCY{3w+fjhoOni(2MX1G!bKP7^oTPc2fF;rhfm=I?qiNIAXR1?jAXBNp< z2p`7$=ayz9!-(Wr~67Pnm{)e~hWW%ML?Y zIH(pH^lP^(oCN^yvIU_*)t!(x9c(d__CL(PpU1P7yWqN6$Y|BhFXDE_EYr`F8OdDK zC;W;b1!BVX#j^uZm<_~G;F@?a2Z-qr_Du+|eR5&;Q1I*g*Ufv@_c|-p&Z#)na@YH- zT{5)&3={sowtFV~L;!8ZvhyZ%`3lC0j`U&&c<26V^dulfbFG|N5YZSQ0K=N5sAcei z(OvLmEEPiO;1$nB{loSk{B`-ES=pzBtMcb!oH;`RtWmFq6GPOy97mo5txv^Pr;S>A^qI!FaMox=lG)@4-Iu5n2&-kk-~-&e%Ms9y`_uS6vr;o+hd0c}pLJZ z8mo1${*EMfEK$}d>+>|f&1i+93dcr+Xmx5GSev7vNgN)&J~kdGxwTlGRqE!*pdP9O zmLr?zORL`%_n)I!wUBb2p9y_E$aiqB(IVdfmQU0mgKwl8{Q0O>&QoKo6)}Vqw@i&@ z1A+cXvT6aMcAID2y0T*~e~SzJRb2qK4I3;Fw=@EmJaiQj+@;`s~S>e6YHGr<9=$kf3y6`}TtbLFMFHXWy0a z==-;kF?(uV$xc~JNE~xSDVzunXk?pWT4PHlf;T}xW;}n;n1l7H>q|(_YaqWIuO-fd zX>XeNgHqA`Ql~PVe9$hyEi&7f%fRS6Km)r~P||P;VDu*pKQ>YfaB3`A)p7ByexB!w zHufcNiGwl=?3EkMxEv;;R|_&ZQB)9rn5)G z0@3ef1a1)mH@s#2I;t~;&iCUHtcFWU1FYe*-nY>at9h>!i)Yx<1uFaT3j$V18cZ;D z)nGIVo66uV##CyMFDQwj!Od%~i<%0Ghs`1Fn`Sy;;-`IKttVpGKMd9Nv85)Xt@jn* z4rA`VDbIEu-D8k79{}$T)t4!Efdwnc_lViqQnE;oMA9Q+`5y1#n9 zQLga5X|r}=pSKN*M=Ow6I+KQo^ z(lXEPSS`Qc^Idt$SeY4p`R}i#J=7VCz2~7^rtJQ&{TMflg`#o$=_WQEzNzgItt-aO zN-*^Uqg3`mBHHyeTbn4C;$Rg|1mSy{AlMj4Jr(kpe3H(uNmW9yo}Q{Eu@ruz;v!8F z^3qw^R(Ij2OgOy(p#C%7m_N57&y+)}v=aip%A}-i{pPhTv^9;rEB>4Q)%RyvJf{YX z#q8E*wE#9w5aQI7uva`<^A`*CyA|(;Ob4v-d%$&mXdAMcZ{O~jRJj^mAh`H^g+VOz z`-Rj`|BmWNfG<~K!rm5mgs9VDfS~Lrf!}XHFdDSjdhJR`VGn%a;Y{q$;33SE`oonK zZ{p}D^Y?n2nSFm)Qv2C#Rhz3jLy)A4@67VNT~=$Z23Q4An#y$1xZG&VXDXs*2HZhE zk`j4o!IExwKTxWp7ksDI{Fl&NNG)Iyb%p!ULqKtFc_X^4h(aKMDhYUs6zh zUgB)!WG$0~6&648kl+jj+b$o%B0+OnlYccH`W-+B{S7!#8o%otT05Zzl{DbHc^gphsvgxbe9*|?pCAmhNxn;Y@btcUrG~F#iFYv)+?aiUv;D~>2!77D8iO>8 z5n+kUfL!>5wlQ(BU*GoSdgvu_ohv6qh&%or5bj}bfCLAuE{;ZhaEmGxyrulsCfDJI<435WH zfo8kYuRuuE{gZRUJexSA?%0Ar)}@d@LEGgwiVr$dVhWdp-e!d6)uABd=X~-=V93f3 zuK#^dXo)&)Xzcj5q8X@PZBvTJxOYXAGKzLI zj^26QX6+G**xzscy64hodsjlhduiMBP1+`r^d!OD1OZ@L1ZbQVu0Q$rKef zIr^#32D6v~K4SHlWq#+h1O{|lllsm1_I**ln^w)5Z12i};nF~q%Hb;`nBZP$V)%xD zcI0Rc$t>ZoXbxvPIqi_y)JGthC5A|YRBT;gGQq3J3s3_QztRz$WEK==7{VYqJaZNU zLL9m&i*?vSME8^UGXdq}7~sAHf%wLOBy3J5&bdT50KCLE{4^%OO(pq4%MQT$3n)Q$ zqU9@S5D9Fwv2FG@4M7psU|ceXhh?6Qw=s+A^<1}ef~Z4_7UUINw|K61I;dBKRU3nY zo+rSy$pE^uhQX_tZ2%FvX07laV(Ubd@&#NuUnKq3yovZMFTuVMg@=nhrN zoq%gAyuNzPkk+P4{52c=6$#xGi4Z5eXBLP~>5H%bysq81^r?MQ08d%Hu5QsYTpZR^ z@@vfU=8;ghCAfO^@h9Oc42>@VP+_g$O0u2C#*MHPe}_WjAA**Q>I}*^qfQNPn~lzO zjUlDlw6nUR&Gew?vXEdAAw9Q(VwVqSGbGgF`>%AZk0R)+l$68cS@sEbj<2f?Vs}sB zkOscDy=g5e1~=i}Po930EX37*I2-d;P(k#h8@{*iSw&}hRoN!hFjPWi0>tE^8u4`F zu;;BGEn2~N?nxic*U233yyfoPN3!8G#RoJAWcEAr5k73^S61oofv7ho>_Wbms%!8m zSfOekFcU!k^m>|pE^9r1EI%Mpt&p%)f z^O#GfpR)67*o#ttTnsb@tNtNUmj0MAiYlQ9B-i8tAQ$=Oi*gcqiJX^YD|aCcqQr{D zYnYF*J5o#y>pXSNad#Gjm(qOipB2ULLFl$+T#elRK9CWr^)0QpfQQ zPs|EDjOZ6k%$=g-S|nk_9k^nXvV{w8?)HlKn~_T>Ib4@)SH|1yHz`Q9zJokeH_Q`~$eD%x% z%_dIBxa9AT*Xf|GflT2EM%>V-40+nzc6p4ni1$4BsdN@qWGhpYTu1orlJBHh_lb3~ZEa9X?bA4MhP!wHTn8%9u_mF63f} zRe_vcLFw;W&bTne1zt)hE2{G=4En{hZ&IKp!xFw!QWRKL@|ru!fJxbmU5?HYba<4| zxXyL@m&{r}qgYq%!jQcp_-dxWYScfCGY#}#*NHgp zITn;=R*b(c35`YR<-s`#5IbD+EDv{$ViiV&;tg!8FuX*GE~zomwvbR9&ucy< zC{36?`MER!WM$3*Q2hCFOx11-2Q{+*jdS9Ak@LaDbF`^~cf1&6LCMxcs$wgjQ1TH`M8&M#nmjeEmIZqlx#U2~^)s8Cxwi&L1q*HD z&i|NrJeSd#Jlt=2blOVFA-s5m_7=&emZ-ZBELh;wpkzV4|{Z^hbNf zIJLv3YT4F1_D~io5Hkz^;HFplqNSs*b*fow9s+GO7wO?>9uqg1pVtVn z!T=0N=smmWn=FR7H(^efx^M`uh%9p+sKdf{y(AW-q8~sw0a-)6El5&sHQt2E6nslss{vQ-`HOboX z5#D~qvZt{8%qbz~V3~pe_Z+X5&_|5*1rVOto(qe}I4n+Lz58;e4w%5CO|!cC+a0cK z^VXp@m1?Qtm7G~1l62qq-A71qK2!fIh2zxwm*jF`$+y+%e?nQKuQ@Le)YUTCx6^a+ zesa@{i)=W~EoKd=2+*++w@cp6yL4Oc1Njh~dxae$yU0Dli#1~eNv}g26EtXn4-csB z^o8i^2!u2QuPfqIKw=Eh#2;C%ZH}6k`2tt&BcdEn`f1w8B}WW@fX3BVF26;ewC}pC zo4EB}(wKjAt5@_%IlJukIqtu=E+9&g<-?phIG!Rg7kh1_i4yW#%j3zn{R}X~y;NUX z(Nmsg>X`QZ1MLgB^;n^%GJK$6hHSCwc%$rmpWM{oHBSHzcAi>F|3(;na&)f|V@+DgPucN(3A>J-mo62GoqNg7) z$+z^!mOhHmrA}FGOgW#AXbGv$LC6&(W#%J59t-EzBOtdp*oG~^8~w5Gl9>7`hUQ`s z;snT`KzN@0RBC#-EYH>1Ut?m+rLIbGK1ZF|$K-ORd68*J@}KJ^faU|yZcTZFEL$?; zSfXfvoE)#EqFFtkOUm`Ms!RZJ5{(7;cx)`1_5&$F zpqCQfqx<&m61@73Z&U3bKLt8oFp$I6@r#CnShs=2OCSvc_uL7 z;v;4vbZ-fH=Yn5{8PmhZ+23SPNX+u5Fi6K^WLpO2u>xJmc%z{a^5hx{-T|=S{PoS3 zb($!t7@)NGJ~QP6V4k(nOj>TeR*)xHB+*Zn>y4J;Dz{>v z-PZe}%dcgY8;zdi>U~|c31wsE`ebRn);3w8E;BB8idVX|kH46OjCK^;wTR|Lt@{Bf zji7VJ`BfC-^@Y$8FMxg@5sqPFrD9G|)@!}05FP1I)Y{h!sHv9}QF$|J{*#^FsAKzP zVAF?$6Vlu;1*oW0mpK3FRBfZsdcdn}&vBSz|Pi>1HfBMAp~QDBpaCLCiJp zLI-Igy5>Fd4{huE$wqGJ898s$e+vurM}Rg|cB`u+xgw>F;C81joRz3r`EI`^uC4ODTqyJ#Mv~74>9_YiAN_qv`rFA@ zX##hi)b9t-D;ylAw2TbBU6{>}Ak8%e%}-JeTPNnlB|EkOV89?19eXL5Q=dP6^4cU!+gd7 zpIy8@)DKAohX%choYh|==FAn1>Rv?{vG5D zjpsgV>_P!^khVSMjbx~N(2i{;r?bMl$JuyTr_C|5+OM2m)9XHLFTS7bC({3)e;|lI zu4T+XHHiO-|7cJkn!vxE=O>?q|NVTfqecAp<7w-!4<`pV|NUe|YH4X`nj~vxWTdB) zG&Hm_a*~rxGRbMlsU=yd#hPWA)wi>1s!0W!l~oPR`L`PL8cUk1Zrv{E?j=>#Ro~6H z`M5^w(Szc`x{`?p=~>gG**z&kO;5-T9Rs!Vsg*A>Z$9rgS$X=lXXD2E-uG|j7oHUt zb<8~1GK`P}e*gJ<@(+M82$*$H1`^R9r(O>cSZ}AJfA4M?b^4g-^Qr{>ah4c=%Ispe zBS#!b!I33F0c@R=I{KF2@V+I=ZctCboGD-+|55{j(co**X3Z`r_$+z*lDXo;95wBmc7=?#f@*i*NrUvD}LF`_x$Z_UyYj z>r2yZ^^*_Yz3b8&*?iF=Y*u4!l+Gk#-EB5!BmA3x|2GIt@w7}7&+IO=0|lZv0ch$= zJLKt=!a}07NQMc!nu$rF{TV(DF2IG^h0~smzjXdY-_2$1x$SQ>7L#hD^*Gj!k-Ex)8~k5)i`kp5fEOa zyKn@wv}gYjiI682fN<9UJ0!yR_W)j|uI1zDQEaPql(UK{u8-T?u;86&fz{l-KR1f&+p4(?X{kqX&`u-gdeT~Gx% zGCj7pwP3w$w_tNI3}+50U*)v%{q~u4$;Q-*`qC`0(T%AxGu`-D>m!$N6o zKYKVrMFK~Kue~Vx4{Q7NzmqYmHwq|tqlDq~dow)m7F9Bh9$lmM|EXxh;^08VOGGV) zFA;v``-?bz76EFDD;Rx3AZ9$tr3{<{ZLuh>Wl4no`93CP{bz4V{o9{?dNSrQPHi-L zfBnbnjo9bE*?uU;L9wvw*-pM}m$|7ntg(ALJ>Q;qZ@29D{Q0qX<=@|5hYU&agFd;s z*A8D-UAKM!ER0)1WYI|sp(Rht9)C+hr+Psk%1=>lyUDy$6!^cDQ6{vi|e|5jI{)Blr%xNxkT2Of?N%epD0Z9S^t?im|VY;K4XUiRj^m)`n3_Iq}K<)^>l4bRT>&7~E8 z7EYi@n+TVG&xtvisuenU*D17cgd2HCNO+Rj(L5 zKB++GZp&)LSQ`S)S|03`j#=JOE{Ro!af&b-^Mdcn`>Xg^Df{cLdK{LHPlv|QVcS0l zwt1X&0GJB9inC_9n{H*e5Ps`7)=y)@{CV6P4qbB{QRsy0407jg`M=5c$Zs*vllgy8 zkY8$8ewkYfYAB_HzKAGYE}PAA`%&{__!0w8IZ2_=9>KOtk*?J^S7jARMtn}Q zLy7sz@O4_rLct|tQqy!(+|L#-=3rd2g>~685T%xB#oShw4%_~0lU-{xJ=LeLncQ*b zb%^Zw!yq!HdG>DBxc@$Ma?vqgjhTgOYkFy1^Go0h);;-F-=ps@$K4k4G^95)*tG4- z=er6yAGZdWo_ljv=uGD;-&XBK{x|b|2lqRyF8c9hxfxj4wcX5V3yq$9D_ixT9nDp1 zObWK2m2K(SYLX8xnLIx_U3}X;+(zDX%bG3u!NaBL_NXnX#hb~trP@2oxNp3#zm!Mc zg#tUFv6Y8*q;<-@K(2t$#d9C%gzcsDYj-1udL6&N=WIA+?jRyst4>9BH+H-Xia|V7 z8Qs3$56vY+6v?e5>MTC;zweRoS;N!Gu6Gc_(g`~ppOu*dwY@Cb)Ha#=$jumYZ&e@} ze4gMV$Z&Y?A2aknl71K;-On#i|DsP_K>+bT-v9s@Yz+Fp4gM$q0z84RfJpT65dB4Q zK0XybK7I)S0S!SZ$y2II0`wpeAKw`fJ`p}SQGR)48A(Z1c`0cvQC(f#|2FuWp60XA zKK=jG;2#|%XljlzcMzdV{M}6z|A)k%Pu~20EAhu#(k1@B|1XKZb)dU>sGCiQ*SVOB zc4ilX{y!xCn)OO58Ig2}|CwfMn;XIZCGqzTs?o;(4~c(FhS>kp;9r^@UMb$7t|J|b8`!H0_2XijJv(JpwJul8q)@WNBt9%Q`0lgXXjeb$pZF^w(xpe z$4mhS`{E1%+xhj4&8_XvJ6|TDD|NhUuV^2E58o#lk1OnXZ;VyC0bluBuTwP4!bUs( z)5g5AW>zaWX9dg!5%w{_WDX++bq* zReT}cQeXX_Rgt1YjQ*oRh<5$*La+eT5qHjp{QA~kr@_a@?RO2bt~_PvB1{Vr!B-wB z&dWiLqadyddqayz6L!&C~*;xO|l)cvtx6`*Z8z@@5oklF#{881{WSUYLnz!q3km3Rwa_q_*>+gLngVd1bCj#$8YVph5iEEx{ zsW^+X_+0sj)F)RR4v%kcn$?pF>X=(EzuYorcU+4>GBFr9YlXdLEd7goX`6D~ZC=I+ z2`7T!dv5z|n)a@PYYqhttLysrEjt}V<6){JWhH5!zH<60C)Y-3O?Nvfc%Pg}&#+6z zb~IHI*C&E{iautAj4d5+x3D~yv}mh-uGROwOR%MX^I4(Kx%~$nLGhm-WL%$!n5kND z3z#a-wP@_@)ywj4cy4GB(QtP{psh<#or;1+sVX5|cxl7S?v5@|r6GKRaKHtbXza@6 zY#x>-NWa^ExE#57IeIx^x$^K`)Hkc157+mZqiL~-(DW4&WBcJs%wb#aa;AQ+#%cd=Xbd={fXb___%m1<_1JX%h#tf0nz7#w-@IJ+n<~WJ%L?2Pz9Yv zqU+qB9B*d-V~*SY{M;($xLT?zZar_v=IN)MZ=MfN@=pl>CX0PmH~`GDWVYxlg%L0h z32|sNJ3n=&y)?l%mZC|4vu30)8`5ABOEgBptO08=Aw^1uhO{a*Wa-*XlMWGqy7dn7 z#t}#gJ6=e&(m|e=;9Qw;xr#vrRb;pb0qNa(k9j1qv4sp-CW@WF%Ey%NzqVj>XRvN0rL!F zrFmu2w1A&disrNvKS!wsT9PHaY0AeZEJI>h1i9a9nu#}N;6ht)$`dNUcuB7vrWZ@x z;S?jRd}T=!iz5SWBE`&5T4^u`X9B8EYObNcr&EQGki@iONd_p{Uw_XLpsjMq!>A*= zYFRVc$_>B}%1o1!8`febYUtY(pkc=_dk$;KqdOiDsr=@7k(o%X0CH30dOoNcotALq zMl_LWtl^UA);6`;RuTea?LM*FwY3DSbG6bNJ-B$z9O* z$qy&TiyYOL0*FOQw151+sOAbCl9I`^6S(%$ zO^3DqTttA1>3^dS&e$ZKz7-YI&0)B}D@x1-@tQFHK%A5U3==YL{%=*_D+W|l= zn>I>c6-nAeiE+i%yLYi9F`cwii%ovw{nc9$hM4JY7Lrd)klC?@H&okD)-A1%!=t>>W>B3bK zMwzxOjGQNLxOCR5SFU|yaO1nZ-rZOkzit!~^Rn^GezZ~!1N6MitB$WBO|Y9So3D|!23QE}w%#`L#<4lTCV zU&9_hvLao-;zRq8dzqX^2e&sdZ<(kDId3bjq`3F<{W}|x&-Ua?vgaRmfe#0d`TAxr z&f=J(0w9u{0O|4l0RWs~uv|gN5EVW`i)kpMBrzEk5U-8rf=ST0>#JpR$mKaYc^NCP^_8;6$eJ`9~mn0I#L4?X_P!W0^#a~W&!Ip1-IecgX zd`n4Gki!jJWkiGbu6X|b>Y21X?RLVI@BtD$@Z{h-Ycxsf<2%*`b`M1S<8(rY6nwz> z@?BFR%;gHAlxSWQoQ^?^Hz1K{L?q@vurVi5Pl^bSq#`chubrf$FzD+6CSd7C)Y@p` zZ3#e}mb`l6c-?UWCB>V>g#e}xyclDM-s*7XO(L}?RF^l(fcJ`?H2h*m>O~?E!gV)Sm8*2v)Q&6J*u8xMPLTut&Hd1iXr3mQ&?pY8Ao+s%&a zhM{+1t|`D(3PJ-P!_jl)-x>)uLb?s)nXi%A#$%90>@6`~Ojt;~G=zR}c*uM6?X%n; zy@B6cGDJpm)iDsE@pNTkd}L=p`@UZQM%`lx@!Sk>M5Ks-?|+eu z2Pm;!1-Jz0fvX2AzOb?5)@R95X72D$cS;9cD@4-+o|RQhY+a7Z^SNgpkbe|5pUF_g z$HnrXVyUbmv$%4ZFZ`!Q!rT$+|KRAnAF2HRH-4Yt-1jjLA-iK!k-RHg$KIiZq7D%f z9eeB8$3C*lI7GIN$jIoBjEqjQSEnd@HA$VmKHtCK^~*h8&*ybrkBeRHkj~`dZI`t- zUa)3&Z??5?E01tGIBkb7=d)c=36Kx{Ec|VU+H5UapUzJcEG#4fXAEyx=CRt?c(MY1 zH3Z73fWpbuqJIhbJXM9m@$Q!1$NugxSiQsI(xJaVOEdb-H`VSZ@> z@#!?Cqo38=hPA*rv6(xuomMu|>wh)jfn`gWAARt67aODcM6Dy+&aU^!>2ydB>VU)~`y@hb7{ zGyYUCW-_tXQxSGC0JwmrFw78 z^YILCa<13+0W?T~`v-d@S zqN9N6_3{w(^Jxz*T*EK{P-1&}{$c@Nl0)}&{a&Jr&R_wDEzc|0?48fge+oABJ$W`U zaKmoB&^EM*-;`%WjY=U`ISDr>GT`_&{AO9x{HnKgT=Tpg4@`riN@XIvk3-y8?>gT` zpA*gFm6ewVo2S+46uz`rylJYIaX15jVOEg|0OCEUas~t*1gRFW0YblTeM`J^EuK?X z_UQOP`LuNFROJ;)SM3CATkmSKfN5Yrc`FHr@Sq^j?m>PkL9y{(24AvOP_^Xj8qJ5S zBc`p+gDsOTZEu20&XTY5873{5b`-v8O0&BFw+iE6kn)tIRu&QT93XHfd3@Tjn$?4i z3I{znk=U2RW_8}HFH#0Ox>p-&R-*r$$hU7Z66|tbszzUNgNp^B#8+b3o>TM5WiqD| zU4Fxi2i%VvODBak!-gKxz}A1CvovPAPMGr8m^y-gNC8Y53qXzypvB%0aE)$beLKr} zHsATptZRB--AO9woYc@@(7mqOD8~OxcPL-#bXc2VDX7clI`BsH35I@9a6$ZEFAQZ}yJdw1cU%sGT(3 z%D~_qgdrZui3tj^f}c(B+VpVJ5aAy3a8m-ln>r!iqY!g+tF}rN1=3gef%KvcRzpcuoJ!i z0o%wITup8jG%f)13~ouAVdbFaa9LBufo|&wYQ!JT(7d<%d^t07b{*!uTyAeS%lZYA z>V;$JmQLc-;y2uo9+5>tzz)!dyjQa#{TF%vv&!?O~RTT zy2Axs(_1HY^ys%JGEGGH&gOzm`&P`C99hP4sEcai;?ht-p2-9r>086U}CI zzvSLMBDC8!ysGMw~AMXw0n2LN@ zl)72q6`t)lkFFka`nUr7)6V+7W%{T}L@s$G3FvX!mK^?NEGz1Lx`SD}%kV-CMLokOqK9%7FR>qeg1T^z$y!c9 z=B>A8C2lN@2MS&%O+ppX88b}(58PYBN45?L-ya_`?wrxO7c9z+#rki%EIejVlJFB$ z{}1Ad3kjq}_;bb+&yjZq(-~hrNyok2kX|aLQ}cs)xbV~nvk$BhPtV^#orrMI7n|l< zS#si-Fxhe$55J`>{8?uA&BVDuo6b_Z&d~(h8`{h-*R<)&Rv#;XQJW|41w|Jni(zgH zUYND_ehU+yudKwSIz0)gd0n-%rBGnIX-5*9nmM})H(xL=^fLata4If^H9oW^V}3r>=b9-1<;6sCKSK z0u?^`D>;E0riFodvxcX<>3qaQ$7;^j05hd6;doAtA4k7}Uv{$#qB}j0vfNw&({?1Q zcaESo*zN}2$c0uKIs>RIa7H8^_l@Uzm&mr$4fCVVEy}JIUjB3vrI^-J()oREqL%Zo zi$J2b0X4S21=7KTUQ|THB+}09$BljfZ+rV+sSdRs zXX4K?zW?!LE{*MfKw2eS4EvD?An!XTOV}plOvPTwU$DJeY1O;u|8C);!&B3<%NLH7 zon_d0{reJf?=h{;$d3U$mCQU8$pDIxPjW&?Oy7nu<1Fl}LkQ#ZSw?{Pf%cb_U-J7V zKT>ZIe@UXhp;(FJUwmrg+!dN%3xlKxT}x*d zeIhrB09Mu5)-8zi|DmFlJxE?vnMZ!AJ8%@T9++Nrx0RGpKW=DvHSS^6i$j9{Z&u+G z8ceflQ$zLR-&zM}1rx7dJE3WAf44n^?W7*PIw((V&-`$0S3gB;P@5v((&~2t=jWy= zJfj|X?aod!ii8AB@x0}B%Z}L1r)hhX&VN%9_L3t1Sa}|v?oHPH?^Z9s7I3npC!tqt zO_}8V?v#DGT*x2j;`pmLHohAovI;^nA+XmjCmUgG*#Y!oYDgAm|GtBLH=~(6K2Orf3#weHYqLm?kf4^CKZ@*y=U0(HZNK$tXPgSLx zM@QFu6{D3UsVvX8w=aCMXf+o8;DBcne$sz;r}I^^Fk42SQyCVXK6?&PquTIgIA4Pq z`cvQTt3*`MF*WU!7gtvOE3cPl#|!3vzL9G)+nJ)#?Df2a553^f|9q#HronOkhQLod z9mSBR)%Kb%zORn49iJ-8?hWTNsRvnQ!~4in`Mtd!GvjBor5(F(#f$ z;9<5)ZQZ|kzyIE7o)JZ#vDwTm@4(m3xV3@LF3{X)ZT{eQE}VxqeB8y>@v2b2-(_h) zNCNN2Q7C85aeRUhoycXL!;rHsHeNjO^~~}psl9(f+#f||bjc#ab|PVWwNzb_)~7}q z>oI(DzQnAB&8@6jl0mlLb#G^voXRah>B+vvhq{BOa(ftCUse z`KlWf7vRpFY?X4Y%tuk4by`$rC+oH}D@Ls{{}@qeHNWY_v|~X&-Sm+!X$LJ*bryac zb(Q9skW_!BBu7#vK}+uLRTS{3|9Sg_dT9a4?|QX3LosTz6jejr6rT(U%`1Gh6=$XQ zHPyPJ;fr|nhS%xDi%&Z~Cv?%<_jNCRDgSq6@bZ&*x%S)Tv8tN#J<-PPA7T@g%w@V` z&4XtN(vUEwjA-qA|3jGG7GZGB z=rn|5c2;!7!gqDoBMW~_AfL(dqUER3<&g|g-%XHqWj1FvmUcMT+SveWZ zhkehAbyDP=kFpowWyOYYzW<_}5OHL+cn}G^w)&}MjNWe}`C^|VALGeS(R)vbVbXOWivmy^V#Av+f5g_jyY;1Qq4UzNIsyu?m*Q34DPxXU2~$RW4|gofiK@jTb}Ky^g(P-=dutYv;>P2w-Kc;) z7-CK7mEIJQD{k%;J9PqNDCY-uS;b8&q{eqVS4VpfmmlyJwL%o;?2qK+ zRk9Qvdk@VqdSM&#mLc%VMQRnxT7j6zDEQ@K6rYRrKI3VhLNV ztl{}PmSG`&6!^Rw=WmnIyPj#wcdTdAEPbg?GtOp#<(m3FMUb%ofK>MNpE`UuwX z1lT(an1W9^jW}{LRnG6uciN+0U5< zwoZRm@N;3aH~K+fEh3yws`E5JFiS7FwLpQ+5=I7l8 z1n+O_*G&@#ACMTO=NfdCUo)9zg2wJoHk~!|kIF_pqUXAZNdVC%te@C}R$$JXDdW!~&em#iz_d@zyuB`V_Q{WA7n{M6(Uc2k0Kah0>qYx4*DgGN8qKkJ zGjM+}iNB$h+Yx7&Nn`f<{27q-{-Ysun$F7}mQtvnr~vtaS_J$6vy)%P->f%8|3k?VTYj$Q>8 zf2*NEZ==Jk?Uumok&pw2RWnPGw9lz~Jx{+}il83ItU1Irt>4re?Ty(0EVPP2vP@Pqmkf)&ICrHj0gQ66FLB|F36d=HrVP~=e)%3(Hi`zMF2yI4 zfpA8WIu&uF1*J|+rm8>?C1p+y=yL;&A46X&!0!Ui9vCLfXa$jqff?e+lX7XZw($8W z$gBzV*4FrwacUaQ_&NiaoJumZO0I8#GJcrak$~_W6s_Oj5sM*p1+p1SZ&@*JBPH2p zrqfHHTmhhHk2PN|CA?JPNs!zy4N$d1kjpb_KW0Sx2WgMLtwU%J$A`TX3i}vooY~t-607hW^592JyaA3`AuVHsT2Sr#K@3= z!*X1Gs=?mj5N3t+$AO$mX1-XxVfl3Xn7kNgc)!WNXdH&NBB_-JRt%ZC;+gOnc)0j znprv~D+b7UEXY}hEWs;35>U-(#40D~03&J!F9h=!#8I5q8n@_P35>_*LzK%(?jagE zSux0^(hJPYaj0Plr2&wB??ck+P|W3+D+8dxiiNdMNeZoO7a%DknofL_bb=abY>LLK8zGqH`7_j<`SuEsVY4v%{zKL zFHDukSZppQBmsIySb>-&B$A-#IF;~lAMsF-oN@L^0xtFfjDc`0M75q2{nNyWOp)QBSe0}(owgefufm^G3 zDoE;Bh%-y*1wSfF4j-{ZP3-L|N^-UqHK>w+2@z;PKmYA-zzT%PO7;oed-0h2ri!HI z36X)Bv(*qfCKJ4XDrXLWaE;n=5U5>?4I@99YjyUdXx3yln#trQVh#&%pGVP)M}OBP zW3ywVs7j9x&ov96f%jIEb!&VSHV~M5Xb$Sv6G63ecJIK=|Nur99|p1?olo zV>6XgPtABZcKs<*josF&RE<+Q*EG(9na>aSOpj|Cn&pI2zzNloFHjSPQs?gW|FVx2 z{1nmnJdVtbC7;&sFvP$fU1@jpOTt)z!Q_sOJUebmoa+`RK`Y4;@x5KBbKGn zD)XzLa}4BeU-H!Tj#PrNCkAFSg|sOJB}@uPN~ypfmS8%vp^@ba+lxbS?XFzCCjc{2 zefjHp=V}k>XEkI(m+ok=6+=zP3 zXUrVhb3nFUWg}8_q8_6Za8-{U%7A=UnywQ>aYSDSpfUvma+yJ5LyfBXCO4Dy9NVFo zm?wrluRl~lIJ%EXZZCsW33P!g>c;ovV(;(8oqk+Q#)5@e=!lbg#2UyxS+D+bzXos2 z^|{ye$TxEjYh7yi`Q5(KO(YW^=5COAtwHrvW{8BgPqFy*c;cr29epkkRfCatc~7AIT>Ir>usf zfssNS$Am|OI$@}dF#K(ZdG@q>$Am{ii}~P-_QAvO$Df*>e{%x*W)SvFXbQ0wtrc3- z9dY)NHe74a%AC$C{;u_v4Ic-cb`Ze6`R>?XE!<*ZBKRy663Qjy+I;W0XrwllFvAMq|Y z6C^&S+d+@tiS+9b3L74Yr%&ug9t{>PIKWNa=a}?T;DR$IlXs$at@PFC@JB^6! z@M$c&<-c-7M)-6NGiCapt7VSGbe6@;lUhWkr)8PLOxEU1*8EJi=XCwwndhFfbsRI# zMei4A%``ephYQ`$_ne{BPOk;cR;0|X?cLX4OpCWqw>r#b7R-(m%rwoNLihR;=W%nd0ljBm~_Yt7M9=BNd8<9`?WIA*3dXXzX>c>8s8=}t#Y1t~_rkKj*K%O$a&X;psP?jV-Eu_d7vjir^o13lt>vg2 zD+ya)0#a8JZ!D*5H3g3Jr(RekbFRjUDP-PQeaKwN-&!r=Tq_n^$+@shxUm*dN)6aZOmzJd|KH2 zytTgR#azFhz0oGtL0?#(wz~ZzVry4>Yol)SE$8-<*p@1B^HT42-jj87}r6#lTQ zdTeLz2Hd!4SMc8kZhHs!c1yQt+u+#Ge_~&U3V)2GuKyWX{}-|QDs^+(YUA3|?HRA{ z2KT>%ML$)}e`h_vd-C3f=Z9Z`$2xvRe19I1bfW+o@S7^2??qWaXLk3J8IxJZM&7@h zO0d{(WA04k9ozpr#96qF&OR?cwU(dpPpsq^F?N`(%2K87)QNoHK)-m;+4G<|?V$DM z36t7`j_re&Tz?+vjCY-%sIdIgm-gp7?O@>L`}3+mMly81|Id5Nzu%PpjHhuMQU1=p z{X4(?_X8L6<0M) z!035Xb4%-sw)T$Bm$a^SV{`K+V`D3mzLyRE^V$MPHst8!2%q58+~Etx`1omY>GK!n z93~DtZfln-WLrRvincrQPX5~N2-`uNylttS;N@)$E*fFo5kfmGM~)}QnB*JRm%Mhc zTA8ZPD4)nk2`Cha?2hBeyn(r7I;bT5Ci6JUi1&(;#}i3*>&t6%0}bVGi*T2o98#^4 z^z{Dns?QLmkx+O|p>%-@zN#3MEEN>}=ok~D$A!a6;GpcN5ToeCw*JFVQIkkgg1(ax zmx+ei*A+)Sux#cfU>iVXJg`TvxzvI3Ir_PgxkeWo zj1k%SB%ja6u-FC5FCAZ#tu0!Tne|?R-IJbEcCtOd_&OJlb)r1K!nGx}XUqruz@^8e z-|2gILt3PV9-g=rI@reQ}oizo+AGItenCAKYSF>brU2BBT76;}Jt^7}44<$e8$N+=dak-{JZx zLGDS#CviQ&ZhJo$o$fIkz^xc*XGf%^g4dRALz>@%XsNcqcS){Pbtmy`zGKM%8T>1E zT2~hkAWL10h6F8PPa|=kC4VrvTeGD;tH-k?HN9gHNqp4T{E}`5rIq?_@A2YMx1WS#jS&{p%V}3u9%Ma& zNre%0HKR!UkKyvFV_fcrtY7&wO&z=QS=UD)9L-fof&?8S?#xIJiSN{$@D12Ftz@~g zi#l>Q=CBb$Ty(e3F!+ykMX|8&V;rYCeNKlr6{ZwhvtRb&KhRoV&Ykz9=gJ8b_gde| zee28CU9NG)>9%*JogS=}#+{si=y6gZexn9WRj;O;bF_XkIbF+Zqq*H4)gopzD4spD zgs1ZXv%Y;=0i1WM|NflT*l`G)_Dq`(oQeO(p*rpR-ZNm%hij|pW74d{-eS7VR^UvK zuUG4W^Ua08kHOK*bHmAx6k8UH^*WorKN1z>A z3&_`Md2!*xw@#m19V^CvY~M&iKK;AgQfF?}=4ySq1(`Dx3aQ{NdKufX0fg{McbrbW zqYKYiEUf+=oIKUV)^ic}_L?rsadyZ}!aS?|3Fb%vQ(WPq;{lf$#t*7A0OO3kP53H^ zhuO$G9%?Y4?3yaJIChg&%=|D_)ZZiZwJQM|>~thc&VcKxcjDzC3EpNmgOe9_6D?{a z1UjZ(r;xalT%{I|j_>uHuG&rUNG{CuBLib7gHy`75^S8*Km9@k~eX=fRDpX*AowFML5ZUI~V!e zzZwZv4m#PY;xajRO3!3j9{Ndo z9da2kQ=(JkF+^(tIT~D*5PAC=ktuC*0;srbU?Jeda3|jpryt*GbZ1zR(q~R`%3c9H zcyWyNDu?ttC0EqE$fftTNuEuykpNP-+yW76-NuO|Vb~q`}tGcx} zjGfXqjoO&3Zv<+h+P-n8HaZG&T*y-pnq%RR2;x^@L|ZPuI(EE~`s~mCb{PqnmdzxH>DbXOjHpUz(*N(FxCA=e-wUKivj@R)_^W zihq(=F5~maax|7k5w?jJQ6p?EKw;mfFS^3N=>ii<{@lYN+>Me$q#I^=vJPL2^-B7) zM;f1~IJl|)8ygj}jbybVx?D($9<8`at>pN)dZq36I5onu`qaCUL$mF~J1fA?dlPN` z?e`>&^PFnfX2LbLgTpj;(@9e8-BT(D(*;+*%TmD2JJ*G$8ww4OO`rpe`N18j;3Owz;cX8T`MT&;)KxbAQWd&tg z&M31JG*rcfT$#CuV?osI#PW&{X~xa3RYrC@e+rMLQl>F`wAj`z8mFce4uL5q9^C-A z%K$Yg=LHfcPdm&nn*~9lMjt)YY-AvrW4sHyCFfC#sq~h2IU{~{X2RTORHKDQsi?&J z5+7@t5Mt+^#a;x8IsM&Ui8~SEQ)iz9H(txfbHBTC&?6u9&9KwP=q zU&BunIRByl6%2!DO`1QVIes9HBoqJBOy>+q?h@O;#djfSEP5*X3%g#wPGvf9dH#!> zIau(A@fJ#YxV>1r6&Wn~KI8{AP0N`yPZZDW_=;;m96Nq2QmFy^4Oqd7CR0!p1QxDC zWWEySdAxcuJ2A>4#5ov>fymVSkQ|G4^;|VJ2cBSpSyz% z<=umRqR^%`kwPtzuVg&&JNh0wKJi3^D?OkRMCX9 z&RZUEfr#=V_-FyB5Q@TypkM?DFbt7+s~B%g^oc;U4?W;I**TRAgwk0ekbo)#TwXzz z;eFx81mqq{QHgMq0*a0yb5y)B{V^gfk;aqI-b9>_YCPMo`|dbq@NOK$jy>F41Y{Ha zyHtoY5IE%q=_v(AfG&bR5%Cygzz*N#DVCdLP!|t6kWukAz6QAjc6xxX5@--av6(2|2n4ox&vd1|?H> zLJbY0Zo4ASQBc@^gyTe1kP6Yj4RWJ~#S;NFT!hXt1P4gAQt8AF;l!#bsBVh%-X$qo)}g!~cme@RO5Ug(K<^jJJ-jcH5gUh3 zW5g#L{)!_VUTE^tyWH*_0+xL#Ac08$4H%jos4&~**i$=jlnq>(2pCWi+>Df*bEKEe zC~k6$CO%1PJfN;QZ~{v6JqkO&eAtYNR3~H{Nr2QCNOgP~%Rc0OSh$9P>Cq6Nd&bf- zqKpFgQ&DR42cdKnhMa|N1zX(W@{T4Q+KH4a(?t(+;LF)QCg}t;j2jOrgCs#i?;Csf zu<0NNHZbB>d^7} zicjZW9@q~$<-}yF5T@OdToe4|D>5Fd<_No{OBz3FQHyUf;XI@lNTJ!d$%wBL3f_Bg zwVg-)aR{acF`rDdwB?6sDCLs@g!c;TUQd3j$vpx(etNoqucd%1GN886W5GR{F(C0d zuP_@6kk0`Kj6&a4=QHJn-xECl+1&k6DO%Z7^rw|A)xU6GkU}#A-t1|nC>4Fb&9SsE z^LLuU@w>=UmcqamPU4Dr9`dmKMxVl;1eM?~O}NG~pke|?IR)K-1Eer~T$qx29KeAG zl87!RLZB*g$uoNK573$O#p8xdr1sk5JH5!*D5NN&SWBLb8|NCR=9TCgqf1P`U++6w zc|?a^noW(j5@OrVj<<3}rnr?AQOhowChHQtMsW!JK*-j#sJ7Y2UKev5583xJO8|z0 z9nIz$7TBjcKgA0F`Nm#ujrnI~8fsdeW+gfy?yR{+;f@mvmI##4;qj#1UT`d>E5&W9 zA|`D~Bp|(xfO=TT6FR^_InFlxi?uM3!wpDuHzoPe!tx+C?!XkAnSemNKc33MW=aB= z?JL&`+R(u3J;0O!bCTwIR?lmp1GnPls1#>IVu5GHFgtFJAsx6R?y`-JR7ZDt4z31E zs7ZWL@i!0I`W-3VfHcM`TT%Ukt$9SbWwU>?qZx#F+9hoRgv8VdR;+`2;z=7hg{o9V<}!b(*GN2w7HK=cu?N_(@03Xh+%W^wS_TU|pV4gaI7@#G%PE zLlt&25X@8c3BYc`o0vYhDxW01-o|y6&S%LZed!{< z%QKU|7%q*Hmp4B_jwQ%zWWK}jz-Vz7_OTzu{CSfC$q$^JDg$h}brX1LQ$6+(~%`$Bh6 z8kE=nRT9{#;OV`{^F%-g|Jsn@X?U0bYk$3I(_^UGuaumtMvvFR_G#E7eRCdlT}$3N zfg6~CieiAN2Cle9MLWWIz!9*};W({(>T`+WdmQ`(Lu=hvDF%OX_dQqZJ1#68y6x4R0&4iutC~e zAziU=|APP=2^B~IHQi25yODbPE@=~p1z7rrW|o~M@GkA752kv!8DX&pHMvET=zt+H z2EkN`a}!A7?+5KGfGa_Cee8X9wrXV(BvSpv5Q}^;mo{Vs-m_-~TUcC#0`$n>p`7?3 zr!Ugh3#}3ZS;fAy$!-5VdRi+LvOqeR6cgn}O~a!;OlrrIM-Qv7WK*EnAfit5dkF=k zWBD8IJ7|Tk+6O=0kciKorfa<#mz@8mWs1@M#v^&BLyLo~{l~}TE&J)!QIqvs=P`dI zrb;Faew=se9!?pU6UBBymCl;ymr$`KbU#biBysetxt!GQ$Om)R zOh=>H=b}|4TywNLByRz5GZJdv5IZ>{fnO+-xVfShmU<2V{uh$30OY51%BK#)HpMR| ztMX?$?$Mye6mZre_t4_Gn-UvLc@|Hn7vdfcdqOxjXkKgfTFzYSz(_6a%@4jCN>Mhh zqFk&>LO&j`m=cXQC@e{rul66G{OlxI)FW--W3v4iGf*Ry?`+aLRKh4x7#BGO;6D}Z zXtQcNCwCM*D}BE1*wtEE7txIj##MUiG@Y>uBdwOz(k^K|2g9gocEg~KEdAQ%JmS|< z3IJBsW_k{!eUVexbt4~|pk&>%MgJ0X=2FAQDZNXf#%PZFtE8mC zca{=dTUZ2>1mogvX^)-9DXedzG+m-yBG51UNUQ|nEunEahtE0K^gUamvMAlUFcTkM znudQi9tju2)V;?~q|U$$boLYSvr)V*p-xUx&Wa`T7waqLyR^woP=Yp!K5 zL>FW7y$Bcm>aDEC>dwm`Z8g4%OAdgG5#ENMU91cMch${AU@Rf@#U>p1e93H1rzwt} zer*5tVJr!Odv(Je&a!erwwXm&jUd~H(jfNP*uhU(WliOR7Sn)-U`F;}mHqHb zXwX4>PP4%A(1u#`7hz)p`*y=CmGMB0vi+f=+nad{0A6l=4!Ey{%i;~J(z+Y&LEE`W zM}U=E=UvNmI#3v^umhuDUIKA*Z|7VM!j2nuyb?TF`C{)bsD*V9=Rz0&PXO}Qcfnb& zdB4Bk2@gB8tsbiGw2ghm4E8HTSk~717GhU>TQ@CP>JewJ4kmWT1rv7T2i*awBLXO4 zK7GEK++$MADYEeS%ElEg7ue0UjGup5P8E!yzte@=3x9&=ZboBcfiEJFLM8BQ>BY4T zm)l)@x7qkNDvo4>f@7j{sZhrxE1DKjJwG$?HwUp3*>;pzVw-0xms`FE_X&jOpn2Y; z>?aQ*iq(E=Gh!t|p<8l+cgfB-K^`XO2dMU~e>^^1*c)DKl9$)KC9LBePDAOP0)rXA zO<9BFy~yf;_ZpUY-NRtqa&8)B)@c&FBDLks_yYldkI?e4+}~0OqyTIHj!63J)e%h5 zio=In#;iV@o|_+3F6JT-aeasFnvH#~uD=kpsYA1^puC!ioqKRXUS+Gvba$W+`ZU%g zD)vX0yOIxJLVmGUA-)@gb!4nulgHsHk)OK+O~`Ci>lLsOGc`{T{+eC-SVT_MNl`M9<4H45xqQT}gNZ>kw$4EF2DSbo6ZRH)` zu@%Rt-k6{Q@e(z0rw5GqSkIOLL0?)dXHpuzVjuxzexI<(#0B0;(`E+Y0|w}{cp=^; z02RYZbNnd7cjK@OK-^t|#-_oLkWS81LMI%W3FQa8fy3)iZYG8bu!Z#m=4ItmDK3&u zUZ0*wa+nJaTr+=wmXgs$O}SE{IDgL;0dzvIaPHi#D9M{+>5!;D5pGm^K`DwRNHS-o zWt<*6{gKUEs+&df*VO6wc!%+HN46TcwUMaT8D-?Luy%n-Ou~>i$i>=D04o7@Ymh17 zM}N0co=_u>hGoh4$O9+GisP_e?7%Bgl4?DFJ!vkorg2Qn$Fr%Fl}Kywv;WN^nt+_G zXbmPrve#GiuJ%9Z&1NM&3!rj8dGXHh(>Inioa{{C)k}^3$Wu@J^{Z)G zV)_(>hzK0RE38hL*JBH<@m8^C@2^5cTS$q<3tKc?Eao(<5J$s<1Wq%bTNO@y?D@pK z;kY-Ij>GGJw9vqAHf7&ZY?81tv-p9IX)A6)uE9X6{d6mqknZeJ3rnTOupV@ubZ53BJ$XRi}^@8Emn?CGH8 zxOE_8BuC&y>%rGUv+bo2c>r}Rn3$H#aUp;Ar3B#w&(BZM!ZWTig@Ta~`zIav8lA=f+8cU9y&^H!CqnOikY$Q9!LbgEmB~bu5NMy z9<6Pwr?SD|2hy#r9sDxEV$LMTMD>&Z2kHObNa6?C5%r`d?$NEG51zOsTijvD2( zu8C$pVtd|%#>E3SEtNcmHZh~ga2WW$JsK1{pymhioTBpz4N5&*`~kbt;?yOkJx#Kn z{>V|Y2bW(a#w&zH9-o26xA7KaRF+2MtrDRvBBIeSciNq|SzgC}?ABrE@$v=C(q$RNS>OEp~Qx z-_Ya0oSd=4aJNPZ;{kkcsZ+$EBwcp1#?|GgEK&ewpG$##z%t%gMu~GBU}#z>o60@g zO^{nacj9CZMNBmfeo79`W!Mr6U1m+b$-K2F76VV?$f6*x`$iEam)b=yC*J+ASbI;< z@%e-V1=1h^(d;KK&2Z*WT0SC#gEWxm3?$Oj8DPFPGP)y+(ySR&OL!iGQg5^Y+G2_K z2Knt(*?FrIi8Mm+pCXI~OlP=@EqU6<(WV+GoQ zi+gyY$X#jDo@%QOCFlWsi42Civ2mZL-7E!!(Q0%Zz@73+?h}!uzvKw89~VkC=0B-R ztJ1kUN|3lf2Ck?dK0Auc8Ek3nsZbesKAGCEM7vwH=+pZ4ZzDQGN2l@3FC5^>ACq7i zbx!4g5y^3!+e~>=QAwMgr!3+U{gryevR5DBu!g>_|wrP=M%H%H79!5{OA*>wR9zTE`Q}{i;-vh4~e=p6hjyBK4N%= zBIf-$&+K<(wA+89+OFLsmoxQ5-~Xa!GO)xpVHiTxth;;LI8b^;0e#~6sUsX#G}s$a z^ounO!8sHO#*gPJ4q9Fq&^{-bld=nU8pk_*%Qtfcl)%~^L{{_wulRuaDO0+<-uFh4@D+n?Rmm`WKg8+V zYnPwC7(ePOc(wrd*?RkhLx|VK+QqOF_LdgYM}mJeR)-7Q+8sD5F8Vzk4Bz^Bu%CKO zlC31?6K^K=H+<$?D!MZA%H4x`=1#1SNka zTEh5;xWlGhi@AGUJNaYM5~cjw6ywmBo$yeM-~4*`POi4d*=7| z>idG;A5uOtZPIxwdYM1d`?ZuH3X8P46Eh!61oqxSLe$V93X7c*9IFJ+U^(Q&!Xa3A z4h}d0+_R(X zb`+MxUyzjmn;nJsa8n2D0600g9Ek3u#A=m9d9-lM_aPaRkzRX|qHdr$IZ{41>aG9> zK{i@xCH}suqyp(Ka5z(25lsxk9$&*w@&*3_}rF zOqJkW@vJBu+@uQ{bxnAQ3AF>@T{&?n1m5!%EQcGc?3OTHxiD=vqCAQFj53S2>5y{E@LN!j7jZMO5Jx7 zQNEP=h@3jWkQQ$CUeA^FQATfqNpEH0UzK9WN^sr^Aax~lKQOVokCbT~`g{*o#(@|l*?8RqEBPT$Py`x$B!RTH%=azhs0BGcR4u6AUMZF?cx8?b)P{^Mt`61uQXC<0qHdq>0lHK-B6?n zNK*j;14vVl-dpIQhu$^x-W2I2^eR$BKmmiI($rwDar57M_kMO~=XseINoF#cYtH$d z@A-VIX9}J7)pdX7U*|7sMXLHDi^KNw^&8}0{9wy6M-3UKdn__Y zbi`0mRu&;?)8?M?Yz7b(KSU%A)Io_aN3gmTA>myL-e^3j}X1rwg zE2+ENR~L$^3wmDb^$RS?Qy0@%8?RQEgaSng)Q20_N2k{L{Hjlzt@oif)(4^*5*zDM z?Hck^8)C!jGVJQg)Ed%e8wzI|0)90Vl+?G()&=y{Wra7kmNXC=8@dJR>y4Z4q(UnC zYWr_DQVtsWZr4}$F+QXzvZNVJk?yYmiIWIM+Ep7f2-so-93Lr$jC4 zBa9b;vOQ)oJYaMTS`W)QkV}G-xHx@*6ut-yzJrOR$Cas`tc|HCz9xW*wsDK zycr4Q*x{+RG5d9L( zMq+05N$V|c5-1B|`y5hZ>c?f&!FAx?TXUzcB(1OE1;4pFTXHh50Kg}MNw;wCdnDM^ znAYEWhc~jKfABJrrUJ@5>>s;4ur_jc;_|>PPNC7XfyajfgCl)U7}QK*o~OjeK~(Vtu%%&ElM!yOk>w@e+6HhOF(Q04 zA{r^cfh%+?hTKMtN~e#?{^1ulDKh2<2{n(NRv1%GXA`%lpf??`CS&UJW11RB1$#>1 z&rvOt@k?Igi@SN+8si4@*=oYRHrN zGvVqr`IC8EYi7cIe$qQ~2nt+iX@D>)se`)c4v{B#Bj(J69FRsU!@*JK8}hYnYm$#0%1)d=xa7)Q>}R4B~O@=T`8PgSMQ zHn3Qpx2Ie*nrvj5>nJnij~vV12dow5dYk8%;vhF6%NOz?@TFQwxH0HQ^AhE*!=X=jE&`t#;APO`?mVy5u zp8q9y@=FQ}UHFgSsd7O?SwZl>5l?0QQ~Yw`0`g~NPyR2*Q{(?|JoPlrS*S@1TL=sL z3kg_b)Q!c}&BQSdn5)J@w$?%>CL*4;LjRB8sp4WMb?uJC-5{}>&cgpKc&ce>%c)sh z(DD?qzb<6z_#eU3&PBt@RsHg9(da0>OS;!BE?b(In^;&`T3VW!{lAo_o9j)tD=vYz zUETcs100+jD}*H~gw<=5PBSRaX8kk&lk&7n4RvdF@vKz2B2*~MTO}Zrfngw?S4w?~ z3Wc+YB5Appv=p)bay;u&{x8QVH!sES7!|A*t*_5bI14h=Om zKBy|Ir1bqS$FpmYQvQI_;Fk!e6M(q*ghWQLFeNoDoe?a|bj!)j%Y%^qH{w~IUztm; zsV$d}l1gZ3s$(2Bx3+cuU%|qPs>;#Hsp+!uiJ8Z7iVqSL8XqAPmKHXizxc0UVX^C6 z-m7eE6QBm3Q?^GPH8b-DkzBdNi`GJL;sS!Z~Wm zu;)X!@!r?^43-wNfk5CPyXDgH0?i#b!vq8%A!TxOHZBgsdddaGDHc#$R}!bc+li#q zJTVowIe-#QNG(;FKbgVkK9Va=I0Vp}0*?;mTMNYtI_%CRtzF{V>D8gsWtL~siH@5) zuc#6vXe5=oZlgmoE{Mb6M=G6t2@liH^6{j<8Gki$h2zw7S`iHoq)S{rKi-2a0MfPj zwoQKVu|BZwC`i+;I>-8q)p*YFEIIb@MPo|FCGX%aa_8@MS)3(?ZBtkI1H-aaG|W)H zC_q#FsebPoyNF2W9va{^^zT+4>0k5t_mc->3*{jS@VlL}F1d7@`^=PI5(Z-+tUq6o4AYs8(-)2kJx&iI zrc=tj{w}>8fq!i%!i)bJ`9Vxqe%mu`?UJsopT+K2LyEojm2rTpW=!wGUv)WagUmJo z@4x0l+=JN%Nf~;SiF*`{PlCh*K*FL@;6(xlyG)L)=bbY;8}3`DpIPN-XFM}34Sb8F zXv^vM>QPSNJvT~gm~PG{Py#mr1>}7H_h*#3hcJz>}5b0*|x0CaIWZLLRw>UNwa}cH~r@?OnZ)oU3J1sg^hPAVbLt4vXmYPSQCdpq zx``d+^faYpCjGhmuG*-UVe|C%{2YGp+cw_+PO~<^JFyHFpW4b-o+(#T|!D{wd9s!(DgI@b9d(k_J2P*?{xiK*X)?irPC8YVA(WE z(;7#F20a9OOR!b@I$nqWczg)RCIF}%vFWH_Z6*X;!1FG)nQwDx>dN`EMXh&Limji=-)oB6c3F1=}2&gz5OnFnoys?`RG3l9~CFNo`a+&$6f z+L(m?A)&J`l}N{y^5~^ph?$S3^1^rjzuz`r_nE(=(+8~5ery!_(0^_Ow$Z=s9X_D{ z*41An$gz%i&!YZzw*903d6}d7XY25$B49`XUwY%6*LM>Po2D?S(a^ATjI0O(g*2uS z?lW)6T3a^$I{Svpv5I<{@CkK~*e>YQfd^gLLvpwJq9Is8oQ#{ojXx6?ML$E2Y-Ctg zip7&PzD%IFR!jc%whL)nPjT!RjPv1eNqb})n#U4Y{YRDhx|p!^c)lLK=ulpcQKuBY zBQK%k$K^6U&c7zD@Z!>OKnuZHx;C^bpyrt8mo10lr%(gO&@?mGv#$lD*A4Vp9z=L+ z815ZiM?v|t!9{?xnCZ@#6$?2hw>nW0MDK0Y^*@#S(>SkEqjykG;8r#>bOLp>IHDH! zfTu0)O|YY9n$1MhHB<37Up;K~9qgXC`g6fqFNUNFEWA|@AAc?CnS%Vgp3TEjbW-`s z(&d}_)drT8mI9~T^X=`d#LCoNhb@01J?#CIi<&2->V6V~;>633b`$!BW*+zkpC)~= zPm*PRU}y^sIDx?Fd^SEYYG&f#z?@*;5#z(h!^gfTTeyLU^g2&o?k>eJ`p|NB%mHBN-e*G=e z<*SP8Q;!_mg?CSIt7p!m-I*m!+ZtFkS6P{JAXV~vIF zysipWy96N)inN|?FM53B#QS?lOF#eN%gb=#?sM_yd?h(fwL?|}-af6_s$j1;vtle@ zs5AfU8}E%31&_7Dww6DigRh!Cz6)7r%j{#M8W+cIFcN3{?PBnVSRVhcqrBRZ_%3il zox`J2=9<>Po-GM+R+fojzCg}_euWPzYdS)g6Ny@F5cRai4vz}ADEUA#W7(~7KNuMy{V4M7~ za@)mWX^_Z=GwK5f*o+1fmeAc#mfu-Fej@eDKRS-lH+d+IL>JzF;}wT=TF@c?K$mhF zrRnAnIFZiQv5Bk7{T=hCCv)1bKI6zb{JBGS2%Pg!7zeCV)0e~#RUkNBk!UQDmo~x* zMvn)4@m2iooD#S2B`LZXc^~yK*I@m~g2bVI^$W~@F`V`6`7I&~rHdc$%U6UUN+FP6 zwAuA>U``RjrY4m#5)w_$jEa4&Qy`EhrXP3{nLcD4Z+pSk^~>pWbp*MX0Wciq85Ow1 zukv^U<|mxA%TIfm(|Jk@-$i}RwTV)%V*^jmiohP0#?H!I1p5TXUoubyfwJ#b0g5MO zA(oA-xwoJ3-pmZ{@3S8&T(GXysx0gSP29cvW#xHU{h_oTzRnFweOheqaF{7Z3-~^| z`uW~?=aYi|1i1XOmoomov_T|mxOmtmVcW9UzztutN_{?--#8N4pRT4cxJ`OxaAzbg zKmN~~P)*f8#!3O((XY3=+EwO5%$7@D4ESqZ7geeLv2Gff|IX0eeKCdkON|e^k!*;< z#5q3)N*Qf^c#)u!dv`JEU}pa)KzP07I#X2jW`Na`1Y<}4(F>|BPwnBh!^2v^(6qr1 z96wvI#CyReCiI?|2rYe{*LRue{>&daDpX&6MP@EB%8D$Y4&wFgj+EHudUtpHUhF=Trg}+hgy&ksGycdw z($_X-t#0x2M&|v!F7+gXmG{i|L3ZznGEL&1`rh|R^0~Rh;efGZi4rTNYGrjLL1;n| z%d@tGX_Yn)pW2r!iEK&5zuAx}H$FJhGM+!jKMrk0m}+miO=oc`6m8Iu+%{m;CNw zlAU2lpbZ6#Ki|7TDw!CX6hhRy(L4BYa4ct@M@n=DlUE4y34{)$P|{8s%@=AQfd|y$d^3rfVV_bp&LxN#GDjc)uVW_3 zc8+TX2qXp`4mjwc0S3Pr5uZjTGXMB)7GNO#Cxqn*QA@i>1hYrHEt58OT-`bzU$r0-9Hqh z7*&122puv!6wL`ni-S~2IqM0paM7EjNF&K?m_-ta${iO7N>1EYuPtuF7g>A>m#_GjFQo71Q||^ zfM7*?{Z{Rdr`4C=P>?Ysp~|<08qNq2MKVqqCuEmB4o*J;OU8kIACoPH4d} zF3wBaA>3RpPpZ)88i?gHbowfso01l?PbxuYqyQz3vAHjCC2u843@VE3RSFu6;*(~I zhOja54CQbM8;1sRH=LW^z{VfS-Xo^z;&S^iT-~J9@H44<)Zrnb7((3G2%%zzU zEs*!6pP1vHckL3HGbjCD+oD#8$Xb3jjXhk`iCDmbyy+jk^(E{FqWr{8S)1pnzhTUu z-OJMmH~TSQ)Gx%fy%VAa+Gz7sCXUJgo4oQjf={a|o#|px-RSEbg#1P>a!P0w@>S(U zX+br)z&=8`DzQ*Sty=YY)&22GeSzTc9>*?9h2F1fc>nI)B9O|~+i@uI|HI=!NnL(GvM7X=q9 zw>rqOm8&j68?@~fX3=hn0NFrAeY&0MboI6HJ~mDPws#jA(tE0RT&m2b8!%kaX*AHy zVvK_ATfXl1Ub z$fVuJ>=)MoMX5Mo{<=VTvGeM4?$>pQ?`nb{N)R85Fh_MBn!UttvTTUk`bHK|5xAX>2vmn!f*xx#rsX<(Vmq{3*4Q5A^q4>VWDx z0-!-jok5=%c?z;N6o3aI#!qnJOGL!mTP_?5ia}4EZIbwr@&F>w_9nd9;059UrFJjX zAaO-SV&dNZ&OJMhM>_=)Xp9Q+GhlltN|bnX{Y9LbWqT`s>nP{_+czFeQlgdf+ufTw zJ5qT(e|Dym118(mDzjlAUow5Wmd;1CzvRCD55 ze>q=l>%#BB_t-%bX|`7p)ph8U>#s`T@wb||gnYTyBiOo2kKHSW$GEtur#54zRY-YPVGg2 zDg%x3<)y9{vqX-9vO7=Eo1-WDN8hw}CX%C2DNNy*v(N?<*j8NJ3w-wI*7MN;rk%lj ziE){9Bop%>ODv1q>(Nu`y~pyh5}wdgs){nUIk#TrV8aTpP#}yMI2*=R69ZDGKyDrZ z>NLRR2vEaJdYDXV5H5JzPr8>)-qM(Iw4d@DfOu_A_mfywg7DG&RZ5|(?^u<6)8Q+Z{R zcbXvye}J6)$)=;pG=;gFWmECDwOS*7nztK<6a3Q zfb%9Xc`7Rl(`v0Hya%haZ;l9qo_KF^P=SROfZKO-)O2&ndu!Ho3x?TR^xje; z14@+59nG!zsLg|n%`u0~9mUNzrdx0SZtcAXa|16Q|J~$9zg)-wsDHPgz6UsHTXgT2 zk2PO@Z`odr+FDZFWLW^%7B;svw_!t@AIe{D34;U{HYZHMdw*a2XnDykLPgLWUvX*e ze0aRIqX{VazLGF|spPvoJos`^ac4zwbBgt~fYK&3llsZ@)oGD!7R>hK`)!uHTklzS zUMo^}24AlaQWsg@{EgZTR;Kdaef6t++f?i2jwv;M523e-G%y*!vS4Z+kE;YB;Wpld zv?58oUC#b<_Say4Ee93g?C_28$h(3NLzy!;$A0R&=3@cbG0dZ;TK8y_-2C{cKP2&k zK%7~3mmH#V=4{6scx#L7klQ|{V?R>lAc-oUd-<)o>yuZFj3?Z}HaCTv@t{mB$yGOr`Dy?pb9TDm6 z`-B*(qA+IRX*jk<5XGO6JF zP|u6g2mwDkfa)eS;+#pcliC?7|M2P5BD`tho55?@2lDjmcTORkpPVfvBJqpxsS1E) zg(-``D`f%qyjdDT`R3GS7h(?gs~r*=Kq&c=O8DGEo-j$bA^Mm&WyHQ=j=yKN|2)ag zH1`$Zu{f0Wh&QfA_|8#2cU*gO^ z)GHyT?;}hMnb{>M!oy;Vu29!DL~-%21(?I?D&oaQu%Htds_=LF36q*AJ>Uwj=y5^1 zuN3y>$yZnYs^FnnsVTi5dGn|7>rdeJ1gHjyVd2n53*t|NxP!?()9W(VuNz7dDBtz{ zJ(lWwiPXBn*Ku4l|Eag=V0dS*Z0vY^Lh$uvIxhLHLs*$^@+#}mb=DDG)l*&`4V zceei9Zh1xlhmfH)p&BRTm2UIP9El^IDp2~nnbKe>LvqmuI#n8dC;*@wCG?wP2ef$h z?k;U}|Ej2(3@6INQf{RX+M<19C_#=5w9=gF_QhfX+&Zor0k*Gc%4)Fc!H1SblCUc}#Zt$ly`W#_ zg+w492F*&JZ&212&yk2c&}h$OEIva}ZUqQ+LQFKD6zjS5M^6y~;gQk{p`p9H1oTNG z_o*<}Z9j+LqgAJIv16kzIxgO>(}}^aBx#PxA>;3E+I-~7F2aP^AP6CHiBfsU<>EpY zfj3KgY$1RQwiv9Mbb2eGlm%78916(}woK^Ja z30=tTx68n#)5KVzqFY1EZGJb5b3gQmb}-uy{Q4j-)bo84u!I2ZGl-EbCGnl~=i_}T z<`++5s~)CP7U60coN&DLG@bXd#LgJ^Xgyqzd8HwBNa*O=f{p#kgex1?q3LgmhF=d%>Ez@4-(^tt zg1+9pSwx)jV9DANyx`FK029^e)HmMr(n-{%=&P8f`!W>&I7K~+BZG>p$v#-=^Z6>6@__B*Pm#f$BB%v_+A=BpKCth;E zH9g>&9E$?wJs8mVX12`@g-NvkV!WjV1$L{t0{Z0`Y&qhD*j|SqD^=3Gt#Pb(1E-jY z*yIZ=Vkb`Fz|6@wuy;F0t|*iMC?hW0MDNFSLhWBW^Uv8G%}}KHW+gRfIyi7`mN&}ridAD{r4+VgwCQyuQQ5H z3nuwk@xH-}%R=<9Q{rqs*7Dm( z4PcxJ?D6RK4Cl25wWVzx-45yBeBT-}d}x0#%Qdj8*cSFAZTm}O$l%c<1^5-6&2O_I zLtk3jqCTd*{L|Xix4POE^N*PdFo#m0T}m-iH>gng&=H^6_v)BK>O1|O3y;fvB^3S$ z-B;rsOQm9cgyx;tA-HjPJS}nOubom)qIil3eUKCH^;-O*?W{(De{O`(uJC6(TsPQ1zk}tL>>+OM z=7;0_x^!1L1O9oxcDrzef9g)Ha{kA87hGZ3;?0GC^4xhB zt;3>)=+=jsFOED!_9%-P`lHoikN0%Ghb~{y|D2U;^5&%Ub4GNov*CFDmc{E{xPjK0 zbj!^g@hRKY1gWnXkLKUm8iYTs%Y2akVj%u>q20GsU^Aw=Q3?TN?Wi+|n?3$Nfe4+LT*o^O(bX)hS#060xAOyDG!g%)ReLI8)#~ zS<5%Ort zL3KCFp|-=nRv7okn+^UlGKgwh#aiDV`e@b#PKCd?S^tGMsT>-YtiCA^{OC#!`f#N# z;zh5>*EXxIeHD+s6?yZpx|qQOtD6I>f-yluH-%~Rs+$qdp0ox|ON)FAz4>eRFFl+x zwe=+`d2svW$Kd6c(fb82BR;&04%zq~{UNto{ppRHVQtL+K4st6e4fSrqxMGh(VaG} zy^-kelewCo3cmk-EBo@>GiBj}yo(VlpNGEH-`D)U%RadAaVYx98vSd<74_Yv=&x^N zD?i@Pia4lqjOp)=a(NeIQfSo!k9t`bz4kqH^j%Q!_wa@bVYA-@--m>MaF6oh4QW}6 z?t;hM?G74G4!6A!&0QaCT^Pwd9U9k7Xr78F?T*X+9!;H!b1aM-bHo?%iBZ``S#a0i31a`%uc$sw-!%%{4L7f-mz zfrtbdw#0hL_;ssVKgGe$=DeOTN{1Aw*Pbq6h2r#9VqEl1JM4#o9 z{AuEZZ>oIoji#Q|v?8a5A1TY!)DN`OO2f3)t7#oS1iGgYIqPW|=BdS@7e_r(d#BS_ zYSZUDZVpYSKS5+H$z-e;W~_Q-tPwLd7_iuM#@1fOOGM_5OlAt7c@H1(MkRB#IlBcVgDh`mEp6S$~Q2toH~KNR|Xiv8Q{G;3*_z1Buxv3%XBY zx5e)$ z%KfzmH6uem_CPJE(97+lZxg`Ksy#0Wg!atag@I%VFxz$nj101&f_mFQ+`V~RWJ#HJ znE6iu7IJS!(9KY>Va~O^TSZ+WBx_E!h?i0Z-~cOtA*%vHK#?`IYGb47qM9?~^4&$08WdZ-vR_7zHG+ws z2CUkP^iaTM<7y!Qh>@)k=crj}Ko}Uq?ComoP}MIQ?34F1UiKm&i}x%&v&mI36H5LK z8pwD9bc1#uNQH@`i^Bv;cQ*3x6~n~Ib&MFT2nH;N&$gd|ied^ZYylB+UcP5`=5r89 zuAyK9;oJ+mfo=fIfw)=3w+3?ZLH+Mu)ZK#uSyYouUuAbC+#ATUpuzilp+Ua#-e_2m zFWi)zHD{ZLqLe{!)w~3dH3>8)SIvhhpSFX|8pC)g0Kuqb<7XK!xp`;5%!&jO!jxPr z0bMmO=O?wStHQ1lS}Sc^)A{cim$a0e2wJT<__5|AabVOS=!jf`$&RHJ<=A1|+1*a5bRzcu(*CnZ^l-aEn-P<(RS1;dpgQ@qpwkKWQ ztKdd|%c0BYw?6fP-qNNX^;-8H^}EFp?iH7N?1FDSf7?U8S7Af4 zFG|?@5iCtewHF|iuKWSih+OJO%T)ad52rPmT`n{0&pP_b z1^)zdWd`PDs}JSM6OCX9N^{K5!g&7Cm>adnCFN?V)v0*KCbR22OVKiN^xQlmtpTAn zJ31fM5_K7Ny*~fTkFCN^uoUN>0UqT(uAb{9YrOlBS=gzJh=X-@h% zIvw7o(O3O_b__d!xPMgLn$Bq08gsDgs%xIru&ezX66I_YRdSu+upTlV5^^m$IRH+W zR7hHY2fuh1J{1|0w-!?UE_mA@_{aCyi9exV;bG@h2wQ&wLuDd13L|e%%|F$MdE`E? zWfKpTd0gclf26RWyhneW<38_tA?B;l{BxH1M}=WiEQEtUkN>a`Tn%GkGEbKNJaJlk zOg9PpF5AEe{fjP7ln{zV+KWlyz|FAiY*i2@WB7hAf=Ld1f;42ZxWtoE3@6vU8X*A%(V2N(&v_%HVcoFWi z2lwk;>|juQo9_G^F9EnS z*sL(H2E}qe6q<8Y16sW1Ru9%RP@p*!2uke^bZ7}~>4ILX90+QkxVo_xw9$5)Z@ob_ zn;A}{z4YaWWnwRs*`%^B(6e+pYmG@Z|O(V}VC64(Xb*VKM9ceo@Rx7Y< zyB>_)Gl6NVRpU?_r;e(W=d0eEj@v(Xva_ppLA?YPw{=su4R5anx77aAyur!;eBmz} z3$28bXH`q;;Gz2Xk~??zk~8<_zrL2Uko!9c3F$z3 zw!?p~nj0^VtXo)6{e++7?UgeSPmvp=mz)v9dJ;B?fxE zzy|+&TEl!1985h2fqW>zaY~+fkxbZ6#l2r&Vk+-YZ=#qY^63m%7|zM9N@4@#u^;3K za4j^`syUnD$j7jD{umw8RYyZgD~&m3Z)6v^M8gF6Leclx4Dj!0UroX);D)64DT{y} z8a`2la6CrYqn#w3&gr!?apK{=i}F%<#?=?$HQf(12=fC15Jp9HkPwm=p-jUlU0-N0 zUbG3#>_CyzqH+3AAkAm(`Pui|?=giF`0U$Hgjv8Z+yq0Y+-j6#7WQvW!*5A0%9nB> zQV$^Y=+m>=$Di|fckVHXUoq6c9+oU#K?J}rTD-kNX7WLcYonPW@I(d1#TzVer2-}D z1Fa{c6!IWJZO8y~);okugZS^^!+Mm2kL`3Vdo9d9QS^tT*yk(9Co2g0(y&+AiWF6077(00g3@u5oF3 z<>~6Pwe|nb+Wr^f`EGCj;PB}EhmW+Q#I!<)ZeWmKkOAkj>842iATS1$ETAGOhe71( z>J(XlDp{Wf)n!1>RyvkHs4{dGjjiO=%tjkL9Zh1lXlMi_8Z>D2RyHhs*45!Sk+^Pe z&xDIDKd)hkp}v*^>tj5r1D~9ZUZ!RtGRX-%ZH=ocYr~JF3YU7{>qPu* zmld2a;;PF6b~lS744!~916+(s5qMm-R@4XI6czU?gkrG9-Git2g-x}nNJ)yk&GSt4 zSeQZjv!V}T*g&|%tAHt1LUQ)mlTono^%V<6vL%mcSJ(R&JpqT?kNdknzC1ir%tv0m zlnLLI+^eUfy#vk*saW>z#YUDq6k%%CZeyd2e7b$A(nkBx6*X;$3vc*$O-uh^O79G8_3?J~kqDQs#B~*=I7Z!$0+U+(`R%+>@WB_Di1(5*NZw zBW&HH3wSVE6(B<91c)P>Go=8~Q+*T4WI{L@bG~c;Z7H`> zM*^3>zD(i?W4$8jGQL;q94croUn4uQx17unKf}y-xOA@9CFQ^;i`9h%sUnhmX9F9B4n=zZW}I z;juT7fo-IHm1{PM#N$vlkr+hBQf-_hLS(wnEq~&+GB6vD!~3gTyLCDaA^t-SkzKf0 z#tJnF#Gc_1wom)8Y+}`;$7QCsq%UeJ13K3ma@N8^F#K$JLf?`93PB=%omNNpYmlKH zpZq2Z5Cnd)Ip0(-XQ6hf+{Sq|orBb!>Bii?VzO{&`I6l9*mgU9YGeslnS%+7_#C$r zhe4~n7X6oWSO6U_n{DL*01yubzypskCZ%6y>^kQYnoU^5JNN5P)G4&Y9i>k27#0@8 zcsjm6n&4?SsQ%4k+k9^pu)F2gjS)EeoK)VO#-lm<}~|N-$n#)P4`(1#QQ&Q2+`v4O^%L#Sw}d z#>DZ2!k$YKAijn)BpRJO9|!{ar*-iIv~C?Vjg8G3<7mmpilQ&numS)?1Z)LY&m+Xg zEPKskJVj=&6)2S(g);FG~>V8zAQt74nT}4n7_?vkP*RxF^IKjjKm;o)AFf^8*Yx zCk4;^Y?hP9m{iS9@(R)std_{;A#jD_pkYS@2;n=(14ITyFdH-NB#j(fa)8+9TW8}Q z!KA!KZo!IfE!w%uD-L|Jsi~Umi0r!m@h7LlVH!B0*=^|fk&{vcQHR0eDS5X{IY{0H zIQVRmg;8;7am08*=pM`kiUS)G$3&nUsPi;B&W_Z9hGLRK#797W zVY+N2^69J9J8X*D@$Be!CW&1@LRv;oIFgXvjvRFe$IB=Q;FCiptpwO#gE*hz(30~z ztcHA}5Htynp^+;-gZH#A9Ao*KtpKi7ca0bjSD^8@V!8RG&goCGSDRhYxv7x9&3vcM zQ##pwr$;W;jGWR=S8U)F2J6QW65#VzY`%P8cE`8a3p6|;98{+=69zxOM=lR09Q1!E z60|?*9~?cdvj>o2QdATv$W)t0|6Qz$_k(MZLT?J_>%59jpPB8>Gaq26$uoy<(o1Dp_X9NZQU8ZKNM z(1!oWo0MlK|4@2kFNDDOZaQ8xfi1tiJWPtZ&gg)n1G z5^ienK5-_}kg7+fS9@ah0@y z-{>up2cMtU;N$%ws!&g3b4Z{o*o~V66LuegP#%I$cwEz5DnK%Gq4gZ<9;t7K0S`A% z=-u*6IwN_qxQ)K-;doX@-quOXGj!~7wVYe}Q5__tDHyJte}{!Ml?J zOQ<@3z2!=egDYEtxv`hj*mItp6~|T;b4L6kuy{F(szs^HQ^ZbZ-#g1oA;T{*oAG9Q zriDu%!I}FC{e+sn3U3pH7RhStVdm$=q#_TjyN}rhpoH^H7SMs_5!D$c(`EbTC6Hy% z>T>4sb+aN$^3SH1usl_W}#kFGIP5Fb5|rwMg+jGlXO`|Z!-Rp z;wsDgx0tbkBw+M0^U2im@2=<X$1kP zWBQtuSyHpouT$<~OBLzPK?gdOb@8FbN+K=W>Na4|qauAV=h1dQkq@j{A`z=?6~Wp+ z?0LecyP{hv2<{r0j=*}@!oSuJ&&N{(88fT?*Qhv-o@Rg|Pw7yjXlTwJKw|Bej}D$I z&nxc$a)#TpLbx;R=}It|$KYP(HvnR8YgDgL{f^1$`DGj)EU66S`)@v+IWxkTaM5w1 zcchw51X3aPgHI;w{#Cf@Pa|W@Uy6L7`XRP<*iRbp{;|1~Fv_LC3G$tnvM0n>lL*iX zD%j{ON9uVhP(F;;h1r`Y=q75js}dkEG`E#SAj1L;F+XvM1knLbe4YyQ$<|A3hjU|a zSIo`0XZ4Q1y8{#6qcTm{&VAqUklN&u4<+3eGGPNTD2 zUR1Eb=~!++Ag~VQ`~8L_02~!^DVZk_KgWITjuG?_j>MbspySPYkRXDC(IhsU%K2U@ z&=M3^j|Qn=FRGY>j{V~+39(AFgbZn(o-^`;RsbvSb)y{El{mWODksMX7?2DAx(%cR zG4k_q$(@`4gskx3f#lQ~`OE(5M*cu2mrdvo^^%%f9MXtPA`DuoKF>*f_#iS4M>Mib zp=n3e){9ZaP0-F-flExBaasY_-1oC38mKaBSgu--Ks}%zPyq)MIHD*Vr8M3UOgjI0 zUaS~GiNbLR4r$gGY+U3I*nwn#_(&jV!o&0ISJMM_VEW?FJdT8TYI;})zg;z>CmHE` zI%b8B_g5T{sSP@Z&aBhcO~SCUFTqJWkVG7>{v}qXTLRH&r63GIgk*)&04gzENtzX8 z>rj1~_jERbiz+mX6XT;ZouY{3gA2&~a<90(kYHByp2hsTAkh`A~h3=0~A|7X8> zs#vOl7Qt7Cf}jBy&gPx3{E5ZH72n(=zf`?_v5+`MqQL(RS#t>k(pgMm*fgD{w z`3ws<_p%~r1uh#xPcen9m8c;8vp%wUQoTjn6kA(gzw~|9ORB|r{9><@xdQb}rBzR-q-l68{IC6Cg+-qL}M(q&3s zBTyC+h#9gin+z+PE-s_b+H#NgmM#1&TjVca4lC>Y!OBVHESF`yCoZdxPusvlgou5Ox?7f!+h#@*7^-TFE)%#zJcvd%9ofZ|tNs0Vptk_`I?>Vg8Nl3F0 zR!`F1blN!X1PCR;u@ zwv+Xr5o>T&#wr$)x5A6UscfJFy{xzkrP$7^u_~5SOmI}O9#m~&RlkzYk91vFMZ+h* zRhT@lHk(BTQ_VlE*sqchv+)3$3u)2l9q43=AZc@Q@m}W&dAEm)K8+im1T&vQC;}`x zSbel^x?vtY^nUPZ01IJ(nxBU9Ke!67r|N{aSI3iqlN`uroy>P|0={TquIJJc9yh^P zOGNQ?U#qpaULTHP3P$qaF_v3IR6F?P^l zB;LC&I3E&@Lj@6fP~Wf!zVplcuAQ!*TqEp@C-P~16iu6~&Fl25dQqTdWut6a&$Rhh zz%u@PxSI;q`iejhAbANYy~^>A%UsdM8icdB%?(X7w;E;&X}(?Ke9roPxS1$Nyeh#g z1F$^a1?y5<#PhEROjs=8EcF*5GWkg0kp-u@1+DYiqfj$UB2>SUC6m$~iLv^a12?1- z+7JE9MH8V{zgn{kLQjX9@!xJoyx?Gecm*n-AQWL4!o$jc4l4T8g1Z12)NYaL``}>h zlG!Sp2iEc01AZKia&`?-t$_Gvn;j-RSl?^^nGz>*u475M#isPpKp2MkH19As$H=)- z19SU;&$#&?OjjOMEhor2uEBR*oh`N`2P|pHF<$HqW z;Gl<9($`9Jf*cw5%yttUV2OBH0ao=AAfU%H>9Lu zfJwj+U$t{B2!ucX=B>Ok`hU=N-%m~TZ@=hQ8VR9=-XS2;ODHN`K%|QSEL07kGy&-y z488Z>Ly;;NM5Jq^cSE-T22hF>RHUeJ=f0osGy9a;XU~~4=O0)&;tF z=M`3U>BWV#7OwQb6svJb#G--wJhmGqaA7OR+g`_FOI+bBk}eYC{?YW=&o_Cs(H`Ej zUhiM#m4XfUAGF z>$Ccg{sB;}5A9s(KFj`0QrEU#|9mykQT7>rqfnq}7clH3)5Zziw@HivD zsskRtL-r(i#8`RX2V8USGQVmxsYZra9L7trGD#fa2hJj{bS3N<_XeWyF>Hh@4bj?Y zwhc{%j^866IY4);W9K5Kk~QzJ@NjAZ3A1$u4?MXYg$# z#1TA);60z!n!(B=H^%6nmBp0Ai+OIB$=aK5#RJ>Bocughh`tV{!rdmGQ_RYa>DR@n z^vwCp`$YFXBFoXMGF|<{wbPx&7CQfpZRyq@dGt7Y(gshl+0(J3Cl5B3M0SyRteB`Q z-be!6=Qj%-$D*G-tL3GfIV?}&da5t0{8L2TsKd{Qk_C%N1e?j1hAwcQ`HnU?R7mG8Wy$A$tJ99x-QUqDp?WGk2xJ;loEqK4a+LA zs0J%YDGT9G(*Y?fWU)(rfZVr@C!%1>7|JC3hI-8Ue6WOgA@oCRo;I@x-_sSrig%29 zvh7ZCij6rn9qM@LESWL zedp~h3h^;ERKEWEr?=|0>+?A0Wg2{u?p${Yyg}B~R0j7!RUTb1eU09(%M*2eYWs1X z&J=4W3O{4+W0pB{#xsNSJK%qJZ5QTuJ@-(}@BS?_lIF|r*M|MnjdM)J*tY;&Xm73z z-=0R+xaNeOv*8ns@!Z>XXj+(g`ByS{y5a&tWi&)ik**fXn+an6u3ekI7PT#BX(U(8Pt9K zeIvDNG(C^;in<8If2&+y8_FqWf)%SYZ{50f*G(lepz1W5GTqrmgW2{(`O-u^6pcpUlSxb)_6Mdoqb z`4i8($3c~cQD1**VUA-J4%N^niRVwkSq|GOkHVk*%)57(b@MPl;e<-Od{Tb%(C6*1 zvdh2PzaH~-9Od2pU2^$wK=^lu!Y|U_N6_~0Br@#uGe4PybeRl z*a31y@wY91{Vfeo$>GpzJ2nj#zGi=Vg50c$=by{B{K}KFEOmZfabUXGI^BJ- zC8mXRh@o`5WNrzXxrkmzI%13I#>N#*%M{!j&=uUss{(2j#HGew!wwIzoR)#mP7cZuhj2u+Bj zr^q)out|z;jIasBe=|H~zT=x{l;&Lmt*(eddNfpLn0PeSRY+S@0zBveP~nuCqy$VB zp;JcZM#6&lc<|#b2y-l6AI3;%_E0NlKX(k++&_jHSs&Hp3a;_%;ei_QOcx<#{A z;UBuC+2BmGB{ucWKXgko&Z9=d^nXjYH2lA#TT(l!Qak_GbjyS0{}bKP`7hnl6qNLT zr&|*LrCYKJ|3kNw=U3%c*50oJ{-s+a>S^9e^Z$iz0jmF{TMCD&#;22Ho8shx+lxS{ zvI{f+p<6aKVz?u5K2B6|nA!YxK)C0~CDud|p+F z*Rf*mrW~Q#@4u*7cgwPw$TQ=C}}qyj;! zwcn<@*Xxh0U}!;Wok(dstQ@S<&hx514>dv#*@U|p*aPzwi0+e7+55{%Njo-5?&i<% znTlrxzFw`=KaXCM*eGcKJr@MnZ^2PtAn*#NjNW}=Hj(?b95=f~X*%F=YWYB=6wX7v zZj_iQiP1|cbx5pEN*U^0;Bg)^9O3yb2YGY-XPe};s7s4oX=#|JMg|$B9XJu2m`~KY zStB7qOd0FYzOD$s#Ip|s<1Z!T-%9_@Y3*VEK{BcEwIbV=%dM0~M5dDb`%{YFR!MwJ zybV%hfGLeD*3D_`&_(jxlWvaeyhQ^<4j`Fq#1yQU9X;Ny>j4Sg4uW!;{&OJHV#dgPL zbXiM3xw`o;*aD@G8C#bH()>g~Jn7=NQ6aHf-^99vR@1R!!~68(h!Uz-@qO|1NOxbS zxwELj(du!sMBlvx@YgKnn)xrTr?2~cV-k)PxB!XdRhz{lmDTP)8y5kVjlA*D3x0ldWgHOqN?l83i_lq6Ms3$^sfUlK^tSLGkMGO z_XX`9&WhTmY>Qs8x7y)rHYN?1qs4*uFyp?~_pNghY9HTbHOp+}xMes$G&H!AvJJQa zY?gc+7#Zkbc#P&}SaMe1AoE3q$RAUG=N5mwR8aov2O--r>`@mJ6{ts~TX&xxzx(J% zJ(*Kj0?yP&e>EQ5UB3JGPaW~$d5xpxM}Pkg@1!1{ux7qJZoP*vBY+t|B)TWg(Um>~ z$o674Bu7s{sw!>COcC6uOXRf(kEiQ9&~>%G7{er6C4ohd=Iw`F=1BZfJb1PVod@i^ zGG)lf^`6TsK8a7q=F6;)&ZE6!l76wLml-(oeA_$%(5vHu6@->>!;NPH6F{7^{%GCj$fgJ1;73dT;OOHER=A?IPB4F2A_i* z4k4gMuHbme>K0oOB0Br5W84Jv27BqBS7jzyVxw=zQKET|#c&nZr_JnhICec<#h=of zt0pU_{dnMdddZsoiPSfC1O=oKIj8H8gpd0+G^FcqL5>R(tvsoX!*n2KleWH8FpAXu zR<|%WRGO*EQY~Y47qQGz9{`1$)+OEYNhruzXVi5nzIgHZ3*~Dn)n^1{d6}@_i8TQUzYl~L%nitngd(+sZRY$=*)3o2Wr5o=@cV| z>>_{pK`JVG|5~7Y!;J%xu!uWIdePC09H$z$>E;`P`+VJ&3awGAH+9F37cVga55q4# zaO!5W{sVi|c4D=AP44l8AsT?IhXCiHA|Qd6mvl589=LHb*!%>sf)XS@pCB!5-oN}P zN+&(UkfF?GNPCt98}p1kik>FOpN%7tfhD$PTOE^&sGLhTuTEcG`N^tZL&aFzI+-T@ zqqwMcr9NNFT8*dQ5F2c{p_xB%d@?G|YFCy8He|)H6?v9$k3t6HqFvPa7$gqEw|%g+71F zqZppv1em;@yy}ZKC0ts{r=ejw4aKAzN9caAV|5@D)*t7Z*1F_46-^@ZzM7w zYb(rf8hqZ~;AVN^&sFCwk}#5RM{<&3EbLkx24w0T(4Dbr`Kiz*?^cl6Leym7od~Ij zc3yr2Q|Qriv}6h0t5OedZ;@YxTS^L>u-Y8y&5i=?-zgM{!I5UdvTNSRs1Xi zzNc+~x$0`%TJ5VeUzU#A861hirD9pbgpoKqwY&e=VXB_^Su!ZQj$-H z!o){%b-`60Bd>D`6XI5praxq?1mE_GXx~{}>Uqn_d?;=niRcJ&2E!kU+w}V4vt)jA zB79VVV($Kw`j>)%{jo9`^n1B)`f{WdL_hnaHR@fc=LvO zb@*QA-JUI`p)2?5@Sc~K14XuU`}NN_#o+0S)JTUyppc-~g^W*Q?(xIDPe1l9i}T*} z0i-yM1dW1(y9DJV11+g%?mfi^T8hQIqmlWwvCj$j*7EN1HbgUwiPBzIxw#{Fw3o{<5@|zkpzT19)79{ z-VA{}zHN8q5w}3zl}>cD`nSNp7?78%zSE(QyGz*Oxu8V1Q#Ol?ujv5V&~>#VFbrK}3}GDH398-{x>$s7C`#!b;b2Wj zlpIWgf%nj?bB^D95_T`RN#Dx)f;UCP0bi0LuZW1&vu3Is#Pp-msaR+*4jQ=!vGhX> z?$fEE=w2R)@xRJ$JqnZNNE>;1?=Lnj*(!z2hTflzwh@pdy{`Cx6;fv%$uZ7g9ekTE zH!}_+piKbAz@TqSK zKH{#Of$$-=JjX`YwWG)kirM45h(p#W=sK|R^8D7AD5g8#1rvKzm9H3@|CMMJvqw$o zZEzoV6!6A^px>eX(HQP*-M4PyUDuKFp`6mYOvSv~g*NOh-=ZSi>6*KE7r0Aeb{V*A zn9gF8V@b-fXlVB^-H4UvQW7*h0Libsd255(x^_Nc%km4nh|RsM!rf%ZrtI5n zlw2U4O2~CXQ3jK)TP zPCzofj}5#1JJ6>w&7{Kw@07EZx)4U)`iSw`xKJ~(E{2NH+wTsA91VEQL+KGV?3TNT z(v(~Ad}355(K1 z2a6WL!N+pW*BZr+t~!xOywAa|3nBt(fd#n9*&V!WG z250!UZ#VA(#N%-RWSH8|lki0(>dG+@*(KABi>2W#7XZTJy;9Q)(PdShX~fbuB9GjM zLye;EClelxSwH;QRJMa@npb~VMzD}PLE0ZNB<7X_1n;EpLMR+8qP=}pN_5NM@#}6u z4VlMR9Aor%9z8{#{kawOO^tcp^{&E2!U^j`AES2u;CdYo@c9#Dk}o)0kyw^}AqfOd zs5<4rz~ecYGiC9_)sFbLt&n3fzo+`)Q;hFPcIT^3YBb#se?1RIz7+O5fn9&seM2E^ zToa;#ue(&Ax0PD>0T{o~*g8>gm)v3VCaGI1k%5fy&r4{J^oh7w(sLcuqj1vwptq(I z-?sJcVUu0&m%SdM40D%8V6}{M{cK_?wtRZmCef+pNqFB5vDc`nccSdh(y@!cA{gL4_xoKWPysx8rNfT!)M;JMr^w>D9a+wL@#<2TAViSx-$Mub1L@19W(*5zW!~l}WEpVHt zjqri1?~!?VXW2iK4N$Y1WHQqcnB*RXBh8>?rHJh~TUmVNNJ=UWsW|g?63K^9Gj|&i9j51!uMU=T12+2=&i% zYAp)>ndNB7#;lTAyk^gQo@Gpjo{ofTtS(3}E%CH0@xGeBA-AabXU^4Y!GC)0j@II( ze#qUHrQ6fg1<6Zurv1z24h!O!W>J4;W6GDTY3@t>w;hw1r{ zmh4kZr_Ty5x%3aGl?$xy6`y>nOBH8SVi?B7HpGUX!>O@_(c%6vTyO<W+mGRFjzwj$#aw|wI2!sML<5oGdR$#!&@SoMU zOslMv6;N7AAN%^exc3hD1`p*igg7V#K?fdFmW^c+N(+YrHow>9o61C3Zy~0j? zx+cNAzO=f2{CV{t9a#9Y`u@+_vE0V#8vq-Iq8PO)MO{OD0l%7FJAH#fE#H*+vdZ-Z ztXi=mIYZh03>I!(*Jh@0ny;)ntX>jY`J}b}^Uo^djdyRfHvclMX;W8^1p$-R)lW)g z*p)P#FXOUF+wZBCVB|9&^3$Im;g8FKDALpKlW^kBQ*OM|)+d6t95I znJVp%1AxZV;#M?&TQAD7tKwt0UAwNy#{ut_OI00qrXRHUBwg4cYWB!xreP{G^3!wm zPYYC*{tAOGpU<}!0=V=Prf+-!|1o>qERwI4FUNcmg8I?p5QK=cROpX-SZAsIc%I;k&j zL!+e~LWo>T`4D;ZP8!ZZd+#^H_msh}i0QWu;(Opo3YQNEnt?s7h5`jw0rY;qbPzJAVHDaNjQur&1xY-fUG~{%*5?`sbHeRflMkMK&u)hq3a7{o&Pafe$tEAnvBX-`khiaoVSim#7Yf?zA^Nc z0AaH>UGX&i{!3DZQ3+9OdJjR^7>kB@oE-7$4}eO5xvuQ*E?M*Lv{K$=e9qi-@tWt# zG3$CXp;XuJ%Ws#O%UQ&jTXb5zzRYF7`RJml6k2$%UG9C?k8AHTV1V2SqhRWX(wKZX z*24GBFF!hW&0KjD0GanIYdAAW{h&D&a7EQ`V=BH?KlX7~FpFJp6q80!-+Z-Yvx}TY z=a<#K&3p@ojOte1@H2BWpdXrDyngC8?w&I};(WKL{nKH*7IM0F)jw=#^dg{V9XFz|F?)^>02B48VC}~0 zurnrre9+O~KZ6|w+19deL>-p1Tf=Kr-~=4M2$?4#I4=tqa={0@7PI~M$TIb!@O%X}jt;bbVdx zAF9QZ4SGrLxr&jj0~ParvFsf0>?ljb%cJRNe=sUJz*F`NSs>^~n*r!te-)&3``r)> zI6Ol!tUVR=FWAC57X;KExK;*}W*ZEHOUCPEQd{X4#ADdhvG`{7uo>|wCX>edztUq! zjFH5u3-UK^otCgt&ne!nh|b@Q6>LzXk;Hkj#8njNd>#e0%oxeAL( zY{G`AH>}NW4on9=Zo4jYKCF&rh5Zg%tEcQU$5NP)u_J?FIGPO{B_s&4*Q&iAPbK1 zwS3#Bl^+JGPf3aVi(U&!{IuE0(T()4Imhp#^HKQM+aYVSGcy(KW%u0WN9~1clukpi zJiQjcj6=HpqxSRN5`*z?Yu9?Ym4lqW8AM;b)VJF@6_Wj&-b6yf^(~Zuhw^kDgE57r z>DJo`f$wgds{C55D1WSk*L>U19_Z}c!7&jv1LmnHX zce;y^J^glq@(k8AXHw^R`|maS$*}GmfvuxCw5OCw#&LbR?#IE0=n-}5^1)PKGJVO% zD3apMHD5GGjSvb&k-mnNbbVCHY*wNsEAF(N-0QYw-e+TWawV5(u`MegWS3DyXX`o~ zUw2RCT-HF`#KoACigVTUFLcMMn0)u|3(13Lnj&j7sJA*4h?kt$@ zY!F2U?!+5s>dQBOSCs%)-Eq%MKwbe<@pWdp(jsECP2;&b(7E^YSMT%jmH#Ax^2nlI zT%-kEBg%bU7|HrhSeInrLNyPp(az!2T*tT1Edi_3w#MqZ^wfgDhY_EfZ~jHTBq4){ zadMw@7NnO`mjc_`jAj2~USAtADG(Bjr`U-nnGSjcwU^O4;m$L>CZ_~Fu9a(XznuDd zI%rp=dD`QdiFDFb-G9+7cT?Z2(CC)F&nc7ZZ0Fo&kK#9~fLDD&q!XQD4zRnmqd) z#%3Er1l1vFabMqEbz?uI=$dJs^ewshyEspP9BNq(Xm@{NIc@B?8 z#pEC5+>vz_HdPzLwkqX$t;EW1Q-;l+JSxmxxh3eVHg0v}QE|NNmZa73xRmzy!rm1Z z9u}Knl{)3z&k^rAnu{_;<=eAUH8%t~cwa<(`Ia2M=cG+X*K;|fy>he9NzjaS)W=*Y zLyBq3WUx5X#=tK*`qQQ$&UW6aZolExl#|4F9r&pcUuJ8;4Xg8Eqm|zK4=ko{iT&c4 zv8m|D^!@Zs>QvQo$&L1;^xy9Go4j+ExAt37)3+`8)#oR!wU_3n?b=lqy;^*-FW6*r z$tfj#<(+(I_psm>{~9~$>Viga&nu>{A(P>2`*i2}zoy>}ZvVCVW9zX0Px)P^6Mo9K zCx@MHyu4%JD=TEdF4B05Pvpa2Z&5cxx=#uDrhffJ5m*ix)nfh@>#F$8^ zJD}p3z^>x5+Ki+5clHX*E-Ox*zDQ`Xod3^z^JgdYuB`!VjQt^t#(EQRE|1)!QVT1aT@Lac>DJ@_Gb8OcEt}Q$^L`)J&hNM%!i~G zk-M3Rzg{p1|GYn_^_5zi+5PU1{88_9!7VexUoS2z{CpW6xfl60jMD!!tn-Eap6~Xb znb?f)HP=apotZuB$xnavn*Q0Yt3UpDS3dOqq~dqj) zbHQqc_Y6A2ay!E@=OX0EQTp5d`OAT4>w^&1fzQqbpGyqBk{I-rI}$Y(&DC(v&(Qxs zA{sv$9NihFRUcNIhn?pU>8 zJ?v;eLTB`BVQ{Kz991hZR&V*9;8B>BYeeN?usuAaV>?Q_A$YAb=B8v2TN32<{fk~> z?6L8HaFAmw$_T@?*U|2P6ydiCJENwa;`oE%EjLB&?K<%nAaYiB`M=2&1At9T-5>aG?Qg7uZCEVPZK)`IsP{Gv_e5^ z0?c^VN>>VbfB>KJDO3;TVp%?(f(p{LOh6;XFWaXY; zI$pfg0Ht-;o1{ za0OS&3sei06o~T`3L^pD6IxFk2z^r3Yf~VhjyUB}z=Z_lo2tCrQ>m{?@8^TVq!2@D zNb1?-%80WdLyhY7a~pfBzqc1*j9G0P<2`1LIs61$618 z*2ul?&>Gl2u8TKD7>q;hh%j*_AlSAt$-UyHdfqEFWPr2-_(Q`rV*;%X*$YD;ND1bZ zz{3deyC~SyER-$G;dXcF#S{>PT;p2|YA}KEU`rW&nnXS{S^0o`yGteh@ky!}ftr61 z7A%KsPZKW|hQz{nG0nsmPq~;}$ru#ij+#W4YdTcwAm0NqNsDaIor4e1m^n%iew(e4k=8h|qAg?8e5z)ho z!DaA?lYP*wQwh+*AdhT1m%MA86$$jgsqXec&e9`Kt2yA}#MF(aJ|E?r|T?zksiBI2D%cRGuDyUVDh?)Y$bk%F$JAZH~5_nL%T;c?D3 z3G}%mJz`7s=C*BLr7B0<3(au3^8pnHJ0SUDuo?EgiW+U#32~r$$qv_7^eT^+0Tf}} zHWXSk$6uG9Rh*A`#F<)jz*C0rxu2TSJGuC1`%MO|;&8g^Y2`7z?iHOE0iIiuG5=nH zx(~auC-?lMN}}npZ!&O&+zd8@xf?gtc~rIbl(sci#R5-aNYyk`sP04c+)2k1-Y0(a zz-@X(P#UN;C8sqE#%VYp3%`5n`dukcKS|F4zR>}RL?8Cffuo-TauMF08f6n2NKstb zm{e{|3Cs-BZ-dLTrIcyg5ZA(qBkmPc5q!U3RvTM$o_^!daw?3qw=IV7XeAY9S2N;~8B z*F*2y2aI2z_z92ncsc%}F!l;!LN96JRdD#jm2u4wfA#GU;-`sz#sC4HVBMnt5u>PU z_4v8YNu{Kik>w!wu?RKS@MqgG8TElRX_JJ$@%Yhkerx=r-{C{&VvV|DUZqX<7Y6nI zj-#cm;CmoJ8E`iJ{c2pU$Q~7>6$-?SLzxNS!y@AKh(bYJe}wye_AH{_$_qhUF4_l> z+Xc<@gJBdh-~(8=19Vx$F^$~$NhlpIuSWwRse$0s%HtNCGed*vXd1OUEghIyvj+&0 z+k`PAWAP*BKBxaQs(C02MBc)SC7|28 zO;<_4FZ2V)j(k$sLlJ2IBTO=%!YaU>NA_#scq$1zS_V)~m(7zjm4PVPoL( zHYV@fagJi~u&HOJ4Gx%`T(&jKlam4zT5$3I=iX$W%K;n4QPVa^56{yx_5>d@2JMD z?_y5dtE>a!A|MN95RGEtLnD>(X7Tsg+%EFdhL&n1JuOih#R9c|`tBdPg=%x@DXZU} zuNE0@uZwU8;0ae*{ml6}+f21$=mJpN9?Uz@@;hcToBVCGz#ESP(U3=(-c|*oh1>RR z1?=B5WxoUr2#^uHrP;bdi1tn;^M@)SzG4`=Je~%Rz&%M2qpGw1)M+jeiQSmQm!EZZfK1_AJ($~ug~lU zfCvu3(957cIg$jP5xCYW;LJJLCo`9;Tfcn#vT5)IxQJp41gNl!lr0*_;u2+gkIF^+ zzd?0@i3tz&#llbC(P?6!_9&c0py36Y#zLGg!6@0}avoUFQ!U{-I<%@`xB&@L>cbk9 z4Kc!8&c{PPRjJmH1+nCPZ8D%S4N(mMw`#M8E7Fsgq3#5@$RJG4f+vjpwTHr8M5Oy< z{^O#;1_Kv;m=8lpG^EuJQ!bCt&}QSzet)SA4t)WUp20EX2moY2be8Q6J6$;W3>6Hc zO+s=>fDsOwjiJXrhXks^McU}TyJ3)k#5r9hjW3F?m=CBMkbtOd=dTKvF#wi@#?ovW zyf{jKmc~#=w}gX!(AvF#fxB1ZPN;{&)I7TD=eZWIplgVmBJV_Z9WlZjN;e2}H^?_z zqPAUh;j@bL7kxe>o-u$>JhgurBLKd0jwjiWqnNCpcUh0Zfqy|3%1Hwj`b6j?gXPbx za7LF3WG)IGiiau_KV}e)iqEs(d-(O*O$0&Apqj{S(+W6z{fy004aLIyzMj6fwp-&b zYTpLwZPi5@@Wv9(I^1N6WI+V$0)R|JtXu>QVWE%E!G+64>HxAq+Hr_~#FjWhRdo$* z*S5Z)v8nk%OY1{o+oSf!jmVC!?w;Ph{-@7K&j$vFhHK@5#jBb0Lwx)L4OtpxgYygW z3NitC`7~8AgrO#zTLtz0;xeER?8)XBe4akCB51sJw_r&xM&5U6BcM;?oCh6;U>P*u zvSvFmPE`EH4|l6C=HdYI6LFo@+&S({-dvwC4$f9)oR3YJRNTvLE5tZYlo_|zO_!?r ze^?oBmuNPgFfw-YF}>Q6dW;2UUHCd9sKxL}?Y+|nw+7Km-B1AIdKpN7@7c`5Yo80$ z2TF=iayvNA*9Si?P+~a8Ui83@p1x|E4(QVe(Hro+W!Y$=?eqS`eyXc&b2RIeX@yz0 z5{7_bi1UkfE|HL?!e2=Au(~gZ_e1e5G6>YzbnooHe)RP%DV9Ol zysyi*xX5d3iP~-NGP_BxF|9Q3?+LW4s(>TVI;22{#h57J%TN1`zwg9L*!)Yk>}^g~ zUVirU&%bob+X}yLKL9#O3LeU3#BlFFbW0K8USyIhK@wtSZST)Tw=D?JC84-PPT`{C z;q@Foc$bbeN;I5qY~y*NK#ox=7$x9?he(bfCg@}a#!^7+M@Hqb`dses!c1hVYI8nG z(GZwRLXE<4Yy)8348Vw(4_0n~m_UrKpl!egNjCE+?nZE3anBxZh}Dx#=|YLyQzbmg zAg?%u!643NlF=w_4qw50jV_u?)QJ@=0&&AsOYw{K3_~9ih{H8R3|9qHCfmS>B^Ok2q3tlf!3q){w*4s4CGaOsr~1$V){;Ci2RJ5}*`|0uNdP z7^M`;2L#`{zh7)~$gahs~l z1oAVNIxqA;8jDU+T~h{|C_)%5Ehat9gue(Ua_C?rQ3$hCE}JxT3?h#W9F3?ln?gRL zf>-vl2J0Rug`4WH`|(F2el6r$NctM`d;RG77CtB9mjze6FxND70zv~L3g zL&EvS`1`URs{P2$CP@PDxYtLnem1U_KXtiwK?g+@xio6|V-_OW^7U@Ugb}H(MjxpN zwZ@Y~szcccupvlh!$oA05-4RXJhkB*5SO~+QCqFe=gw8fOn|Y+vp)h=+j)XiK{woBg0;m8?`&J1r>2_eSK1#S<=-R;;XG-wx zf!MEeH-Xt~1(Ag+<}n7ln>Z}IiP{IS0C9Y07ZhVjpB|z@j3xy?0Li2u&zS>##w9(0 z!Jr)&O9*z^j%fJ!?`l=_-EgydNmSR1#m|m_4(Yu>0gRPas%vLmUZan$W&x(0MBB@_ zrjjnogpg9LiKLYim~;{+K0U6;j!P53Fi_Gn0vKQo>dOiM2M!7_@Ycz8#GC zO;rYz*dtblvn1xbV<626^rTu}G~5Vb+7p6_J5waebom{KF9MI(L_5N_FuENdD6yU! zH7sE|F=|m{KpRSB7aHe_7l?T^B`e}sKBlR2CL28+UIanTP3iX(3@3n92rSziLrCue zQ|1^^sU;rCbJN*%7K~Q}aVdk{SKMN?iMqgFMmP1!#a6$8X!wpkUKJJ{2Osk*H}iUdL2$(HMx^Roc;|06Zfh&y3UNu;t!8p>e)wm2POAfmGb}$X4ZGm7pfMk zoT{AdXs3lHp2C4~bP{E^scn#4VDSH9DMXS6a!jNzgDA}sPo=pUjGQdvGC1tD%D8TE zRLfdd`8V?qN3)w({BJ?lRh=DFRh@mn{~>nPT$4?DgNgO&JTVq8i1A?at17pT`~ zV+EE7a809S`#4}wP#uN8tqTs*Z%-)N)k)Nxik3zc#m*D;ScX?7nbl$O&`-}@?uf^op-dY37KS1jd?4(&l`Re1_tY`56M6XWY4XbA`$V&_osal$Qu_Li|A{gpe9P)!&)L4p_Od~JM?pV6*G2h`y?>}3Qt4&H#`+ ztF;X4D_wmpROHT;?&#B(C}$$K;)N@5a1>+iL#&xzJpwB{(D7K&JvvF!d&WJ0#X8$5N&Pu|jVc|{OVth} z7k~Llj_U&lX@MoW_E4sM(X7$T?3XWg{J`Sx-4X?>j!|WqrAf^4MigP0%H8u(q)B8K z1;I@pD@1Do0Fq(__EaOgH}6hMxPx`Wigy?9g>3~-# zOkor-x(L7TW4aU!UA9C%drzlEieL&KdtHg#0x`Zjd2g$?!@PXbpf*!lQQ& z@ru^a-uppkL2Ai*qAJRJat)7=Iam_ zP)Z&iYm5NK@Y-u4P|tM^i+cK`wp#=r-TI>xjXb6YZmg!W+`iY~beNQ7FiRxHT1FM= z2&Bp^b9~0%uEl9ZuERSl;b8Px-#R!88v4^mrsFkG#*yP}X)$hCZ7>0k^Uu zrxkO#yZIju$DAw99g9bnS#ac1Ae21@MoeA{9x%5-=Df`5(-oV6s$%p0zRd6S zaRzc>_?`S(QnpKI!JaPf7&>!=V1I`M_r?_5l8TT!CuF5o7;?<;&*v%u3@R?H#}~vT z7l_ca>-}r5FhGhPU?kCFMOnPXImQLSQpkMcg1?HzCEdkkuZk;-*$a2`i;s(IZA$7w zOB#$zYIqsgNRZQN3>Sd29!^kJ3Q`%Bep3(XTdfc)3er%NXvIs!eUpfO#5h=7@-N-e z&9iR7FpuCCNT8b=Mmn`4jdzj72eNeWNO!!OvaZ6qQh9xrb%g;tZV9>ZsQiE}g0P3( z*)5;st)$T{kBB8tc)3~05Vt)MUy^ML`Yc`*u&b%4$MbQk5xR-3DlrcvZPwt1W_Eypp2)Rj7R>)U3>va zd9MukqB)s{{s(pM+0|6szHRO#kc7|$qzD*LdM{EH1Ja}kh>C(3Kzi>TLhlfI6+-X5 zHx1Hzmm*@MqexR}Do*bEzn=BXGc#Xc@+xn$_HVE3eV*5K9KgOCHQj9!5lIH-O?oYQ z>p^w60A71DN(qO%XRb#Qr3mxJlHJ*)M?s)A1uzd?1wa&~<5Gw?qJA1v?0u9j#Q@;j z?=vY`=zx?*>%kVI*PmU#Dt;6u)m^Az7=u!5rcxmxeXs&kvCT4jQ3g0G=!n@C)uSGP zREh{CUeiK%0A)U60Iiz{b-#CVV&ghnHjz|p<4UH0R`Srj_Y-)qOjq)_lS-%mzFBFR zeMezEOI6v$O)6ayQ3F_!@RNu8ESk0o9|M&|yiXLS1cT-AALkls#Me z*U&o15}G1iEhntLsUGDc<+@2ZEdZ_EpG|R@txt{BoAOn(M?Id)R`EfT9Cgz7Zt4p% zHO$g;2zY2cxDpj=d@Zt|3%kWYoA^R^aXN6TSTA}MhH@k4UJ|Ue`jkoUN)hOvM2T!BeNk!rjVD@q^20C8lkL+23X&qcOo#iYy;{9W1ttd&Ij8g zMcZLsI2^tDgT+;DL5Bg7l`??AHP6gW=wGD}Yg6p%>aNN{H89xLKTw?(LnBMB z1~p+pd@0*ltN2sR#n5{{Xk1J;=$&!4Qy(p}r7XjJiwglFla-Me0lboOF|!1Lrftkr z`II&wX6dkl9N3(`U5uqwLA})?9TVRSY|owXfZV&k$ZJ3!xU z-2lqEC=ySLf6}~SGJB`5fz#9M-4b_!dsrGsLdL;Db=&U>2t8)oq%NXwO`p2#R9QAz zT82aIj{ORIjQXTl?f(Tsrm|o}l5YwWaXsr*da{n#=Vwd_jGc z4-V!}<8tNU;ammF2igSpU35Z$J3Ow%*kpdS>)J0|kO%;%rqZ^r`R068Y`W9G#Wkc$ zfq0tXI$j9eLk>oJQdtP5nYZ-{%3a^n?E*Y0&yxkUwGc|7Fk(dUL~z*Mzbi#^L>Y!? z@$Ad)9=Q~6eicIUvH>B5hsqMb;E#eIBaQzYkzApLY_$SuT;h~91EfM=_ZFhxO~k?Z!YIuDL{#BfaZt{Zk61wM$rHn0lmEGAn$ z30~j{rHf+XnjRwxa{cQ4cPZ|7%~Rb&`wtigF}j4x)Mw^i<<77;u%8myMimGfTRqd@ zQhigfJBX<^H}EI6`Z)&yBh+sqG^FI*w|GULdm+ zQ5=1A!DS^DmqsY?orx_rM5xA7wv)|ude2^3YjRPd_tl#fzuWLQRQ|M%a%-5k`C>zc znFnZq>~s2SN$;|7ilV99A0DIpTu^%V5HF7zyl`_my>l1m#jV$3jJ4u&6#ytI-9h2moIPiyj~ORjxMtnnVIij!N&u(rC}>!pzJbEs@d! zE&7VX?%{0wB^`ZWPN+{^qOh4yFc;aO@q25;G7T}!R)$S0u4mhQiOkbNMrLI))r`nv zGGk=ve!aIo5)BNj>lSIdtAy->-F-1akJolOJ2C+*Gp~x^0Lx^U+h^!+ZAz^d zyp^$qJLRU>8{&MP7n9nuLu3SFpXWdDUrbF5uGaVOHIuqXZ9)megdQC~Au7Q1$zWXw%g&pm^ zAn<2AR#^!&tAG1}f7Wq}`)STK^X&B}{7^AnUPOW0Qw~79EcsjJ?9bNPH4^Y7e0QHzLoF{8c+ zKRinfy6~Sm4a>hs%s&gRgUHidBm`a91)YYyJ1-Ks2>5qe@$WSC^EvkLq9*aQx$Zou z?kqk3H2BfwmHVsTu}&9lH~$cyCPV5j+?`Il?w@xio<=_UWBM6V^ePwUENagluE=0Y z1(A8`ylHRY$X2TQMuL-Gl@A7W+`r-_nR8&hW>AFxT8Q7|gUWC;l1jId@)34E+(+ua z6W7DRFod+t;vEK$oz!CY#nz#7uc1uIhtF;P2i@|V?1+rzKj;<&{yk$w=jiClBI3qx z7EL2Nzu25AP5G{mIUj#_-Qc@xFX(6F-#t#;;M~7U!4|N}Gm0TSiT-X{8N6^@K^js+ zi5qBs^Op}yC5mHc488+G0SZdgN1y&ihm;7jf`r&l7B-$~XkOREg>f+#DK<85aL86LEr{4gDZq z!VD5Ndzx8NjJ8ijpN_o`h&Aba6b`54`>@c@u8+v8am%N4X)7@3p!Vi*Mg&>^2 zqgZ(lK_rI7M>l-|6dL6NWjdmfhKO;1F(rl#y1cO4Q3D}AEjU6z;6^J9>`R;(0B1|L znj!i?hRsxEdf?`9x7lU~uVIxN`q})JhG%d4HoGLpDaFj2{TJQBhqyhm$)nlGgi3xS z_0S^eajUmQn!07hmhyAgjyY+=IA*0($hd?V-@mvKWnd{Tdf>XAQZcDNu-Rt`Kn%q! zuOC#)TFUspj~)OWpy{ac0zE~`c2=fx(8+3&A!S|iNt~>TP;^U+Wa`z z(Sr1G*D>LD6mA2-!2d?ObV0%a2H-jn0T9PJNJz-Y$mr?m85kI@U%$@C$jHRR#LUdh z!oqUn#*JIIZr#3pTToC?SXfv@L_}0nR8CG#US9s*y?Y7@3it2dN1;%Pii#>KDypig z1_lO(hK9z*#xGyKeD&%T8jUtJHMO#`vbDAK@$vEX_4W5B#)6ozu&}(myn=#)!otF$ zqN3vB;_~wH`uh6b-ro1`-}m+P_4oG=4h|BDOJieWlarIv)6;Wva|;U#%gf6vD=Vw3 zs{{gJV`F1`dwXYRXLomZe}Dh`_wNS>2Zx7;mzS6S{{18VuK!+rDf@aqC% z5|WZq(z3E}rO=4T=vb+QM7Wv~U0N7jMqIWmsTwOPKP@UIJ^@<>u;!%|*2X86ssT+c z>9twXIo&(Ej6(n*xZG|%9*;p`85EEVjV4+payQJ9jQGK z?w$L@^#BZ@md`bVKo~yf_{k> zgo?dJ`D`4Jp;ClIkZM$;>dn-G?Tg(x(CXH`G`A#`imQ1<^|@%7mAU)UqH{QsG$J+Z z$VO=<9aO6#Sh)7}{tvVe0DOiJQ3J$tM!Zh9nVBVs2ab!CRfdg+`-Y?#D>E}MGqV&2 zGY7K(CySss9~ZZzAP=t`C-K;cii@d9-%uA}){qxrS7T>;%6dzkmCcov#Q-UQjz z|3eoN(|Ua4g}J^$i|r+Za7`eDTO0t?6y9ul~~Zv9YDaE6Ydb z?zR>dZmw=GO-%~eZWXY}mxziIp+Yq(l9f7o{{t1OHnl61*S(R=#umfISj57T$bpPy z_l~-ylk1$B!Il)o9vjb*5$W~+fC^Q*gtHY^vy?XQ*R+e)cHGP!Xo*Wm zs7;R{LWNrYPpD8yadA~^_uF@GTkC5|bBgetwY^RGHQo6CAqo-itEHtS;%)Qi&!7J{ zS_qqzoRXTB{=d*d`Tw`NGmgeRAdpyh1_cE+w=}o5b#-?Ax9)7K8W)5Lg5Rya?Sk!#4-rQLWE!`W)kwyfzh>?sl~b6^M~%Xb@k>W;QeG4$8GZOxYaibd(-73aaIf%iN z8{J2Z$Mj?bpX4y%4Zi?)t)i}}#2~?sL&*83Puss868h{qU$Dw~mOP%m38I^KgLAYKR! za-sil)qcx|;qIN!QBTM)aj8SPWENbKmW0~@p-<2+84&jdHj->@r1JggHD+!bztZl# z0W~lHt&%FfbWY0#n=uY#KcX`GU_t)JkUReR{KH%Mk#MP-KH&#ZrU_=QvdQ!$uTi8? z%*K{+Y0vVC@RHzE?{)i@g;q0>zenqZk7RZ6Mi{6uDVufLi~23MFkNYmq;Ouf0_Ql8 z%r%U`F0PMCezQKbVNiHXuxXNA;Cs`M>hJ27F}WO}mTAu}d#X8;DxvlX*I1#BC3a26 z_N_)cp|+!l-@=W@8oz5hzJIuJ*mH4G<e_we0fBl&UP z*3~7sP!BLg?$RmGstfPrI)BC%0DZANo&GAVdWGz)`7u!=l5G_F4b68^QJcb8j64seCh;#-jPwEWcJ(&Cc|D zJ~G8W_aGO1qVkOS=zYlxJ^X2#ZbJpZeMw*20{^)-2`OnXhsRX~T%{S^g*_YL(I)7f_ z%cvBNHx2_Y&$m(@^&Ilh%!0pZdoSc#nU_RfAYWuXgj)e`y?kKI?W_#YOx6}rqM1r= z1bq#Ds}xX2K#G+{paqzhUz~IeO(~q9hNOI2qPGQe;O6{Z^dK8Y8Us2Kn%T&nE#^ml ztLE%ysn6t>6sIDF$n#I#z50G#B!mm*u3cE~c7MCTMlQ&&Uq&$9-Q2=aaf|21l(whv ziyw&4SOXl;&^M)-Dpr4JIi8o_VuBR#3DL7)A$}5YFp3cG><^+Mz=y8QAIG~D7qK6z ztFdm z78gkNp?bD!s{86Dl5%ADNyxR7Ou^pUj5cb|pyFxRKeq))Wrqz5^^kzhFAcv^OIB3%IA!#m6)il^eq zGy@T#%+sswfGDg>54N2j z97!crUyvn5>O3QIp9c_y4Gis%4W~3DA#b&wLY-&b3STVsYDp=>z;iZA2AO5_rQ#>c z)sJUhz^k&ig`SbpJgLc^oa)#E+rH5<`Jq9!mRD5k7ary$01B2n;)vm0(Ogf+HYkY* zz5lns;ICj#W-Vv@i7wH?ik?7DmE5sn4yS zdnHI|8M<5RVP>#qLPQeT`o!qUOqX6E!@8I5kbo~GQm<;ny%Fng;32<%=1_Q?R@yfl zJYjsy`l0ZwZ;n^kl{S)-;Y-NPNzyoT)-k3b#5%HK*Va){YlEfkK~Io{6UX~b_>6G~ z5T512c^$vOz!*Y&p#IK7#ku+205>As+K{>&4B<^^@Av0pa5PL^-(i36_L!9ahZL~;mKT<;#~4`Hs!d%k;!U90Gvm>QSFqnpzJbB4j`7wG)2cT=9l?rj#P8c0 z<s*oR^A|4F<$ei3kMx|c6D7FRQORPn*`j6BYZkPNNvp0 zHn_GEIzMM3t$3n+6vAk>^ka>rfpXHhD;3{9wB=REK#9dX?)t*y<<%J-eAjrr;Gm;3pux37{O{M$1h4McH_p|5_gM1QWNWA1@IQXiGxqAy?@R{F zw!#oA9s9Gc)qFjR2WqSxlY>L^@ht9U<5zzVk!v!%G&Et^kgKD?rM6G^Cw>SPF%6VZ z$*uEHa}@=Jkh<&2ZArgE4D5t2k9^V`^>Ot~cf0zT($LM*nsE8SN@>-Tv5TJV)$wfE z(y#Wqm=7&Im$f@rXNkJq{SSZb52US}3cYY+PM`X-Eq(Jm#`*2ftovJ9b!Xo*3}t?{ z)xnpB0{1)CT9$u1THSdRbh&!J|Dxo+MO#e ztDsN-Gp+{xer8)e1Q)F*qIKYu^^i5s0I*DO7}CEngYtExfECL9G9MZt_|K%%=4GEta=F4zeLqcwD*HDvsciWdn`W1<8wQHc5| z!=td;0#Fnjz%CKLM@8{QCxN1Q2~inQQGE+k*9~3&a(l?q`UF^+zl@47H4M2!6WeGA z$#U}*6eX^!K+M!JuL&{c^%2`?At4w*6%9D)Mn<9_L^}vDZKaLTzKtupRgPt@1 z0t65k1zg=c0>P%^L+Zf-H0;oN@J%HA(|J5QntA=4ZSNfPZ8&}np1{cit9-W zeQ>Foxdb7$3y$g8jk$yIt%-^Nbp%3)un=|2BQ<*$Ok4yCaK^xtkDwk%kRn#wN*Csf zCk-J4x+{XeEx}je;1tEgXRgUuR5GJtIAc^WkClOiTHyAtL^CAR9GCKTH=JuXR=ghI zcL_1{!lE;=J8jt7@)X&N*!2S65a+lUXJ|ze6b6vE6G83M5Fa2JzyOkJjM(Am=z36; z4DhBs`i&B}a2IZFLp$o37`NzMp6U96*ZqxI>b<>ib=d%oi*RYtSaDql#nF`qg=l6I z912{d_>o0WUa;ws0km20rPra7yCjCukz~_pX;Ls*bq4+p_^M1;k|KC#iBIqXULZ@Y z!|2DDY0L|ANAdXhjHJY0#2~$MUhzVd$y|MxGvg|968Bi%tHW)ONw#R%U7S)D4-ha+ zx|Evabq3yb&t^)@&G#)M-U8vir}RJVz2oGBP?xGLYvPezLim zXF2zlGv*fabeP#I&%mlQFh?{A7ZUD_gC#w>MZJ_{G7PRtCc zQKZS}^k^9d27WU8j)D_{`1Tr?}DmuT{C+Fm$`_GQd?x=ie zBt-57B=mV^Qh_gRwwwtWZ2mmW3Xr!ah)K4~Ny)$!31T;;z#o|zko93n*f0YzFz<6R zLw@StQiX06j62bJytXL>J;>dW)br>ZaCE+eoco=xF{gX}M;)b3atsbu@$obuc^aHF zJU9&F^MQ|=8VTlbHX*@*IYnb)u;sBa-m=n#eT#0fQaM%LrFQ&fhkK>37|YGL)a1MVEf(7oZzMHYw-B`8C_kM}}G5<;sZLdEGQ(b)|-c$#spTcD>U-MXwS- z*AARU(6`sFLrd$P8~A%=7@f0iyr^46)ShP70W!=3EXi*p$$qxgPV@Mi+PWUuX6%*L zd?~1-hz&$8*3)PPB-3W)Aj`q>!S$VPf1o)f$uSR~R6!bQXvrJSy=iN0 z$!=CwYGqXB9yRaLWVp&!d;)yP>`Fa*fp(_YF8*dqrsmfIwWgYx1_jNaoPZzPEwdk@a`UnIpQ|*KJ#i?IKWFCP#~PZ-Dd&t7uyvZx)TVIOhUu zS+77pYn+H zy#_?!KqUW(T%EgE=ZI13MMP=qUfxDmMXh()bq?=*EangmcviLj7;`_7L7c>P>>d#{ zpxIqHGP^#7FPOSrecSi^B4o2tEO8Nw5mouVc#_Oc@6OI7JF@DkY6m{V(^!ui)nqIz z#=F?AluEDHa_wxqo$twe1Ft$#_p59p?C=|1-HCRV4t`{hd}*J&K)mqvmcNUT@N0Qg z7Szt|QRaH%rJsu@$6J2?z-z`18r}WwEB$(k4cT~KD6ZUfr@UE!ECKOei|0L#(L=6) zuE;Cnu^7a%9&gi)zehG8(EWDtwBK>uUoh7Mn^WyyQr1-Ei9II{O#uzxJY=TdJvXY4 z{9%u~(W&-vHYqsxJUvg}`7mry2$A;P~NJyOZ=i{!p1QYBK8pnaFc3xMV%_9tIL@4bHiUov@LVTldqi)BCtB|R-t_*C;#tJm2uPJaZxv{u^X<3Kz83-vl?2jWFN&GHltY%l|>?tcvmfqX7eu)3>|FC8v?Hn*Jk5Ujzhn6E(bhMq`hTq7@j+R>&n?b;IziVy z5rVr2!L5+6d!lgB>5%alZ7%}gWr)+ru{_xw7_A2u#+<#4C_Bcz+afIT1wMt@(MsS` z5!Ig-{th6E(Z@|TrvO9H+|GcYPB_mb&Kd}V7-x}HaKES ze>~qWEp;cDby#zP9m&*n63MZ`IZ_C`t<7_sY?MyfusW0y zrshkW-(CB$Nlq;|wHFc*e`!bYiD~y;#^*DuqtEO&Zs-26h&g2B_;zXX9hKj%l-~&Y z2N%M_ULGb7Ie%seVtf6Mf;gFgwmOQa{#qn;K3 z$cBXw{x450iI^|Z%SxI<*NcUh3WHO%^#{o9te`U+%U^qMFJ|$bjMdK9E%=lyKX#M=OS?Xq~ zjEEKI&Bg=gnKY`uLNS?gUyE*;T|ED{J3D<*pzCcLxn=ECLZY^X0g!NA&LOYi#f+t) z;oZd@#=SFX=7-NOGGwzxmiI2mST1GN|0}Af?DTyhaf*;vRlR!p^uKjy*VxBzzsdbI zuagV(`Nri|cURwi@JHi@;63e^_x|3s9PgfRSSj>U8U?TQj4Cmj)V`fu%d6z%Bq$Kk zLa#ajk)TIGxND7xpBt5;uCdu}?j{v$r%Oc_{uC`#)&UEEoqySIg>RF!;>157EY4QcrdSi$)t>mo(hoKB;=4XsVqaKrX$wY-qDs>Z<5SW0L#x#rPLH z>H1C>jN}HpFYd_HfQ14stjtr{Taj4)VxqI9YCAeMA;9iug^U05 z&%dFDE&I#Ob{|{M-s|*^z^gPyW60=uB6DK@bvPhePNs)n2?tS~N!h#HS>QWLZ|gYy zzS@<@?d?o!QS~g`N-E(>#%p(f$aiN^;jP-*trDu$)aBP3h70W=WU<_@%js2W0X_IUr*E2toaX51z94ZEQD2R zQ!Fw%G4ol`knM0ht7GaBl#M$#1Yq^r#}Kzhu5M%1ZdiY9;0B}-!{boR_)VVcS`HoB zdg?2dyag?MT;=@aa_8tI9%R$-a9K5{k;F1R^UW$L{Djf4Wkw32@TO+zhAEWp zfAA=F_iF2ys=Fux23h-FZm2qBwM`pz)Bh+L#6crqE8QohhDY3_$lf<4m+8`Qq!K4H zReGeKSrOjif*30+ab*&c*zlBnCiVt2W-Eunxv8?bIlGK@c__CI0Ec-PRW{#gyH^2Q z+sb&DES0@sFU&~|AS1s;%Fg*%uSCcv!`j27txz|5f@#Mxiyz>)l{-50Jfwpu8i=|O zruF?P>eS=j+|b8Z*Q%vP?E}Q2Xsue`QeR`83@SYb5)qrXSiZg{>3^Vda(l4(;q!gz?dNFa z!kz2n!fGK~qj{>S<*XD?%O^z}V-R;dkK&&pRe4@epet4-t)lNH2O7pqrwjz_)^lFa zfI=o^=u7zOq;)zqEMu&d9|>AQEonlTuXv$iGBh!xre@8#>gw~a4-zqd%vVB`R2G+% z(OdBO>s_V~Nf_`vYR_-om%2!S{Bq(+OxAEhnlcY_i6%al*E*F;SD#l;(xnem5!6oU zc&^l_u>Y0(@4OiJYN-AJSeQs?quLtryUnfGtE|Bn>^&;?6rPAMMq7;@;f)-lUa$1e zrtNb+R18aD-_RxRG_nexss()C?OPX}O9>4C~-Aw^1rW=ML>CDqN0U^OTj3*#2v3 zv~H*>y|rZ>zUG3^!zjygo0S4RaP=>iII#-hFojVN8Ve%n-wElQ;`OOR+gMjv)oKQDJk5? z@IOnL!E9W)Y(NCsE4{LRRd;bd@W#tWs4g$x=13pXry{GoGlh8eb+1uYXWa7j{gkPW zt421@moN&a%V5pfY3D6{CJA+c%6^9jEvtZ?q2BTgnW?>u1>0AP3909s^Ru>X0SPP0 zYKtDXG4T6c`H!$ZM3vrDm66#2KX_q8h);>_+lRg~nj|oq`BHCvPJ&B)n);R8cQn5XrK6wbat28PHdNv6qJPl+wXpuwkZtxOqP2)Np+JVs^|2iH8p~!?YfQLT)7QH>uY0&3F$Zn8DvC z$_WzENIC|4i#FVz3(3f)PWHwVkBzZB(GP@3)yjiBd840Xq!CX!{-{ z3Ku8$a|i)oZ5VL)pbK~~guo$g*wxqaeZF=MdN-ynPIi{RH{vGq-th9#@gj!xcHM}$ zO_H*^mZFK8ReWqXwIFHgFlqJ^#psaxGrHC)Bc4Sui{EXeJJ>q1ZmE&8up%s;U)dU^ zuQm965^EmcPCE#c))+UY=2vQG{hc=?o;x z#K7AcKZ{}m_Q!R3Bq?Q-A1t>%73E9HAPri-zZGpW?{_ z8N~84(?mkE${y+PlC-n0259~o5>TTdpMLm>RF7L)7pWa|OJ#een47pdM0q7c@Q;44 za6VtQ_5#b|u6D!j2k4N*-j*$A^U;Hdw$E#lEmJQ@cd3kLdt!7rZV%LckQYGi_QEK3 z8ESyK%U$xTdW|5~^|sh=e0#4KyF@e(Zha1zCUo5(DVGF7FbRPJ*TB7 zeV(oRH)HeNm)GIUrg3qksE?YZRMblkhCxdOenJPzKqOoqAcQ1fa-q^5x+Jnq(ttCS zHWng_gHYliR9Fc6Qt*xQV3s97mbk_Zgs>Wh@U;iCsfTdyh6wEj3(ADv-VKqI2@%f> zLkWP@c;-=2m>xh^PcKO}_(#&f;&mbnD^c1+K zW_{7lN%jH39tYQ$jcMe?-C(|uATNmYdb3wj0mL2opBS^J5aNp@@kNpN;9>HF*iK#n zc}(n}I;<@-wo4}NEj(_>Fir^{JKY{TCKKQIKF-ZKzUMqv_yMf{JboxDb|xx*qdjg! zJ>C}|*Et-!1y7I#5@(mGopX2#F-ou@~pD=jVy4&PfzD3F}d@5ZS~j??m3^xI^A# z!frelS<=pK>`(7xj_1iAWRe&=5@ki>4-FIfpQr3CVRx+K`ZD7d)v@^Y6s3BI?u;*g zx&~t(&7VlSY`A7gls(LvI;T91wKwe}N(FBQp?WCa>g&iBbAHJD;{$^r1tBEY@ z(kH9GBg;QJC&VZ7*d{ZJxXDtHM?3u{#s(18#SPnJKrxUAv|~!Li{YS|!EeK9suR;bMc%~@9q9leCs3`K{ zlPtEg4chYbtY0Wdm*H5BQ5J!tC7d>b` z-W0w;GzU};VE{3K=HD2A=u)Rb*H!42v&P=!^`qd(X%IPT_$jLzGI?qt7SaAuN}Exykt1-A5==Ci;(r>e5CFn=jlp~r z5u^#DJW+HNXs<%G`-`@1(lK*~QGBlVx@pj+7u+@~O6*12LJ6e)ITY^Vx4cn+=#{g` zc_D?+EYjPql)adO7TxCko77iVNhb%ftA=_D2G!koS&f!Ryz%k@p<{&5?q5#|9JNX4 zcl%U99qCFXlmx`kZP5a7qp=p&s5=%Y$3=shs9^Isq#qi#<|c9#~k89mJN5AtHDm zi&B8>P@VF(z908DxYdKN#Dnoe3yb4JDfDBJJnORHNfnir3&S2R%;{F%RjsQr_ z^7Mf}4*MADVMDdv!gW~*f zx$u`8NiKqxtp_N-mNK`4G1>!UOpo+%m_23QxgVU#U$UB_Yu10D3?Ye!DbRq_b0`q# zNGII;lOy40)f9)bklI;DgVM;5Zn^>rQfGFvVjST%H+mmCGENxrbAE4)hq~e3S78C) zX_AQN0`ADsDx6pIABp6B|KaJ;ySigy`=j0kN+UEdZ&5%34;!wgkgWFyx%C5Bs67Dd zsYaMM!|twwJ#b3k>Cu7ecb-g>ol4^=f6`?iTuqe{2Au>W^Qu+eXyNNZ{O7a+6y3c& zm9@XJR1TI7-_4l*)jDn7P&Fi){v(@W*9&~$B|VH5sXBibik~V$Dcr9{9Nz+6XA}AN zo?>$Y1gC*{ph%pYCr4>WRDdF?BVnQ@n#}>?j|R6_3*5aoneSKXbu#D!+=BgHtUGEBDsCL2%Tus-WjUu0jw?Sh)Dz;@Uv(Txbe zIeI9ph2YxXMUI9SOLF@#Y+U>s*S*CFM8lHrbc#)(niQp7fOd~(SN25SNP14 z>I$WZ!po&O-FuKIik|+OuSdcvS4VQ+7{??YOVn0VVD7;WIeQxZEO7S2lu^MxJ&4ha z?u2hrU1JEBX#rVE5`UD0l*B|Ois#Py+{CkP#dr#YE(wvkBg~0}9|=27AQW*h2OLB- zE>L(5!W%$wxDJ&^DX95FDa8lcClJRF`a>lNE9}I3P1u>4(uA7G@ZV;~B8bg3>6rCrodUOIsY_eQAO1gyUAQ#FBK2ffi`)_=YWmBUi(|5#J41>_Y5WQE~3*|y~$ z@A~w#P-5%e5MT=0h_JUYX2K|W3sgX^H~2Sf`N47szJft{ou76lmx>b8iO$cvR>D$# zO-Ro1BbEG1SXtA;C+%&sKni$*9JY!gXbk%Pr*P>;`UrBsZu;S2BX`Yk;fVA%m$!(& z*O(i>L9KDH5_ySnGI311SD{|JGFKRVREU3*)4%sh2$vVEK{cakh*&P%OsMjSy=onfaa%8~AU ze-BRsth#?({qPbjf`utNkSJjrDv82?3y2b$gbMx6N=ZRI0O4V`Fzzt-iW0O>w_1UM zr~o`;zae`Pzx;K7RTFkYQJ<@^5W{zn*AC#IZ$H$if7pxu>Vp+s8~<54E$wi0s!j9B zD`+KS?AJqu17nKr5c$(;LaN;KEFJ!bvJeT1dY{+}6Qh25^gFRiZmF1e=he^{BnjvW z2lYgEM^In<20;=Ip-K5g-mJM1G--7IbfW(jz*U@HdY-)9UgAn5FBkr8EcLs^>31vU zYtzl@Z8d5$mJzE_QZ}~x;eOJG;!_u>Ii3GTk`3b9#X)~W8s2(ff`?XZIM;@F@7TDbra5D2v{%mZ>$je&v$ zofsNVcmMYR{`~<%0f8fd<3ZzrlR>i+vkTJ;OUo-CSC{UX6Nt06n_F8~uPyeze%t?k zaCmfl^5f^P)3fu7O_67yZ6Ry6 z)(7AwEZ(-X<+@6gA+|46%BjNu*O;j0&fV}_bYBG9<3amn3G4Y< z+v+~Q!+c4a(KKYmvYQ~4!!+>kiMGi?)c$3oFZZ`Bb)Sk zw7ALc^JGug8FARwJbW+`zJ1LqoI&8a(X#zYo5xs2P!{H#h!%=$t$X+G-`^~46*zf1 zgA&s7A6GdcghFZ;r>@+MV#?GPyc=x3%RFZ`O^fu zhL$f5DCk~^q<#e7cIN8@?j(dig`dy-9{=4qmg*c8gP=W)nRA=q(nPT;+Oxwc)mW&TJLo=F0ThI0^AQ z2^?M@b5pZw8z!LMWV`;gtnFHIRa{Feu}O^P?bze&@=dSM9tg~^=Nto{SJXXZ`}nd+ zWX-qSmnr#jP2#?#xmD$-UF1Rg=GXcM9XrW>2UN1<0*;+>oAr?H?Mb79p6zu%k)HF$ z-?d#EwNg*EkJB1p%^wNA2sO>(!^s8@IrKuL{qs-S7 z$Nx4FY#ijYG8P&5>AK%I@IB(s!T9yVs^fP@lXi6zmsfX1hGdyI+$O+h{$g)Wwx`|u zHzMp0N51MPWj)YF_DGEG+EO%+T(piiP^tD;iCir}g7!tH$TDi0dTpD!e}1$j-d+c6ZtMZ0MGgU1HX4VE`fgtxpH|g@Oky1llp=G$p-ZP z>aQN{sXuK!B0aI5Uv}5ACNEqZZETCmL#m8;+IMQZ!aIJfMf1LWb}jCppV7(xxc9MH z0eiDxqTiA9x{fB#$Rm;N!w&)?-M6|Q9d@5i90vY57)f*ryx9IH{P$=O^6u^V{Qdm5 zKc~Ot-8&mndo=R*bn4yxUu*L0htoUn?mtltAl-lS51xrXJLd35_~!#RqEMS#Q?!4Y z&|K4H_YqRq;FVZ3{MN1lg{z3)=Nn&6m3ey+SC_)!`*yD=G?(zdO+^Cv07(~Hfy=avT4Mvvo+x(m5`c-0;xG^Xn17V|#l8_~#X zj7d>`edA@c28iK(G*=YY4ZefMTUT=xruTU4AY|OHbD;06! z8?%sWil6GXyzX(KY2xXI4ex)=qJ1%FGI({IvDt5aXUt|ou+}a6sQ9*YN%Rn!+cnGl zXQ_No`6I*i*_h}4Y<~5{1xVNEs7l{-rF@l|eM!kj)W06pUDue2S=rQ<;p8>)HYigK zATL;|FIQL7m`%?9S#04;S4jV48u>xz#!VGo4J(bg?3JITGFw#P;@LGsby3m$5si9B z(p({x20(YGQa@vK{*5uY(RV%u{|KhJf{=;|L$*1fade^9mjRFuuT%|KDX_~Ot#rTm znw^0E(AxQ{#yP&qct>NgbLCg9H&Nqx#{aD4@>iXMD`o2kx+ijP7;4%<`gkZhbj(IDqV#qsNc#$KE$KVn-@ zrCbqeH}D`PKNv(kHe87Y4Jj%4znFWku%^O?-*P9UQbUmrhTf6h)lj4(y^3_C354Du zgkB9D0qIR@Kza>G6{IMNSP&ExQE7^xU>yG6%sKOX^PG9kT+T&unSGO+{d?ED79vuw zGzn=h2({DQzsZbCddZ+d)Mw|TpfQ{sA#xgM8tDYC8;WXpuJ0z zAhm}|=EFGC+_llb*X75Hg!fTCdrAvaAu`euZ0I>t$3v{oD~S#duf8eS^XRZL!=_Z_qT^)Q(u#Yrm?p z5|1Ti3b8G0dbn>FJR9xhz;u%=5tl|GcbnYa9EB< zD+@}Gav469Z-vc7Z9qNMk$+?4qq?1TwNSX(^d$^)TNy%675#!&R}|o+@sbYsy|%>t zh`Sg_`oyh1&hB@>c#82=@nl6#h6II(NkOTBi|t2J5m4IL6rNcF1L)qAO(UGJ?%3l` z*LqVLu%BsrqbOh8#xO}O`2iMH?>=P*4c1^mz=cTJf-I~B`t=k9tekD^GIveseJr7J z-eHqg5UbU?_L2S)ezrIFC$F~8`&(}YWs58BDqa1{>;%qclU4m}*VpqZ~K( z<2}MccpN}fgm4gBr3RCzf5m9g8?c#FA5@gIN5zExVM@e7Rp=rw-HN8Pm;uHv(}k}Y zS8a}P(}0Dm?|R1EsiucwIwISv-Jp*2i~{7?7KOm*Ek-K-Su?V>hP+Ld{;_F_ME|Tc zmsf`ncv#t*)Vh4@O=AX$Qa>CMbNB{lMX@oXBRD$wXk!=J^^4+|%Xh(J*cBLk|5v3x zuEEN&gybfQ#VLn5{B*^1!`1h>TTd*2+j!kxQHhh!X>4Uc#rRfZ{y-7~%fEtU%M99+QOui5Q@1 z+V21cXr;Qetvb{6CR{y@HD3ZHXiAnok~Oc9^D$RC&y`kkRdRM!;9``snNb1dB?+4= zyL%?P2`eXmRK7)_pvrfJn~$9Q3ojeWnoPqeC-GP%Cr>%xqYSn<*)>5rSyM)kPhNRL z1$(6VM&6QN$l~=0JWVQ|`E$(34IJPUY(v2HD%hPiKz2NQ>Y;H*Ne+9KuKG)W6|)bx zG4^jSPLmmDv*FNbgR}YN_|C(zCMm>FJ7{3%F0)N$PE!1nBuF#~y2?!LeFE_%!Nbwc zrh}Dyh6@q&#R%|5oQe*D?;s5w4-_K=rcMj8 zk{~nTkS8;lIs}Lw2@-YyF?L*_e=22HKdWnQR+(}Rrn=~0?$BN0BooY zMhfS>U-iD8427dY^s&IH<*mbQQ0+FT{xnWC)SV9v`dJ5o62WyZTxp~nE?36#VgbrX zKd4{@m@>c45~vXbffX{-4glIeX+QK3HVq(#%2<7=>dUBtBrLGI=7!uUaQa;xnFR4F zgg9ShQ+`2aE#bjfd?X6S8XlIL#7`Q(SMk{ywv+%h0rVPO{Fyy;n-ahFWpkQPix@k@aijv}@dxMg5xZr3K6Px5!}>7*ms z9XQvax1DupcMqzWVmPxbu#p0~b=^6fT<4M-zz06(1rA{)P)M=&`7vOtL?{-bcHuM*|OAR!ICBvn>*hE!={Da;kq)f2;57)(7#nUR8Xn z)3%MdF|y2dVmfy9>s3E$bP}W|K<$ zMZsEwTqFc@n_S|0X{o5h1h|CpKyP|z-HBW;>8Rnc*(8g$U3a$%HEVeIOmHmR^~BB$ zRN5($L3~`@Avq_qp&}}=eY?S>T;r#$Z#78l!hVJ6P^#<13^s|Mb!s)6R2`)TcJjgG z(|CPUZ=7{WbkGYm3yFiftyDz>0BRSg>-876KR=|g=IGIuul0UGbh%~9scNIg5qRyW z+bOCCYhdnH%0!I3)@2|!fSEMMfZ1^OH9;s;)_7^t zi<`i`rQnfEFffWD$ce`YH*k>>mNbDQGX(>kkoIVR5;Z(zLix}D?&H)0I8g*Ike>OOE;y_6ye-II> zT?s=G;Le=GLQ-V7usAXpGj4u&(q94t%<5=n#xkYKa{aJ8jrfC#^fQSio2`0<*&wjAWs2{eil zx~OwT%G5eKA-$I(KcMgg|rO8$9qh*srXF&3eUoi9Pbp+nG}62!$dktgEQLTCW;0n+keuF#OHC=;&# zfx-a?r_FiFrS`;^NO4VU?uv#$@~7bz`~J-+OYrcLYoH*QguGZ{({3SX(2%T+$rz2pS$H z1;2iEvQmsqO$y1cHdLPhC}USAJ_~6+KfO$h;*8J!<%x(_0l3XrSfoY4eOSVKS)|;e~-;MS(Pz zW>~+yiRwF|erGY^pEfTM(QEAn~@|g?t!uKvSx5!C#ia!mtalz*iGBl=1Z`Vt3gr&uy0k6( z>yx-bchmSeq}o}n`~0Ykn7Y0r1Zul_V`ts64f%b?n7*sH z{L5lDn%3`2`AvG&q%QSLPxpc)9?KrL>MtNFzb0C1nrB}sxWA?yP<{B)VgFqile@vo zV8|P>jUp0q9%LH;< zevx~j(7sqTM;YaCbC)ysW4BYe3jfk(Q^a(-IPQ3qVG;=@f7@c9}MzR4;6;SzOW-y#h-MQLR5Sp zB5Rnr3UDMYyffV_34p0`Go+vyAo!oh%LAfn^N!-r<(CH{oQ~5mXoo_QNd=Sk=-asC z$2m8xGC!Es`yGmI*j+n`lNfE}IRG7YryJ9UjFCN5U}AI!hgwr^Xeltr4neo%vu8_B zR|(->stPgYm-$!iG7B*#!b0Ite0^!8#?>{$pJ{ztCC`n_efT11xH@5AF z+0Kzo=UFOZRAS{$66(2v^l{hGOLCd%#YN(w$@ydX&9f2=MUa}@0n`aWtUL}ltxQT1;KeE_KaB6zz5lTPzhGPMa5??| z3$}godiT#0yOc1d(B5FkjT5cueASXfh?p9u-CgPnsy0{e$2Rl8G_>ZWtd=6kLUA?J z(@02XnqtG(TIeQ)j!v(@MvRWN2N)%*6V^L*A6p;mfj_9%dB6yWe|lv)ebc;C1=P!m z&++3DirhVjSSG`+tdHV?VPGe$pwk0)?5p|a$522^CAv(va|&KYX9SHvIXSnXmD0-W zmhO8A-{Q(k)-Mk}tzK8rE6oK#F`5rG%YuKdJpA~$gu9tfajo$&!({*+w2PJ9GRiK$ ze`Ny_T)k2Jwm$+QD&Whof)1Tj;Pv5H`B|y)92c6QnOr|l4#ZoJGZq4QknCr*i zz*j+wlzd4a#t6&;5JbEQ$SxyQvqD|%4^COGdf`!b8H|SXB!#|%!^u=;oN^D$ZQ>tm zq4o$QZYzhF&esbsRIj2TNX4eg)<3hwIMHq*AAK6!nu}sjzBc^lc=!HJ_2g%(Hlfh< z%?P{@`P$jv+WE7F{CSyVIVr8HVc`(KymV+RnI#x|ILQUpa+=^+L}^X4t4z?-Qb)9O zXmUpWynt8zb`GFi*R@a(P9gS90Kj&2B+z?fJMS@GFb)*pKvdP^YeJ{NDOte?L?w6F z0Ty=oT7I}oy3t)3*DTr&Rviv)5(3Ai@vSmh2B=&%CCCmqUu z#@A46wcH=%x?l1zjl@s$c-~P0N`3o&YZ?c|S}<1wkPc%;sZOPjg>VzSnyln=wnqIR z9BWFR0C$N?^}h${-c5nSL`KJG5X{ConJwAIHCx%rwr#-53dz5=TtDkk#UoWhCIb0_ z_)E4-Smd3#_=a}@#jF|Pz{?ooxB$N!3@7l$x#zz3qX=T_opnErR7&1PDQ;kcEc&L0 zH~L`A|A9?sNz64k=>e3LI2v!J z!yEKB__fkx-9E%m*}8^$XQ^S%^N(zLH~+~Ab$ zAQl=^9DaMGp?evx-5~Sw(Ai$BnZDa5l;Zg3T2w0ZLfmecD=(xpEl<{4_gv;#e0>e5 znr6O%%7L3Q#L*7Kp?1299Enr z-=+%UQ6+#+J4}vNSoee}m%tOz@R`Bs9H--+=U&b?MoKK& zA*WTN*O3!Pi;I^Tf{E(-tkFw3mt&(h=wXGznX%)z3VY!@sdA(Qgftk(vSk8CXq$NC zAB=N-s)YHj7zNVSYI?qWNdcG0hFuRJaBexlm6aeqB5VH_%UQvTw=;j2UOc z@;yzYyuxH5?2`O^A${@bg47q0H4ns1K7LE!L4&U5DhU z|LD@76JCS>B&n)xA}O9j8Gp(eS*bCyxyV3hf2qS&Qy+Vm+q}s+s)P%xxCR!~XvzzJ zmf`NA1`tY#+`rQjq-OaTk)E<?q!qq%=>m?3(j4mGQ-T+XQgsg@o!bO+Jr@2}E^l z_b&YzjG>dyozjfsjo{{lmc&m_16kn;!z4wyg&A0+?(DUz%Xqb7%BnpB`#~8>N~tf- zm98oo^4E51OI3o(3~6pVu-Xnhrx6Tks(Impy`g7d7Z{a&3Lr2`80!noZ}mBjkCwzH zzzWD-MqAzCmIhmCc%aw`04O#H=<%b1!Z1(aO+t8z(@Ovx3wZNmabRJ5krxduacFhk zT_2+sxAy}+7=MVt9pMeR80UG4DD*M!&_Sl6F@VwuUG+|3) zv@jfw_Zu4Q$hs@|44cBO<%AHjv1Kef%i~gE!W>lMMt4mtpAsC0uz%aNH z3KzAh%DC55G%O>d_t5D;^Hz_}kJz5Bq>g+1r4j;!g8~mtzz8{3 zVEa2L@t6wqeeat&U$$gu#*$-E1V-JB_kdN1e*Lgsmm8(jk#>I&3VBmJI^cWs*~U_3 zREfdr!cb+&@=>MLTUiD;o#%5161RtaowG%M@8Pb3Xd>W1BO4%g_3O3Z16Gg%eg?AMxB3?)!-^P*A-#C z4M7%n1Bz7u44W#TW)f;i8aLtEo%M6#$*1~ENjxT{Fe-6y^MP?e8Lxb5 z&}iC=V|iN}8KGc}D8}t1o#+?zg+{c}Xu&kZby%fer~&E1xBgIY$T>F*?$!`|>SeZ) zv#S|S^Iptwnw%f(6C$O>sbKPilR9>nkoWna>9u!!ma79VZb!_CTW5}3MSgN+#Zc4^ zXOKbKCO`cC21hZRN~@}>1E6{Puzx%_NTg(-R$=59$b=vh_f&9zAXf_g`=YcT9m?!1lh(fUvQ0NW31GtHt`!()CYAXJ*Xa zyas<(Dui}h{IB{++#_jCsna^UJf5?>95@>0GSas{ykB~5(Wt++Wtp}0*?Y%dQt={<_!6v~P^DoIJxB!z4W)-ffhnoc z5GHqOIVZ?{RBT``z6=$6Z`Dnql46=DuT`0_rB0zd6{^pg7!*%Y`-3H0&eHOQiZv|K z))H^eoaBf|c2dmt5ePR^%BWK@Mk;CDNjZd?P=M zD@n=a7=Uskc?unxhXH6vQ56K3M51n0Ba(GSqmq;!J!A1OoO%|Uiqv3{BT_VZra!l$ z?wpAiz@ok=Mkn&%ttM46dD8Nf*ot+tUU+7uXeH<2{`2a7r4cFi(e@(=_3IPeqyXx6 zFJ1J~C2e|&kPVa^krCP9^B$Ms;FfT0j6%a%=7%uj$4c5jDYzOMkRmc-1L)aTFMaR3 zj?Y7WLYPA0)sKnV^v4kx|ju^M5Jc=0;0xp^H01i@c&>^i>2>w3YGW#@jD$J5bIBOs<%OkDO%Zt0?gkA%cdPNU;T?gr7 z4%b3uA}}I$)fBWFeA*~}dmX`>DE<#p!rov3;cEDGr`tSc+P4+q=Df&_8D8cil-v~0 zQXQOqoQFRbZfE8o_KeqVTtK#(qU3|4!%@-P1|t_e#Jf_fb{uXZhh)+y(Z-6*l1kdv z1kLb(LnnoXMrrjIAVoyrrGSw5T1ev>Kfk(s{e9%{ZvhRwh$N{lde&I@ z@1o;55Vh?l?M)PVa{|4Ig>gT!SjWJ9moSklfX0UO?T=>oY8oHR4dWV^`VSEV6j0dU zFF8n`Kc=7`XA;mf=J7Tb+@?t4lYNkEL`n-6P5o;g}R1H!E9`VeNynn+H5MKC%=g0Jp-nZa*Jano5a zqgG%)BM?{60?9ZnCH8z7GDxvggzxM*Oywh5B=`mna>?FXJ#Yf*MO1$PZYs>XA+Dl} z3BC~;iP-O9DnWq?Ui-`f=7MhUkO^cSdw5y|BC%G3dt58(L$l?UHuFz)d%NbzU5!U2 z$fuDS!@shard?kt3t^u(*>wriZbPLvAEtY%-!L(+XEzV1g~z)Y^UBc)Ffsc5%ps=Y z!v|u`1n?CNNpaqV2~XPpMy9RlQg|Qat8HXq6ye-sXv0IfBY@)O2h)6$8eVzYzfwrX z0%?2wA{3MH=iPfu?#epbGPd!inLoTSp{Dk~YfigNuKr;fOzxz52BXx-AM8n#d`!$Z zf=Lfnzazo9=jzBD-JR$86ky9%>Nmw0g)UYBfO92|rkfc%AcS=lWqffn*a^jwh~{*o zc^hdg%1En8f?x5;$6`>#5qTtkF%@GAhdqa!Q^%j z!3~hE8#=RZyyegw<%BOqQlcF|f^_00;0W1pKTn~TNfiF*)NDQZl2RT;g;a(jIG<_1 zKq%SeKF4iZVBqx}&x?ZlOgIWnf-A+#Fj3EnEZt~AU(&6a9tT7(NSwqtQy9WRIblZ+ zMUhatGm$7BM>E~Z*`MPCslGbfyx zbO%BAIqtTe%3NxXa8Xk1pHZ9&DPDZ$%$gM9>>__Q6zqYp;tRDMkcHHv>B$>)q4X>{ z4d~__Ku!QnB^9pdjX+6-mRHVbgb#+PN4O@2hK7b^oHXXmBOP^+F7U(v?m>?vZC&AV;D< zCh9~pq7oVv`{)@)H)LFiCJEk$0x>;Z~ z%J(509nCUfd70gFS)}z@aq@Cl^s_58&wZ=U+*%x6ny~EAwuqwV9pY26Ijtd^DpaeKg|fnnOm`1 zK;wK2R{v!n#Bf24JRB~Qt9|O?aSxC^Su0a+2s$b7R+Ts!14b`NlK#r(Yp09gf;#Av zs*GYxq!bRuAjVSOdPG<-f$A<1)&hM84Hhl&eEpGzyg*4)h-}0y+pps8B5L_1`uR9& zOxY7Q#PG*x{EzG}O)QXT*5JI&Qu8m`J?1g{A(Wn*3a z^j+(Tks;1#fJjA>x;#Xn>IFhBmEWrQ{%p(l11R%#8yLS}A3fDu@%8)jH9WL*;!PgL zs>+mo@&}?f9y#C1H7^bBdU|J&o?{NgnduA625{P7Ik-t|wi`ANf)V4=h#qH&$()V0 z;8iq1f>4j-CxR1kOTrQ#3>)lTTU^#dVGM9aHB+$tCD^GtoX6o)y~1m62^RYD&x=%) zk$cEkT9rT3Ot@H<#D&jIRxF8rJ1Gv_JLGfZu;Fa*=1!&5m&wY7-Raox-xii_R?YVi zIZp3glRqBae*ZWTk@3R4FTlDvXXRD3#M{7+n+ed;9B8w%+H2X(`vgf*l4LR(nB3B@ zkiK%607dRyt#J4Pw)t$xg4rd(^h~6DNDw$ZEI$UmyCXGMPU-ayqO$Q_b>qA8#`ksk zy$y%Gt?a#zZF{Qdy&b>3&*Z&b$^9SX?_VYN4@dUC$L<}M@BQ4{{};ReSMmUe+drk< z`y{!iira@=KA@?fprSiKjqY!^9jw>wpRey-+TUZ@-)A@8|F(DdeqryQ-`*vE2)uod z?(*Ib$;0#Y1Id3!QjYuk>qper56D~VdvyK>?qbnr9AY+oUveSK7cEVB$<4P%s=Qe1 z;!5#f?^LUKz>AMLZ`WOY%Xls4_|Ef3SD&=rX;eg#ZgRZAU)!NrbClFyZ2ex;Lsk0M zi1PWjRc=@~_WDz9m{%NSBUtfmvcKKXNzCYp&$pBKd;TEMDgOOQQrv0s==J35r5)u<d0b3 z-T(=o)s*=7-s+?Fx|-Shqa_RL?a%Aq4-6g@1V$f6$Hbh(#Gd_){RjL#|IKHzaj^w4 zirUW*H!%RaRVJYlY=8g&W~W13N6j?cCSOU{*|esRf?qszrP}QSxDc)z%j&$WK1qkZ zA=ii8h=*Mg67W1H(37ba2z)K9$2-gV%=OpA^p%KabEy~TK+jBjwYkb&`PaYUtz_x?oKX%{E_3kmM_~a&T{@9vf6g1p>tH)q%Tr3n;`18R< z$J3$rzrnUf16^O9H(sYg(WujMMVAD&1BBd9cS;>vBE|2 z-A9M!9P03Qcb3wJx@S0|owA%TIxF-Ag&=EZxfKvYV-lYwm)BB_&IRA*a0|lfgbDbP zrA^Y3trm!fnZ|kwm@{7J;0tx7KsW4lF=LQ~TZL>J1)lZ)fo*%fd@42U{#A07Ki9J~ zy?^`Dhw|YZh5Uk>pl!~w#Ogbrs!|1;cB%s|?e5eNv_-$vvL;{fN5FSRl)7m3&cpKP z^pVJUXO+7|lk_3zX-w|T8*+mMYPy!IO; zbZqqW?G2xPYTh3?|Mm4sYTMJ_l0)NxZ$yTVU!U!dQ!9Quc#P7aepvSEHCxLNLMXFk z;zIv$IE_xBmYLjl(J!rsg=LhMv-z|TW~8RYf6U9RzV$}7jop!X5*AxhJs162{O6Ju zi|^0n(i}D7T{VtOj}FXW>dzGmYv1D+bYg#-Cs`R){a0w6C4RkfEAmxnQ=(GCrWyG^ zsqS_95&G+G@T%|0yE+lf1dBK8G5}oJGHiHo-W7AJSA4paV?9%G@AP9ROV!ktHxmex z3igi)Tzo*=e4)Eak^Hk$J53GRzG*0_+nzviMz>hj^sRrjBIVYf?|q-iZK@-xCO3c6 zu0DIX`1R0_GUR*4e%txcykcB4?T9h$&_;)J%;A_gIrCg&A#DHe$;K^Y%+Kd%-hYpU zrf5%oy-nFCpB+rUx21I^Tt0t&_x*2$v)Q@*i@#u|<9>A!1>%)D-6g(PJ;a8qC9Vqf|vc!Rhdw>ZN_xHf}EP>}JTX#~_uESBWmXk3A zcI8#SQK*LD%%y4FDVcP!jAwI|pA1(Nj$=&H-^kW*e%76~dnc8m(k54V@X}Mse~c!P zr=n>-%B29t{@q|0_r+powfT0 zWXW*$`OBYaSNo-|5%P(db>h;28k{%%GCBfoQ$2v`S-&SE+-)vA?H7`E8`nE# zZWl2Zm++VlG^-KVpV!t-ow)7 z?u$f0S6fqi-{|o0@Yvv^mJ5~o2|IcFs7n*kvJ|QtFfl5bLFC#NUU+-Qv zAy2=cuz*lhQd;(){6Cua2g!9wRGNCa=~=DCIqli^YP!06db{ffKz!QiEvL zn)@G*CiAByUkvJCZLewU)gHSt%@+6LpnTp2>KB@K239c_PI|YJ>2T^Vlaaz5{B1m% znJD#(#!?QCR(7R055IlijgM`nfx;%wF?kq?EE`PlV?2#!8ne-W)5NvXgAeo{XJs2L zP2hAPUB9J0W}2?Ir+4RDE`fQ{DsSeg99uRJ$*u;4G(@MbPm^+63Yyt_+jILpp2ueH zKKU*+659@@?c1vf6ZYy@sh%$tm^*s-HuU9y7nJ25*(5aN z>pFGu-%b0U8$;8J5&C~)Zm-R?Red~OU~gHT1o3iQ*ro*y zCS_RxtrC<)d@qU^;j?rbxvGnDV%(iFmjB{~aJa^xa#H4smgy?;0;j(+vK5$GEylC# zC6#1+!FpD^D%vvUy8W0>u8CUZvZ+d9Stl2766W*Waq-(cn>@M-GX2f~qZ$eWrAFj# z7vAP}*~$!;59SQC@?*q+W#_T#rC{P0!7`UUUBTR)<(Ez+eGn-egaHjSR?zEWa1az) zPB1-F*hNs8_i$}Xk^;p5f=EB{bjVs)U#YGwL=f(knH1`jT~}rMA<|gp7UK0#mA1zu zwY24lsBN!A6SLPfjZYh`SMCUGqC#bMKc;tsedg?$cOqHJ%N}|+cNRzu?quGpQ$&@l zD43&B6WSt|3oJ}mTYGPm2)~b`-iz=P=1h+I;IsS?u{CHD)4bQG{IFMIq+)_Y?B2KC zpJJpwW|8)MFH>2ct_nl3huIY5lT)b#4c@oAy+_)5`yI;z%^iZAQ~3`lH=K2uBD z5l^4mR({YR{_mK(k6V$t)PY8yT0Dr$_{)nL#g~SiBfIQ#UV++|ANch#9TodFh$(XI zj|=}`ubyY)Gdv`ba|Yd>b2Rvf4!bw8+O9hA#q_LPH+x#W47MKnaZkPTUC;Q3@pnG{ zZvHO5)1L~`zKzM#`HA)n1!lD@df5%OKcfm|ITdice1F6G;Y*5$Elw8IlIyS{?mpS- za(qy<*@~BuXPC9?Aq*|S*T9ffY%|D>25l`n*;_-q*Oh(B# zNg4D!CB+y5d>3EZ#Dc@>DE4~M+Kq^^e>ezHOBQGk^aWKN+AFoU*_d4Y>b&+Zw6`Cw zpTekOk$ocE#~d0!l^{R=x@Ac*mp|PzjV8gl>C+vJ^TPw&mP*;B!G=MWKq1Yh&dW4& zGb40kH9V{wu84?NmtVDD?@<19WJ_zjL2@SANp@9H9Nwvz-N}i*vr;`q`LLtC?%=wG zTG@*xp#gQguJJCF8yyGvv(Dp*d%1(=1nY3YX=Ty7&LQWUX9L3OM%f4P5oK;UnWO=8 zTdBgoKHJ|a8wjKCOmii)wgkVQ-gDFlxaVZy+^KK-KwwWlso8BEl4r}_|J0-izJ|+r zEu1|b{G>!LJ354}@gs#5fFbM{v@;)Pd6GC)5{UgZnJzp~2yar&7U9KHR_rhlqo z_-QUdKbsofWZGi7P!u;|ubcOI;ERbw)u`SW=q3(e5(c0uFGMIK*;gpk?v?(_w`J!^ zzrtJQgt)>Arm_emgZYRUgt>qQvLzBP?JO3VeEtzpE{B71Vknry89?*i`JI%QQfdj# ztd(CzUIRzAjrw173?fl~fh9h@OS8^u*776X`Jvn5Gz_v4##6)63K7pewAT*RWXl7R z;%MiH&Gvs;>tL5@2K1pho0~ zT(e`jN&q$d6Y8u z3B+r1*moA-ukRJwXbuS93`}S|p@BYoasvO|wc%PMYGVxb=q#wL6kRG%7A)f;Zp%a01W(Ac8{Nf9mp{ zENmA4>hFV8XOoZotgFTaW-FzRHS!mM3_JZLb%yK%FhBwjiKu(U_Ux`+1%3;oYyJ!< z6FlF=Pw2fmQv4%swkTtBF-OTWFarRZw82LD{u56R-yMNqUV!?70UQouPqsE2d*N0k zZbXgLhgSlAZEmmBGV8y~OF#vr#t=Qj6s&hS_=EuO8_5N7x1TqyzE@8(OhzZ7`$}i~ zZ_lD;ZjU^D@$-4HZwd5QYkus>8?e3?^X9pD4_$d-{GAaVk*u{1?bwbGk#xQR%a8N4 zDk?5xT75h9Pnk*5FUDrRZPbuBP0c+^7N70a=o}B~2-*eu=m;uTh_=Zotp|Ll^6Piy z+ncq=cXeDF`c~s>V8Z%5zZ^5s??|2FdD|k?9++%-b~V8_)2)_QNJ$-u`}3M%#Me^T!dV zLtE>w&@MVDqPe{5Z0Vy8E=59Nj@O5(%Wo_gi~2LrUts8<&7tk2h^CTH53Q=`ZA}&raDM-Lj)M8=?(JXBe}6}5EC?<+FbR&u`)`xxZhjPc zM?0h7Z@j}O9T})ic4HhhQhGm_I6dS+>CS1ieiBRP|b3fXum0b6oJ#x0?DKMw=07sZvx7&r0rLr!IR8hi%pV`e>KPF{q224j1}?q-?U zDZGg7mC-^@>FsFR^a$DQhQ_G68g>gsSJ%azP0MB!;GyC16J!?c@3q>r4bjCc+AJ0^ zGP*Z|x_zGZ8b5}Ia%so2xyJH!;)Rl|4H%;ph2wub4#LJKLaUSvY}|0u@q0yL(^EHx zJL36fV#HZ(rmSr;Kr>v(p^q0E z9{W=0mUBYz=UTi=s!dYyT@Qw!s)AJ3VtzZ;cuiql;cYP#Q|jqbAZI~D@m6@HMo^J% z1kFkKASz-pCt>wcVsvAob!rlCW16)_mld9YXW`snxaFLpXvvqM z%wUH7lty+*uHOm%YjNA*6CUiI(k2`+U!=`!lO-#hMt=P`VE}uvW9!={UQL%zYtf*$ zvIg6Pg;<{0-G<>KLrldV`H8FFlUimNbr*Vlm=Ju!zQ{c6UnmndmdU7!$3iQo1L0UP&9qqm3pY?O4Xkvc&xE4rzoeF3oA}< zVF`HqEdMRxa=!w5Tx!;u4ZEFoCE?mRCY;rxpdOBV< zNx0%PTd>ZHJfd4dWnW%>Woc|0I5Q%co0*^YG&M!<{*XxioKC_^=H#dSrH!d6Cod&O zW^j-7?oXu^9fU>R>!F&kEn4i)txn?+)hx*4y}uA)5ut4V4armgyIe!hjYk<%nwF7_ zDh>W!*2P#zm7@LQA@$%!g$l8FzwdgNWu-i_^w*kVjZN}%wxUEFn0_F9-zn%pKE0$cwMA|JMkak|MXX#KoKHf9sG53ku4M3tmLXB<00*lsNRH{&x{Fz5hhW4D`9Z zY&gUJD?+BFp=Mzy;(Alr#YV`=htDsB$I*q0O^}uE<^L*>-Tog1GF!L* zMS;xzzZJ+V{zrk#>&~6Pz~KK;AXBQBzVcrMGUrt&@^uLRc zh5tVyWdDl-Sz6uyERgm5SAlGZSe9JeTGla=Q{PorTX#_)8y@*jfvlnAqCnRAzbugb z{rk5mF!}#`gp7a+ifL(WYl)5Ni0$g^>VDKaFnIBlQPN1`APmcUUbnY!|U4>%o`EGjir!EAZ7abWUFuhKb*JXqHM*Ai{+VDAst?^rG1&OB!dFrkSsPv!9ZZ8@&dho# z`NYky0${Rn)*U9XhY9&D;g;Ji4MFcmDh6?sT%5#lCTa=k+On>d3v?fE_u*oz?R3}i zFuj?pwj*t~SiPX4k3B`H8ybr-p+q7X3c8CVcDq9*IC`UFok4>0QTE9qGHhCD8R{mN zYU)6UeU$r?)lGm>tDoaR+vXQMf?Cl|E%Jv5mrKTFWAa<85BQ#*2O3Zu)7HB<&C3=* zpwIqW`iKz8-pE*Bv}3v;_#anpnU3jv16Sm-w5M*&J9ov&C`L*R=fLqx+xD>c0;whu zdjyj#->5HLS;l`5FW;nJ_>x#H5Wey^U^iMVlAxCiyK^&H-LR`>C`v6B3TEBS!c1l+ zvgKF=i(wLTs)_cOd9c;2jk+n<;SL|5_=$Bg`^G>4x7+cJZc8R*4H&aU%J47N5_vy? z8_=h=2X`*|V}VYQ*SJNBa{cdYZ1FI^I{C~5)eBg%fF9b!GeO-BN^~>0H0$y+=aY?m zqrd;OmJsa}7QLcmf~vHGGz#f@Nl8E~o1z45stCrB@^=C}E~Uroe%mG_(5js7Hq$Cm zi-~uP(Pp#|M?c{-J4azut)25X&%QpIzGiT@xJt?NfF;*4vXz-Ps*P=J(d3J$nQQX- zFP>+U1xQSDLX&|SJf*$(9tOWX@IIcpr1DATjyAE-kYPT69w_3 zJ|VuF5+nH1TN3hJn{IU1-fn>{8f%Ue;EXv&N$Nh&k<;tuwi++1mc3u62Y(x)ReXCX zXg)`0{{lN0x`4evLx(|Vx@hj1f9tA0#>DoA4i-4tqYocn{}=sZ+NUD=7kQPjV))l6 z$MwHQpQ$dB529)vhfil4Mu$#T?p+@Kd-}Oz_{W~VvD(qsQf}bk>d2W_JMPcm`k$Yx z!++BDV}2)apYtO|$T96>(s{W>Kpw##|!(^q={3huj$zHi6>LqXD$AbO% zk00Ov-D;Smg84^UPn4gt?@Y=#T*&zh0@=dX2h$UDtYG z9YX>oDp7j^s3cB>316KbOYyZznv8`HO$2!Wh@hSx%UfJ--q4tUG#MFh6nKW)d?Jjg z6VY^6i`^i(2@lSgn$W@!-1n*E!k2GN=zBg?y+9rJJjMj3FrRwx>gG*!pbkUfmRf|8 zaOQ4Hcvw>SCOY4C*3V3~?7d;Vf{x1UUD_Xoy>g!veMD~FE_`0ne)o&8(XN?k_D**B zAlx`Oulm+O$Gv~p;W==Te$X3sLj*Y09M33 zSe~IEcfwjz`lV)m0i(wyExXGdRvKOM^!~SX?D?dv2Y9QY5uOd`^|hNd+M?;fA{N@o zg)dIrE;Ti=O$1w*U)F6EH2!n0zgCSFqF_3fGO*lDq$B~fQp+gDKQsE2Q5Fl}P{~x= zT`Txud1fjk$34o@=gMm)t$r}`ym)!ZRtf_A6K= z{FOq?7<{LZdPOVKZ62HbsO-efHSA@?LOAn1?C%XXI?Xk6?_V(EHN#>xjz3GT4r32M zl{<_$m#Nh3F6ol_&mY)N6s~?3se1VLbMz6z?;(26TDn&>$Bof@t$4VvFkd|^L@Tv zoTnUnS|^RR12_eHRkxYC(L3!KCytLYJC9s4j>G8nc zcDs8-tPXr*6H%FGyWy34tnx}#F>r23?pIfYz?1^4|11X(Q`{>wqeKdR37?ikHPP=) z={U9vhlO&&NDN%C6_IgwjUYPnrr>LuKhb; z!u9E4y;A3kGGmvyI^oG6cvy{Ez<%eM`MSgD;No%0@yhYa@3!^f-T05k`i}IO_)~-H zKk0!>Jc2rra{s=)Gz$HE;XbDwuh!4V^bN~?8xAB^`*T~HEeH0$sl1WSrmPELmRsS+ z%jch+rHMqmTQ5FL35;ad$06Vwl*KRSBFujUy;}Enh6nb}hwth|Jj4(WM~Q4lm$hr{ zN6#bVX)wkrAwx4ZmBrYgWxTK<)Bh8VxiJhvjD_+jESS;%z?4S;q^LFe8iE)Tc$`mQj9(?#OrI=b~fNmfP0rm zChUQIC`{~oOg>ZyGZF6Q3E|ZTfdPP->XzLOGAA;D@qkw#*h>Q7LB%U3NP0@dqfzlv zsQ8(R_}d_m9}vtm#tfZj!_J3aO(FQ5_NUMFQOoMfr;5YVK*fb zZy_A-)Zft|0Pd97cq}A@3b~&Pze+Z~LIu1%RgY_fPTK-fdmxWPkjNhJR01JY4*v2I zkfMQ}9f1%)iicT>t3Kz~JawjpfbUB7nqywqxfAJ`yh-nrl1$B$Zb%@OC1O|1!!jjc zpCuf)lo3rmcuxXciw5(@g0GR`=Ln225ZoGrxF64hp+=qG2Z1ewr}c${^imz*L9gLq zQ5mU4x;DBJFk5_vEh)_q5&4Z5l5;6CW}ba5KW1G&l-D4GyCKbd#Fw!}+`Pf-fQ9>F z;Vwh~hlOh~Lc2uxKLmipLeIx@1tlFp^{glCDA_Q` zw|ZklT7JxBT4L@-A{#XbNd>Hf5(%WVGk-!XoO3ph9(eK)V~DVe7KqIlRk01|HL995 zK2EI{JRZ-5^d#|UknrIA&l+^1#&1`6y+6vp>1<#B-Dv9O= z1!fx=H!Cw^_R^wBFh4RR$}{gQCC;0|q)3AMdjiVwssJ(KW(N>cz%{UuoIwG)CDGRn zQXj{gHRpO!m4a&L^NSk_So4ds6NA$dGf0aenTZ)W&Nemyji2(LsL6{;% zGTaIPF@nR!Bp{Fq6DLMukJ7(#Wos31h4H4Qgx81WpcXl=7fM;Jjlx_`+yK`WKnBu5#l-$o@Or0X^`Rn zw~8~ku7szdpdf70xz5bo=21a%_ek~ka!?e%9UR}7>j}WIXgkZQ%Z9#J(BridVt>6Pt&(Yt;fN>Is3(heUGV)kMD#uv0DmLR6EZBo$ijE6G!YK z*sdL*UFP^9eUUAiyF4edLI0@A!Ya&Mt=qjYM$?k7NvWAc&AMg~9==3J>PXhc_mnwy zC#0CSrWo+uy3p-!6~U@kUbc~#-rr<(!S1(GM;@jbEYVd?=w#|;FXJg5bV%(%KXF&% z^LEKiv+6}}c-`9Udm>fvYWzv^8r(+H@ojvtU$<7-!Yx(83ox9I-` z>z-&B{217~D%x2>0#x?85B5Np_?a<;u9Dv^NrqzA%!|J^g-pD!Jy3gQx-s}YcaTLr z^bPW9*36TV@~0vNU@>w>_Fj#xCHsr_*%_k=Tum%@L?QO1=k|0I>_SR`7~jya($EoX z2)h;X8fgD7cVsJ=k6!E4zlqq@CjU^i5jFCA z&Eq6`C-{{mmzy-%^}{iGZs>UK zPzz&!LW%S&1_e^`jB4i{O%CM}J!xdB8x1|FcPbvgd+cG#I=R!>9rX7JcS59>0m3F9 z{w%uk+>%-c5;%7>WDW!0a|_Z8&HvVIHgmq|uEykmA%aeDbyARih0-6}TQX+GFl37G zeszRwIZTBZ7lH?W4}x#2z#GQn+$9{A)dFp$M>2|?dk7RY%kc&E{sO1RY!u+J|Epux z2>0UNyZK3#y@<{pV|D7QPsqjxxkV*PuOZeHyvjKG&jci_yF}G>uP8&{RZMQi3+Y9K ztN|#%8SF?-4=M1$pa$0VW+m2pzmli4+^pT+C)8gbS3u7ShQ)YFxu$NufnJ%76?8zB zAX*mF1A?+tdb5~mSwA!q)-Yulr5?<3G>6rIxLfi1`#0JblZ;QC!9sIS1UtH$+zi4H zV)ZcBz`XnQz=;GRba6V0+-Vjyf28}yf{k9RWhB<*=Be_1;;-A>3#GZzUo(%TUo8m+ zTv*I>M8Vau2ze5NtC1bx3_nGS?NDj6Y@8nh2CU-hM<=FCLWb`Pow|h2xM-b`d}A`< zgR|D7g=gyn&5vI0m$y6~_mC+saRZ>+Clwukz<~t#RXkK@?|+Pi0AidEwyW=o!xdJx zeO9{{0>MhmPHR@rInjwSg3mf%mA7AX#-A(|NWaiPopc< zkrO^$+#r=?xIYpJwZl@)Zxi)>m%HS1`cXN|>o zR^DkpR!YrC3agL|_+n8P({h46-Du$eKj)CTk{S10s`&Xwq3*Ab#!)h-I9dbG-2E^{ zjkku^$Mvxi4QGI~e7?HT7kV@5U?Y~IeV?0h$T#U1%lRXX5ODr?l@H;!=2vpbUBX z*Jtdz98=HFCuVZWtu41Q*dXr`$y+1D?0-$W8K|Clq1L8>4-T#DQqy}ZulJDd4ICP~ zMU>toA{ek{Eq}G2LfMVR@4Q>s;Jom-A({Q`sonGG2T$*=e)U{E_`W@g+4>xrg1yK# zu=rzwG_hL5sk{7+TFfqT5vF-9)UIo(OXwxC?Thw(cHMO3va0{M%x1s_YpUCln#WI5 zgM&=omsbCUFa`hSDWq5McP;5y{{GxTL$|J!5uaHN`u)4desauOR=PfH@pZ9whwRV( z_}=fEX~ki?zjJok?Vt7Px7F~UeERiuD30*vsPQoBq6g`kly}6R@Mjr@Wt6WQzqL*s zU6whrx!}x-d&i>m;opk;XmHP&(7&NJdnPM?J3annN*rIm`s)j3zhcSR`oxQeyar~a znIL^m@%{c@e$vfvhot=L`uq2DF5FkWh(Vn!y>V!04-V3ExP}gr z=D&ZxkKVeYF1|8Fq|MKt-*7Y!%&+emTi7`2L10u2ES!T93mOUx=Kd!klT!UZTm-4U zaRwKGSsQza)%BLuZrpnmmRi#Cw1o}b z4WAzEK5sKUfBtH{v9h^-!V$aVHIs<3urgB9v)64A|DB?mK8u91#8qlzXisgQ6K_Oi zoPRBN9*or?$vdW%fB?e7V&w)6{)a8PMtFVa7-+WiZYuAL>3al9PCf_{|Hit{Z+l79 z`>t#~USILvS(50v22(jZR@Jb=ruthp_$JFMisw>hvDS7*YcIw46&@hJbc%j*FiyOV zT%pc**(Cr>!3*UjTBhRTHw4IphJ+5;T&DXh{Zh2w)wUK1?GiGq73|Z+s;^5{7Z2;c z25PC%C#_PD-)5_Cv=v_cfb4XMthc%=B(Lh664RsIkWn5L>+5mP5A zEGw0&7)f1vxJG*sp9`y=A7m#IeJKk{75JflP2DP=#xmsNErjsXrSDm`*@?PtwXK_K zv8R>>!=n!EuoMpi7WNwlf~c8d+jv21>*oSOe2?TPr$X`xFrgr61d-SS8WYtN38dO4 zyv6Q;ZWN{{S=dK!4Rhl6$m=#K8NTQ5yV-8VS6$0N;ffNL#k1{5T@>!3yH~HCANLtx zlY^fMB$y*T+%^ch9@j7bsTN0~yo%FBnYl~z9=KFS-nYG@`CLh|G;iAe`_rn@YYMTa483bP2tBkM~I#28)8}9-(JVc8k9<5hS+!Aa&utsGMtC`p)=A$4cHUl z8CYw7S;I^3nkxr#om?98LwgcgydGv(CVd-n)>p^Qs+eej^wu_Shf%}*1uXZogFzo*2rc`yC!Y}j7T;dK`B?AAz!7b-ZJ-)#!_PU!U-M@~7Q!V!!$(3}9)LFNQ zqGe~d*H14AiaqAP+9{}?IUsk@o8z_%P7kfah6AhkA}3+HHZMM0*Yq)aZYUW|_;pLE z#bP?ieQ?~kC2Ba;r&R&$)>)~ao@xMoDV5{7a{N!aDDS#nk`+{SE7ky_M55Y3m9g~e z4IP3cO~f3Ar1B9^CPg6}gKY#r73uECr1r|Zw!y0(th+g~FEzeUyPnokJS2SVn9Oud z#JT^}$HLu(>jz5CTkHCP`{Qk0Cx`RWm=5VP)*ftZo{!uR5{t(!ob*UY&-2?@7Cn1u zh*FtTZK%JM5#?+AkgyPmqrzMS#>rI9#j4LCwv4)b2LtDH_l%Y99GUd~Ot~B>>;Ac_ zJmuEm(4W+bSivdLW8m#I2Yamqb?HjpX z>0m{?4l3sT@|W5X-ga~vGlUY+v8wW8CO!l5-j=&tf7o?HCp|JzShiEIkELAt-14UI z=8q?(^5$#0j490+zsZj*dsm;Mx9cq^Iw zMA9p9lNirgaby&+rdOnQA(Pr#a3g#!zNn{RRq-?y%4E9wFfB1wLLh0{FolwJ;WVS7 z(7R&340ZUedP+6-PpvLZzAP@G7U%Qjs+qy1^7A@u8l&FnTmu@h9c1Gh^L#fAIo;3#ikm>t%op#S#dJjJ~4R+H17s>Y9Vmsuy0H;Oqq_YXc}75CrC z#wl{n-n@&yuUNpViK_NCJY%|fi*xA{djL<$cbchceGYv|QP29DE8lbct4gPg+IRV9 zZ0%<*85zA!E+5vmOFzOx?uc~^kQ{^jpI4rnebwUOr+pLXyDRv~&uE_oa!YITwA`0g z&vK-ga+3zJ#UAo#ynGw|5*gKC35M>de@1u)Cw~0(Kwa=gt$psdVeORD4P`F{Tte1g z`=NC+9|XFG6)r8g3;Xk*oq|0wIuC}LYxvN(i0-LlDhF}wK82H#fEZO}@4&{xPD`Pc_N9^s(+T8S5C$*-g=o<{xyZ1&R+hF_cdgo7t zKic}2DK3iao>$mzu>o+rldK{@L0Iob?Bon1a;5D7>qY+DvuBbwd)vAWcv=;|m8Wy9 zRmuPUZhrJ$ETh}@i_~P$y^P3rypzgJq~{VNud|a11tcr4eKb|P{bA?qRAHj>>!6wF zjh{vBr`xR<=_Z_67rvlYBdv5pgeDE&a_92B?wNiEqC9)U>iM zyiWfJowz|@*BH}6VKX5IMIvWZvCrNun$Um07X7y-5_R{lBjQu$hIBx|i!R0a z;NbRSf*(G|J%fRK0wE|efC2y%HN+nQ0++|jctQd;;-Bh)qw3>P_yiOIh{#U}>WPor z0A#4~S-gpn8{lw#K!%hMU7r{y0m#t6NMd~aSbTC%e2`O8LSTHd6Of5WEYVLS=O<=t zfZNQI;&~I=$Ks>wllt=G1N0M`j^dx_C!$En#ri1&fhiHniM5F2d_+>|QOb+J__T%O z;+~YJJPD^sNs0PEe0~aTBYrwCMF|yK3w0I>&@HO5772(w{1jW)9&5UPf8UA!aEuYs z7R>W@ch;cG-OK_4J>eU*-1ee!j*O!`BbLCR9Z9mVt2iznhI~_&-;!|HNno3Hl(+=I z%$?FrKykWxS4D!j4mCU@qB3D{)SokK!Wn2|EE0d{D)UWY2$rQDp9Mr2-Os)Mq{H!c zpvOGLuD!xn+<@h1 zO9GU$Oj9=RMIwn1B`WJ%Pe^2Uk(*Zu?rthK~h_DurYNp6w6YQJ{Cu zIi&_jhBIws=Iqx3|HVY4GAUphC@I90ytQCe@q~~`z$t9mA(Gb;Qr^N5`)poSN5|te zx9iJ>;$V&A zCzxfiipF*@vntrRKI8=~+{`EIjG?dqnne=}zo3e=A;Aron4j&V=>Y(6k@>=9sY<+A zrO=FmXde=VtJLk2~QQVO=`7}=3k?u>18JoK+T{=@TliTjHybZcxhnG3_i8j*(0GFReI`tY1W`pbsu3&O za_T+E^-9$GXEW(OfOXg*ECArq!2rsAOm%(mh9zb+-d_iQ_8b`q_H6c^sbTwW|8dpD zlcTQbEen5;#CUHVG$UhTy>)l#6#4D>soyu=cGKC|;exG0bU4#^*lHr-OJ-`C@x>=!Cdp7SYuu+{S`SZqNnp#EgE5-QAFTmKyz*Xxn_x8yx~+ zsxX$yc1s)4yhSo#GcV2z?((6+Zp{j`dy;dof>!12b}RtQ+b{os`E^K~4-xGG;93C& z0l$mm(piDSo^dJ=Ovc3b1M5YD=NTXc8q^-HD4qc*0#a=hf${5uZzuf<1xidS2l%Yc zK3IC%N+g{JQErZ^?KfYTL#)B`*-lf6iHg zSeaSid4p1PJ&&1X#qnv;9z=FhQg)g7)deIA4ef$qQL#p6SHdd6Eb8i#Z$6{%EHN8> zhv+w690?hw`{1Bj1a4K_;GcPz4u<6tN>Ny&>!|2raV18kIV_(d&>$rx$daYQ%92<4 z0w7jDG^$h;Y!tFt;9agy6ygUo~uJjiF` zd>^OG-_Du|Upg2mq7HD)RJu|+W*D76Y_022H|c~~`R}-XANNNd7N21#>!c*TABh-` zx>8 zU-arglAH~Bpmh(d!=U1lAmZ3ce;Pyw57jF|qA}>JC@8$8*+~QbF&9~4M1`^S_>f?z z^4A$|NJUDc5(#$tnEYqpHF*!_s*c<^W>%&#E>%eGQYBXywUsEx|4Q&AuwLOq_2pO4 zfp#W!HWqhJIFFwspVnYL2H~ST%Klw-8fG_F-1@KMf_~k!Xv(y4dw%2XcPb7~?mm^U zVw;Pt@?Hke9Ja%SILQzS)8;sHr?q6Zrtq-WfQab)@W@PosjPU$9$p^~IsB1*=`~ijd`M;#1^BGW;@~{{_bo(||fM z91jh{Lm3R@^shO={uwxxF~Wy;HaD1Uh2}a_-*w%47r9*g-ZQ6z0#w3S?E6_vo!LGh z0myY=-2hnuQ!zuk9IGHj-YYB9N<`b0DHj>7h!5{*%Y`&J$aCpIh(&NiT9L+3IFR3U z<$ce;3w`(AZEvrX0Uy6NKkpf;=uSkwZTWZ+z4Cb*e&K7;b%FD~obOytzb9Pz$aM1~ z(dgafF4|wxJ2siQeC_6csh`UCKLR$^_StDee^lp;hAhq)@wtEI{;mIeudWSOh?{tR zo_&?M{S#1{mowgp{@!QDy{b07niuo2YjIVB9VIUeXrO4Pwm#8=;#R~;M>Ti8m`ron zv8|a6vS}NyuJMNk6t8d@t=-#M;~8NX=D&6j)^vnvF+VOJ=C0mW{`zR=Yjb%z5B;kT z{UaKnB~l)^o%J<&^~FSOJ>u$m^pnrTm9^wn zIQs)x%KQUS;R>9Azx`c*RovF7&DJy3t+BxtnHI<-ZtFF@$sWEfQv%T;Y`rx09~s;p zr#Fr4G`$Jmnk$7U6Sv>XY=11>o?+j9N#FXmv-N^b-`U=orKat?U)kPm-Tu6@vq|4x zZQa^5-q{)4eY3MW$G$^P+xSq#eQvj!F_AleUH6te`aT2hs-+X zzVn5B_b_c=)MQKa)Xv(<{_5btit*mq&hE+d)}{N0V=Fu3S9jUUcBD-FG5>9Cw;phr z>@4i;3!mCYL~MUw+0vhIzDn7jBErB z)h8pNFgiasuDGB)yP~49D!Z~Yp{c&5x*@A6wKS?WKB&8-zc0SKCZ{fKus_>3%*#tD z3EZmY&|olV^<9?IEHl2m;&`i_9Z zZRSYrx#D{{E5rql#<$ht%+Ie|$xGahxSK4j_&#U*eR2RKn8`3;b+~5_XnHl7SO5OW z?*$#t^XJ)#%3+l^iyXEKyWI0%IMe5DlrSV@6-mPXhl^m=Wb>-;$>u!SZnE@7f7kZ= zp4+lxull=pKT@JuM2rV|_E)P#t3T1*Tszh#-&clg4)AsU+*~95KM5HlY&$sc=WrwO zLYdb2G(qR-wwrO&slkrli`zG!l@31p9~eP`Muc)Z(IV-+c({=7Lk_mk>?;8lVW)Q- zKgEV){(mrnQy~Bjl=z$=p394YdMO`Z6yE746!@;v;y__Ao+MTXHS?)*a`y9P|Hi5v={ct>qDd|9r`Rm@8RKy1>C# zq4>l8Tw0OQNI^w`uRqV%lED8-$U?tbtd|jCN&Ha1g^mZwddBeS%U{MM>SEP2xjvg= z2$3)0&|(JwOgCQa8iI>pFpQR?W=$l#iw^~=E7tU*!0};!hd^!HUmuqBd~IyX(f_gJ znyrUxhjR2MSv&y29wrf(_z>Tl10=3Wq&~dZvG_GC?P}i_GoEUq4hJ4h9;&HJb#370 zcpDeR{bghX*AJ8vV;|iycX8&%j~|}~NxWrga{cfivMv23x7%LH4P53Z=XGVLQBGZ4 z`v||GppktdpHYPu7ZdM12-faJ1v&F-?{AGSRRlRbkvUiJv1n-oi34xB$nBZ!(ytc+ zt8sX6f90$$FaSstS=Orbt42NAO2dK?->&*mX7Oh~Sc2DArm9|A2Ru4^`UbXHSJ+UY zVua3d{dD87pliKt{JbtfJ(h{vY5AL{=`D28Y10&49Ehu2I?zjeSaiEnN4Oxh5_^~D zakxns0mp1Pi?7{ot0{pH+_}HF5DqC- z=WU%i`d_s&HP%>EC<0yYr3=@ZtfZbhV|Xzq>7IHbPXz;vg0wk96y!!Z@LM6yX6y*2NcI{R@DOwDFOS61iGsr=NfZh4@A%_s zFwZlIycVmoHxp#q!;?4WMrYjVGDQQpu4nM#>aR0}>ovxX)qHpR$hk2Ubo&bE z$^nr(_jk6}ZDtnC9yh{su64#DVfJ_!MZUH$ooaO^aQ;*dulgHj z4Hh*8B7DI90$~0s{tW5vmXVgqhQV$MjAc#`bGhc)0to5HJIr5LemU8%KKWmfCIG@- zgH^u<3+7v4Ac-JJd?fI#34n2Lj7k9Bk$~rYCMl{C>>-ii4ZFv1@z)w7f5y*&Z$%7DPw0Oio(V%+^Fc)Qr6+ zrmw+V$=w!oJJnZFdmU~}7q3(*VcQY=F4B+}gf3m)uS4q<}Dw5OiQUE zIYLPKPMzW1p-WHN-7ZSoH^#W$FI+KuLceazbNL!pW~uA2`&UehvX}mVn9^f~ zuU{&1f|?4UMggvKsq&@dyX_JhL+nebrko_t7)6)1Y1k$;D5yM}eFF_}VVp;{jp3jTr|Sl_ znt5F)hj-pV$$G$>oMFIz-U!5O!yfILS^rW7JS6voquWkrF+TrV*R+{1X;?(}mA9n! zx_dj37;qK@IyeA83rt}DAl#Jd<3$8Jwo{xJXJh?U5IpcR@=Ow8<%=c-G~h>slpiM; zC<9yucAE7YMIX0XA92q;B6|EhhEV8dUV$3fz)R09rg?vJ2(36c{!$QiLn%g;tpgiT z$YAz!d*4pJUygld&<9*rEWp%x&Vr?9!N(tDVK#jF$9)|@@vyV-MZzKQco*CujRRGq zm}=%tn4vw+(-%sH8c$7lX5P%QKiyqF68mCwX4?45Hj@lQ`cF@#91nLVO5w?QQSF~# zVmAz{V9s{&vjAm#VMY=F52W2AXXZU6{8SB56udKZc6}+ru`sHC+9o&Y?N-8QpBPJc zz}r_nUmu@tzCxZsEI~XNN<^v=NvTrc0chg(pxm*8Q4}$|SMSEJzbwX2Ll62f(6dga znQ_-6U(J?{fb&CA_isgEIO&q0U#>sD7LDXxXo|c19rB#~TEcWu=8_9524q>|@}W|N z2-7tKkjtrxJef1rZ}gy&{DIqdtJb zq&v_7(4pb;lrd7ZE!Dy1LuV@R1W z8f%yz=dB!nwKDi7f-Zn2#RnY$XeywE1J%eu)TlztC@3*dfYlSCvIlhSL$vndeHVme zh<-D7FAjZ)6Z;Wo&6`-fkSP8j{z(Nqu^ht4^VWF50;ob4N$^@HfeR#C9~$(DElhGY zsnkhO^XU4iF$+WQ7*B~u-MlH!l`-Y|0(Z_r8A=?zpWtQ$Bkj*GQx55gjH~yusSS*7 z`xLM032`R}cUA;qkUR|4ROjN!waTTN90|l7l!Y~23&J= zx-m~|oLB4`Bb!BmG5%t_u?QDW{tFnmvnS~h2EgJGzBK4x&8BsJcItmyMIlVBVL-in?i9|{x?N;7FEMUR2KNe~+>!go*jDw*WI4CO;3_94vNC39wUH8J-9jn)-(_3 z&|r@ME)Ryo2!L97@;BzC=#XG&Mi80=amPk^V>5w0hz}lI-46C4z;y_@l00y&a!3La zc+>#VLFLtnLbb_WDS=7t36T3_NZS}Jo-hA|H+K#JG%Y|J3GlHVCU-Jy-5#z+%}=+; zyV)D}b-_*K7P~Pr+O)T5;E%w|Bc|AL*erre9w=rcvAq{l=nwdks~d^|Vv^f9OqH05 z*T^6HbDF4t=(osBb3}E1L4^)yq?F~!c|L^nBSiV_zV!e86uUYrco$}B zd@m*zcr&At{arN@w>Ojo-MktUw8GZ$5nKf*Q+<;!U z&owgScVYy=X@DlBV9_P_3Rcpa3{%E|fAzvpw2InAn95RPhGh~p337^&xTl0~>DL;J zN9pKS^zlaz7Pdb!%&DS-Kxitz^hBN5F)W?{XUD+hr1EV4oK{m|V4UFrWWb34|Dlrg zD$qua3Y?n|W@gD6cj71Vv1wZHtGXhh6H;U@@ay-(02*1npYaPM2U2Ptkt><6cgXbD zbt@;%UW%Djs^CtJ>1%9%SX3d{FEo?T+=2!vdnP=QlTy!G~!@enszYR`6JLC0!SIn-Jx>B$VnZc&?{sU9{a|G>-GHACEwM_WRzx z4E~IeOOBhpPYoorOw;ZQ2v`P(CP50B2(ARQ2;EB{ zD1QTgxI|^|rv$K3aaRJR9R$@tRW^PC>!6^l>H_k3X!WOfShGfUVDI70p3@z%57fH4 z?PV1n0{8F8{ECwK4i4jg1EvVRU)X5!sj?E?(QFID^$GnQgYOIU!P zK&RT#uPWPtf#sB!p?-pIiR&AeuD~7@sqxE(8W*}foYV%2-l&YfP^qet-<`FrgW$JV zxp*k5?LMj-*(P8!weH8Vy|F<_c}yuh>VHp8Z&$xK|3#|#4A|1jVcSTof^L0p2_je3 zj1P8zFTJ?pgOmQaf^agy4wMyk_x(soFyk9;gAhPb%bAxZJN>p~fHtg=4(QcH^ ziWq1n$3*FtcKou;>Mv~zqLkKY-GVos23WA+E#QW)@e?*3df%(}I(K9(%BdDV-mCwR zt*T<`xuRREu~d*ZeT4J=88B;N+vc#H*Wfj!Nrqda zO2H_Qb7EzVOZvG9$W%Q{2Y{QpHI{xOUqyj%4Er6=_E8m} z{V9Q*2&H{;Nut#U`_pJ4q>)%QE^uqETQ5xBW|eji3X~SN=vV*uv;|3{y|;vhBB0wA zP#o@Q)qcK8IW1cKqe;d`RYE0W1&CHchnUd$b6ME54;DpYdLmEQDrbxpI$zh`l&sg3 zpB{d=A+Emg1@zAMM#l#k+2w~eP-7{q!`3ZhTW+d~yz!DUtW7FxGIm1L2KK zQc4su{|atPtDy`>N=cW1>#@NnPVyD4%FLL7tV}=$3uW(zC|i_X2zj}zBG1^P!I9w3 zdkKN%QgUpzXnJ_@Nz9nDqvgk0`zJZjnm3jPdzQE2OoCev8|?u_NMKEt%$v>^ldq-^ zG_9_Ss9R7XmE07k{d8LH@fRKXR~dizd^}U${T=-n?t(fS`yBRJ=NH+ge?_^?mj;RF zeKU?Bd11H5j$quS`xpCiZA#$vQJHGwEKUp{FKS6{*1dfms8<-FkJBD-WiBz0PK%ydZ9+LiV*w!hgu(9ud5;A6i3u@Qj zFDcYL^i>$Ohd$}fU5a_A@cZqEajCP#gs;U14kSr zI`u?pAI>P;1ykw9k>9%J@;$R)r47VUrkV6`*{?tH=ODmyBk2*4J|>>!iYd~wdXa9% zMlAA)3*Sn-OOB69NL^_zkaJ`qCdLm;?PFdOYGFa40Ai739i;@i_N0Ds!>CBhW8v)> zC#j}B4te*vd^U|rxgLKx&61F@R3Yn2eQJ$;ZT!?J9y46<`24o;Rk!!QJ{@+YTVM0u zoZZ%%H?esddi?hvi!zxu6b!;pHOC+bXq@=a$t_83q_jCo|ND;(2xyoC746B2GZodc z>`Woih*{B78En;ZFpNgrpvEwJ^4r>*p1YWW5~UK4DWae2%+8PB`|NcF zl3+qSqU1OK+Fk}J9J5~?2(;*ai}_>6Iw7bwT8h%LZyp!6U)@yOOuJ9FyrzweqV$?g zDEPC|Mg*68aL@SyFy>Tl^y!5cEJ5`ZkQmvq3K)|NYKRSRT*!!Khlt~1*wLZ;x6V0D zebRzz=3_~xWN=4jns4?fcwt}s9y=#TBWNg2`GMvG_Vcwz73@m9SQMxHgzt!;dXIUk z0Z_i7rGazriH>2{%tvbD3T>$hkMOk28)c|+hV6_55LuKY^ufh(E@p@iZR zE7(t;)Qh6EjL+g!d^gIY&uix%0ZCX5?7EN=ZtuD9{jcaxr5gPFsTM9RId`nw-o;AU zgf=ub+O%-MT$?)%m~dyaZ{9&bqEq4$fiCY#K@euSaF`ATpaIg{kS!Sh*#x-*R}L_i z$jfbk>Y$wI=H^&#F|W?u6z>unaXoWK+_tsbT-IA$fc=>F4Rr4Q~8{@v-H zK)Zy>kMip;cf<=hUyPhUL$3|B4gU65x}lqo!%cu0B;@q#`vZ}4N{~urxDX7D(Y`F^ zBTp4vWDTmAI47|;BK)!b$9S~VZo3x5vtIf@qgYDZ>l0=XjdbtNzaHnO>Im86ZuYpNAx2i6^ zYoLks&8)564lyV}-i&{G+S?J`HV)psg?PbR_#jxJxq{83o|#X^{+g;njKBsdPM!QI z_R6p@JuYB)Te>>ID8+Vt?m65v3`>ux?_;rP4SX(LN=~#MC}B1&kLvdGN|73_;Cr1g zvQL^p&D)8wCy-!bSkF}7Tegq{T)XObFExjK>jrh+yqOHrZSl92qL9a<+EU&bDQ*uX zD#1h$Y9_0&nss1hg+1z32TDkN@BU5eZ#D_Ed?E2X2W`G8xqkuzA-%a9k z+d<6@J6t+^LliY4rO6+eNrq!%L<4=))`p?T&zQ%i8vD^66`#4b4<-kpX8Gq%YOno= zq%ydNx$lR}F8^>q$WyoY=y#Y&+2s`&BkA_jj^+}a&j>en2yZKHSXA)=KUn39YpOmZ zI{lg!GdXq8kyH&ickTWXPvnGetwM|B0m3ks?~5qgX-Xs?sf!q*U3H@xLjm(YFgBgS zz!NY4=$s+50<8)?qh5;FX$Kq}J~viih>(2KQ9e8;Kb{G9TT67VR+Yl!x3{{!{J}Hd(FyA zN~T7gIQ9q^kdXf#M3owOCc4Pd0m2jidPSUlk;rd*W9}5M#0|DGec-`5BbVQdV?SYJ zI$_jH%gn@tHoBsPqJI(0>*R8eRC|l^R(WQ?=~PV4ja%af)H|8N&$~?IW89v}-4+v_ zWAA-69Ps-sT7_!c*#F4Yu-VnJGx8m3>g;ECwc|x<>u=QAqG)#7qDIaLSD9~#>%AvE z^Uw={Lv*)<;pTBU)$DoHV{N2R9G20asF2W+hyrn-;)TC3hWD5(PTgWuR-hIe*oi2( zK!QmBlYpze+0pt^Zf+M814c_k2>?xJ`31B!UCZU_oMz*A=e1u16SU&5+&nFGTD0nY zix$ck_aL^Dn*rRSB-?E%iT%ufp+iVH>osXF`-1m6X7EyhA=OS8V9KGecm9$=JA>w)ZB5#KnDR4wF&Ntq=_@Oi!Ig01gNAd$u zC1R(j%NU4#xybY$tRvg};q9xZQV6ig;JHplNZ=B<%N>)||`$eY?DpNDG1OL&9zkWeh?>PIcjD@V_T7VO#EhF=J%ll_eXu_T3RPP?nD zZS#9mM7+7#;w9&V#~<5c{Y3sh!tN`osV{yT{7EB?5)hD10Ff$!m2T)AL8K!_MYuR<(H5iuYlARs6xMREB3-+A9PYu2na_va!PIoUhk{p`=mT*6yc3C+@cZMvNQ-&OtsK`E`85G zbCAS?h8wIv^5cNz&qk-CzJkqwf1Kwrbq8U^u1rSR(XvCUEjU@uUQU+Kyla0pBa1x1~Gk!ysWHl1#*0}8+k2WItai*R7{vv24q2SmdBAu zi(V#{BG2}R{@XijR|&!G;c#bFCetqr9!Bt|SoopCtuyYB(X+awGhR?Ld8&i?blK_9 zHjGMeiN_mwr0Eo5AS}()at}!y56cYGYqVz%{0t-d%hJ@Ve6|~hBJRc$gUkfgojW{$CWF!jilEE0P z^Apu8*Dl$eDTJi{!o(e%zmXh~ID5sNBQlEy_R7q!8SH_*e4cdq6ZLZY6YIo%jKXD5c*_+uQN-b`L(U8xct=3n z+?!kRVV*ND+Mm{Jb8Iv6-eN-H^Vj*O0XCb4Ktj zlh$jQYoJT%XZ(Sr=Q&_zjnDq)kZ^zUwZK)`%P)c+J%BHiK12#YmkF2tT)lcAea+)? zOeEF;Or$%JErSCl(tl;)6Kisl2yOSPs=`-PkJaPDp2wRyrM~eFJP;81_6~6ridde# zK_cNmb}B_XswR#I4?#`-^Vg0AZd}Jbi3dRP(uRkS8;N`89WY7u8TE3$QW-T$6>CMHC<-f zZ|Y*%hQBeuq;@+?9}0KHsMjLZTCaqubEr;fnHPv<)&I!qaWW~FL%DP6RAf5(?L!Dx zpq|hi={-$%^_&HppbK(18;Sk zA6IT6U4gt-CMnKuL%Y~Yg}RWTdQ>xAjI=Wzj=Ws?%RT>TOj(P#TC{j-awZEF9f}w@ zJ(jZKdJdE_Q>%-ls~^f&?TPX05}+Hs(tTuj3mIyZM6U@HeMj*FL<{v;FSVw{vOslS94r&F+%- z621~o;i?`E;Si)qb@vvh5UQg|)f{@IW9=11uWO0fh?&>&dGjqD%ZNMTNSzIi{!0~c z3Otrc;B@Xvv-Xmyu@*5*K@Na2BXYc1uC@4<`=z(C6JPg?gnovD!+yfeUD_M5dCEkH ztPxZ`2_kUcxwE6Ar=z1C-6>Cm#IbY^=yl3UclKC!_MtnwxjVa#I|tESec2sx_q&Fx zI$!H`38;4VWOux(>g@a0Svn;8@%W^3{kU_as(buf_ZD~8Vs`f@m+p>^u37(%*Z$r6 z-#Uk^J3owf?4i4Ua0~v9?F4vw=&F1ERdvt!cYju(jC|)U78uOIl&U912{q(yc8IkP*b z2DUYWP@=5BRr8`jj9gBVmRyc8Z#d3fGnO7AqP`TMA7P}|>P3tu=$GfN-E~d5w{R`_ z@{r`544z*4ZTJvx(U8lZ!AFXBoEL`NI*07^hXXx_?G%T-Cx-Dk@TYOZ0g`g|0jJLl zd+Conx_oE%-SDHF5$_xZ|C5}d82zEd>Prv)F#Oxkf2^RJk4)vy(T$>U3%NG*&9@+l zFact{S`|zTk0{#gldk8~Nh&WiMy3-$ayC2@Auw?xkfBIFs!Y2oS(os!aQ-B(2h#t z9ZT!oIew~KZZhF`ZZ^#jRVnUMq%oY3g~Py~Vc~jFz_KN*zV!-}E2~{Wo9=JCnXSH}7-?X;%>5o|0w@0~B zS6iMLNc`>tSmrgjb~FTbNUdX^n3b#k87%1+m%WQ7=N+aHcNe=Xm-rXelcCE(hIyR~ zUR8AZb(ctVwjAfSmoGAYmZ_~;8|?+jd+{<>%hdiCwr%@ssHgK;V$d17IwQHbtdy{# zQ@cVr{G2mdrFxPQ9`<>=ZN=2>i+OjLYf107n!I-8Tg`+o_oP-I)Zz{DZjFm*AFX`R z45Ha>uRdn{I%>B(4lkDAYcWX(bFcmCf7&``myH{qdA;WBvq%m+tshHRv$I2pU1v(i{B}th@%(T%&5OpUx*sq)>zux(Y)mApO}(d8PNS z^Rq`A4Tj%}7(o>Y-<+tgl)tX5JB6W-*R*WE^&4*b)k50xHss0c4vTN@FmCiRt`ACW zy_H&J58g~?p{Yy;ywZ}t$h-NDaeFCmWjJATj1h0NQdIC_Rn=;xfYD`{@%!%f@^FH2 zYaYZ+0uNdJvTgX~$A2Yciz|8Ge&=mDZf_c&e34=JPd;eLf{f(Rtun4W8(0kPUP^GI zG1TpH-^>Fiep~H+lhe7iFuDClYJ(^7huGazzWj~Z?k`ibqum2})Y>0cAOHNJyS8hc zL?^rRbzN#j@=4gO$>r-e_cZRhNb>IH z+`sdEAJoLu)(snT+waI)a*|pj$?e^p`t|6pK2!cTd;In@*Ix#f8ZHUDFSmdBPyMc9 z{nf_!gX84qg0i+D|5jk)L3EF{HvhpBe)*%tE$6A#n45>GJ(>ijgPQGcJ%2OL=YLIO zIx4uRmho@*nc?T|tulk}hw$@9HQ$d$e*XS7sWMrv7y9pm#>rM)-El_`FPa8+BK>S# zeDyW&`(`eA^6ShNXL;w;pI47j<+U3@ZKF@?mMWRH{%YlIt7EZFP?(IQhZu`ykO0>+v~R{@-S>&TRp8RV8a}sRxF#53EGYod18= z;7fWY+?Ed%ZaVS@1*)s7nH%fIoR`m z%fa#`(lY3{Ixj{orB z+W&U?MevmyZ0lXx6%+M9FZJzh3MO+$L!zp`S$vdJlaP1 zU;`9N1*CKv@1`VR~))KGy|?rwyU`e3RIFa~XJSKNr6DVSYw$C$MP7JsSPqj_{J zHCEPhgQpRXYDx(SG8@H~i$nyPuv$cG;%$wS*((oNEj9R!0E6F8W=ETP{2Qo!O%BYO&X@)sBT1)l^%Q6Ik!BGqM+|jF(?p0W;j*ewfpD)L?<; ztQ6DMj%meZrN*7PCG`g5VLt&V6&{E}iJU(x@<+;C1URof!7B<0?%xi6U(wrvm7 zEi~myU%2{-iKJRt9SXBJ_UVW)`Iz}W%(UN_`;z8gDkqZa6Vv99qu8pmmX1FQs ze^*yiLj%TZhp(=m?R?S88WectmM`bVLlC)9+7|&1yW^P{-*vvt?n;C@Y~Dou@I_4h z=Z9#b0RYAHrW;kpoG(cKv9p$Q_s6JsPO+|zc#-9Ou1ZETPo*jvD+!v6h2o0LAF0K( z{2HlYx&%Nwe>18vcKyr?MfR%gDC}S`|NM8)WBEIO4rSv4cBJ(mgXu?^zWXy$Zt@52 zp7i)%RQ$Qj%@p`+(DVE8{`&`?6!*Vh{-kicm7O1Si1E7d@9Ccbf9em#b*`6Qn zH;H`;`0wwo_iU7W512>i?NPoeF3V8;&%`Z$C%4?-kR|(lRapEfKBBPvk;Z7t4V@)Y zI^gfbxdaZm&3@SD546Gf>L9pn@q0|J1}={=zGmCS!fJXv+Ye)^h8V>_nXH4ZRssFG z?Hg+0*(BAF&w94V0tb~18A33#4fc?4q;pA*8bEjMGvd3J3bJy_A6m@^3ODaQc=Xth zN1YF>7S(zAX=13SdJ(_CftGw`Q?XC%FRltk-u)F~;Cb{jAGk^Ysxc1An*}_yzGsaFwfEA?(O=A(6lXv$Op>n3V z;-W8|qpQr8%XAp3Zg`5mf0?ykJ%JZiNsoEo+`eB^jHR>rsyoxpwG0#eV`Z{6Hq(8y zUq@uvywUptFhdmM(iDz)kIbZ$dyENb~rs(oxj#ZdRXbA2eO`9{MABXs3ojtS(li-XLseT z^++FISWURpHrNDn$<_O~VfDKm9PB2M_#6SL1RJJw)owwzSRKMW;#?E=3@wBZ*e&y^%-_u$rcf%_=E4u1L_^G80@t|3&a2$@} zHC<9%cvf%5We#d6*9N&zA{06cSng9SxmhJ4IV$%sT?~%M^H>B+5&)c|T_*i=HHSjm zr=Bf(=BpW*-++*yEEao3unP;ISt5PLq!;G|K0@ZF`Z=qu`pY@>0N~{}k$D;+IS0O{ za*oL4L+j5LVGdPjEC9Lx0)aO%kvtTQh87;4rf9pU2Z}H1}3yyGFP_@T03X z`)SKe41ld6G={>{bOn38Z5;2Z z|2t=Bzxg-4D(~l9hoh~_3H~2U;yoWbo>=q)2iJwcn6KHdd=cK#s{BEe$Vvziw0PB_ zSw?2duH(s%;2OpE62ZRj<^#X`JgZ+ciHCUgbAQ}4bVuvwZ_CV{W^)#gTaOnR{%x?q zMhYNr(4c*V8BUZ@PybmKJbbu?#29-)WT>tCNsH7CvLKWH`MmGGb3gw~yq~(VrSj*n z*;9V3DE;rRmeA*S%w>j^};%QGA5dIg~gZ!@t&13Es!XVl>IDrVYqys#u@Za8$Kq`zG zLx(N{I#*r1F;9t+X1NZxvrdMQ!}h*9Y@ylGp_zj~wHD+u&5t=MkijwdY$@^A`QQuh ziFQPY@`2mhFJOXnr?Qw%wg{eZHsm)Pa3WrQj6bD^A=;h}rwhH8DfplF?Ica_aKP!| z7e^8X{JhjsbC#%@5vcBX?;7RlTx6JJY1oZ)GvT3o={r*Vq6m5_!aH zd{CIR$eBoIwetI@@<{JtVsp7usWu9h_AJ-v;hlQ`>b(V1Qe4pvU@IFtM!EmV+y0$J zyxI`{y${{njQEoUpWxx}m?3E|s%!#FZ~Urb!mLlihIafs-anLN<~)KN(oWc$W%%Zk zXq=XC(3)sCL{HQ9suqolwMc}vG5qmKvb%;yL?Tf~@A(_zRw`&jKZ%gEpd+~KGta=#OjY8gv zqGxJ51JaHrQJ*0W?9MsRV?|Otrvq~wU(B@P4J#6gWxaoz-UrRyg*e@VV8Cx2(AIOQ zuxO+{XX@A17t`T920Cf=BHnM zc^}kDuQh6(k$GCINB59OS9_S%%i)F|$$B#4ZSRCsi@YzAmddJldG8;R;NtN-;;8TInOT%yfT*bdB2F46E(X3q6o-RnlDlvOT5%xeBe_QwN45r z0@7s2tQdlU42g~^))^}_^h>m-7T>K*5S-5pHG=ds`-fp5D3L4oEgY`D2q$Yie>NB) z#txnzV&L*Md(fWHDeb%^7TGjc_EGen+qyH^9`5W{`iKOPi~cC)Y3m8s-#R$7oK_Q_z2?v5qqc*a(6Cii6DqWb-TXE4gL zq_RdmqSD?uD0a->n+5|BeKZMhWvWkvXu90%ikYSgDx%gQjno^S=k~ksE~+FY+_K#P zi9dkNFbDLXtx=B*urUUg$l1=s-%bxbBlt=>Dkfo;=rbX{2jpgI;ArPf48}IbNwF z&G{=allmeA7cT30s&@rke+!4e%S6$@O!OHk7qorG$(bcF{8N;Xqh7O~cy)tDwTpyb zjK6u5uZ^S*f|*p(;>`@FMKL_hKhxXRGT0ig5S%z}c{G||Iv(4?(O#JCT+7+`Z=~dh zXvwFYrtPZ*zVeu6v`u7HyK8KALwK`dRlB_l^2>EA@o{=?N*wwZ(4vQ#6ty7?cl;KA zSi;uz#w9-Aw|tliPMOrn~K|3O_q{e#7=<=JbM#RrQsm7Sk81|b5yC$>vtm2neK!huMakpk;s#vBVDdW(_r@#&^Gyb2f& zVy~N^C^t_IjZNeSWQ@}fvae2lUzq&0(3kh;)e^_#9?yfr0Q)#L>X9pA5DhR;As7r( zX7VILNii&GORDvn3))5+yNe@kX)t z<^&#ro%j{-R`z4Z8UF`S!d1wYmM|ko>{-z4`ZUV>nP}QbihCDGg8XjX5c>=yqg!g$PjLhNJ-@?Gu8E5Gy2{RLkR{{Llk&?levs_${l`yYH zUvb4v`&=L$u-|zb?xRKa*>*;3!{PGea1~Om_YUMK4HlsdHJGqGM|5S2xnuB%*|>&2 zD`%Rx9(FVQwsiE1km#8=QSFRA7FyL4A;1%}4B)oN>?R7R`vs#@_-JbnSD3eyb+snIF=z z%lAxuhfbcRLrQ7cakPKxGnTLNZ0KJ;y@p^{Mm$w;xGVcP6c>?70lhFlol6=DfPpV5 z=_cG+IVf39nOHt4Uh(`B$sO+yH9`$X0N<0NE>PfeO2|y~L?I5y;x@{wve{ezgb|6R z8MT+9vw!^>dJ_Li`^&QB$JJcksj7?zErE!qPNDx&Iwtlf0F754i3N|)ei>a9eK$ix z#^GlfBP}+zFZIAhJgCuelc{eu>3nO9TMP)lHS^2l$gU@e#k+82c zjPEikKFR6&8MmP_zj1)xXb!6M=lv$UL2Hz{-!>V4FXmgX+go5gsjM3*nrp=ooviKV zdNRdmJLneQA9Op`_I1B?1C9cojf6^K> zXgQb^O}3f+!R@TM(T$+6gT+MSlkHqgL$=Y}(=Q+GC3oh7cN|4mhN<6a!!-sc`Hau% z|84i|WFg;3ZfkwnD)Rck!^F;2hdk4h7hQX1#`g7b_`ru)xOEUxegWx9ANYaSjIIZH zHUBpB8GW81mB83MG_l<>-wQk@$}s_de}C42(Nb{V2_<{CP51tk?Gzd{)cH0D-OW3) zHS}QIi^=)H7ndv=gy6rc+sFB%`1UW8M`jNmBSaEsg!9il;-}j3?+s(dUUVbNTu=5Q zl72hv=SC2p1l=$XzJbUtd-8bjx5>Ys=8rRyE@0gAr`~KNb)GbLFVZK^Mp1Ic<8SER zVLY48zZw*NSdNXp(|!1K|KO@YOkLZmBc>5ju=+Q8(W&ESw*K$qhexo~%}Aq1VkDUL zj;j^5({Zq=^ZT*Aty$Lfg088rvBwQ=-urU7fiEZ6o{Ai2YaXXm-%fpeJW_HTNsI%G z)`1g%4%CU z`b1@vJNmp|J3w%X{ckY1?ND^hBT{wk&DnOxm;+0{|C3=p(fbb!&aToMpZj)<=8?>4 zvzC;N%c<_P5t~&NM=8xx&(v!(sBk=2W3F+g=aW)4v~>$g=pO5wTwKhP`X+Vb<|oku z@P?A;TW@c8YE*uYNC@x9a40{cbRxN6t5SRg9kq4WO+g z6@Be5fIeN$>GTAv=$!Gu2mMKtDVxky^zU=ICsc04Z7+dA#4D(9 z?6j#-sqe6o^^0pJ(~R%4b;q-mVy`_C;I^A@7dC0ESZGV4zUi_~lvH(6#g+8F{W@OI zEqX#H1=eN2_X35CvL(2!s^PHnEHOFEmnB{$Go2W3(ok>Dy^Jd(-lC6#{`iLSzAZ8NT3|E0yD{Ek z@_kZBm1%uq)YD<|j{nci5B1*P-Ghz~wm+4n=huB~3tHLP7ZM}$`MlM@l7bFPvRben0QDss%xv%VY&E65nN9>HN40(~Dz!V~)S|3s#cCfB5+( zQ`f#qn1vE?E|U5FqKbN^`7Y7^v3Y!SShn|xPi86e<7S<(8;VIzt2uTo?hZLG4=umu zhO?kbGw{uFU(<<;z4p0*dors9{(M$WnSbr%Mav%la4IkLUZa-g#+PP_6qfdhiR3y) zv^!TsbfebOt3v$5YjWmQ#Il@M=gX>crTio+?;IUDmYlwxRb-dt4ao-kUmModPo5&3 z&B(Nav;^&->`fw8}tw;gGBZ20M=jMeLzS8BLgtS zPV5Y$tv3lnSJb3&Bj*+3evF^+oh7pOeDRY-GR}8|Z`IGO9`b80R!s zYNDQdtp8&Qn@zj)M(bHu!+W&(tKHYqb_asjb8Utz|($aRtB{(kIOZeKKYlu zdNO>^`_8o)$+w-?hF)fTOKVSnJcwwuOB%;~CMYHNio{3naRHaMosjZ<8 z*elR7qf=tWZOuQP>iU(&pC5407pvE)nkIBn*`-!&R1Sbz6-D`wA-Gq6K7LAkcA^+~ zQR-;jLAlc-`1`X@R(wES@X49KVuWD&P5OTx>Xbc=gaGj7U1;h|@nbAGm}ip&_h0To z$Lz2ybKLteL8Cu^K`fZxwE%rrGy#)Ehfg$e5MFl|%ta zE+dUctH0gta&N4q>9^nI6DMNBE1;L8A zVyqxW-Gl-tgd&7Q#@z>u-bLA7Aoo$< zvZ!E-KTF{!A)Co;-7Cpw&kNE?HK`=Wa)iskK%sXxg41dcYWxH-1T<`kaaIwg)7l6J zSl{w@Dr#IgmN76p`GL&TACRli8n+vI$?)z9EbY&0cnF2$<((lc@rIhHK=s7D-&_>~ zQ2OpCKd?g_6bF5$u{$X&g&eNSwiepx%+})bBKSd`JyIwSNAL4ed^F!C@fAm-K=IYy zasg-ZoAl~h;o5I&V)(IJ89P-B4BF>0X1#!rzOk1~0fbLg{*9SB-tVIwP)Fa6NNxln z<*6WmaKw_%4hHcvh%tkSz&m#@HXE1|V|NTw-jNp@GY-rYL7}^qGF^4<&VZr6Uu6DC z`%OtB(}COVG~yKsv{ad>qW1)pBFG$Gs5JnCu)3TZ`r#N@IWTCJ<1BCT4v=K#IDLjQOSx0&m-2x znapHT`Dd^Br+-n~H(RRX_eyKKZG21lu1cg56yNY>U()NRJW&{S@6<-9;XlfXdi3-& zrwUfx<%zrUC?oUP-PG^S^cHj07)^Q~#H9EUcwE7&ptcNCBLL+d(ZFV051$Ktc1K_~ zV* zzn(`0i5d?1l>=D%6#cS7-#XrSuga5NT2VNQ~U)>F3Ys=FXOegG9a zF!U>>sU0`?)=_a@~ANKT2k?J6sFHr6D({_?L8s=k$ovKpW7u8-NE$b z3hYLAQdc*iPDfvJ-gL35#3U+s@m>goiS8s!di0R(d9wU0T z7n46!)DPa4ov51@zrV6#HqZ|5t-H>OpNgE_Hg|^$zOZ4sSUMFeNu|az$_cZ%g<-Ys2EeNH$G{a6I#BXP? zzQO@M5NLD7o;nmucY2qfCkY?oxFLYh#)WuqjlmT$`3OclaxH4?{R(%%0ppt9SwSL4 zoX|3zQAQ#D8J_Kf$mQRqv@2z23W!`@H{hB|D)c#e0p~dIY?AeVnalg+5jg&p<=-(x z0V2mrIzm*%;M^`9E7AYr)4=zQRvAMmH7Z15$M_5e#LfO}_&2I-=01T0end!d zZ!qrxsRmVofyly#AxdCJGdEHxP*i`&b$jRei0UlgP)M# z1(dL1VYI;7Lm}-D#l8r4#G}Wv%xYQ)`9}1QpC~jHG6$eFBGJPjJKZPRR>hj3l*lwM zMh2or_!V?OnD&@VRMhG3F;V*iDXNYL#AQUsV)=5{P|^TD5dky|qukdbyjr%a3;Qjcv~Q!RJYt>923&BO?l$JWWxe+y+=w2vKhj2n)MYy7F!gnKgDiqZ3m zET+ayYR6BXW|%n?ilgG!jVwi5<3Ax1mP8XiAE;7g5kA@p>*WdGMiRD0&ZIs}*cMIv zshzm*nD|mUu8^wydnEDi+DYO+?Su;yzX3!N%qd=@EIteu^Y(NCotgB7lC-s#gz8ON zHhNx4ia*0A`4z-Kz5TzCfE-}RUb(B;l7oVI$e!T$t4bG+MS@JwX=E={cycf%qNAh1skU-)jh%O0odetU| z1o)9qRwQ&5seX?{$5ntF3pwLl!024SSy{mC7YdIlU>GY9@GB6EA=T&u{CWSd|!LK~!|5_2o@c_@$@U>`doS*4-nc*p86Hr>lR05 zmDqBXc~_P}-j-^JmzZyqxS=3Pl`_`i<;kd$?DkSC-7<&D3X{r`l&s=}%8Hb+N>-yX zw=CZ$W5teHI4vb|i_s@S`|EQ_l=C+np8 zRaWsY-MZ6!b4_K%q*dKCs(M?ue7&+P!>`VGjI4_)d!|bk{Hc1~5+NQPFXfcT6{~r9 zE|J}u9qW=Lr1w(T<)ujMOR=h#65}r~e0zBj-5?{;a5+2SIWy4uuz^FbL1DZ>$)8aN zXjGACRMTtJaB0+vZPcl1)EjR!_|~ZNt-)BL$pj7DbZIh=ZL+LtvbJu#{jF)w0&GQs zVMz!W0mwXy<^jN1>1WRn;5&|hxC+|-7=YnhLdhTxG;ogG{76E<2HhHb+^Bb|>Yy9L zJD|GQR>N#|G!EdYI>Uws-93H@BZI6+EfJXJ`yH^e*U;h=*aL1f`h?h)Q2@3wLR(;) za}*F|AKDA_nrp})2@*^n!yFsi(I(Mo43LaT(Ce*mT@uudMt6(UamSzi^m{t40D~Ga zau7jeD(JN}f>#=ra{RKGyCaeUIt>*IW7_W>L>3+=!$@7BJAi-@+J+1hz=6+UL7{ly zr)PH!rrnwhYw_Z}W(mZ86~IL46T%`I zC7K1Xr;owNRed&;?yLF(_x1X5oiLlEwv#X->`)IOVKWe=-3<`??^pFl8G&It14qY{ zyVXrTWVp^whcOk3JMJ*V!n}z?OmXaE{vf~zbcP;);(JX`cbfPvQ)w8xVjGk)?4<~p z;9%o=UBu2#a{%BX3}Vrb!*$qAC+d@waO+ZKV`yw&z61V|zV_+h#{dRSC$3*uzLc4N~wFEH81R7coXfh`4pN2hz|LY`Gb+7} z0@^}xG4dU#t8LFOMh8V=U*e#QYFnISX@3oo7uCeE2z(!k2-r}d=R3!(q`|9keOMCM z8b2XFF}|WVjg}tQVFkM=G~eUyN$=<)eVecieBV~xXKI6}>;RkBj03dx+dLiT@Y5~| zgHhB$Ou=O6$Hr$=irpVLK=10{I(zs7&N$JdTmTrZgO1~Xztx=_cn~LU7%BWS#g~+?>y+1b zC*_n+))q@okXtYlOG(Sj@6XM@zn*#2mb<2t>VeE$MW(w=r@YNw7~x$Q_x(6{C-3!E zn%3w?zlx7pa|^FI(>0t@SGE@a&VBTDO4nV_v{{+>@a^5SO~*%tXU0me9$0r+P@u(C zES(du`VU=s64NkDyB0mz@zJ1Z&J4nK+CKNahXF!^N8Q>0vCrMCE;-#8fLPre469kz zIPQ3iYut35^2T)@F4MU!oH?Kf;|Xs8;v9V-tU4Y9dG)!TcYbpG^NHezll-oc@efm> zI9Sb{{s!JJ^jmLES6(A!1P7rj-3F$q4AWL_LrcRfF$LGNiX0MF<(yY}vsTX>6}T*} zid9}PxP!PI*d~aZh8T5-PQV(+VS>aZ4%_LKg|3aNuR^#b(LbPj{`Z_ewto!hp8wFb zn>|eooD55vxscfh;FijW%OPFM1yYT=lnz7csjWF=jDayOOm4p02YcBNk3+LaI^(DOe)V^?qOqc3{fon;pgH{B3cQV5nmBfWVmrXd#U6%3^D;^S8fF4MFs7#!EG zPXNlQSnlhA?jM7M^qb5744lIQZ+L!WjL!%f0gY&|s3MpS_Y*knkFA5z;elY~W}yiv zUD8CFErN;iQ~3r$;@{7vZ$E{p1EDm4e`i2|Fheh}Vae3!LxQWIDTXxYZ=OcFiH^G3 zj(RDEF}>aZec+!y42lEl13%18j=1#zkU-Gn$s8mJgi)emtA|aDK$TtNx4Kt~c}LAo zeupvrwqpGKZ*vOr2-N3x@M+|&iM5x!Ya7oA-(Xb->`_OXS+3Ge9-vVIcy2qWJF#9h z4h2aAmB$l>{_QIIedL~YIJW(3M_U2+e#p*D2>$rKodcRrA6v8lP`rJkXoZfkdUWp7`MRG?@91j+^>LD--L(6bZ0 zW99F{(Nq2ZleJy?KVYzgwS<**>H6+!&))v8-v@`SKRyi({{bK<9_`aLCKPeT?*rw2 zI6@C4#Pvq2zHl)1@Z5b5_pkXwiCDE59-WuPqc23YP)12_ihI(eAB^SbG?c!|mi0Uz zP|;8}m5&QW@#;2;$~^eQp>EOs4g?WmWt|2*l0YnoWxAEwB_IbQWE3C6tJhpT*RbpJ zG~2VR<^ykF`T1K7U$I*JOEGQxKQ0*LDtNp`@#(jc?-lSUd3@+C8sWXD?K99CdbY5D zOMVk2&8T|- zYhbNdlKttm=KvM`zH%4k6)&Gs(3dk2IdV#I&B zgTcP)X>_+dI}7>~Nm%zVULUWLD6S8?NfAuYBgD!L3fryKJI=Hv4sMUm-M*k3v)=kC ziuCs$MEnmJEV_G6)B4dG&64r{&Mqms_v7vWF!%=_#YGqpeFz~DpaRcD>B(HICoY{b zb4>Tw1Smc+;2nNbGfn|bexK2DNC}C$WW!x_J{jP@ix*PYs{G=(8chTl(PNwkcF$w( z4;a(?mw{=O4+AtMwi@5Pk6;B{7K|gA8GYUZ%wBt~#^k=2X7&PJoXZyOUA%q9n21ez z5YQ6D9Km-_v32O|7K+yJ^<$m9$Gxmj;5KIH|P2ML+2vz@sDPO23^L}|{)17PwunW{kJ z(B=U-{fQp;EvtDuk9|ceC(@ta;?^mTL>-zB;6M4Z&G(!~N`1wiM? z7-9HAOJ4KoE6?&|vtW@q8G9sQ+7HHrBE5P6HL%tiCOGghKc^SkyOFs!UwL7knSVx} z(dTW9CW#M&IH!C#6}?G-GClg#OAwr+V^(37$4SY32|q_0=2kk*)$l*Uk?5+tGHYDt zNwJd$3nLm;-WsO@-TIIB_M8#-N63)G6Kz9#DM4YVQAq7Mg#^T86nqqQ@>_h>h zwMQ@S(M}{T<&`c@0N_HMc7Cqk!=#T4oCgC!MsbC#Wfn|C(bv%y6N0dckwGaxnHaOv zFkWT`S8vK`NbvL|m5~5AJ_&_j0hLd;WdKZh9flhLl4Ye1!C3)8lr-@<0BFgf`hjz; zMe5xnBYvU+Cp=EfGOeu za90K_e(|T0DWgzYZ6}mI4i{#_SVWhgI$#pulm_-vjZdcmTul@hGC&Pxqb+ou9s5eP z9EYYwtzK%uN4Y$`oHe2j12tBJGdrHFB(GHu@-O^|I49bB!FyJXC5;xLq%DxUM=q2Z zE06hCEk#$YYJLZ^TYo#MSN18AOZE-X$W(ouwN`9R_D`WvE(0sj!cC_E@kD}!zbepw z8Jb)$ef{#3l6^<-AebTsJ{>|oU%=t6u5%DmxWLb8ls@*;sS!rD0mCHgbj{u`1}?n> zp>rI*$rdtI+N_Ga)f&p3MmDt7zKSv?sIqL*=&rBzRvgoY+0eaHdJ8Dj4u_S1v}Y7Z zTHN9EESXo-?m8D&Uu`*=SVR85~0BOX60S;WYAgR;{Nrt66zd%MDY>K8?S^@ar=5QMB zO0QhZ1wt^|?hE(~6=AJfxZ4t{9%jh=8tKiW+RQ{dl?a)!AhB9<8y-fz0J&B^N`!9avmOVd=#4)B zMG4{>KfZGr*l!G1dMkFbHbE7CF+-4U@^xtV#bDYReJhh+YbbBp3T=zEQ2BS}TaT9y zcsLv#`VYSK2c4101tAe0&t4NsJkDQIG+KLlx)0#P-VO!K#T_;NFUIaOs;Ms87yeEo zg%*nR5<1cZMQMUTktS$Bq@zghhK@8t?-+WA(0lJ77@BklqDa#RY!neeP{9&!o^#%N zZX55oH{bRc8GGkb_F8k!_4|k8fhu1zMD76l!*yL~9m4Ol4lq-L;!T7SDR6E${Rp%8 z^es5nL`!l}cUbI*<0>T;jUOrudT|xm(-Onn@vuh11}IwDL&6#`P*In0xb`%Zb=@>Y z({mixNp?n}S1FE{M!g>000ZoV+4W@4i*T$nt95%<4i`Y*(efg?g0n=Q?8AOQiW7g* zE*rezC2&lNQ`frB92oz;_Fn0&$9|IIe^g@lHa56Ic7y;H%y1G)fm`VSV~stT=Pfqm zraRV!KMKB@v<<*TF`8lB1+2XCLt>IalW>%aG4p#9hRZeaemdzT%zJF|8f4H~m^r`j zZ~Ox(&;GT4=&%CG8)E8w?{0mhvTFZ>iJE|s+`XyfuHAe?&r}{^{MZ3V=UD#BDIhB^ zD^*hQeh~&j$h_6T75xKHI=%j$MIf-?fw&C-ae&o+Gk8CFUmY4P9W4XetqD&zlwmHpw#&+6);DS%3{tov{0n&lV4v%Q4=+at!x7$Cb`Khv@{~< zXLDj2o#s}5em>A^BSw+0^hjqrC*nCf{Nj^M#mUw4uHY7FjI#I@!ips)*)DDyux*Ol z2xMLliVr@_`k;$@$sbN;ae8?94Nj5@fF;F4S`H$b;^LpzGc8oTVbeT09yufY5l_C9 zYiH&`3gf+dPO;~1VbFA0&i4ln;gGRy>>D`tCwg-?3Qk?enfF*Z|gKJ#vz6)4UWLTu)ntRD3rF7xzy?ZQZxcx6Or*fz*))CHOG}V zSKC49oM;fzuL>ar1bM|7I3HU*y%>~$brCdrn8FTQ%YxoSyEl<+>Z{;3FF78OqOv7S zU!}_ip*bLEI%pIe3W0a}Ag+_(0rET+QF33h&dvEL^7+E&LI5JBR&=_ zdwqKZi@dx)nv=`S_`@(&-YESXGz0EW!J$MnL?OUSGlX}IEX-Hhj7`Lo1zw(h4v&uw z%RP4lj!mS&8iKq4zepMk^3-3q+K8_$>%m zcVv>0kKz_pGn_V}3Ao1DT)0FqVqiYP=3He6B|Si3=s5k=lqhhav&4-ajnk^&LD6%? zt#p3D4%{f!=2+MG`kl4Tp#Bzk;}R;J6PA+@eH3J-pabWuJpYRY*o@?iy2dG_ z$ZfNs;tj%i(Ew)^?g0oy=YZd}45A_rlrBQbqlnvOs?Ft)epaabfr_(Toa9vy^|TFR z>yaq;!DyoLcqyFC96=XZ z@QzEBM%=zUs~r8V1P!F`sgUGx&;=ECHxs}p4mlOAZFPV!(6O#+vHpw!Jbq+dt+bl+ z*Oqg$l9Dof^`7aupVf2)j0v0L7F})yWG7G}SEyRAW$YGYS(Q6h9fPlJ zP^}9}s~<7rP*$yk)gmIvxg)j)VfKLiLj*Gx{0@PFkr6h|Ob|@tE2$z(MCDyk*iHQ1 zh8F01x2CsK?hbu=|By51G9cLt0AvGji!m@>{)7^Dv(Kw!D*_<^yC+5!k2H|Deey^yvV0HTIVi^W_USO8en zwBNKaeLi4nX>C#rar+d5_QS!;59tcUSk>KGQ$Ms#jG(2-;5$KF7YjOW`nSXHt9sy} zqWzagL_18ZI;R)G`3{|y{hikRo%Sy~ZF#%wlCI5;=&9L)uY@4GqEU_P4CG9NX+&Gw zA$#R9%Y%B-rK~3`>FN5472OF315ZSyMP)SKdiF^J=o{A))zne{7?gA_=5LfvK?uQ7)iXPYwkHZ~+H3oH& z4Dq~Up7zT;_Mi`zCO|*ISk%@^O`-t%_UMb{=5e$?3?uEy0+i!>ZUrLu>@Q+2mXU1L zx30!pzu6?qmRY)?Xc~lNiWJ;w6%g4uPuGoy$HJebIfy^I_w$bN>rKc3hEIdQXVFDm z1#>}gPzbHa3P3;{fFOq>yo!H>9@yb^0u9r}`tYZ#iY5@r=GuxD%Z{(^lRfW?h>6=y z8rhB$?lZOBZ&bFAr`YcHldX8%#GHl_DEG%B#14iqp5ABwhzVfq5$VAa`@{-Dbt=JVT((?(G%mBGKBZU{U}c20T@mO3S7g^FF;1rwNlg+ zCWI_jAupU8Lj6>3+Lyy*_(QkPWpM|=r z5zW+T7RDHY4v7G?jMokGyuT*Y|D3KvDNWxvJWqOlNLYl49wk%M+tdccw_M;ml&_A= z^w~7$`@GQb?raz!6@rs4oVa%->Pl1K3-5?WNd5-K-?KPF4$caJAT-p8A(46}#{Zx( z`utOFi+JcYZfJUZ3|`%vq*0m+cacm0VPg~V=T5)E`VJ)_XEaJE`1{J|9CFWvPQ+?Y$azR(s3=UJbJ|df@cpkIb2`7u+AX7+qdj8mV4nUy)lYP_6l-hyrj2 zk>=V1-7%E2#rMti_4=n9FLBpqrZmE-T&wTl7e(|k6VdM>KWa8$0|0*~J zb4lxMLEORE@~k{Wo|5HBS^o?X)(d;fyUuf$-QWJq!>E2g22ftZg+LOdU#V~}L3V_* zaGzI7Lwv)KUN^lIcrfmN6Qj--5aOYtrX)R&)H z5j}4fns|*TM3r8FfK;%Y;7<7mWp8D?q=2sC z(XST-!7n&cS%DSm4&4_vs_m0n+qSu21Va+yZz2+j@5-jO_8Ens&O30!NWk}CSpn(h z=NX!Rb`LUaRp%*oNfVTKYH7-~f z^cMZ?iccLn_zuWshc@B+{adX1YCrVqQKbSuf=YgrVt;Vm*9(2bQb#!sZvG)e&^Gcy z@Z7r~iq>H~hoZ-U(_27s&8SDC+AAnzR0k;ekuEFnL*noUM_SXZ>w4i|evod_M?9U5 zqJ^_X=fv0sln`j^ZY1UX&s64=}|q9Y2>!oV%El+0CsJ4>F_f+}2IJ-8b)&*lY4~)wHV_;jf7BT48h^~_O#vVJ$@D>#JNLd(7fVpIyq*7P*tTb4`9FqjcTR+QNU-#Y(r+vPX{>`h zR#|!RylsMt3${*7IR1{C)P$yfesAemr@325YJ~#WwHv) z7(7fvN1B)C5&;}(G|`D8M;SP9$=5G6?v|~)mO+c3s5yMo(o2uqE0zp8 zR@_7>$@NAAGMsM+$U?ul{)%JY|NYtKjVEDnou6wp@=BwTToAm6t^$EPUy=CR-*r@5 zJQ7g@ZaKS1kj;k^0T7!OQkKWp#-w%ZwiA$};Q-y>Vab-2)^4CkN{W_(O3WSunpw3% zG8HY*OEZQ|$2&Wj%DwMssRruzGJksyFL|;C1Rnox)lm;4>p<=vBZox>Q%{c5C|@+M zQ2+k`U=Uu~qy>-TI%iZ*Qvr~bUiwGqkA zI(a`;?5DYHBHh*ae?l*O{UMV6C&k4+U2d1l@$s?I!IZ8w^v;C1blCF+M}vv)E8=Xq zlUksz^)^fQ5)g*ZbL?`4gqJY4PqI*px*0c6pV9{AEIiw0nMd&~zgw9_Ej7KoVa~}c zu-sc3C*WnS@1{z8f?eVdtC(`DZyH3=z~H&Qx`xiVME9oJH+AmKgH)7E(-S&18EWg0 zKvF~VnD~vQwq^|@r?NPQBQ8#1YvZc&+RR=(u|cje9zY`keYJ;^0kx)^1>*7YirWj& z)eW;rkHpl^?jXF=Z%XOaQlC|hvf9Onn6mG$AHFvGE5~qCl!XjLAyu$gg)tU02GFRu zErTYLIM(`bjN9z8!ZTK1hM{NT<$DU_Dwzgf$K^+76d2^K8rsIr`g%mph$j^uKD%HQ zdSUGPkIRY+GDp8#rwudq6elz}2ihlZNq;^+CbhQbvtVui+kZ^L{qU>iY$ri7+bzOSGa(VvTBgDypaglw!5p=nHSC6TPw!_-lT(8@=B z2=-KQ7=%se*VL!u!WEQYCPt${7rD#%0H|Nn*j6&{H)Y9^D3YNNZ!!k->DO0!&BToq57SC$ErT;mGd?Wr>mazOTTc!*pn(?&sK}ZU|7&6OJ z_w~t`w4(~WvgAn|JUj6}W^Jz^hS3_)VN^9O5UrtRa(To*QCSGzayaawOAbj2`Ulka zfe7NVg_vqaGbv#J7J;i#TI-qYg(PUWXlc+*>@5~f@li>A@2iO>4R-96WBrvCqL)lN z-mpDIXbT5;Cp*ZLb2my5FicJWMxOBP5;^irJSomu(SYkq{P?4n-j74~$_1ZRYwJS6 zfY2!v$_>y!9zMt^fC9LHC>qGa!^6YN%ge{d$Is6%ARr(pD0t<{6)i0-+V}p?4^#s^ zp)xP}3=Nhc=PiZZM_?RWlL>Ve1;JGx5ZTbZHm{p;gIqTyMBd`M8O9ecTp!sn}VFo4WtMus{y~#RC1O31o81@c%G@oE`5u-Lm)l zUriw8DtS4Y3Dj`?LYeZ-|1^ObtndHtAW-~&2Z7@M2MAR2zk)z@{&D{o6DT9O>;G;7 zH4U|w{Fe!Ia&iKv5`ahsE{;fApE5C?lPiIjhZB~-!I|{Gn?STaWhFGdf`d1XmzWXB z%gNJGmjLDMEr3Fknrk^YhJePtsp*;7xp_*ifXNFJx=Lfy1c5sy+3^C#3;zb2(sE4~ zU~gzaE8MUD0R(P;o@4k?Xw04TrHY}?D5HY;MO^qUtCaP`K{`x|8)bfg_sGnYO8h#@ zCfZs${%@Popqd3cc8i}m%ftd_){<3-k)mZYW?lyKTtd49w%tDCDMD*g_PIjN+&kTy zgpy1WV>QvW3Da~W;7ZNWCEe1<1<^B=2zrE;ZU?PR>5}tdtuGU}QcI=JG=7L8M`rfN z+XfdoXXVG;;OTnf>72u3Q*P2_xf|kd6j>R!cbC0`O-5(PfvvTCI_;Bbw9n4@pn?NUTMrj{^mX{f zFr)b!U=BylPJW{w*IqJ*J!QY!ck1+E%w4}EegN|$Y2$H8f}85^9r-7Ph#u>+-E1jB@THlB?@C9kzF)&(z^}(En46RkVS%is`TuTy|5=W~`o~>+G z##GhSmXXfu*A}ap_nob+;c=6y>iT}xy*N>opbIYck>||$6P-69%d>rS%bB-P@jl&! za99GICy1!oY3#zDYm~YN-7uO6I@(J%MpWy@$NkO_r*)0=ntJ28vUp6~zADMgv zkJ64s1D!t|FLbXNep@hgp6z(4=l=TmrM9nO=koO=!|yL_Lu|hBJ4X$Cf9clF|82#t znlM4H6X-qfAfNK=qsnr#8f0!w7uY>a89!Za{U|H!m+NPug3&S(1lVr;sm3ZB%+xInN;H+51wx6;KCU` zRL>9o-gtZ~oME#BJ9zRg=iK1mO{;%?FLQ!^UMGj2N|QjFI#*6om_q?Y5_qNh>FMd0 zurrGH=w>B`{^T)-gD#WcpI%{q=(P}zcuT<`t|;msX2Mp+2AvS%8eP>v)ES3Trh`DR z!2UrDMpTI57GCrBXJ&XHwit7l0>==T!6QFY9@t*(y;ykzAKYr!gW4#U29tR$H?z%z zK}~TjNb7u;nMPd&ZK45-Ks$CYvv37SUmvrdVC!Eu{lQR1&INEs(JhpAAJcb zOtq67M7}*B?3R;If+s`QmzZN9G7ij~RFx3{eRQ}?CU;cWnA)!jKIu9)_ z#RACd+9mj%-q1AI1~asb+o5m;4g!(6y%=#{O!|zj%&>Pm(!iJtQ|gqSk+T>2QLJLD z%6nBLZ+f))!bSOJt@xw7y2S~lkzRFkLb*1qvPw&$58?i-mFJ!i*|N$!*T)rC?1mh zR&vKUJu5c={q5o}J_9?gM5?iL*I_NCBH5aJY6MoiUKziA)f!M4gcO=Y1rtd6SDHM?|Wx~e}oN-(AtdUcP2?f zqgP-7n$soYUlZttRg&c$vTfI}VUy1T_q7kIKY9g)_8;UJS#Q%!AjRu)0o~I!K82?J zQ!W6n6y^0-jqbjWhRwm(gkFCvz6yG0(;Vub^yZXi0_6_y2KlGWvg43X0VfZ4h`|PJ zJjQGB&NJ`VRx}gnX~!T_YK!mFg2>@?VUV^mAzF#yHp2I0n+}kspXYb z8@9-WPH#w9S)9QRwq?%_zuPm-W4CzImV1Teqe6j7pGx-m?1Ipbmwd}+^3|gXw+x(B z`?-1i=Z*^FjICDNR@lP^+evDgj`V@1^T7gs7tlpprRdY?azsaY~@Hfz?y!K}YyoQ{AjoZWMLz&lHH+GCu+?)zj6 zF*vz&>POz+HW7UH8XDipJ!7-a8zee4aho>mMUGRly-FA65(OEizy(FgOy0^7eER@c zlia=Bu!H4j!vF{aYZzPe$!M>kC6mMYTML(=aU~5);$z$QLh~mBe=o0iFZMI+czt7Z zx_QK_xbZR%uQ}@~;A=2n@W!Df@Y-Dlf`|x~i8=^n%8#GbxC~0b;t2ef;s~i5i-0U5 zLhmXX48_}^WnCiNxQYIn_}8B-C9unX*UZ6%129TJ$gAn_2PS6OAi3(mdG0^H!HZO2 zE4N3Jn=lxt4Jl$!v;`d5pTD`+D72GGJBgKyg{zxj0?y)S?$8EorcGT^oT4hR{suo6 z9;Tmg61sK`_w!~nu$t_wV&RV69}*l~k9p<$&#Yloz%A7;ALj;&AKVLB`^(RtO$WH8 zr6NHGeJ-9@GJ4-OTJ1N1xd@JhBoiH864qDqiOOS2^ggLiO@G&MYMt5(?&p9@PPS6N zZTial@=$(%Ok8^S$5}3Rg#OC>fpbWF4pVwnXn;SfAMh}dpf!965(vOrec^X8{wrHx zf4p5COK{OfKufm;PmdMf39{PEFo4tSi%zH`=Fx$f*SM04L{P}~GuM79{E@5+6HM85 zru&=+5q<@OSj@5d`4QGy4reAB%Gnb>OBnf#o72fh7Lx)RIn8b;)4ChMyMQzMw@B(M zw+p(V7lWKFb%UgOA|dfiCE^GL0@M$H>tb#I^6;Ayh#TWDRvc9J8W7Mz>r3G!vO|43 z!@WOvzx#m{Bl$ei^(n)}M+Gs#bWIs;A1PrW7ilr4*x2{qANe~aIBrKe(4IUVlb;K@ zX#0rBWi&&05J#fZ$q4hs`bQpw1_E#d0FX@;hr7<{$|q&q0rPX2i38y!2TAE;NtKx7 z9lWi0O@h_3TmDImmv%^Ye1h*%%+z-BG>(umfvor#OQk-Cpy7b2GY1_RECN_V$zV}p zcmW}Gm+QWH4-cg#c}OW%+9k!ABQ{v)@z$qJRDEXc6sb{$qQ`m#jTQ7*!B1cC!>~*O(-#%-U!?`VTH!0R{@}^0DIGj&%oOtUi$5;EQq600RM zuRU};m&alFFsm>i!@M^ug)Uu1Jd1?Oy1io$L7G`V%x>z+ba|M4E6>)kmVVTf<3$y{ zFpzAY2l&@AfGMDWQwHckwnJyO$3w@+Nov-uTAL2K?2-e#7AU?36K6+#)br6?p+4X-K>5U_Cw{z z%$6C&+X*fk2|q1tzo?Xw6CEdMg@u5cc>Ur9JOC#Yf4W|cG|EU1u5fm{ z_pqzZp)ZiI1pjN1Sz}w@s+Z|8h0aUNKEG5SrH7)%N6UBB_paL2)G?9Wa%H<3igqkw zP$*S01XmaKrsf{CIJg0t-^jSxVCG8qbhpva6(!^fp|2(+U?8`*6uY+x*L|Z`Iq%hG zRR(_d+#!P&xU<%$>fcUf?rC#3{65KXdzwM%4lb&DxQ%66Q8e}U3s>=>#l=s(> zY%|-6_KNjyab@x{OO5SorY~*N?XCR|tI+~CgKkWh!F@$6j3dl6PDNGxOUzR|uNz~DU+GIYqGJWs-i0@KP z=s2pRc7)Rx+Qzmdpxbjc2%h8`7UhTlT!cTiqYndEt=WTiJ4rn3QT31CJJl}3YMJ_a z6RHa0H{ujNg+APXL}Gy5pLDMPKvygJ;zr^~zGV(CD}SE@1G&A1*eR?TB4$|z`_yQk z)J9c$GG`eow%dzC0_RDw-jvu#N}^6pQ!pB;OMtRs{6k3iV7y(Znqg2qI(W@q+&13a z37)RTL`r%xt=a{uw|0{5%Xjn2+70<#o2WgK*u)i~y%^QGeEy{Z^ktnTKfV&9*?hH% zT)k1lxG;FUR?U)l56w3;qBJC5*YykqFxiTQcMVo<0NXu|UT$^sXR96kExf7vU`?SO zj?2!3X&YL;!o#}iefkEQ+>+_Dc6q$n>gx<2q#fv2h=FR}$@#;JokUHep>vm06rR|y zB!nmx){d2k=*Ehn$Fq|Mi5y5Ah`ouN9Ff;D* zq^_RRLLY;7uN6ZB)5*^X#IuPYr^&hTjxO?{TC7JIxZ74kQAg5q`nAt~ z$_#x^nv0!g5c^)TP3}MBLv>5D(hZdS@Iak5%xA67H~$=+8XuXr_Gf%;L*`>Qbea8e zX0n_-%Br675M&*|^Q2gL%+O$Al5-G~Vso^PRw%lAjvvJ=J9kkB@_kFa<-@Ru%~&G2 zWXjf$emzHIVe;tCBCW~&=JInt?S%@l=QqRX*o)?Ff1J*`Gptng(usEBo&v`;FOR_UHL_zuGkA$I=bylcy|~+Y$XTL3W2MW-ERTiOFw%2ro*Nk|M}rRm^8t2 zQiK?^VtP3H`WI*ZWp#_Z+B~VEX(tNl(Uw)9`sOv|h;v@=14(_F%RQRr{%QTzigNb@ ziz5VNiM)eIRi;%(L(@lcD~3EJ=IZ)^eOy5Dugrzo4%LTq;IA zEVkqwXn)RNRkga7Bfm`;c$MO~OJJ;$O|eFj;lUGh9a4z!jYQ)gbY}p%Ks1!yy|t%P zYtjD$3A2|a_Tk$7z3J<_Nu=G|{M+&$im5MG-Zd0YGEFqa;XWPgJ{{Cfn)ySBJE(}q zzn;SEH(z{RmzJaVdMm%>HL$-YKeoSa^Q3J6!b(Civ_M!02v&S!95LnY>~Qq~@P1-W zWauT#>3}T;FvE11hAs;kjwpJJsNa1WrEf8_|HAgCMe(1aJjY@vGw>EJ=F0Mlsf(B> zYiN9P_e*v4)}@ct$-Bw0FT=85;`2UG+^kYlP-6JCb6M%ErqATZK$o9ZFkL|jX=JdK zJj=*BR!i6sTxXDzPw)TiznLWN0+=f;HKT?|4UY&e*__jkL`wI%Pd%XhJHd|iI z`c_6f{rYj=+4~TXL)^4F&c!Vk3?k1nMVcyG*!+rqI&UtF-qkex8HxE-IQ{s=@u{=m z&$~+u{sqX4E2kNEh#4_^X-|3DWWLY*lNR~s_rl!oWaf9TT zOMi&K?Y%EE+i2?BdxvZP5;(?2nL7qOa_b)8=2-ruID^9apbX_NOj2)|MLY`SRH zt5FP|o9(Y8)6~K*4qC9q$(27#;VZ~%&222z)jlI@w-)AM8ov17Dsa2jlUmj zsJYFn#26lA8;eQpF(w?CY$s{)G)>qg$-QBHqaivMpBJzACO$Pm6^w~sIurE#-Qzgu zq^{*Tfdq$iy}Ai>>doM|%?#t4?IIb#3}u`@5UYvI4m=+EkQL^@{n1BKD#0n=jfq1< zX}|!vrG1I|OwalJ9a_y>5MPKH=f8TXjKJ@$MUg;743|dn1(RCd<)><(YIQxk-VQTn z-wnRz=K}S^SyP>PAR$VH(-Xuy(n+8DAt4gTB z$<<{2T1zuxqe!%{>&8MH=VQ@=;kH?h(s-U3Rre|k{rlaCF4=%>M9-?7i%fU1!PJz) z2E(-6`P58ztNz=uZgy?j>zfc7DU!a&68M|+1s%BlD~f+v{Hqr8<%11iMD21*)Cltd zpfJL!v)%$>wl_F@#^G+QFd=a5viAf>fy{Yk`aPo0i0Bte6ht9})|b?ES^qjF82I~e zgi7yhpunv3s527Quo zEYOeW3=AqI49>gh^$tzm6xbfJ41Y7iuXRkzH&7?OiDL;}AA;;angvu@%0^QAb^}L? zRX>;K%msh0?;cd!D@!VN+}4fvQa$V{(dhepnPFb-sQDkJfqjU?KbPy&(1Kx~$9~-m zJF?Jt8ge+*Josn7DvCLDf0NlmgSFQFap=j>kD<#upQgQ_-}kHUJzX}uMbJ92`HZ_x z9b9?MUOl5|m>z!1;7(?+ut-fUCok<$5-x@d;F z=QaC;IMf8e6wtjU5Q>R+*x3YK2#sXiZ@HEmiUwHXH5r7_5wtXIfCZ0bxJl9i>5>z0 z$pj$(L`#g-Hi3l_!OAEwZGy7&lAk(RMbgJ}sj4a&|eoLpB< zJWTa>u;)14))r1bd>qvw!v8qv84Tl-a6k0j86epMlrMS189^Uj34DNC~Z6A@9R zl~H|hAoa#?5q{~s@tXqY6BM{AM6MzA#hzh_r5<7!&9mbsWnWW04MYTbB>}2ZachRR z==*b%k|5mo)=Wn~@|*R;F_wIX7@5%L$ZzRa-AvoncCity!Wn?to+jL58&XcIWbn|r zF^Bd+P+z0r8nRQ?#|_o$BCKq86bbm4dJyBNZQ6Numjb`CIi;q>Ob=E+Ejhn&1`V?+ zmE-&I=2Oq%16m^?ZhqxmS92tcb%$e~@8mx`t7oqDvsA5;Y_6V2kWlJE{@JJBE)FU*zw*v8$<{H7Yq?bceo_ycQ;diZ>IECaZX|a&*ApvHu5y|HV zy>bZB)1NVEra}v6z+BV)YwzVmav6lncSUgCx|wR%(g-TsrEpd3aLNTEmCMUQ!(NwLB;NhF(TbQ>eic3B&OT*i}uB7)K{+dH|vGw}E@m!!}O-zQrpzymc zmw-E2vvOXAd>@{(K<^56GrGiR&iwkS)pkG{4xe>tNi%eoL&t0vHk0JXQ=7f0^#v6An5F+xchT(%#nN1+Fl@~7yOX` z7olh}8*ZIz^a>Ah#TM3ViR2 z3OhDH0etgf=oR+AEEl(?^!NY0aLf9)!wL7X1a^EP|h=tkfM9Y+UuEG~fyJI(z#aI|SF~MIhvHAt zBa0+Z>N&u{hr8<%o`I4GkBMt$<`JO>bd1`v$-@zKSm0`=jB=&~KLRQHUBw$s#~A?k zZb4mOhw^Z^2k9acawBKUu3gSFD#l7FXA;IoB&&zxGjY%``IwFBcpvkCHy!au%t?U|vjz9aB6?6cX`w;WVC)S_!&Jz0JFe$lGGxik*Hx~4;|G7sUPNi^3;>>|t z))8%o6GO{srIGjNg1`!BJ8c>ijrW#(2LHF9f`u}pC4;axu|JTkxYVr^pkf%tij@`Z zp-SOs`V!!PC8ex$CAvNHW%(#;{R4RkAgW>E`zH3mwyC+pk$GD zqzX`R3g5aUt^$wrOvtLkXZUW=sRZ4x1BY9kW)%~GhurQB7a`jhv+BV)7mdPOV}Y+- z_i?t&_3W^P za-OB<8L>{%6zw7;m3E@C{k>cAIFrs?c#OCE<6Ll!)ux_QaIFo}x`Sdw7dCemc9JdT zV8GKARGJX*2o30>^PO_@5kC2^Ph-|<^H;vI;&#kF^xp9g5-Q>bK*XYr9ns32qS>0F z{f7)rGz!?M__Vepsk9i>Qt}r`3KmLv&rO24k$z%@;%tkk4@r!>q(@_Xizg&D{nAvj z=*!;XGc*&3CdtN^@S)1ixQWs8l!^6~HVKuA*Oh%xDdX-dJLg7{)F;X7mwUY|xtLgf zszMsfE?0NEEjvXwc#4P-FS^>t7*rb5jjI@JsUT7+NCy?vdQ$AQJ`_J|)Z)PY<~em{={(ra)gV zAG}*lGkZeoXqQAno&2LZ`LN(>^@Hk|y6S}d>NKb7H2rEnlxqa4CT*!EXtz3}ueQ{! zw%}(?p<7+xR84tZU0Hrj8Bc9SeqEDgb=+!AEf29Hv8E`$K69$JtFAuoXHBD9?PH$$ z2A;a~-MakzhT`4oq`DfG_L_0G>eSV03Rr;cPJM4;ePVD!^J;ZvT|=c?JxRZ|N2(@X zs%c}jCMvkDX}5;BTZ4kQeo3rrsB0qf)V<56Hf8A7|4?n%t84s>su|;{8Leylqu=x` zvHG~KVe)4K(~UYm9tB-u3qyT9%UVMCY{x(kW1eyOd zf!wndliJR?w=34eFC?|guC-g8wyR9HY0|fANq6YDx3SoDVAtBN6|~(*>M*iuH@?w% zKB*mN)hY3--MpYv{6>fMTIa3$HaV*fDd{$U9Na5fOM;+f^P(&3eb<8!u*a{i)Nft7 z6%hBNZV6(ydwo~nTDR`8R)lnqpOxOb-0oQSZvTQFo#<}7bWgOER)kvjqqVMVD=puU zZtq`O+7-R2)7^nm(*7( z-Tg2`%Oj~bOSIQ}t$XN`d1_L3uUZfBmsX>D&pWPef9dW}`hhh1p7x}Hs`|c{1-&dd zP|sQyyRO!(T7UjpSFc)c{dB))|6ta8?WgVok+iyF$UtEKV3Bn1=cJzR1p|%JePh#I zKY9CF*Pcwc5BjE-qqZu|8VW6=BhSC?35FTckiGIVI~MnBPN5Mn-Nn3@BC5*nP9x7JOsB$YYF$W2SrM_6E-!J)Suy zKXY9#w`+Ljx%cb=!??H1xbN?hR(T-5r_#eWxPcud44Pb4%< zB+X2u>`f%>ji<>>hW?(&@|es?p3G~QjJZ5nG*g<-Ma!B+r4j%HX0VY0Dg^RKEyz7@ zz~L2&0XK!%0G{~(w9JY^oF#YLMt4i*E_=2ISgT(Me7WIKtKzHVhBS6K$|SgS{5-nOX-;fOyprE1M9Xn&&&>1eEuxN z$un!V0^hCY|X7$|NN$o%L`ZUHC4O6a$ zdbPBB;ooU7t}P3#brb<6M9`KjjAH{tHNk`Qnm}3_FjM@SJ1sOR3C4v57*aqcH`gWx zK%AI`=gBW^-q3H&u5rr40C^ZE;eGooz}xbY6Av1|0#4xz)|xPyA!U*Za?tqDE{ih! zJ(h>wZX%ft3Kf~JBL*Y3H`BLGrVz~mmCy6WLhp=aVn^*}z(3X(_y*Z5u?Yr8TO!M5sw+UBGGV8A)zy$gEt&!Hi(&&Vl* zUEKP;GRU;t9KIWCh}=&pCNaKSoSRU6vwCBL4qFjH|O`i$a9sqqXhB?1k(3(T|GJW~U1Xz7WJe5VX z{dxH<{0$EV*!lz74{o65H%_}9)}vZ^=WCC6YIJQ|`P`d@zqE2ne;uAW&j#Ihy%pU2qE%Z8ubA5G{3_X(k^dbTg@ zTi`sopJ|5LO-7!C1C@IlTfd4yZJw~(2Vb}k)~b}1a%$(A3pEp~RzU%6*pY}J}alF68LTt7B zJMSZZwLj|UEorw%H!m4M6gQeVeMU4k&5BTVk+$y5fCs2l6XyW;OEY`s&4- z%?0Y*2UW_ux6=~~nXUKD(Et6Sufbxfko*ou4X2`5TZx2ShZm!i808?GZt9d zB)CvDA{V1EmfUguMgl}Wj|)JReMCTI?5?)BV(JZ`@HPPgkBKXy*nr8}Le=+!41#S` zz;>!)6bexndl(8p%4$ZzTiQmAT6$P;b?} z=@sVk)K00) zMtX*-mi&%FvIKnv{uiBGC=1BEek4ioDd2y4xGhq2YkqLR7PLRo{P@~EYRW{}zc zM%jG^HQBXqqrXxh2{rT%p?3(qL+BkrL7GTFdhfl2-Z3CmKzb2HX(HXwdq+S)jDSc{ z0YS0d+%M1ndH1|~_Uzd+`&+(e=9;z6b)3Irxbixc&fY3_%k-~j0>CG5>P{EqjleU2 z(NoX|a9IX8Ch;F}48hLUqs@|>tZ3|d(?pEnLkdZe+zO)!foUrJZ;wG0BY>QI4^RBE zULF6v#qI5V45{#*li9%s5@)0Cz%0#f%t9R55-t{kXXmv3NJ1g-R$Ldjf|=1 zaZ9&EgATpv9vNTDV+UJi5F<)~xo!Nq44#A{`=wYE1r{&Xx_aCD%Zm*+l?UX{Jdb_7 zMDwar7@x%%KY4!8@Z@W6S}D0+54!N{ zu;}S9g~I34kpl$z*(kkr`8N2YUH<`jm}2wU1S(A|D3B_l4+y8xMMZ1Vw)xxcE#KGD zMP|3z!;{73slx%O2Uo1o*v*G;ZvO~O+jQtI*5hyu_6;AfdEaum9Yehz8l{S|80Bz4 z4JA>;0&O@*$LM0xTUWtTTr?%~k~W1;_Z`~Rj=h<#i1JJEUN3YvU4N37+; zdEh&5dbLOM`hDO4`O2nxEOW#~!o;cOVx|7ZCIt8A ztGViHme#0u%2i;d?)H2+92`3Wq5n_6jS&w0(}^wa;uP{dPX}y(*M5tVN>ez+!UO3j z;=TeTd{?cS;20c)TDlmle*IC^>V}XRwQF)kph1zCVJcNPpizQE2-D9ZuZJ;eCVm1( z$6D0OM2O!MI`X;gX5UelyxdkbJeHWqzP-q*){WNS-vZHwOb}K-w&Vn4^N#Q_lI~1V z0SEv`HH_{DOE-tLB!B^}IXDVrz^7p@qDF%D^sIA0dRw61%17K z%U3k#C6fik!)sNqP?i`5DioNb=#v6QzzncUPUhyefT{yXuNK6xsPOe^27N_K5rxt! zSR?9Nx!}Vv9)!~)j6#RSsjm+o1+$nE9m(lX@pF?*4ToRznn6;59_NBcLMu!>XvRlr zv~fD$^M%6AiyCGt%R~0py{#V;VDk8p&9_9zJVR%Q+l&Cv#gf6n=bsk;_YT#qR=`iq zi8Q=boAZsrH z%%22fq{0{Vi!!+ZzD|b97*0)_{Pn@NXQl*MaA`Uui>Y&}-6jHx08_#l z)vG7F9Mi`TxzTG~3wR>_ablyj=VteyDJqd^7R%}N%nqDBMD<936Y-f?dS;O(LW`oL zAm49NYdyxYE0~Z++n}WtK~e02JEWD_-4eNHcH$zttfKgF`DbT<0Bgo?+Eg%P!h8vdxa(+2Mv3sufWmmMK5PRhEbAD*igyL+sS_{_4o$x z!CoFP$AuT-G^tu_EvB+NBJ0hrC}1Y~m6e6wc9!zZsl>Iu48 z4`|KO))1lkuncpoL^i~XAH?(qK=41_3S_z6L+9uX|D>JM1mjQUWgc3U|Haosy9Q7z14$b|3pk&P`P7jVce;}(z3GTBgCeR%VS2L7VT?Q= zUst+RU~Hcn@yzv5@4lvwzfB_TJV%!TUp2yS(WHkv$&;kEk#ry%YW+e<%c}Ep@MA-5 z%O@$zoQN1zy*oKZ$F-?Z^NIERS2{OX$H`AiWl=t%-P=P;BR8S9`@LLlQ^IV3#MY+t zw~*;!xCx$4=RQpM;8$)Y9Jfz--(A}d&_sYC2zUX80qsZ$H8B77w3W=}e65`}b1#*@ zyllBN@Ha=zVp_y;f~=vt$-qoMYrI_{z!RCX>-GVc^1wg4jLovDtymHKv_j4MXGH|< zGqR?_cfGzZw8vae6=|o{zA%rfoUZZGcGNh?HMVQM=gtGbB^)h37=O(UI8@hRF&_a% zjG5&;PP|n_%bsYSb(aS<_a07bJ2lKW?odlVl?>sW{$XB1tX^6W`ji-$C4$wEs3M1h z%iPtRym-C@yS|&Uyu8Y$Ysh8!cq8^`#!-v5E6d-38sRK1xaPYg3XlOh_F}B>+0Izez?5II4}##ry4&usl$6TDksS#5o0P zCtAe6g2X$ms0b0_kMCJg;^RNx(s{+Jnv;wx=d)rKjF_&E`*BM*!Wn1cZ=p1M1wOAz`rt~MFdvk+Jy0TQZX_usBj z1GEzVDnvq-`7V@16{CwuhTf8;ZK;ks8nN%>)i^qbFezj?;jCm53umh(H^*^H~%_KNqp24Y3$Yldcx0mo!NJ z9wS*_@$w9SIv`2S%_U0qbfc?C_g>!oD`e$L0w_VDNl9SvX|Z+y%m*zOX0D3Bz~W)R z8r=OK7Z|L_s#-P&v&cGl;eRG%@cbi*(kRKT5m?S+vbAoHH2u<=0>vA0rMjIOz5rJx z%R_%;NfIJ)cI-|9A5dY4r+!(STdMKtptvWgq}JBP=e)FzrOSDZF8DNt;C6&pZKq`@Zjs(Fc{>Mf2T|1#i*XrMFDVH zE<1LCNjT@v6p<{@qj+0WVymx*4Gh(dQM_n++F?dH zTSh41F{qc}S1F0aS^id+?+u%Rry?FAH)*YHX)PkFQo2*jeugzyMeZev(}+|*EP)y! z`D?2ECXHCb(WEtPg%wTuzlve{_qfU#Lwirj2}$0-0Hl(#s-Z zxRl8$anL|r1ERLUD|Q8f(ka14;MJWk5o(0czJ+)pex;>8bTYt9Jem zx*FzoYIyBBSKG7R>v$OG&jqw_m6QPm(I;=i!*ISx&{1&dZ|&Z$sfgAw$U>)eo-rje99W3x&9R5R_Ud2y z(+9oidqQ3o4uFelNF&fa_#UU;7q$!NZlZU0R$0GPYp>BytT{7}u_iED{EB2*nE85j zWf5iT1Yr8yW!l}y+qt=U=#<;((KU1eHyN3CxShxmP@~G+=+c zq$OaN!O`ex(rnqyt~b)ECKx;q?c&EA4}Z(kkp#(uklU;M(s%kArN}%X=v&tNvB-=;u=})SmnGY{klr z3=LZx)61oBh^iVf`&@kMj=VOhbZJpdGmhITi?wVg=m3NYEqalM0&3a^A9Djxybn`0 z`E}D$W&V_%?eOOvs6{}L@h51g_lzO3wPqMVf2xntv* zW+aG?Q90)2ASJNyVrncNg0))$2sit32FEIsFA; zemK@5@i$+WR%04jkK67%8B)5(gs9J1YvOKN%XdNGmy#+rFB0Xn3yM=dJj>SCyz+x2 z(023PPKjSE1cQl*5h$Ggfqd{`@%CQ825+LbnwpYqoc4jd?m3p1n zPIcwAS)tnaZCwo?wCe0gf}ss9wrVT_L;JNw^-RrybTWQ{*I@Wv5`cw-BqgeEy^|T* z{vhL!ouf}Sh&!Y#%N7d1O1g2XnY`9=6M7f-@f&ze&0u3LQQP3|qvW_FK|p`w|%A?%{nXA8;s?Q&f<50#AG% zy2S$mzbVN)F~XQ~_TQ$;0vTo{0$Q5~ySiVq7(DwUG0>3`u9hX3Ipzu~ISPwz&9%8x z_fkk3JE-M-r4?4Sw^IPqL+kK@w5WTsKpD^%LXeoMye`{p?T`e1dc~YxCr$dj#HFlP zaNw4@7F#mZuN>Ss11Wl;yWa5;qC|e<%18+PG5SsJQycm8^GsLXqar?#DpekSw*tWC zsv>uL)g{SB^r4nF<5-Fv0-&DAcXfB6XE4}}PLD6!)xDEdqtS%S5euQY_N-^DC==2X*}>IFc@Hd$fvidCM_3?=4;H>|%bOVT_~ zUX1{SwknNNC+UZz*Pc@z{-r+JDECd?iV`^(I9+(wFmv@T&$}2X>C`P1zW;{GU~H!N z4$&(N{g$65T=(M_f#U>~ixzCBcD&)q=2Sc-l^D4iolNhsVkH_eY7%j}3S7sAy%)NjTo(CgWW&BfLqzWlS+BBF*vZ{iQpsl1J@@ZJ4{B$HF&Xz7 zU60E77EI&W*Nfun&Zz7(G``1X8u{beI+MoCr)wjOH0(0(2jPn&9UG*h3f_~g`cYfl zFPFMFf4AyDo7`(8nsOL5aYtU6xHc-EaKBL|!K@ChlKT65x(M*z?w8^V^Y?SLkpbHA z$D8Xn&-tZ(C~^G}{vyp03X2R-J62`h`cxi2@%(CW+o%Jpqxn>2Z`w4L*wQ6T8-`c< zrB|{3kyeuHnV5eYzsAFZ%${a!#h-?oBr2OZhf2JDx3vm^Ka5TB)_*x8zI#nS?<~N# z+S8`=Xn*wY=lCeJd0}SA`fpr@^=kUndL|5qZ=ASw(xL{Z(9E^hYYzOO5^nt6^aAd>!ii|l6 zA2$q96?VyMu?ImNkKLEjSAi-+CGkhQf9;X&>5^{jkBej$r2 z8x!okTxl1li%zJaJWkqCr*BuXrr7?QXB1NgHk#u!{?$L#WC0>czlrqEZl&U9%XB%E z)d;-PCw^rvfJFLl!4fMnLzT16kmSM)4_}Lm$~RbY9;6HU@pHF?c6&lzE!nMoC3PaB zMUXM^=HkTaz%A*fuS-($)q2d~TOqm|4WB1dRiog5A*@)lhf&g@fLI6O!xTFnAt5El3$?Qw|#M-nD`AG@j zl{+4RUK&T+C;!P+;I5Q`NzvCvW#h^yl?N88kOzw_V2(RGzOH z$vC3L2-NQ6J9>AL*Tt46+-G9tEA^KRP7vVXw-h zQjX!_GpdA^V5pIX0`XfYviwZE9>g4?jR9i{)3ZMg!|*od@R)5DNOtkL8|62U#M& z57Ipw9{NptHnv(G9cBlu4vlm8|7G-QF3GhM5v&;=(&O?cmI^mDZ(o~0yWjuHDV@?Rx7so^RjRR1yA`lOOGV4GC9KC;h4AGyboxuE+xj;PA3%&wq1f2MquI)->%8Wk(Iy z3Ap5q@zt1k;rcm}kzjl~axqYVJvkr?1TV=Z48Th8h6wiPztbRo^pit^{QIpIIt#Ic z7CJN8gce#w>N)@3??Txj%SN9>z6ep6n@Ay2nF*SVd}+&?jQq^)By`nJ15#dhsK&|x zq8{AOMV+);bOl6RKKx*G?)xUYdNbT8WE;{)v(0hWMrAzSU+hCNn;*~;zO&6Z`*k^2 zgX-#6_LiIk*`!Q|c^kJ&R{nQBsLO}%)xje?g#A=Z>kDyv5AH-bzX^5{j12$QIo4tm z2kf^7H%FZ8>shSR`W-AK)5UgI>kustoVqy&HR4;A3iQolzpw2s%Zggr`zQ<1*_V?b zD15lXf0l;CV}9{6w|D&lOv+QX_<~X4n*b7{K2~jAk-})d@ijwq*JT zTK6q$Nd`%}7QPl$C+MLos+|hPKRL+f(L9@U(4hrzE_EVeN>jQ~&iNUZCU2#M$@K5i z=GT>{0L6oJOCC;Ud@m?LLh@|y+fypd%y<; zUjedSXaelwsk>UhSLuVPs|)Tocl)0b~m z(QW1k99cjPf)sCm6(?*3&(6KRyuFd? zz*~ugC1z9-kHjgZ+MeZ|_|=q@Fe`jFlYMxLI&P(kR<=7$g}@y!nUYLLHO^a^Wz#L(iLK^b&rSbT=g$}k~N^vM+;mQ5;d~4WIN`B<)vb#SAU-nDk zZbr`pIdZIC_FrwBM9u6t{%tNE`1|E~{GsUkA7qaQ&U7UcUjNxX`<*lZi$f=nuqQC1 ze)f~61|+Y~yrE~i>OXmOVh=4>8DB{pKsTgOt|Hi1GA3B5KFY%imafEfhP2;V% z<1fyiP~J84oz!w?o=c`N@$I(M(!V$|m+nzz&T9|kd&W6uF_eGOA*76)tRkb{(*AB@>^{2S!$9HOw^CtV>OpZfcHY6}T4{laA z|9su!Ubhi_}{C~2fshR|IcUd_&-}G zgO{(UY5_T77FT~oOi6*P47w>-(s_MQMGhcG4|w&i`CWDv9>V&uNr1ydgK40hTXJx`+rlz zlp4_D|5d~OONKqM!`3R_U@zuis%2%*K}Bcr`X=z-DD!`i%vn;*k(1Ar^#GN1{rydk zyq_4@nCYL~aL?8!-6JZCJu3bGTMcV3%KATQSn0F!w!yrH&c^zNzK-T6UHt=tgHN7z zG?z6IdRvA%{|_A29F+P$a9C3E{}dc$W@YC9Zuq?X{M^E#{|$$gJgCZhR9hq#E08SO zSeM$|^z{EKIO^`{?JKOV?k5Zl_Y79SM;?lWKTm9!ZJS=0Tv>g+w!ZP^?bw62+wTdk zTX@&&;*a^{c}Ov>GG8*4D#LXjS2o$@?>~S4xystr`G?J5aS?}eo0k2_WcsdMQ)X=| zuvTccBFl#gz%4b_KG39COFvaeOhnP}8j~%f+lfzU=*)8IY3Kl>;#Qp)0JzmK_fRou zoLRf`phS9SoDw@B+qB|k3Tlm}Z_Qq+k(#e(TSa2P>Y+c)buMbC*q$2FRC!s3}XRP%*VLRVVWYU?974e zI5H$i%UcA02M?nrRSm&B(^76YhFSV>0av}@aS$;_`7bj^ADM40%$(F+iTpAD`n>t7 z=+B!q&EQ!#I5>D!N+*Hg)D6rUdhsCzC8}CS9h^&n9u7Mf)^bWMqo^7-%N(7cOJ%3x zg;=;`=ka*yzf&-b)B9q*lby5bUXUf(o?esr*x{VZkCuuy4VPLKxWwVhenqgSiTz2K zNV>~#Mo=TW9{chp>FV#IGJQP_i*iE_KT60xZQ^yast$utN(C@#LwIt9IUsdQC{iy) zBk*piwAneYH-I$Y8r{Kybb*qNi zOZ@peM^;u@{$DIu1 zxWXthiGn9uz=XUVeCo)mFCmgXFl6Yur|ahd9m(TDNE2vSD=sw~zuCeI_|*y(!HXsI zEo}l@&OYyZn4kB_YMQ>vw8WUbn(&*}P;LiPUy$)oI{@9^OhLjp^b1YlQ0}?eTC3U4ZpMIsN$0ZM^mJ%h%?gI3hJ4FojBV zTljzB8frzx<-keq_z`x?%j13><)V@+k6V+5qvYF)?f!gmqo|!meCOMo0#X+w{+{05 z@r(HqNXs>QHp?qZQT5LfPw%%?>whiJH<%vue;;)@QRBaQ)R-T1up8`u_3NLQ=W$;T zPTH?77wFjk5exS004+aiTD{WX5gVU2eH~qS`J<5>F0Z?0qHDC z%@+8Q^n_AbcLU)>(ezpynDr_1l&c3h3%WmroaU-0%XHis^k|iN;xy!iQd|~AlPW}H z3NVxx2~um&ndG%l?3RcEn~y94J08`VX4^HzPtm)}%gn}4UoRD>pxmTx1kc*(90XJD zje46aP}IM1hKOtKOXQ}Kd(Y?K^=$q~^jsiPf+f!4UqvAby*gQu>%wZ7P#ALS^qb}K|iPQX6gJzSUddDG`q+^!SF?6NT2Xu zw8+hBGaAP8ve#ln#A<`YToY_m$Wjx2m1Fm)00|EmqH2)6Hnwp-%Aw6R>+-MnUw1xL zd3q$X@feqW;bfi^0pbb}fah*iQ%jvsvrg*qKFpS*`%O*?+)7#76?YX@*50`)u-(|0 z+R;z_W5n?pu-2T#Q7Q!(KmS{At3I#m$4A!)6t#E>9zSxU=e-DMCPYqkvC9ngoC~j6E2706o)vMmAz( z(=B9TY`p!oWxeD#qSo8V{`S=ytp~TktOWjJuc8B?OpDw^BZ@3*|I>EF>R41JhulYgrc&~;vZ*=WJ5 z&5)kyI{HYTJ0VhWZ?+DHc`IPD71=A!)^OX;`%INoB?&z6Y3BOAmEmqo&ahS-;2&T? zc4U!Gn5!-Hs7d>vsB@LN`kGU`?U!_8%>mD*n%nfbz=o&W;Tb(MtB^xF2?zwT)($P# z2|G9PR1c)a(&;qjvO-$I*tvm+NUQwoIOD-M7>S z^}e?K?XRfnnhxqm#4f-l*Eialt>OlX`{sAm-Tk?>9+5p^j49*Xk3?f;53;RO^@XB* z7aNbiJ-!bq6tSZzaQ9368Baa5g?J7fL#VVuYH z+R|x4Td==}$|>8I{wL=hJf6>6?md%yy+z(;J|U^~Zo}w%+Ls>c&d1`XoLTDE1N@h7 z`#2Wt{nx+BIGxkl(l?Fmr%71cr<=)&|NYSGVQGQC`zx!k^=Etq_N6uzneGQJh%8%Y;=_LMvSY=Yi@ky#TOBEPF&^88VTF*-`|a zz{L!h*;FL~u{8*Z} zr#{lf8oR%qh}uXAYVbtGf$wZmNwH4>(0HKIx>Opm3OrRG z63LwC+L{(4n?R{tlkWuWQCY%#B>F!?cg-d8=UAAH? zgb>{d0)0ZUl}+BXiH_=cr&NNZKOUmj&K5=BGXwKGy;Nw{*Ij{Ag)35)GAH^Cvs?wV z^RrtDzB9k^9-}S%mb)ugnR;WSp~8_N!|UZb6)}!@t$bc@*}Ieh`Z>+ zjlUB?|G@dGh2XM!ViEjsi3ZW1`Hpwb_%7tc6iB%tC5Q(v6-F57NpSbS7Nu0A$5-d& za4Nco3c?-RV2Z8Ri#@j(%Pg@Pqh!QY6n~GU?-cy? z2K8{N!Px|JmMuAvzNGJGaW+j+p{J5dMnc9EoXE&3Ic8XC$Wr?zVb7cbq!e*42>Ics zzw3w`YkJAI?j*sDhqEhL1x{t2azRQ~d7Zz?Qme|qFYgS$2|7|JYax~qdde*=%IOTs z=YIwFteZ{R!UHCixvIhnF)7PK755k_7Jj)EARcLjm(yAYb*wxnGiP=d$yA=CPELoIUEm z*8HrlDz>dr{GCRfnZTw8k1mFD^(q*3^0U|pi(mr3RRio(MN4u02KU8a~P0%cu7lsepR3MGuP`%oOJU98H zN7ni9SXSnsCU}$xJjkxR=rOeeOa142k2=t%X|09HsK@NmU|x$DWhsfQ2KepA!UZDm z%3e5UMy;cv+-=qx^`rDhRS`~aq*BnBCWZsJc;L@&d`;r;^-cW52H#$PR&uktmS<1@vBge=}1J+RN`-{^gC zZ>J^pEbbz(8UFC;ZUps%sj6%;?vB@`lHG7P9AH?Kxonmq7lJphJP(HWU5bD$4SD~4 zD^p*ZD9O{J_}c&da4Xm%Axs(GJYC+2X#2i~V-`*9)q9@17{_QI#?}|`2i?vSQQ~~B zD1&I_1OcdU5PItt?k7nCn}JmJ9h!<2AtIt-y6Gv49ZD-5ktFRh$9}h@7!)^ySj#$Z zL4}@@iMiZ{MJm7@&qymsUQ~Rn)tw24pjktA8sJCNCS@JuF4PGJ_6S=zD4;6>V1Mxe zG8igZ`|^eB%cgr}9mdfw@woaQ1U5lDDJA%dKcx!w{D35xt$WTq>IJc~yNdsgzS`pZ(J}Mm{h*1DSc!|FRE4 zh8h^@>mTmxTR0wgN8bNFdSJ%Bf0evn1vRiVGcZ0gI3YSXJkxjlXK+OH)ymAE>Z0d9 z`Cym#tC1(Kc2!=1{|=l!>D!AQ{E8cR={(@BpZe56r253~Mr8E9&7QHX3nf zJdu4OF?;N0_P91-+(30gYZewuF&6rHBg)c#KtrJj%E2wrS*?LV4uQ^P1kRYWtLl)v|>d+m)AcepJ1)0KO9cE31dL#0YqnX zs$_T-Y;>n994*$9XMIIuKBtHQU*E++NDv7Ttk^pDZfi~vKL;X$Nsyq8r*kw!KmtGi zNo;;^c8&%;zdt*-T|RfRHGf92a5Ou=`*i+Y`8KhN*SER(b>eD_)Yy0xP6ZV5K9B7vFz z{uwC4zT^=@WQdRtZPj)M77%X2?oH-l?5OYnyOT=*6+ftjV5Jav9|o7Z(GK@nWZ-yPph)B9DM1I+Zz8VYaV$0lK6&;`HhasCR5fX zZ^-7LX{eC$wW^0ejBXYaD<@)WhpySwcU%6KwXNdhcdg!J;Q+bx*UNQQgX?fO4r2dW z>@EYS`1IYVF}z}}J*V|LirjBg50NiH&{n;32#xU*2K{V#_r3!1?#nw>9OU;u?Q1RY z4UYGTD3D6k_Il2HYTSFfo5YJR@UJ*XDhgyd{caAtO^YF46vwn71vxn1<+75S|LQHg z!Y4DeB^MHJ-?I=?gggr>EHFRp$VBck<;gfzjj)`xDfYSAL_N{W$;$mXB27egRb34kgA0RGv*U}+I`;Z`D!s_uem$kPJ`2(R0g?iKneBo2 zWiF(FhQtC;%+5)1mHiPX=$|>bCy_J=&8EErTe=H(T!L=-z*E|1v$5&wm{U^Q-Uh#q z_qR_zQvnHZKK2E8FaQH#)74JTa;v`9wXh`yoFW_%f7?04v9R7dC*xl0p;y8A-td~7 zj&Dc9tpv#}*X(Qp8)lxwj|w%;O>T!{W2?*E)G?MhU#HqBZ-;KHd`sq zU@RpLy@YYNn$L?Ihm82mT0KEy*MZ(5o5Pvz@4Y+>f z5&#fop|$5Kl~uOIp|i?x4abgZl{Vv>y?U?UEpXWM!MCEt zi%ToV5_6#+48PTJBZb7@WRGF>-MfWVKSQ~I{`~Bjh@W8ulJ8nHgWP{TPu^XJLiDkc zAyQuo32cMU*)$ik>yKeFYn$_S5Tb=G9LS zw5{h9^QR*C$OI#C3cg~kjC&(EwH|2)zY4Y{GY|d*#RjkQ^})kn7aJXhzsQkA(Jq%o zwG^^0u;Qe0MP8qW(+ybDkjsw4-!^4H)?emF#LOqgPrQBS^@KvKXEU}2H$Txgd>Z|1 zD&>OxeermuF+<*};i*)Olt9g>l8Tr|rK z+&=0Q$a=r+&ye|~rzQ54LS*&4QQNlrLNy`}U8#1j?Hc>jJs9IqAW0o;-PHrQ?}T!) ze@pQpz1;#F6=Id?F?@`<;&reVNf?g+WAW~6&x;2*2n1+1hS z2(9QwxkBjLe;5@N(k0E>gWtY72t|Q}k*{t&X|TEoa@DPPYTp+}xmi0a<>K`~>0Y1w z*Ejvb<5!fb-DZ!{$yykqdY9_d_;xOo{>+rK(Y_~KMFqOdm+>;-k3d0tlMollpKulF zI&h-r+zF=mDq75WBgjVQYgRyw zN>D8w>Vn`~EY^?KP-D70C77L*s>VAa#SMu0dvi&5sI&z6as&iNe4ZE@dbe~vTylA4 ztR8t?aFnT2j)*2Hs~4m^J>4~@I>l+XWraZMz%v5&PoXM!G(A}H0DYHxA|L&kBc~B+6O-m5{3RcCbtoEPj9fPT<()-f!G|>qQqGJm&q1GJGp&!8H6`m|$#uq5S)~@b_{5QbrIH(_&q_Cn$3x zb}}XBBX)C-zsPRfzhM^nF&X2nv}kZ#D7#591YqRQ4Y$k(3pMdFvibK;+q?)UT2r%DI-zLN>Tf1^)^P6&U`7PwCSo=@}o_frvM zsQ;e7vtLlX82a=m=9|)I^MRA4;`nH)P1wH!r@ggY8s9%qzrXtDN7D1Z-^S?t)y}4< z;|`LzPOkK?Fgs%>;Y&$(zs@sZ4!%<*{v3G+eXTzP9={PyP5+2WS_ng8=bvz>eV0^Y zV~|4?tmN%E3{=C0NKzML52Lrg?(1uQvye=jX5#|Vibt5P&YLek_Ad)$i6xRr;FN zM8^vh^o@KoA1XhZF_z23(v6w~s-KzZjR{%{JFzYCC zQL!Z^D90jV;#Sj9w)J#hna*nw#~ECDQTIt#m~|m^xTA&-52%SYFJZquD4VKtQ_K1_ zQhY4-uw`>%ijPxT zsmvQ;t-`TiYTEFKR2knCH)IiD_Q;%yanp-Jsk0xE({B;!m>hG5mb38x<$Rh|)iPi+_Y$8-NVu-@8HHj-5 z`ma&MFg+=IvSjuL3h#&!c8P!#4GQPLH!qRA1TdpAF$2s_Y{b09!BhjDtq`udk=GCE zZKPE@4EGHo@}xNUT_50CXvCzBUjXeRLNZjadJ<{I3L*tm>Zj(xEbz8MO*b4p_5)dp z5RSB!2r~8|jM_I~+RR%?(1K}zmjINkl_(~TkDN(~2(DORcT00AomaotUimKtQDf4T z8c5aR{JNN`^{JZDkhC)~!wn>C5Jd)^WPvpVuu@^KkB#ZWg&K2hV(AZOQfx3~EEdkl zY!taodSH-Ag?k!?Wlfebp`$5)geDsUr4xceeN5p(l^fh}{5hk+I~je^=n+F4xTX+w zAjo$ej3^iHK1Z{^abo%TdkG^70L<^~s+o-f0WEOK^eFO-Rt10x?*T^Kv`4OeDcAmq2*=CQU!Z(F*M}(A z2O)G3&yu~5?-1S(0)R9sMT8DTmcK0vYcdNJ?)(F`eSZPepi`RZ5`p|8aDxo)yO7S% zq2mOuPE9T4X)y87wy}4mn(Bv^iNj|ITIIFEKVK_N6?%ip!e?#_Tpu);K`5>WMxCmU z2oKF2x`|QeNK8uW0XPjnk4=3e=a^9B#z;*D zWF`EbzZ1ET1hDtv>FJ!e6FE;r@KYA2pX!pazl@$i7B8#P^aQ!7b@Yd;uZ=pv)uDq~ zLDtpH96%Ubb#iMGw<%5xqe}mGYft~x+Mj3N&mq8PMvMjk$NdmmjhA#`iYG-o#4!=W zm}uE@BA7 zuEMZ}r?A%zuy{i1%%uz*sV9W?OUB}^V4=4HLS5WJ)|ausV)(9L+$B@!xdI71UFqny zSB4E7f(OxW_yIshMnGsX((_ALdRkLDI})RiuSsvIs&9@_)xk8BWU^eSp$afkP}Qbx zh-@dM^FYlhB+D;Z{p+o);owXj7gd@9RlPkGg<(kRftoR&mO_4J3>4Gop*J*{1zOb= zPS%|%$?O)=Tl<+cmz3$Oqs2Q4c~=8>_3+|vgv$vf$)=OIt>yCXgHYBa#`s*!Mx^g; z=hJQyWAqi!3v;{Gt4ozL17G>%&Vo za8~kRmQ3Mxmk$n#;MZlg(Hr^9sB}sXlKxerR2}2|0s*TYRr7l zP25r$5jWPGC2;i282g!f!1mcXPDVjJ5D) z0lzsHL%FkS`H<4hOxIg$mL@LWjo*%%PAXZ7OpnxF70MZddF9L>+ z0vb93Y5+wPOB7UWae4OHeRt>G*`1x8{TuSbojKp@e9jx2*W(xVb)EL!IU>I~zkhz- z|C@CmL7E8*?$ZLh9i{BY+^&fN>U*GY+c;UDOI#Fx5j@ca9iV;$;<5#fp~2u4kPi~f zM)DRV1&iAP;wS)3zRH9LDl%{U>Vb0MYw}1imh2iiB23;Dp*|g;*9Vo)0l&AnEJg_6 zyAzmSR%q}RW{dIlBtUIRiO(C#7~!R5FW#zq)&hkYAm0-(7$&(W+fYYy?4^le!^J5D?0oARnTiQ07}0D#nwY@>xXsAPxyN5^LVFrrikrm zX48GHl!SO@#Ao9|-FUA6wwE|A@bvNlt}*~KuKLIsAw=<4ywHT<1DHcXoGJcZJ&iIM zml~{mP9EL%*J@VnL!`MN+WaqFF$#6B2eF#B5XP$7W zn-IU|V}8w5-VeWivv|+%{ZzEs&m!*=**|Vae)K8NaE@;5k2Wid^o9fLce0x0l8pso zK23t7Fx--6h~l_}X&NK`)*Wdb8StO=VBmL{AmvgA;0>pH<8oLs{j>i0Kd>}u6-2^p zNoBzncqqg~Hs$~w4WN$KyblzZb#rck-SD*+DC7vPcFlm! zGe26djdkb?Y1gOf2$H~ZBrtn`wst@l$4r?Fw$osy%jZ^O?yZ!w3XRzqpv|#6>OkXs zOSk_{r(4TKFu5ynvD?$SCoNUaJGaMKy=UjRJ-yMxP61A%L3vmRWL}*a(+hM08le*8Y=MLsUeGU=jwGO=jGk$%-nC?i{V3;~11h;`$U3V3(`UNjgDXyM_Z^H4*t z-UI*M1`~Mb77RoH!qI&HaENtgWZD8EXasSalP?mBcrC>DD->}&A{%4N@^S<6Bn15x zbX>e0`utmFBUgT+MSaYAgfFj=YYZ?Uz(YY$Q|gF^1gHx8Ab)`?js_Xn=Ql^gW9?+G z5h3PerV`>!AXF@oEE0f0MBznB+YyF#@KdCR2pn9yW)vQlTX_j-iia|yY~gK8{n1pI zK7r{JOVKkQR z0Ax5uEO``hWQ)j9R4v<|nBSP73iU%;2XD0US|>j?z)ptKw^4clSz=^L$a1miP zJSU$!#q||gCWj18u*KY<29WZGH9EQDg!^~t5In$ukDr;ny8xdHoDn$a`pZI{_}Uf4 zf{dj?G)ZIKwyYWkvkjXQQ;Pk!bRfW2(H!#Jd>}gr&t`MHBu#`zQs6lHKpYoa+#lAf z$=vxhN_y_|dA91X^N8XtImc1p4_Y-bbh@^1VLFh_5MYWV&+!=oLgxoSmAt%xOO}bK ze=GniQRKKy9Epb}mQS(gKl4xo=@6OXh-XlEs4f=c@@H&V|3M&n#So*Kg66vxzI=*~ zz@b4;w;%}mGACI;X^6*$4EZ+?rw$_QSfQLas4n$k5PBsb1xTVX{YU}CI9Cf=1`S!6 z;t9`axK&*`5Pg4X+jyY-g9_n4u6>s7L;+@);Tn=KH;U(1?4XvUoyZ-2Q{Du>>00z z2oBqV9abp|R+`n^66Di!@HN`xGWw|aVsa`C={W;yTQaxa;`tQhaA8TXC&f*Z zmu*{I)XQUM68UK>W54r?*D<$sxwx6^5e3|-kUq5w0=MvK+FVxogqC*#V07T}`O9}v zSNy6$iVSs$PreKr*G!9-c$&vj2L^OXbG_HLzrYT<@1cpnLc@hLjLE|d=-xwCDI=h7 z-wdbGg9`c18#ye>S4(jz zEz>@wvZOe+>eMS{u|CtUPy4i94+*j*!?Q}D<-@)_Gq1rO+YR)E+metoq) zR)1QXs)T*fn;oRJ73vg!Xa6wsJTm3cbjW_2CxV3{&2$FgMR{+MJll9u$0HtOO$WvI z#HJ-Z`28Ie7PVnwN8;Df>snz&(?Pvau!oZYMsYDe<4|bIho>i7Z@u)gxC8Z{hFX%~ zUu+l=g-t=5^`9g~Y1N;Qw@6|PB!HrUnMDF2^z}yo3RgR&Bctq(9bxL&&nEx@?Yob# zo#P3t9lu8(+tKp~%sls**#9yAJ%60fUl#hT&1sXaY5`n%j?jz&{ay(UW4aBc#MhO; zP7q-Z6n~y~VJufK{b2&o@Pi`3W`8XoA-+KMtdM!nP!|&U-!xHPJ0q?)M3wJd3H5DW z>}Qeh@I>O3r@Rr1+Mf-7gj@E$7H50Ub9w4<0xF3HQ^CPc;-GrxAu$A=bn$vJaDovpVG8v^9EmOc|8j~1lvzqUJjbR$?=@kd!G!Ko>S4j-g z505@|5cvIwB_UXMbQ83F?WvHsIU7LV@tNXKZd=$4?SPzRhei}QY}Vf|xS<(sMP8_X zi@0<0rI9gqy$~Ss~DyUw$3zjEeWKv07fNfxi*}$>5~y};ErMF zSB+l>gvGmNF?4d{!PS{6ZlZq|tqW`-YIY7_U{W+%EE??<&!u}W`T(^idoMd)7kkeZ zj@@lG8y@`W|7hLdaroP3tp-6ke_iU|p6fa|n#qmU=(j6v4Ll?PfM!H;MzRM#2O#f7 zDa;UwzxO3W(vKyhz(SK2E}nb@4TbZa=Js-y4Db7rB?jn{F$&1FtqDRt3x&dAhB$;c z?Q~HyZ5wIMcXEvr_-jN0k0u~C1>;^dlIkllne4~59t?bAx;oR2nF(2w6@;!fM}n># zEz7N2bQ_Cle^+G#pKn`}ywh+`)k!jJDOnnDWplaWmO$Uz5EC3PbPw_bgCmpFp`nH;9Det>IWeL{~=kn4+xna)d)y z^L=ESVOPW-^A0r)+&KZTz&Cu_BYQR<+_w#dDU2?>x4e4m3|Lg5MQLld{>Gbzk3GA8 zkI6IINmXl+Y0Q^Ap_e^V9|s0}*TsO)&FWjwe1g%`Pz3Eu2GB^bgNp|2C1>*GuWU@o zYtbMXqAe5>dGN>>s!{`-S)Vdp)$2$R2~75ek6*BRvuu&8c_~u}k4tzk-bf0E*D1(9 zM}Rrk?52i}0ykAFRmQ5({E4)3IG@~gnO%qT-RQ4wNinK8w~&((CtRX8LGVX%JJ#@- z;H2V6Q3dVudy>+l#^a1Bu>qIrk-Kvt=IkzuAg$H4m7pJz>oMzDAQ$(MJu;={e6u&E z=*eTwlCvr4ycpl_WjkGWQYyo%<+OpYNihET)g@LP|Mq6^>J#3XniS)Ah1v^c)eq=H zSK?%$q!=Yw^52oX{EfFPu`i7v>>2o~lIY>K} zop&qVK~ic75y2?Jni#Ixe(=#58#Dxi2fk9^W+XHvw4Pg%x(q^vWI>229IhBsPJMd+ zK7i4XC?)umgaAA-_39W|3dVqZ2kjfGj>h6p9e4ne(8jfVhads|f$**bgSq%k1w=rn zK;jYR20&)h$;aFBCmkBMEIBd8 zYzC%89n!rs0RQvy_qNGJnnq$|4e$+{WNVMz;Pl9~WF^C;G>00fXCx*ItLa-4dBnhp z@q~c*pISCKC=>4_gg}r93#kPf;g~kOy-*AW4DF2_o3Xh3kq`-dQ}VE9KIiz<>@LWn z%;Jx2cQ1-2mCp0z-Y1$<^%CupW4yIjvkw@$2I`22H-+p1&qc8`hG;a|{!UuWti9}< z%{dMVkV1h^dlK)2$+rIdldZ*-(Bn^|m1G(xFkP-i#iNrY6F-DT>8X>RfD zy6-%>ns$NAEpX5uUQjrmKj3#r`)Y^8z+Z*7wY1+^e0{|am``tH?m?dii)bl`-LgV2 z?Z4<+zo0f5ZhAokR9jQiq(O%Q#Yg7@+!)H!{tZBbO#7X4;sJj> z6E_K+=VG8Xmb%#@eF1e|n}-5oM;Iq&p2k|O=^67cW!vx1s4CQLM%1%oJnyYWx!va=~3ZV@$c>R%5* z$?a(Nfv?=1)r5R`cdxt)durwLEZce;Kc99tzOJx5%+Nd>VGVoPNz#N#P8CH_vuwI* zgsQtZR0QV)ZH-VJM|+w(KNm`UTB?4yLnK>A5QNsQMu=RkL`=w1qs_M$fsOB-9{yVP z<)tLKaQMQYf-8k~>TS_;`<}lCR*@WE56j9ubIm9$1wa`l&6l*c02(^y z^~rumZ|x&n9|g`9;B@uUyh+jOi&5*!K+yo!3_ULejVI_Z7L3s2pjnoZw^<+z zP}VvfrHj=xsk?g#r+59UX3fi-K%&9C+0$>!KMue(Q@+5bc$Vc=mXOl&zaM-rc7GX7 zysR<%PEZtlOOgT?E&yZ2rB&__;_IZ!6w+O;2l5>$tR16l76x$dfde=+lN#Aj3I@6>nA)B|2o z&==Q99ST8fjjR5Xhws*eS=%+nq(WC*F9Wn*$}ptnjPZ~jxC)Jb|0P{n)t2%0+Hh7u z1Tc&F-0C~BBO=ZaT_Ula2#3C@3p@JqAn8CkK2ans=%RnaU&hh1fAD$ca`B4Z;WiAU z+7W7c0%VLw3x)#xs!$q>*&2FM&>qdG$4A1Iy0pmHwDp z)25F*pwKfe6A1m0{FTn&{!ZW&=jV|@WJ0!5hss*w16pT+s`Zn zgIb7lJYX_((0UO9Jxvz_q@*3TkGJQX0tqLLN2S*~BLO_y0qs8#h=N*ZU8CU*2^skw zX-PHJW6>}7D@y%lw#1mxQZJJUMY@d??yTx&jFU52U_y|AQdzV?nDHJi_bpxa`A+)C zUY;Nn-I;-!EzQn0=LHH?TYNKgYs3>VoXcw&7di4DPou1E=6Kn{@9Ug+&?kOrv_PUm zDioWTIvJFCbOU&Pt@XQgB<0%o6!=eL_-_fHfOgCY2lZ$`E4Wr2tdXtrMf1l3>@);G zriKAztQ=zp7K(M_x~(St8hZ+V^W_h0FreiIapyLH-tYEo1qyX8%ShX+$eX}NR#7F> zzPdjPzi!|3paNp4>cOGLp|=Wg2Led@1W_)Htf?g5F_`b0G!EV3`;MxvE{+*UwSuwsg`f{cZgP)l2{PxVsdA$(#2>Qu_ z5t-e~Yz64(v}AU>l+fpUTIhCh?4=v^rP%+b3?e%@(NqwMX!tD#&R9X%!B1`E!o8g?6x^;L$M{!fmHzF!l;l#is~eb>1sD_HcMehN z|H-*P|3-MbiXaAPV4NHDMS_QO3oSZwV`*T1yTt|z& zky{1+#H#HIHwPUo2Lrn9odw&T6_u{IfjfhIQgP-xH%E7ME6(~=$(he-HXN9zr(~T4o-m0V(vRBuEEf*Fl3mrn0w;L+)y* zr;b8+LSzC7=hNOH>^fLk--DHL)*M!HhQG9I+Rrr~a(fOK$Kmg$_%bf0#Z*PbH8kzs zphvOV*f|GLO_XVIJ#P{m+TF5G+pcxP<;*U^ibGnmQQ?>y{14$hw<-SbZy=6$OW zJ?|XM(ReIVr7wqs7&TfRoXw6^b@@{F#?ei=`I;8R!w~}Ql~!Taa7p;)oc;}h3URNQ zKz09OIYp7_uxcLh_M~tAQ~NiC;(kc#rbly;3#`{6zt*8z^SNG#(AUPW>ShbY-ZcV6XfYW&d|zS4QU zr&E>hf$>I{jhnV^K$IRWtNMFa#jYQY)RC;web=eGmbcqUsOOTk+M#xjPe4z>g`TSq zd%T!?j&~kD`-gbcfg}J6#y1qf0SJsn36X`EO1wq!cqaNqDScBmtZ4xWWVGBXO6w+L z0Vdntkd2-*`u!zto&NO#ddmp)H>QnL;S##(ixI^_T;D37yJY0+maaFK0=B#|&`Rnz zi|jY%Q?dRE4j?m`=0shyemKlb^w$DJG5A!h2%~WZRVOjPw%=c%3eS}=MY5^LDV7h@|UWgFw3rG}yT9hjAS4ywxH}V08(35JQG!Nw(A}EIuDWEEn3t?TM z0t3}BbOOqeXquKV+CVexd+iiQgMND-W(9%jQ)h-h%$QRky7ZaxKQnr^v&V}okKJd7 z3}&ZiXNLx79}Uh5R?n_{m@y#EvDwW&6`o_Oo?FkG8%mg+5T1RmIJdPqJG?o!YB2Yt zVs`h#-2R8BRQG3xfzR}DPrtIv&YhWi{O8$s#W@fwb+I-0X~pb^4|8LR)a|@y?>3)) zYMm1deM%pkoe8}AjiEUIn`MqAe{P9oZVwaa>@YoTtt(C#$opV&s}t4mRd2u;In*Ic z0xOQ57tRCpS^#;r4~T15^p*<+o`RI-)s!yiEOZ#CLon)nSGkk4IQ$wkN(7hB8!kI| zEITDGJ6A3{yzq2=v1~WD{IqTv@1fc8e%a^aG7+|NIdR2lXeD57B}8O3%y89JDe#WC zu5toOa8@UpRj_sjd2>;?Ct3ap2k>Y?c;?Gv%^?A9_s7*^g9b02D^aoy=X=>|sUDUvCcDXk)d0@ONFu zX``cZqx#A^<3Z)d{g2?bpv|eE&9TJwM~RzuIhzCbH=Yb_UXizb@^O7e#I9p#qeEn~ z@8jn1{q_4VHtYXxHUz!sJ^S+C()x$LFWyvc%zA9xSK3@xdO0$;E=7Iuh4s~|pv~7W zHk!`XcNxC=l=!NNl?Jk*y)k?>`tc=#&AM@pwiNV&Mf3$V|K)bjt4Dve1<~Nm+*RU7 z#PTKJ9suS}fSDCdB#E5vZHK||W3?bKoHpj6v4fW~bG9`*`x=yi9(OBJyf17Pb_L%m ze0n(yNPW2YbAL-mS=an8*qlJvRL6wTpgDdGNs2SwJ%Mh+=UqGlA+7ezYF^@=PgJ|1 zr@WoqXeBbtEWqhV1QD>mKz6`-JD&4)a;5`~XB;C%yGbvRmU5|jb*sup($G=a@UtP*XP75wgGvSm`VO|IZzG{IA@>ng4JH z`saNAzgh=6by$^S>)`%r_5aN}aPz9sIrIO*I*9qdS_jRc|K$!^3M?Zi4E`7862Y|5Mgi&5e zCa13;&s&(VRcYsp(#qC$0Rn&0A6lqd7N|US%fbPzaR~|(N}ZKxP3NRA-BPk{3+zrF zwJZm$*!We$c4q~yq@a{cp59eVfhNk|&)}v2saMmiibvR87yMGtn*oRW|YYwSiR)#YfNXYt%!WcJY!=W4R9I}D*U)##$8?pWNHJ{FKpTJRZcBuyPS#*jy}rCI$~}~pmbAI_E;o1AQu>vzc1%>+?GNqvdVWbk z?)td5uYI2&%id*L1PV`(3(;J$g%lBs4&s#S1`+d8Vq@!dUA3>Cte142Rx>jgKa9ML zRU5XP%)j}`(XaG2Q|&w33jfQ?>iVdK9h~2ust}Mc`L%&h>&R;gs{EmZc77v~EF2GW zh_)nWcAN+dpNg_#wykC2@t2*uS>Nh2tM$88s%*IbCD`0M{EjhJcz%cDGl0!(12!io zp!g3yyliZmr8`z09Sv_D6mK$n4V4l@R=X;&*i;rxv;m}i-c!M{s~qgU)(}*3E2z|) z!TZMr^0K~}C}^~u{JMWow>ZO$T~%PiRQNxx0sDv3DOMi~NsZEK;nSemQjBfq*d5%a zq9Dpd?MnjpS4HA8Vj0JwfQfcMZSRpGSGP0=9Rm_)qtkeSW?APmAo(nOgg7KE|FevD zZpinwz{@GeZq2FDkfxyhgC5&Z?H7tK#$W3MD>U$^<1Sukol^&ex-22Lon<|L>=bPV zy(_If$*PN69zCl&X77FGERE36Jj+zj%L=+x%WwPZO)CVlyibl_9MEcC6}_yxPNu>& zJzg#R{y>4>t^7DXrJSHWaYChCt3OFOZqHLp#-(OwXNttBWFM{K~ zzrKA=|HoeWXXan;O#a3mb#^(-qs~Jm@XSuY?_U*2Sq8up^bL`{E4iOfKj0gx zA<6KP!SD>U@Kd=J*)~a&szmu~l0`3AgE_{x&z@mIEKT&%R#ALx^IRM6?kXwYE0Q|d zjy|O*@uh7oyT-3D=D^bHh+&3;a#wr1FQt`0@wv?Pp$3rYZNB^;W@j`gX}m2U^jq03 z?041#mBTa=!qNO=0^X;SbVo5kqP1@Sj$5-Tos z1dco&unfETrqM2+O6fJO;w&!xx`TBk8^=LAxaNd1gn~yN*nX%VZK)WiO_VOFj7`JA>one4z=4mBRj-MP$l$mecqIXYk|fn6O)+La(L0 zK9#XQF5J4CpuwRAzheePFS;o81fs7fHgb&-U+%qQ)=Co_GtSg$wRxMJ-qUfs+v@Ko$Vqnx4O5HchH zi~)Zo*V#|$X*J87YYtAxap}!k@{#gx07xLAKeSq73W;6Hx~xiuQw^9_@!^nGkUspu z%#aJX?-q!1ef(oSSE47%X}L5w>~iMGrDC*(uL&D19nMt>Q>yfyF~>D=d!fE_)_eH5 z+pacFt+b^Tjm&Z_zH|NXakMgJ?VZ0cIb%k2Tg$MI70pjBCRRttz4$`8bWWcrESQ>E z+5B;TR@cqPiZ9xtxHaWN7Xsr#ICsJ#RRrj6@ifh8wYzdnt4-*RK&VE1zLNYU$$bOZ zeJc)B)>*!V^h}APYWVAK`vUQx*}H9aL#z1DyU@4^hS-zU)S)NKNJEKUrt)auYK!_qUpRx_6?sLGlPt9sJU>z!kUW)! z8B2|CZ*JZFb@;Yb|HWII1m;_%&gD%%zdmqen2;^A74Ef0EA<-KKWLZV?Q$?Z9*-W3 z;W0LYlP!$~9NAOqXuuDNvY??4MsG$|izh#wZ~vIlv#~*6f%msq4aJ@~CwN)oootfu z=cJvnmlNvRl%UMdzeep}F>H>k;cU<2)GG>RfNmv&lujOw9ziubop@2U(08GK3b${? zC^4Q$=qc1v1XX6IE}ozl|E}f5UK<$*QVpCd3Nxxb6MNbH8nNU+IR3fkcnNb-uK7E6 z0g2to*hFv&goam!D63wr`fo>Ez z+S8yKD#-tA6sGI(dTq!3!?@6;FUluMSj*;DtzwlKGi!)vQP0IW_hc7<#TL= zS^P(}njW1(motxcewtQf?Iw0rW#75_cG>21(n$=_zy6iz$6Ih`)|k(&)6ewWN*2?~ zf96M88Z9+VJ)J`6UGI8pZ}@Amx#(8nE5C;5Yh0@4eGib&L__r*>wfc()cyq7fB!KU z#8?d}Cnr`<*nhnckFY?2)@`49;T@ae*5L0Ew5G*cp`GJhm zF&5_$y>@V}5f~VY@gu{{B@jGoveCU3b<^w-Q>^2M;ww|pTxv=; z_)&YAh|uX1j5m;KUxexLc^DCbyCn4Y&GFs>-d!8C*b$q4B@777SfgYy;BHq(B`OQe zVT(BiKhoOh$$z@N82wqTw*xz5fIdlK&?$%?7~wK zr;$nO;d9qLm7Db-<%2H`1IuE6^rEx7_1Hub4aEP}0ebG zc0vjo;I~UXzWGk{_6;JZavAx$NF&V2*EJ;53{2t`#EX4>3;BLVQ>G*qwFPy5hE|o> zUeC~U?L;tBAa5iPY$S-=j!y|Cp}Ah*$q%!Gds_KhCC_Owe@qiGk;QW*#R}VbAFhg? z$q0xzU9-?FUB73h zQ-jLAu17`y_+HLm(I-p8%G5Qb$+5v*r70n&nFIS%27V$tA3JqCFNd1vR=?AS_m%S@ zDn@>mPb0&EwJVrp?@YQx&j{$JW}z1!S3I|1Em=iLX=^#SAcZiepBIL@M}*!EseE8x z`MSMquMAOaey5mPY0z1klZ8;qMqivdt@;?Thve}I6L=qcJLUOZl@k>y$CWAf9p=-pjx= z#jBR35}NYKepg*@l}gsm2$(g5mUj{WecP0LbXxwUv@G1ICpBmDD9s9Lez~|7Lr62_ zUDI#UJ*JZ>6TV4 zIdE8zN4@4;>SL>)Apx=3EffJWp6NvEZppkO25YOeH^IGH-7MW zU8f2t?bOv+GH;y3+a<53rCJI3qYTqX=j)N67F}uf01in)v)Sc4^2>MFARwjG>*yB3 z3#;It=#E3JW~6+!tzhLBvyLv^4#jfk-m=nST(i7eyvlz0zo<^uURw;mQw~w{f;!?@ zLeNof)l{g|n<0EBc14UgrchE7y%9#)%C^64%*(?dRPJUw^qH1q<&Extd?n5E@K8X- zKNNBOe2-k2Pzc56WNf#bc79bTS=rSPFVxf2Vc)(5VIf?w(?|4CL=pS zHXMMNj;Q$FHR%(>su)-p=216lJ5s93H=DUIC68Q`Nw{YQ8R)_ctl$Pbija3N)fWV~ zrQruK4+na_RXxQ?nQcQexS&aRsM$8GOFz$Il;zk!7~Kc-i6!jVK?5wv;MhPQLR`iM zXWa&m^@GtCz@rW_yFWPba8Qpti8Cr51Ub7x%Ck$`@ z9)1@;xVt~R(K5I@1Nm64$wl+k3xOWQKk~C2)IWYC1BRiSj$^rx#)Te1kH0-aLnsQw z(PZRL{Llx55v1Y>Tg3=R;PB^%k6vvIa-A7w4;=l*$Q|5yI7H1I6=@w7-W+A@kIa^r zDE}FLsz0Crs5`0!rnJ{CTqqt_aN7d0qoW`=2@{^w6iI~} z(2hxji*D@`CN%hIk`R7&;z}Oe!(h@iZ_=lA!d-Dv5H#sIIO+A_Vua%4)r!g3yvbO_ z$%}s`O>mR$n-^1Br;;d;z}889`lNr}bYulb!RDm5JM?1SWZIdjgoG&*+sBda(>G_Q zueVOckf#|u)1{l!*$ME>*~#+b4O{o=+aIRG6{m^@C+jMv67f$8TW7L2r|JhGt-?<_ z4W_#Xr~PIhhqKIj2~TI9nT1Nt0*_0zv<#5@q{`jad5BzIpnguZe~5xV z-IxEaLEA%#Zw(NfbTB6YB25A~Z2=X`GfvDi7zV^f2kT&-f#~2v;b)v^;NTA!e3trq z^Vvbdvp=nX3W3Urq5c%6GTf=CeCi(-0CNA?rw`9mXu$FRd+xtfVWoNI#Cd6tdG4Y4 zpRLrx!3C%Xz!5?f&R_T)xNw-aaOnPwxpI*$e_rF`qT=7DN5UZN{b%AsRE)?HlgB*r z{sOBK2!fxt{kULpcF|ht*-^zjOlj#~#j>Kvvg(Vaop?5_wKJh z(ylLhw-)2^{5_?=~5z%DD&QyvqY8^LsZB;(Y9-M z+7Jy-eg4Ywa(;mnQ6hC|>6MY`E?E$B(%U@xThoHA81G%*4Y+#)3nanW zy@cr4{sj_eyx$LomJ%Ks;vmRJ^n4OiFdhD2OHlSAvVR^52|~mNyzi){zcg^?eTC4V z9iLN!e2cySgxH8-F;Au<^>bfyu$iMd$}*3>7U7`rc&;r21Ona1J@6T%jS9WDL2lU` zJj>i?jVb1t$RTEzACYW~yi#mGmtr_%=-;;AsFuit_#J4fvh4AC+q?+dTL@a_*^5KafH>sRzA*nJ zDw&o04oZ0T`DqqHRBV;v*J&OE@Eh0^Y$o55WT}!d`9*&YB66@A;CPz?xSqY}7TcPf z3%Et9vM`XckDDJMzZ%bD`9)ITzvkATs8*>64I972M!^4}HH~3$fJM-{_hFY}^HP&T zOBJVC+``oRt_W8rc!&5U+0CU%RlS_|%3g??J%~uxArEa<^!bWgmV`qAbSUeCp z4*kT^L*roe=Yq2Zp4olM9KB|jmc|t`HUR|&YEwB3_CmJU(~nNr5&-FKMBb-08kEg| zs_FtosqJB|YyH)>vq~tkT~At8T+I~1fs-w>IQysbh2!~|C^@`&78kOdl_hHRO)7NY zqU?iI^EB3#sjPVaw#PEETXpcO6=RGp%d3^s8l6rW&sYdP%J1e){!d+k{a&DU2-H*-!1?r;aGe1I_aHVg0Ks1*VdpOhLr({yd(>!YR4oht6} z;;&B${6!M;(AZ|x@`O6Ef}aZ1`AK?|q)LiL;UuB8Yq<4>$^{#R%a%{ z6ftvIfi3p+&Hq>jCB1Wfy|;s(#=fn(&K9?qzsO41skvJa_ty1cr{0PCtFr@(&X1C= zd_XE0$Io_dR56eE?iR%BQqFCz(8r=X^iP!C9*&sm6nYT;_0fUoVAND_*x;esZ?=bz zS^{1r9!=<<3J3IGlg8K#K2T2nes>Te@q54b+^N6xmQ#<|4ptvAe(in!eDY8G=j-3% z@BVt)z(_spR)O!^DMBD$|KwKv#}#o(r~{iOJ$M&--Gaio&Yo=W`Yt4Y z`Vsi0N(TS<)?c-l3F!>mOvA%hFokJc^6VVKHBcP-$oI6AR!ELf1dYWqW}N#wnPA#_ z84zeR5|Izh@;#&>c4BZUlh|CHds`e^nHGA2oY(bqz!IRJBOJdzC!$QnMB!`ZD6@`& zH0~`Rz+(L9?|fR=A&oUP>-675VxhCCgy4n8qelMJq<7)3K|4B+f9Df#$mEek-u5;# z9CZ~+#}(^U^L1x0%ZHcED*C9EBjT!5%Le`O{-@Crx5~d(_~`6dK8xc#xO24hHvH31VPP5$3@yeXJqf9tXoqTP z{zfC#Un!})ha{AAqlri}mCpiC;_3D^XU(z89mdpfVwy~}T^EQc5!K9wawhQR`Mj`* zYU##zCQ45hiUhlAIP%|_GOyd;-sY||z29gmU`4HZd05Zk*l40eJzpYvc#oaO*C=y+ zzRb9&S)th9Mmo;ELAks7)M>f%+Wt#zo{{%?D}i%kuC|%}5w-G~?;IE9omv@Ri)y6q z@15THWt)-2eIFh9MB>vO`xcw7rT|Aj<}GNu=I0XuL~<~75UhD@zndJTV@W8b!QaFVt^74A2vt&f|VDI^k%Px!^&zedacIOU#7gwf5YLEIa%&jF?G{w)Xts zydB~Fm??u#sD1lu>@Y2)whg*WnEOJy=6&s^)cb(iIhtaa=YhqjL52YGK417c^+ zJ9XTCl-IML{8P?dxwGt9-mXTAz|7@qo#l&;SIme2^YNp)CW>%1GL!}p!%`kv(B7Wr zr$OGy6Ci9M1n|*QAj)&R>i3@>P3yP?myA)aQs9l0j>}?^Q}_x3v)d#P#UV(gl%M;k z0cix7FW^l9?P;kJ|gzmq8$58R*9G9l@RDQ}-v$QceUvFv4dH#v4hzVY zlERxZl;x=s&lS!FLUs^f?$v%E7vDpB6e-w@AAsf~zDXP_3!DT1Dv5_e`90MyK1_Z2 zeX@6v!unO?1PB!qV#3++7bdz&9~? z)7uLPTr>ulC?GAFyRvf>pl=KQ_x5mr(_)BX>L*`v`c51E7U@Sn&S3tjH- z^fW1{5!PVxn9xmX%uNLlviyQU@!fim93B7|)!Le%8r-$WXwv3uHa(_kkAs-gUZ|#v zP|%aP18Qf|AtcL~>4_n*e(NFRo_Qj7!Kq)&!mr)}6ySXw{yoUT3)T1x_cT-VbL|h0 zopMrSZ8td$gcoO)bk>A*V52&o2{6BT(D^ZOh!EfV>Z!vK1yS%Z8GI!XGS(9gvLJy+ zRsxQD?7OQ07XYv$B{3fx=tcs&(XPX?0^QyQKu9n*ELed|C?F+1+l>`-_Ex$IKSzeg z6a4a~plOBBINP%cbZ9IA{)#E(98=tRbOgdSoEZbN3jwu6gC6n436R6}bYQ1^Qy2JP zg7o-W?RY_YDnJJKaEbgR5Cet<^qj-35Ws2QG=3mr>VkiQF(8Ob?CVVRh>55Eh)2`8 zGcygZHF{y9F8)2OEAsuKaEVt;sWLwkTBI~sXc|HGxq8?GeaWY?$45Y;kL3gy8z$0r zFNr7{kkJV2!GV82K!Qi0a5E491k6MQUe}5GHJM$7$O5o|@+7bXHT#iPa?fp88dLQ7 z-t6dAWYSTndSkBbE>raulLaC6k#iWuA}EFozf6sNxOPQ16;Lk%pT_~Y)HE0VID0B+ zmnm_TKhEex;tF4U?^XZKXpmEuzW!=-`vrAAQkr>R`s@^<#oS+uUqy2@9|(yTA)Pj- zn}~B;c^+f!`?WWC(@tf-ws<&x!;ahJD}*SnVex0r;uaI5fwCDH@R^6NbrcZ+UPxTZLPdVKBZDAtZbPJ)2 z19u|(_M-bSS-C(`*Ge`DNDBWBayd2^utk=)Bf6pj05Z(BDZq^sc=maA4kE{y!iO}^ zaSjQ%yM}b5g-(9Yx!H#ZuP=5jOR7W@>}vC#ltT0PVx{(AvQsh2Yq=_K6(aldbjH-G zzrd)y2p65iPHmV#NIn203KG+(rKJL-)cO-Q1~Lmi#uU_-1W%gB8%>oJ&`SaAwRr}j zOdurQs3FyfcJ4v{nf;}6?LW_UBFlTT%fBCQ<5Q+d=ah-2T+finkSx9*ntgNy&`v;?|un^(P+QhouM*8r`k&(oFUJBhcgzMW8LS@szbtmPc{buE8^FQVl!0!oi> z^eb>XapMcZpH1&hzU>{bYZ;6G4eA9a>u!6iH}0wFw&BGN?mTX|bcpO756xwJ*>x9O zq(gnNL+R;S`S%xcBWtnm-JkP#YQ#B8e)I6uywJ&GZ;5h}TX)8Ovz5wmVMqLDzEJR}-DlU@_ZZI5ogJ1Q6T< zP5!I|%t4o$Lcd-GwtJy4!u7M!K+7&DM;4qp5CEeFGU0)wU!X|6>y`N2TmW=K&=&xb zByk`ZISP*T{k?+l7Yx0>rt#^2A?z>XqH5!=Z+uTMK@QzGLzg(D^f@$A(jeu~jYGE% z-8ghB-QW;X3JjehC@t!slwx3o&DwuRmc;!nt+YR{oHVQ(F1dRONnvh$KgB)vb?F|Q>Mw6>)fU7Npl|!KIt9y44 zgb2g-fZ^_|4eg4mv2~%r76Z%{voUk6?L#IPD&KVE5W)|dQ>`eqg;(OpWgwb5B}5-z zRgqr*y{=v=zEh&I#VEvVs86+};;l;8Q>Sk8sty3<8+^q#@|c+p3$FU5VgH~Ff&)1Q z*4(XR=&%7m1i+w8a4%dQLb=Zm$hv*$8S(R1Q1$*((VM!X+5M&CUU(Wev2xop{xwek z4>oREL=!?8G|w5TA#0Y}&@pGyHqHRjmw_VFVI|}8#-gE$D%G&3YW!rdG!4Dmp;~fo zI#Sfp`><`eO-41RV?={%*wUF9d^XaNGu##UAReMJ_}km$lUirTgK>t-V+;?ca?}Dt z6U)^>3;dvkD!>R0s>VY^LCOeA=;IE#@4XPMClWfAPy;+@&h(+*m;Qazu|ScBz$f@r zKU|#(e{zZlAn{rD@qBnDv4Z03wZ7m__*$rDAnqA?vhY`6u) zB`n7!#RvHm1qK&p)@8te1i3`Ov@)PpDC7A!DR+K~t0F}tXwueZQi%d1py9zJ2S(p3~-s#n$_D7W_&<0{)Ul>#;qfJMJp#_q(o7nIwbf_Jlv3iU7TWz>4j@k1y(7vcLe{$0A!&Gf=CQ$S(Kn!5t^5P z7EMh=%WUCA8~WfzRDt3;_^<7GnwofnMrt5T)zG9EGUnGLa%CT?OM+=pfEdaGe*)J( z6p1TlY(kx|Xf!H_z%1(tZ?2XIrz{xZ7vee1Ai{)PJtIJDVU>xunAs0ODLNT+bw{VaSs`R zlMF)Lmz$9J)XDW9b|S`l`F+mgFFB7_2sEJWBem6)9RbDvPS-Fsa@7n#(*$PMSxk>8 zqLDj)xHqO)y;5if%@v-h!Cv?f&omf?!js{KSmr>|Onxob%rYA*fiDu6q2i#4_^Cb0 zQ^6jj)V{Eq7XL)9(j~3g01Euo83d1lv%a7BjFT)tKT(7{@y^@4x&}_9aPj3bwRKLW zeV#0v+E_m@vpt`y>GkPYYTq zcHLr4d$2n*45CS%O|H8@|v@NGfqUA=4=N@ynRHnwk0QYC!4QD2#p-1!iA|gMl690vo5Z$FhD%#e zcM}HBjk*s$EKgt?lrK>rgL(1?^>WBVgo^NC6%lZ}qhYy1`4To?O|-So`39jQN{nmaYp`$8SLbK zygK#ta(?%NtET@0^Z^gvv^_<@ses^fE>ViF8v_ag_|a#)39bWBB){17wj~vC0_@cX zJiu}G)~x7c&BuRX+pETC@V>Tpj@-!}7DP#==HMU~_U7F4RcK5GNhW1o^7I~IV)>4o z?&|1f2kWc%?{+6f4e)N&0A%Bi+|0_10s4J`;usXy^X4+Jvw%Dc2pnn-Y;rqicHz#R zGz|J-{}CX8rv`e~0nnQlcOH)UjAk-<5`)DgV&x zd=Q>MjP(S<9a+4Y|2thrGxsJp=bV9gtQ6^pTN_W22m*5+? %2}mtKVqSlx$Ao@~ zWT*u~uYN6l^oi*YrKtLIK=2pLJ488Nl-~0DF6fZy7)bp`ZL+H7(Ru9Gk8f}C04=UY zz8GAjGk4B4azNk~^QXa}|FnOxI0U{qzW1OsdPN0rLK1|D45x#1biQp4)E^()qm5fa zQKX)c>rDNdKNa=9`K!P_4F~7Vc_mQbh`X^d6tAI`Gar^ouE{6;if}go61Tb$g9FjH zH!Q3uL(q(<{8J-$xE7X1l1qsp%i!^F`d&;iD@1z_)&)Tz{bOR{B@kh$@veYubllAt z7Z6ZV3S7Jynd(}6=~k)*eOZ}&bm|QNAA2)CDq1|VAjYDE(Z3){0tj!Dk97lKW9y3b zr>p*HEXmi(i_*%kipgCntynD4iH;_ejsoK@z@><~^M=jxn>z>7{QzT2YScgYsJ>Y7 zH_d6myZ2s5vu4@)3IaUgx=qgWXU6AGAxU>cG+;G^eK;S#=C9Ho$q27i7TC?q z(CV$q?3fxHyL1Rz0_=MiMC{!q{|0OL5t?lnm z=~k%PWci0pe|p6K^FAvMvT=wNO1-IxxE*Yin}JKg3CJh;kAc49VsCKF&8D_AMOj|x zWu36>q9z5dbe5e!73!+c z?=+AM>94tkXu89NJVle**v{iorPDm|911Yc!qR{M=fa;lRy>K@Ylh6lPQaS<-y(eb+;*WZl0@2 z>l?|q0kn8$dRobkQ#j?6O`r!CLtg9V-=)&{zT>4vdk;&YOFi0)=akOA#O-G%%Sw7m zYYMS)NiubBNLe^8(-^2{c}h9`yMGTlt<|5_FsLs%uhXY{864J->LacCItc; zobozi9R~$Q0+H(&io&9H_ond zodn!XnkDR_r4T3n~kY9O9b%d6r>poXl1Z&^_DLgcH( z{3z+hD7f&VwcUk3XAeJj$pVX?lThRot+M?I@Dge2o?#LoVB4cmwp}(5#D-OvG}Jk$ z&(EZvp9yaYMDK)VCd`*>nj*|DL{HoQXgyR5PJ-o?;_R2)j^QsSX5q3_51O2F>C>BZ z4(YyyxF9Orh^-g1{z(wPebJ482C)cHHvaO|1JZY%hqeMRvI=U zYMq!Nc!mbRfnZxfsBDu$33uBME{nkc=mkmySn>YsRM^{^1xL;f1|7vkjpmfo?G2rfbhgrABSu>gED|uYjw1e>C}*ergS_+E5c{a z9Hm2p28YSodfkzgWnpv#MDi$&kr@!Um=(Z zy`YvpOl=yY%d-{$8WyCWrjstk?JNT`0Z40_z92kJWv%}0m!KQroV-gOM=LCC_Kf+L{ zTI(OtpNS1(-)8XZ!NU_Q;?q)cnmKce-ygGJ3dL4Tvq6Z<51FMX2%<*ca|OPu>7&yi za64C^AW`fNXJLU#--#d>-zqa5x%CuGC;85My|ue5;ksq=$%{Y`i>j9xijq<*CkkAm zPUP??5M4g<0jiF&q+~5g!R_U7;3FRgMjv2V=b zstyOpWbXmlGf|mJ{?m0iig^pV#P?d+o=;5E1eOLg3@j z;w?1*#sMmnxjnp`a_v*avp+|w8G`^Km?_a=vP6x$_F;;}*LwcHC&rH(s|!}XHjB`F z!*}1WHdy@I?)>+yF5lLZo|S*QFzg z*^z}@{oqZU!ayv~Dc_zvd8fmKZ%=9}TmCi*BW)}z-nCZ+(*u7qr_k^vw6>JO0`p4d ze;6g;Kc72~H#3*R_D!}%{~TYv1x`-{l#C%W0>Y=pzlJ7a35cv()EO4RG{8W`)4LIA z4j=6rvdMk+_;P@0ivZU`L1R~$&RdWNh5tm7;43)D2TKM#&NHf(B9=r?fICQHg-{?pOH2vT2IAq6xC(=OhA^!%4b|~Kv?5S2 z0=IAiMp%)!Cb%9k3v0|U!2=rD$HbgzmQjSqdm!+$gaRs5j{@rt=l{<=OARe3J1JyD zxgaQ zaTpbFPDHH-mMC(6`@--KTO(9fQF&PHYeRhkDtKild+pr-ZBmtvpw?HpaLjd)+-h3c_42<6!|8i zm~tQT(TDeWA^!@N_pU>+-kI#CFVn{@a19jjoTf88lWkiCbS0a5^!54W$<*nuu|hH_ z#cDN)#FgRT3W~h#(0>Zp)m*VPVUEVRebxK^T7PY--3;#Ni~A@HGk(a5O)qw@C#gN` z!!Ex0XQwaWooCf<8+|;$=XO>lr6)hNaA#^qZP8yH9QZjsP#2fLJuc zSBNs+mjT*wcbi*59L@M^@>2IY!=eK7*tEP~V^tYBGmZ@JNx56l23(vf^?`<$V(Vp3 z3|k_Qy0<+Gz{Q$9dsh-$h}F=O*{f-YvGbXzw)5og%CVJ${*$o#^` zJq5|aJM>_#h5fSeHE=RiZra2eUM+E`ARFPfVPa&PuJ7$Q?~6rs9Zq7P$V1y2TCZB1 zJ$c3kGznV>V6qScDT;M?*macj+yC+N#B;)K*0Qh?A+4-ILyEjw*z6`r3=-?8Nw#yk zZ}U}6xR|y50oiGSEvT7K81xF(F74i6>>ym<`da12&65^bJeek|>KL{vZNe6&-L+>u zB~`q2RJ^{kUZj=h^rU;5pAUGIc|=E0;9#oFhfrVUBd-fprW>E`C=IxWersEcMM6-3 zmc4syf1}Q@SNvJc5|EloW_X5ieuib}m+#qm-4~zjUVsuNU1kZ6^{CTjyvW-wZ%VIR z)w_iAT~qT)BN+Ww1%7(Eo3|&^?DcP`{2($co+`w^g_KC^6*NY8JYe#K0h1_S28lYv zgTaI)0-c6p$4tYfW#Dpipw{I;xip22jbhfGp;9WqOaK;jSs~OA#(nF+GGDJifbkf}2#D7}h{#2*-6$=tFu#IiqBVhNA}WjXeT zNBD0HJ{vrrjeq#1nat)8H7-g+AqpZg9+sWeEi;IQkyD;qjzaa}kNJgmAKc)V8hxcP zrrG%Ls{~X$BkX`bw09DQ!xa#lA#aw#Rfo)U#SSAz+$#hCKZVI+4 z`hTVvd#0w8!{rlVY76KuQD8yjrY|iN)ju=w8j(Vb;E&U~-X7Bv|BC8XGaC!A^5mXR zvzjS7Q#nMa=B22)($(4dK`;=>R6QF45q-Mfbrqu8T{USV*B93CbPpR z2?UyrU0>NXnHh=}k9IM0T-A|~pSfsj7QW2NPoleqRk2l=)6+ptD$fbax;fMmmc{fI zy^tv4!t@5J;9*!2WAwjI7*6BBxw@`NUSIvRZmPB6W4B@21+lI9AMSy9-iB=r-LWzgy4<%M-azEs5*7i-*q#{b<^H_ z!(3}KWE2vgxMjn%WzDpel(&&sv+W$bWh=Om5xiNHxtTw@Q~iFs#C0o*X)~vCBhP#* zr)wi-bR*~OdZziNPu@iY6q;>#a3FMqxF>?6~9Q(pf4`!W?p1-nsUH>n5U(#E|m_5~b@{lb+0DO5(C-C8Z2}&Jo?Y_!bJxv8Wy{Xz zeP$}pU7!2^nPdDUCJ0@>5gOxV;2DaB`YFL(aio7GKqlRem(IW@-8N!p2WI(@tKA23 zc89H;hjwF5b}u?6#1A{u4_liKEXEGZyB%c?4@OPSkF3Uy>_d*!4Gv914!!f8T=EaY z&JP^M4$aOFqP361x)0s8k8fEV*>)dVx*d0N1x0Efc?$)F+&PNvK9;dNwADUw|8P{W za-?o|p^blA8OkeBaNlz$p?ei*0y zMwN1yoqv>k=eS4v$U6VXLe2?B2IoYv2{4NX?TNu~T)-I{9QPi5U~UBh?fk)=er0`Q z3%on9_!Ge{u;zMQm*ZW(#K4|~x4_lXRdWuCk}2xyg|ihH8vLmH@sZ&AP;>(46kTKL z>axq(7Y9mBtn-usl413gUaqq#$z@BKqq}MvWc}I&HGbu(otc2U>!k_S!!$aUGtQ$s zvs)$417+RL(p*X`ml|@NGouzYbC+wQUR;NtZL_Dr#=mG@jbIU&VBd3Ntn;H7uz#|p z=-wl;q>(73bwu#qeTyMZ|bTl_kX_6lEnOHH5V<%gHFIX=`ii$?)na3OH!+nqfs9 zG{p@yR5UGwwXKBB4TWq?1RSpkLI))bwT{KM{mCfBXZN2|-2{SY_aIi8lyJ}@^W@%<+V{L8i?_?a|V&v&+ z6M5Y#2ydF;Zeir&Z{iy1eci{*J;>ZM+R8KD*UQVtJJCHfJ|-q6)!(r^)}yjqu!4QOy#Ms~{LYtz z8X5=YSx02?*k9*)f(6C)DD#Tub}-jvXDS<;Ll5*EIbu{&dw&PvxdmuhV6tvKKKUt4PJW z@Rv3cf%n#T$^%)fnOam2oo0#koT`zKbG;nq`C)r@YfOv$>ECX#vMYwam6fjZ&TM2bo4*}`Ur#!( z<_0Cx?`{btZR_~qZ@sXacZ#f+Dy~aEtA<0;UiLU_d$ANczKW9I`|c_t{c14lrt0vI zSK;j9stsOSYYO%GtRXGn?6-pF+`Deo{l<;gpQRB!vb(gzHe@rjh8qZ4o8KD(e+@Nw zYqAOd^o-=ZuXs?tR{Tb!# zwQS_c#mAu(om}k~oX1}7BmcH4=CV?fV5tWccp2Xp$F)UOm7g78sq|RmI~nR|H$JImm?4%X}0pYh*7u>S_i!O5ozSB$*#(=Qi)9o)JR$y&y z{STH8L9N>g4B^56&~y)v_LrOD)xoMQ)RJMpPPE&R?OG1BI+Z^g=Jf5+^2uhWQVk!8nX zL&e^cfTnUI{y#a7znWD@&iwK)$8T2uuzr6Z?CtE|CwQ+$>{;+{g%3)u=ij|!9=GQV ziXH!KkJviv7Hg!Y9RJLYUU-kc5wFj^@BGn>4`}*1`mS%QS?joY&Q$5w-A?WA_@eP<@z+5{K?BKU z(qo^y);(?Zl^m2ik z+Pwj$#V%Se;kJTiGlfpQHdVa(ZlP|<_?Ka`TPrrj$GcB-myvS>N}tmWT`#q-`(z?r zg^Pi`~*J&(1?$0XwVgzgW?Tk;GR93VUcq?UMfBi-j2Ka3>({i5_+ zW=JX@#h)lHh!r{uchRqGnJ?j0FYJ!+pK@i9r*UXT8T9E=O2O|BDIvk~k#<4c@Hy_z z6Zh%#pi|=K_4C1=1g5owTZ^yDNr0Y(`o|ki(>q~&4ki{BVd?jNvx`gdG_l9c3!wyF z$l5t93B)OoYF!%Flee{VVjt(BJsTlEQ@dx>WDA|yuT!LbdMxP`E4!ZVb6pf!ln`Xi zdf#9Mg%4A-cdf-i&mKADtLZ#UEJ`d{FMDdguyibN#lKYH`G4!1QxI16xZU!n&%Mf& zuAhItCd=>npqKY?rB_>(C;bHqa4okaF@&_3;6{J-`&g9vCpGIy-@aD|wZg*e9#c?X z)q>C~VbbC8yAk4Q$TI5{wVbfcYtIf9M*3rRE=6rMK9~6-^)QEr>E|Uu`TWu)c z5X|ir8!M3h)`Ds(%Btj6!*5(I%}En~&wTk&eY0sx%-;@1hsDWd=5CM@C76i^4S}r# zgYwjiHzJpadyB*&MLe-iyi%e0Z*jG@WeVy^Z8~o&W<-~u7kN*{b!C~#v>mC(KX#hJ zYa1nO^RN+m$pJuMX(*{o97vb~ASmcDaP1|i9O~syaVqq?mJaBH+Ott+7CpPPU0~eU z_MF0Lf4^F((KnjMEKNJ)R>bLbWpDrKdnW9q3$Ygs@A?gBJr6Oii(CT?-d=H_q~nqK zT?E6+W79`U_vObhj259p7>+W>GLHwCYuR8NlU|H4Kb}hirZsdpW)1CWmIU46%RCrX z-?J><169O;khMj&^CfGE&}2PaEljmlhjSO33?U^k$rF=MD!hPbM#;b*Gx-8A7JgyA zZaH0*h@J&tpiUgql+|boR`Y;xz(?-0IHCvtPM@0k*n)-v0C_L}JYbgW;&9A)+SKAHotWM$5d`0C$4CUKW&=i+cMP*>Pty&tbrTq#mmfSf3Y`<8PMU^|n%o zC=84;hQ?%m3wklSrsOg~E9nxYqM`R+YSh@|X0KiGLSXdIe`2gZdplYDiE2^V+>vGw zaMAf*P}=GR!xA)20w{$%wNSAO6B8!*vj~ALy^@NRMrvtdUj5}KyoJ|nJ=GV-2$qG^$&9-zH8RKL7 zEkhgU9@oa5jBbS~Sb8WFqY#oA?M!?fG!Rt#vGnw`n_ zZ#MSG8WbJmRqo|fViMboL$2mFuU}*5(t3f`I1eCQoGS(U;y6rjz6lWf24muDj+`bd zh$jG70d8Ekg!I`5Dz!+cwtBg5Ch^z>sbjrO(a@(GbRbq@L%GWMej>*@c=j8VU4bnG;yxl1rW9c4^m9}b0Z5Zf#4+y!QhI;eDk|oiAQ=xjqV25W>PV|*@|M> zAELuAzbbC}WZmUWYLCcC=X9?T3)nySrz4Y;Y|Jc6EA~cN@7Vrh=9N~g%3@E3r4#M= zN_4*{74m%HmPSERYk~hZV()C7TPAQ`blTxI422@`2(i`R6icu_9->Kv`JK_FkPAdr z3w(au+!NJMMbX_LLy}5iMp(qm00>269@9Gd@L+!moieeEuHuFi;ve7*4D63^Jfq7f zg;6Nw*<;-?0V78vjHA zTrt;Tvf9tr-M{IVt2x@Lde(>bcpMKV30zLhI4lCZ%`d%maM3O2^eE5H@KhPWn6xI< z#FQVt$q~wOWV&Bw*OurzbxT&XEIx)WWH{aWe!>-X&NgiL0X1dh#D%3PqfC*l!U!TO z&&FyTi*}D?m4qnO#!Bnl&HJWP4DsLNNhb0oi%B+pt7yJx8!tQ0=~@TAo)qsE8qIOd z>ZhcSy9vMb4!n`;}+RK@Y8YC7>ln{Tn(n@<;| zS2>nHPR}Ya;nb3B*gv+J+P*3Zv%7Pd_z~_f>?GQ198$EKRJU99SErFTO8uRFhgW8v z?sWC}eVSErqC~MhZz;2V!zne=vo+$RvzRVY#`_jtE&Tuo=+@F1prMM~#P8(>f9KqF z`A`P6bbsjYMGn-K+TEIN$x_<7_cxC7xY1TgRG9J$rHm*4QHMaK)S91EJGXY3@Szle z9w&4Urc%`HwTotdo3jZM3qy|rKJ2wr-XrPub#f2N8FKox>&dpAjxvixAX!1?&Q5FF z+vJ{kK9t(Cds2bP0yaGw^JV`kaO?5+)N&?j--157FR#(lEz(=)*yQtjz_3a``fFF03A1?z9aabPEZH;A zB8G%pLfyhZ1WtQijkM2xtq{{-N_6gL+jJSr#zl1W*gq4Sa4Z1V_j}9qR|JZ$jY$4J zsQwc+IgrHiKu{}*hjKs$WX zz?J~;6HF62Xz~W_QIwZgk(ZZGOh7rO{}0&G;(x%F`uckRNB6M3YVPlHCB*3}P4tNNv^I7PuyOXGi5`}o5&k|t;o;$~ z?rwF0BK3kas-^t@QZ40k0-dvBd^?=+_3D=Vm4brVg4_*!e77;^9HE#@5sPXb*ZWF#i0-%bSm1y*@ZRIzCxuc=PTZ7!{t-_GM#h z``-35>hC`zDU6)b_$P!qQaU3aJx4pfu7>8d6G;}v>tMvvQ6Yiae? zsp3|=uiyFS=Cy{{Qz6-4wJ&cwfdL#Hqqq!G zSs#$WjEAtxxb2x;Yyunq$IEpv^mK7Cw>DKd^~aM9dOC&18NMHD$&z}!EGb4;kCqc6 z!=JC4R+Sn_iSQ!c@90<--?3J(+zhgnDwYE1iA|cuq@V3xxs3M$diDKBZ@d z{RaXzu2osV(-NK(z|+FDuV6^gwPf)vrA=G*rOY4eJ|1%4N_;2MEe$q6_EvspWgK+( zGf@$`QiByKMe=wZ4zHvZ&{a-jxB=ZI!}D2pNwDl2QH6`lStWUTVASheuzW3ul!`yv zPT};z@?tJI0bBuTGsdE}R<^Zv?%dgLI58mW0dJD@=ZK^N?#wn(3}5cfD>{8JHjU2O zXW<#06;8a^ut}`>xn$>pqJ!4np5Cjh>R$y@kfd))bRf&amTO6T0;whWshtiIwzt4o zuJB2z3`s|>a?cs_r^cd%ibGh3w+n3!T3Orc}e=2Y!BrK=we=`cYfEqsUH7s zz))1rI;qtE32oDH$ujyoIv9rEzB{w~g#q4u(S zIftIzrpG}Mt7~mpx|HC|#<@HT&rc2mF~ZlhAtbo8oPLMz$=30}%>C|xd`f6evGkRPF1YsW*# z^{Fha2E`q!ChSE5Yc}iN1q`%4E)~T*zI-)+*=|{6@m+#Z9_7QFDVCiCei?lRd z2`9adGYw_qLQ4m8 z8<^glOkbv@kb{@&WJ9H9JYE5LHp}~Px=&zwCzFuw1=wY;DV@=633_gXIf2sf=*~4F zFdn*R&zDur9s9&HIN&-R@qnA#(7=cek@xgYajv+UhxH*@qKL8X>Ldr`ZVmy2xqI1C zNT;sq`;xIO4{GIrgIFWz&+7+U>rEv~-QiM|sK_mnkt8nPP^2yx2?eJ(kIn)s#w~n?&Qj5Z|Q4N8VA&=BAgZwyr}LgPjB7*x=5$I ztvz{2CgQ_xkt5Q>{un|mkL#_N;A_J0yv;Ivqi^@x(vChL%gF<&npsmnQ}Qxb#vWdP z=BrR`IqCLF3~ySMaoU%8H9u z@cb^iDBQqZ)sO-%t3CZc>jRB383Lpc`X|`inzeIePORYuD{ zDxR}CGrq?5#}qmWcJuBW^=hu_v}9E3tv2V~)6&){wJSZj zzAp5C-=ILj$qS}{9Thfrq4zNIqEYuIXh z;fC7|D8#$UJ_??`wsO-VqOdICSTkC9E_>jH-_|l*W}H_gx(6=D>`FC`cbbh~`Iw?s z00?VRpZ+linAacrT#(q9(J$@Gurfb|USOjW4e1pZ4oY@<7QNB6a+cBUT*P#~X})=W zcE9(1j<2h)$Ha=8O7K&&Hzs{Qo`_}V^%T?u`NuzdP$%x!e+l&FMiu9(osS~%c;LNb zIKRPB{&!#AM}F4)AW&lI_aZmS+W_Am8#`nCEgD@PlQpE4Uk~V~vWE~pSXMpxk4~Yw zVx%p4tA3w{w;vS+0H`f9~QJT=nO9 zE^o?8^h)@h@jpCTEWcLlJUx*qlM{^p#o7>`2RM{{n}HZbt)vM>G;ycAwew{hH5x_w zIge_X4G!GCYcW{#I9A^A-Wq&fPhZ~ostnT}HbYsmp0U&hV(Eb&7T>l3`TqbEO|T%HAT$(^ zq}7b+(8yN~|8^Q_z4099pg6?6d$;+uM@H_nX&qpsu-xQ9-HnpZbpO=k_mC&~aRM(^ z>~pduQQ#fTTqmMi8$cj(A5l}F^GQsqwF&n?mPg(MD!l^=2VETpf9<&Nw<+TTY;XKr zCKLF(kTh=kq&xaq(09GCW~=D@vJ6yi6u4uLAQ%NG2+gqcs7JNLY!! zo}X?nUH};4fe?IR2G&>`0Kor3Qocf%&~Vo2==>-~+UOO1Ziz+%V1#8#G8rs$<|?n6 z0-#eatENEFDZsxdqJ$rtFUyD7c-1Xt13x0Xoai{1z+Ili%7e6=Pq5C6H zRxPf~v^XO-%pHK`Zl^g*M%cy>ug9e2lhP)*vve+JanEPw@xV$lnZF+SA+hOMhfHkAE@(3_6PzxIh}wr2Y~81sE(zY6FM<$J~|A0bCwK< zQBy?gGVU4xpXM=t;Gx1>KGR&nk>Qz{+sxUmc}_#QP~HRu3Q#JEm@m(*+z#Jq&8v%H zelD3#Er?gR{mWz_bAjjF?hDF1+cNI*!N%{FwOdbGf5) z;T2i1iXsK9&&@5;!cY-ht>6fo?N0|W1mLvAX4MS87=!ZzK&~XX88tB&bu$WkQ!bjB zj*zogkRz3a7?x!H=@@+Kt&?mNs&a++3Y)iblDk=6gg+x`au+NZ7yq-9sdlAIQ=$w{ zfGD6Lic}&K^}J{aNKD4VYWngmhA#sopxi+%a5bmeLG8690*Qihv$OJ_74CuJ3xP^h zPrzS^qOx?IYxbeQg3cjO9Oj=8>|5rVSr&L)X_c9GQ?1HiIO)c`nE!BPCS`bk7)Z4?VjhSkCA5Y2UQ1(GAl=-lQ7@~a#@fdc z1BXi@ipV9k*jpoh*Ii@js{D~(cyGM{K#`V}Z#hHnsl)`v7QM!jj@pWP-jwzKjGS*R z8;q@`%O)8Nht6an55?(4E$@Dd1b+A>=RPb=&P9gP<+9LD7 zafFyd(Yja6A+gahJJPVS$z>!wJ+_>GtEv*;aCMi>8yV_*C389|yraTNcelxPq=``3 zWKwzEqY_y=7~QZMSA(u}n2-216r$}EH60VSd=}Fr-xB&OJbSTe?NiJO+OmGOv0xSO zqsBE6?p6V%46)5`XK(-YV^HC4T%v$ijPnk5TCXg&w#PMkSVCIf5-U;}Io}|a)afM_ zkTO!Y9gIPtl)I(h?t+FGf_J5sS4rfZc0K8q#b5PN6}6N2;)@v#cV>aFoZ_+FEtMk!W_wA^bN^(adp>XAAsBgPlXt=kjGTv-H7{i|?@_>AYr+>B5 z4;n|5tg3$>SI%$TRYGkn!`-W^ZOge_Gm)N}($13R+xl9aZ1gN@5?=Qts@L`OK2rzd zlV3<=Eu^1^{w5#2D89#JuxB0FZbH|+zsP71SnFvTDa}9N@?fw^^}OmjUzh1_m|Tb7 zs#+iSQgya7;~n*Ipv?bTVAB*9;zbxPU#g`;4%wFVFNzOT^GDpNVwBDCGz;|ol2uoa zzW<8SC9A^SwiBX}<2Owj-2KtVAd?WM)_)T=QuiR76`3s~Q&&unvcbmZhlN{J69WRiw*bjWqkgi^~L5` zegNZrdiM;|v13B&Z@%G|m1B_kv9p|}z2D=;zedv-Xe%5NkQ1#2fSByZzd1AiLUwK) z^*A-(-;$vi1%&M8Oz26BPir8G9AdKoNX%+%vSr0Z;vr+3Gv zaR7hN)H)4j?C3k7QKre*pe-AcOa?Ce$jez3g-=7Iwt>8B4a|Q~*eZNVAmfkUH~zaK ztQ%E7O#wXLb<(;FnRsDIE{(Hi4s)8uR4gj6ee8exUKC`FWb7+6e$UPqJgk`Sj>}cL>1A_c}WG%o4fb z96qJ=#w{pdBFJHp%W>fPz|^8yWTy))cQAXNO^FR4GsBhO&b2@sIbRk97hfGJK!G2& z-{5>UGCp+APpxVD%^dfiWiQjLsH5dG*@nUU{p?)HMb@y$RY(d75>^`vpn()GxbRN$ z+%q;=HRj>)96oQoqk2-@G;-M_)#AsrPQ|t(vdyWISZUtCgEt#8a9xuvSzDw-nXBrnw z^!dv8ZF%Wb`PDZXVwsa=QV7*YNP}|51SjU;Q`e*4Bk~DO(eZ1yWHu=A zi&vVbZZK_mo~=JsZ>vCo)X3-2B|*r!ifWUxp(WC$5$FGpv-fanD&W?4cX~n%Rl1?~ zCP)VZA{~qF|t88%)3fo+!yO9~umb#VKRJ9cHtZ3zw zdx^?qV5i%wU>ucMT~VzG)-wLcZg`idGUnDn6=Tu;k&}w{>pAvvU7a$va)pK}Xop+d zgXU+z+KS_QZqDjTNn$lEl~Br%VBx146{-Za!Tt6n#v1^29SyC`-M+IbIm`P9+ZDcv zPszIWIG!(0%rKpQd(D=XV{o5=W!^mNm$6}vC&ZVS2~>O#JLDPymd zt!)CiZPbNr+4pSZ(xnx!Z6+5DX;F|Yxehc9V8SVldN$2_g?z;JddU&f5WG$JSkw4)#AM7bZ}Dh+HkYuEE8JhcR$n01am)BYo<~QD6hqPi zfzxEwP^w)arGI}px>@~Ow#_&4m#?_5y91o%zw41@uh?p9JX6KX8ZuvwdhlgGT)21t zV0rk!0hYn@?-04t{I`1n`;~PhWUuh!xBBBv!H!vzLKOeqhM#6XR30|AavYvp_R{Ej z?`n({s#Wf&b~bmSlpd`sK0UgXV*hJm`AX_@)3G(*U0Z18Vg3}#XyxeW_4$FV0BMb06TJS4L-YBBlKWVr)IoaDfzqSU&#y!{+dm4V$`zI?ckKP^4z8>MXCPWlNlL`8o6eZ2Uy@7uPS1!D#- zO`!py(GVeOgp`*-TtS2A8|Xa8B2s>@q&MuG`hBLCjZ)R4IfK`3o^s@^pITl)p$;bd z>AQkfC@tfmmkCoAbi+emd0qLLNW~$f{9wyX zg;*3?%~$wpIa29fHqIbw1giFEKf-__tG+=FO}i5qNq_1#XayMSx(x@lQ?0 z9d?S1i?KM$-*EuB(j!R~z?sD_*3I{CL`C%Eqrsc^s1O6R+~LOlVwPX|9jbmil&^^OObO*M}0qpi6jYUrUlr>8XFc;e0P?)A!@VgTv1Z9K5oh z(-04jzogwUQ@3>l0NEkgK`vu~bRr#+pw%ZLZnCY1WW=FNQ060M2DW4I&}`qxFYCN< zPTwPD9WT`f(Ixa(#tGsiDI5^~Jb%+qsRHLm21+7~y>tCTGec!bNcW$8rTWh9XI>{eW13aqFhF?K9MoH8#w<7}iV4D|RN^){*^=kmoSuH0QRnkvMP zzr4izRN~S#ZTEAqWuZtH!AEw1@p3iOO`GfwHg}hhf%?Map+$>F>dlk1q9mO#r$?rJ zpym4wUse;et3FO)y1S0wa0QF&MCf~u!GANa*+#iql&I5%R%i`|s{vSYt`-BABo|NkA%)=-`1#%ukt`M7xv3X-5T(i|N>wm4cA27L%V>R!OyWK8E6IB||=JDlPsoeo7PQrnAEkHVG)+6|#dx6fX zUfk^X1VhVXZlMdBb;b%>k00YKMk}+6Z`vHDUUY-fC-x2n3VwGPm2;4oInvP8o=T$8 z$D*N`aTG?<>f?Bf=0C0*U$ESObplJ)k6Sw?-pq*Awch1z9$CH6)`{$T$53^LYwOm;F_+Ar^3 z_kfy#@C`6)mhvg>GOW9moW}aCyhM@ecZI*CoBr%EaBy4wl;Ufy9`Q4frZHo&Tg(4J z(f6p89?rA!(P?-MzMX~lVO|#Sn$-&=)F&k;g7>Xng-?*nL;qe=g5G%@Zl}>1#YLVd}DOE>Bz3>MZV!%Ct23ng}xdK&L<;j>CB}%d&o8w zgY?wOid!GVT6ux8dsW~6NM5;pEOTBn;`8miGk))vHDMCYizMCB$`I7}@w;btq%Q`@ z0lIfS7<*??uRKt@T|V*TzNVmpjV(=?h|1j8cJJN0cMfNSSNDrT@INBq7}2%_Vlq85 z7aDq1N$+>!^XS(%W{BS>ZrzvL@@3&zRRt-%^)H$1p0|2(H6xtPeDdNI6C7L>Nr~VQ zmU+W%mGqo?myK(@pz5wm+}*Q{3z16#hfYU|!=mhSChgjXe}SIVh|kX$utQfFzA|Kr z*jrwd08Ht8iy(-tRgf~qC;LqoL{7D6?7qg2-0?1=eCr%YHSkAPzl77}&7O$|A3;Tn zYMV0eEGOJpeT%odHZ*G5C+sQT!O*{(YKYu-flhMIL~S-tqdb|`)Y)Rg`Z?drCb7%>+ASD zV(zEFlkHXmgD9R*dF#K<0$2O+E6&8HWb2<#3@$6)QB-{Nb1?Ma7e)gSp5par53T>S zOeC$rsrs=oa80>4=AkUJY`QEw%tH}Llc7UG5trL8O&wi&j=j13 zLif!KwG3ON-daS#v`-Ub6zd81U^&vuG1B;ilU?X$ryTC_)o6+$0?>_`UK)C^OZHg8}gxC*oDv_Mx7_IUT;&`LbssxeT9zY4_lt79*_YD-F zL2Kr!NpUDTG^j=?;Tvy!b~dVbOS(KdP8pLBPY_|>ukMN`s2LY)t0Mk)mC5Nn$@+asws>oIbaFab z#UYG({E?4yrj!sV>{^U1__pnA zh9cy-nI){}o-0I%E-K?H>7r}fYW$|9_Q zCq+oa6BIBXVDuPm&y2MfkFjs83}Yq%1Oh@^=3=}Y>KrBKO+X+I3iL~066~l3J8+}E zFU+kl6=0=O&P^Z|W*j%FDy%Bm$h2IE#k0WUG%5Uvk0Y9{T0;CrFxr z8(@?MASeWaaTWt8QU2WRSGU~Jfm5=ulomSlXj6r zRd!3CwDWT^Wz@4XKdkE$#6!b76~ohz5K zKd8|0Ry~@DN3|UK7HlJ1Em<@EARp^L(W`)8GmTBkL2S+X`pDGh5PjY8l1C&8>*ffG zqaUh3LJa;XC*k4mX8AqvDFbEY`9$9<4S+oQIasBro{IGjrrtERl(~jw#H!-WZ^176 z7`vDGm$mB_-I#*b^_T_4qqJ{0;G{P0y^tBHlp96=3x~|NW|E5V?pV-Yud;QQ^Tub5 z5*ieUM_f6V`~W$rgk)WDs17b6kPK%o%1ly5_!659@=DP%Pz^?uG7g%X4R3F6La)L; zR-oXyNH=j5zVm!dohgHF))R*s?joBTFKQTae!h0mzUt!HVGY+pD{(e)hkJ-X|MrdBRz&ngOpsHqj5q)dQsSbAS=~wH9MuI;aYsVEp-J?nt%og za9m{wAwKU@5m?`@dOF{p-P3XmD!*0U0C!~>_`*?|ScPGM%*Aw&ut39P>7+>8=nf+K zRK7_l^mSWXx+iH>#E!k;HWK@b-#WEQ2+}2nWc2 zg!+=RhKNX=K&~-7ly+e^X11p13%Kv{jXsrM-O&d1W`wy%a7)-}L$|4rOtfCM6APoq_$Zh!8Bo z>tHzekIb)YgDNz@w?D{gF5%ie+WJM>hBMTQF=R6hv;X5B$@6c!TS57Zfllt ztD}u-SV8F6O~$djhB0@q&cXw5peACLEgDp-8*8NeX7Gt;Cj?&(S=<|6*&APynD{dG zWK(ToEooxMXkzEgaiunHpXOac+xXEK<;h*AcPm|x@AoGT#@;QSwXEmA`?5H(B=K%F z^xZ+%#9D2f^7#p=$GfBdvJs)iCw_Ik+g6*zv%cHQpQKKnq#qyuw)jr4ZsO}0S-6{g zc7JNknv7f;KRk0hRh!<d-jh1}RZZj$T_q|BLG;V)dkCv=lHznEqUd?8Lu5Jpk^bRRGMP)-)m;C7QchbP) z15fuypC$6${i$U>i2)ZNWR)rSa^cOGhl0!b)it8Fx$Et*aAf2R`s8)HS5+&n9+b z(~alSBs!9CuLEz5#@=h{j|L-!IxV*cxyyxL}ki4=J zwz9{)^0i=vQn&Kg*zbsT^=HBIY1pcn`6_&3_3yafkFZs`2|q@Y)otUo3zQYs!Zn%+ zKW3R#Wc}J%_Zo}F8h^?f-^AMYu=TITV9XR(bCxQAE3O(JLmd2+o?oStZKI=)X>GG^xXPXT?F(b3oF~yHKKiCXN*;I>^{EQeBwqV?#O$w6Q ziZt2ENhji85Tn%xpIG-qOAUB@-Ad!(nLI0wdpOQVwG}S4jicGl`?@_mX%#IVy)mQ9 zpL_S|1X{Ofr)FZO?(5ETy4^;p-6oUWmk)MZQ+C@Q?p79VqS&t9cG!78y1QJo+y7v1 zFlBGJes54?FF=F$ZegsKk)=ugT}DHsc$s=K5kMY{74(4K9F}IIsVLsS+*cI5XMZ6j zfs@F^g#%;IUngHs_I{XrYo$O<8lcrFQ2m~7`UlXTbO+C0vC?3HB@G#tBG5P`%5PP$ zWFm2vX5gO5Wz#aS&`Vmh-PZ&XgOH#>0SRnLfU&2dXwcu|NnrB>S~D~QLpV$*^?TI8 zq2O~A0(U5RmkX5oL+KylTEG+CRcOjS^m-BeKIxnCm2YmvAk(5F91ifF1hJ7(Y{1V% zA_!M>kl__O?VCT9w_Qc^-4g%fgW!*3fPwG)Lwib&?;)Ww$9dTA^F9DsJ2f8*VE!51 z2AiGyKF%cpcP}2lwmS-czIUC3a3ez98W1KVs7cR>n+)PQ;mNtDDdPE_o-~Xd4>IsP zV5VroZedUjT(ClV0~W&1$HmwRhi$G6-Ip;#f_T8};8#ehk+}?29n*CL@ZB5(rXj(G z4v#I1zMB_8<1wc|1E~GtbpU@VKFo$bTu?AZ2i+G%EOJVhdaA_``-=@ zzyCP;mLO)4Kx2*>P`I@V^;ojRQbFIBM-j^KtGYqO74qb?!Si%(K_>8=+LFGbc(!nxso2#ZP zaL)`1f}yAaRgaEvBt=s6ZwL-rmG#Ro97~^)6kl|J?Gs+6IM4z(iE=& zGrat}K^4wCVU-FfGHNINN{<%BNmyWrvRTo$Z%SBiXaU z`7GzR*$v5G&#y3m(9h1-NKnXlkSdgZL{x! zFSfo>!L*@@fZ721E|jRvjdvaTn?3%B2UUw8GeNaaWkGSTk(lV?ussko4f-c}Mvv9J zQYL~5%BRJQyYN>IjKsLSHS+H>Zu%I*-M6JUe4OtS>Fg%qyAG6Wf6EPu!)NKpD(^bm8M z1fKvO38QQXhusHfBji6;zR7j}y6Tkc@q&GmPWdxlJK1+W(3wtQWV<}q8_Xe`r|_M< zGFP5rDN+;$pLfYk?wG5jBeb}FDs|IQ5iO^9_vHwe$NbUX%nh}5b1m?F7^|n?!}TlK zdqg%X#dourzre3;qhmsSzQE}wKRO7C)&GZX12lg+X zt_q$JJMZ!>t|wm%Uq_81HIq*e88?8l{V}j!|0zvhw)4ZcJubXm*O@CyV@hLY6VEDDVvdY`RUV_8Y zzrl3USp46k59XfgKR3j~TKLHYPVZv?gY1(bR;tn`@Cq#_X{4vCzQi@=ma zL7ccDknfh{!#$k9Yb$6BbGWu3&uWatED?&vr3*%2y%LqM#yT$TPNiRyq&u=W(lM+L zUHj4ED%>2(%+jo%*PwEvJyJ+qxd?L+U>VT|rumW3aR!rqWoU^&zG2rUI0d}+DTJ{R zs6L^pz@4Yh4ybThseW1zrJAHe-}RTJ z->7KjaARva3f{9FN|fg3le%_GuAtibE!Spyv5Jugt#yzVPYXUSWZaHguc*RmCvY&w zHG=B$LbOnV1Bd9@kbH>dwRCURgc}z6EIGso0X|Er>uvX0l-<~+OB;xBR#p1NNfid> zBc@NzyJydXS(Jukr!5QkGhdF0s!yOK{7oYPWe4qyQafUi&^<`65tQ*}I}Mnv2k1|@ z0HMQx5H0c?;PIVXq*ds9R~EaPH}-O3IAXCv1mNJI0}{iVxt9K{@a(R(-ZYpo8z?rj zT(DB^5E|XuI(mLsS%YtShL(^qYp6J@zIQ)d)do<+z1Y;H)dyYEOHuF^d9xv6zn+(ESCcEe?{Y4G&%Mwl z9k=S?{>NZ{-M3R&{dwr7;mYrh+oE)F#E1N(6*yYcEU^egzcCN+0v4jEo^U!IGAjnX z_WEbRKJ{KuKFSo=%HCCVcW%=1#8kKsL)RGRsA^lb)$6P}6iLrv7o#xdXD4n_Kgm`O zE6ZN1*O1wb<8_~_9cO;S@$tYEQ>0hfg(NI z>ydIw!vwR-Fg zalT2Kg$RI=6cck9#86n@EO#I0rYlfHQ}^Ocj=FKfMFGC?xSk{89SnjeaBVu(iMxFN z_jQX$!E|n9A9>pydusdH?v`q^f-E;S38{#aszN@-OH)%>CasD3G*#s8pPqq`FNTuG{ij9L9z5AJ8dlpzaEJEIrg33#oFJkQ#Y*hSBSl?0{w~4+ko&? zgl7;Ls$9f(EPz-GaC@8;pmsoT)^U_o;IH#{8f%dGToIU5fxK7=gpdjT4xzLp#48;~ zHS)v2gNKLaL62jRN`Md4#nQ^&j?i)^|D_$+f*u|iZJ}g|6hWi#P%i?4up0WZ)i0y< zp6!Opy&&PFxW@wv#}Q|W)3L6tmrIP7Wra|Dh+j0g})=E%vpzThw!|AWh?(CY; zQJim*i#0`2^a|`5?52<7urAXg_vAz~4A`YTj-#HlMbDN8UlFA@6t%ALdt&k13{;V5 zHuuCJJoWmC{XUB!=lfLA?I*9FJaKE!tZI7V@;mcx`y&>(xGKBDLqBmR%V;%09idp{ z%6pT<^Fa-7HG>5+Pi0+!f#ZSzK{6{Glbx!3i?hdwIsMjTPnJ)ACio}Rgv_T$f)?dK zE17V)`qE#85Z0o!3|P*tIHZ3cl2VrT;>%q$#zGVCHi6EQUB{!#&wo*;R!iD0(Yz$! zKlQP<`m_}FkB@G+XjWxq-E0S7L=3|u`snZ~VGG>`H8My8uic`BHAr45X8z)fj*=_< z8xFhinPx5C@Z+3mnX>M^G`Bx|mrc%(j|m7{mZ!d@Ayp{aAoEB$z(0&!A_f4lQf7QwrMC2X{XX2cI&hE&WA178I-)opnp; z36C$x01ZZv8Ma=~pn1W9M9gG5v!DPi6sLtC#LZxVIZd$6JO)6QzMV9#W`8CZ4Abi{ zJ8_;cphYEnNgjTm@o;Xdg5bPhvBsF_cHk z=Cqy$wBf&K&UYC8pNm^3D-r?7ZG>+;rXq1QBn9h^_pSKYkpKI{p2as^f~tVhhU|J< z+AYs>|8ePiQSfw?()2k49DMz2??nW;s^x}>_-fYc3`T(>hI!tLv)V>GM~14rCI=-K z8-f+$2-P3-UH$>*1=#YOABa0%{~7qs_>kt|(2`G3f3ou1T-JM5mGTG9@37}BLzv9D zz=aGO+H~;-DmDVmvy`AZObEU|;Khn0+8-`~@~$uZZ&MN7#qN1J!rcyp5M#GXVuQmH zh0rnw@UbmqW4YgT1$$pS7=?2Zog)04mvI&%_UiJ9IXuSn(^LN@BeKNHT<(7Aak;vnS~ z{nZzyI{z%ONMW!~Vin4CaaC%I87!^&Y{{EJHskz07=r;_yLg~2(rYZU#>mLPwC2ia zw~JJ2lu}z`>JnoXz%rAXXtWv1#4gt%nN(cTYR?3awrSFSBtAzk)WK`wWMmw{C+s6~Xj*#MHpfZl=`G6FT)pfsv?+(HudQ=gYhmfBa0B<7U zSto!(yw*7Y217bV#Ji*}K$rDAvc4FkB?O0=WnSAwBw%>HRW&E{C_;-BWaYtg422i5 z%w`G{x)nH zZ78j`%JPWB5<+g(#qmjgM`So5B&OcnSbM;g?H3^gP~#!CWT+z!YK4QoT7&tn!p-gA z1h=C3EQIqhLF2%|@hp)(7EUjOn1oY+q!CYwPIdy}VIt8}TgES+`gNf2E9Mh7R8Qdj ztbXl=>p&NzoMjLo4hDAxQaZdc%HecJ4p!s=w*!acV?tXFQkL5OE@EgjpzVSS=RKO? z3=y;@;OIe9k%Vpn8U`}YIO$uT#Q}&~iCb?tga0U|i&&*MWYDS4mE6ohB5;f^(ikwf zikCYKglAClC9WZFSV=CE$*6G<6R+^1B4;Ri`bcrUL`nSq_z8pLCU5OUJBxE3;L=of zU$c}Y4yM|LoY$%`?|&=Jh=V-i`zL_ZBO(52xw;d|VD|51BK%Vw;Tt+3ab%bm<^>-o zLboc+zX)-}Is)tPd`Q`3Xg;pefrjdlte-eFaMDgKI=2@Q`!JapEgwY zX^)QL#jLG8sSE8>=fNGVQGwe!B@6{pB#+ey;9@90}c4nQ3$B0;INv z63L$O_|(3FzSp$C^>L)bj{B#5$f48a^J3%OrN~55G3OwBM;v&+_sm{1q^@P0W(EtAvx3H}MM||)KWmAGW1dr?6{3*WtgZ?cuVDyU z@FKJbR$J#iJ>5a6;rm`zP|I#S_tU?c=Sx6C->W7g*9=y#&20n72=Giqw&}<`cS)J0 zSFPSbbPQf4%KdZH>f2xo`~z14cK=d1^8p2X zRmM%BH4feoBTPzgV&x(!JrG_!2YXL@V^XjTj28u+K1(7gP<%99wF8zNB& zpdW_mUl5q7F|V0}_GNT8 zzhO37VOFdPhJlGj7p3-pllJ*BfcAVf&!Gutq49hMJP>a2 zJt`LcP)V*E*>aOmKNgutJbjh8ZM>FCK{?HI{$ZaZZ2w{WKMFBi)HoE^S88pp|>^#{l$)xqYv! zl}leSy6a_6r?>N*EEuttb_DzV@rv$;U^4<5kvrf@Kz(=@=5Uf-aw_6Hzj5~NwNptM zSiI;IIx$@kK>G^Wf1qc25?MZWx^C(@km{=l_yeYh8?h+XHpR#Qn^58#ZTYXE{ zp#Le`{{C-^yeRJ6B2Pt54|uVY1E?C_aSusch-Xr4-RvAhj1A5xS}(>Xsfi4A>CGa! zX$uT(Ji?L->bkq<|KxV`{HJSc(s6pKdf&(>zjpCVLjC#`kB6yGpTB;$GI!}$@+~O0 zl1VaEU*t^)AG6vQnMKGPLJc1@w~n2#-W29CmWGR&pR)DtA`bcCWF z-x6mo>-wA{H#iY>)3!M@xGCl)wX%j|0OKTO*`4^-tGMu zt_G(s71@b zRtQp;%2NmoM%zo!Bs?3eALw~?XJF4#uBr4wqk6K+OSe1!z*+-0V#b9qJ{oLL@-;dW z6<-qpLgci`V_m9|)qHy}afQt{zmKf0J1UA%3=)iaA2DGHNNpSpY3kB_;_dvwEON=6Bx^i3Q|1Gw0`t&d~$$DX3t*X z@}-%9aVri_a)tmpzmOiR6JFc`P#|{t;m@^F9l_uGy!nFS6O()Z_CSd9k@x#^Wllv= z#j-y@h`Om_8>GOfFZ^Vnl&?k|<(Of5dx}GV7FoOy4ID(r(<(EBTS9euCS&MyFeEIu z&K`bIeBg5NRdy7J1(FPw#~?UW0%Zs3WyskOE&*?pJ~(jCnctfMx&}90{8Ai47x8Bm zT$-Lf3-H|E>)E7FeAOGnprQs4dGg>49|T;f(jXkbVO9x)t2RlOGyhm01yvz(L@|_7 zZWh%ttln^v9nuXIhCTUiQm6?%uI(`3{LR1js*(cp4d^WzPV6xH zIE{+vaGOID`cz#6Gsqg1SzXL=MMoFP5Ll^c>usBPGIUQSdo!9F4I#Ye7lo`k(qH{- z7XdW?#ul;)K0S+bfag?0KuD8yU?7zBa>h-Cci}q2>z3fbuzz~AK#&;|NE9%>VE5R} z@+#vI*?sZMN017c))+A2u|pK3mRW5Mdg5{?K)^!%`#ZwYVUI$58oDaQ{BH8CIE#Bf zM=8&H&Moro%4T3fOtdy`FFM%kZQ3SK-nH7#W5nDIcVO5$ZV!<7>=i5!y!u{e$)@yI z5VzGL1vC+J-TQR^PJZu8c4dD%-EYb(QXoKnZ|%*#*ZaeuTh3Sc_~J5F<2%>>odNMj z?*}LA1Xv*{yZo(9vaeVdTOWM*y>9;K)I|PFYItYq!nJ~sCtaQe21n8=tyS#eN4Hrv zCJ~Q-*=y2CM^F5>-0#}UqCStAw$r!~B3s+?e^@`^;dRvlP+JzG-tS-j?z(RuxH`{| zg)@Ut1-?*<6_@?8MW~5&Cs(+(gBscOB zFfYRk?h#F3-ylaKX?X8wPR@?L$A({E4o5uFf{1SF<>zH%6`#iebSYpE^8IjTS*T-? z-qDB!ohCo5=?xu0h6rW0LokTE;R#kmVfNM#Xpt`F`i7Cbkfgw>bn2FvE0NzxZ zT+uZ*#=VEf%9j9i<(9&diGryR+AvL{2N1m98wjUGio6T`u~${*?*GT;Mkhl67AtRY;hCHIe959C(J-MR|eHnXlQWP~f*EfYJCf2Ppo}Z#j zQa^T!&GP%HM*U)!AJfAhB5ER#L~Z!V;QQnYl5bP~`0B0^71gUQ41)P&R)9c^)JK{gNJ9%rD8DE=ff&PA>)R(e ztjRES5J`JS{)Nt;p@_#`=_kQQy+6MkWTXI}*e>?=|Kp%?aZR#+Xx&VrDwjyOsJMb@ z%4SfGNl&u3b`aTC95#|dtYa$MU|HJwSL`l9Hoz60-!?{UzpyWHU!S!ax# zo4P%Mtwac|87Q#m3ztv>ujZZUGUm9&>;;=z6PP-v`jX3!iORLyuloDy+O51eE*Z?d(C+8UJitTGf>C&BVbzZ2CUBtvnzL ziuwZMGQ~8t`qgAX;H?n2Zn#PVL|G=B$t9dMFdQBmexWj)MK7GUGW>f~ID<$yZ(BH@ zMFjInxY$s*RCYMOQY4Sabur{Qn(jJJTZF(#1fxqNOI##hTR59ul&VOih)ATmUX;#I z1bIPeslUB6WPz1L~xVc``@CH^;!O~R0b*hyywa2kIAZ$G|%u)ud zRPg}f;*I@L&u?v~hE0WZym-I#{shBOPQBL3v$TgAQHH9gR&fg=Q6mUN~&R4+) zOoH(deTosWskr2TK-eK1APhN_(OSBtiW&f#EcU-)S_i=`#9h=b5eO?{t>!v`ay0torHF+mGer)5TEf z6s4dvKIO-{>}j&>8FZ)&=3%R`LHi-JtBAk<55eT=Hjp?Pyyz6~!FK*K2u1+G^)WC+ zLkx-FCV&CemqU?g_lpfNNV11}rjIwujiCXwE@Lqd|Cz^n?(UA);;Igu?dwAkiBh=0lCcwojI=QzmXs|RDTf6 zBP;Lwru&g_N}Y1g`p^w7`J!Rv_`oZ9W<)A$Y(YPhw@Bv0W%N94R&KaAD59A$;3ktfkmwz0^FR%yQn+ zJ{!;AQ2LA^%&fZ1-k{vkN||A%Y>z15SW(Q0vbiMpKlTrDD^iLo9~)FXp{P)e3HzH?Rc&qGuyesU`gEtdHKE47<3IRDM?4fAS*2_0 zC8|^VvbwZAp>~*~lr086ZUr5kEg`Wo>LgSYiiM3N)Xj+%qRF*O3Gm*xN#*Pwm6nxh zJBay&`t1=HmDRfO4oJ4!J&vDA+-21*)%Cv;o-=(E+s}n0S;f2`!M}B@|839!Td>@l zum5IMO)fA0O!X`QUwh=(z+~8%-28mG8X``m>2GBTa<5OfYUCAv0g7y3>nxeHDmJBh z#>3f|bNPidb<=gz7faQUGSONmy~>L<6|$pE>YPjzxrN%xoejSjD}g(;D!WbkHO+q; zAo~gM%Xbj_Kc9c=FE>mt_Uvf3taO zi4t#r9D>3o!l?{n)D>!ZYMQtV+MiN)q!L@>Pn(5D8$PLcD66(uaCX!gwz=1|m2uD{ z|0!`kX{=A|j7V%1>TF1&Zk3&Hk0o`!$!qD{eaVqmURfheMpVTZbiK=aIS|sOmDkn8 z(HaM|)5E(LcAKC*b^BClNTK?hbB*AJc3`HG5#M4 z4HN(Y%E5I1AIOsb5ow5@!zE=!|CcN&sjK)OvZVh1FS4Yzmf9UXsdKoby`}K~11@R$ zf5Rnt?pVkf+~l;hSN$)tOVn@vzmX*$V-n+ev*UtNBfQHK{)aE=^1pn^I?>wy;Y<3S z^Cjc|i!Yg$R+SaknEgL|$*zX{*qpk&|Kdwll$UolRsRPu`TA8=UGuZNbHrrbxo_hf zG1>ZGh{<2SepP!${uf!2<^oGZ?0MTQjw2?Cl^qt(!jYJnm7SCOe<(D{v!Sf%B`mD5 z9HbhcA*~{->P0RTn#gjYg@vW7t>wSTk^nk_+mvhyFU8%6=e}uLAIFUwU0Gc_Crhr= z%s*R-Wt&?7X17LRhk2%KiEPVdup5)Cn_o5j+RW>VdLs)6KqdY;Hkz(WM>D4cxhkNG zlyh4gYJ4V`SStetMB@N;2dJLgi`GhPndx5%^bm&0M*I3rk>JJQ>Fjt*Q*YU9WHSDW zC{86KDguTB*)=t8?0lBMyu?f{O!VCi>Tx&($)6&pg(pHP zZn8r8&=GcmJfo3ze}`RIx|!HW8-5=`j^x^j?5g0DFjH|!rMq@-6;68FNy%w^)Q@#w z7%|5MandHhiH%aJ1&Jukh>*-_f!DQ=x0V z?|n{_(n*;jt*G!%oQ^G%Yk8g?lb_12&!A*WZa()l$|JneTq}sp-jro7#wyh1`##jX zUz)jtPbeT(g?rVwcv#4nM=840m3vAO&7gtaeX-sK?{0G%$mG>kXj?z$W9TgT;JKt< z`cMp5#CEmNyz3jRiOu2`v$4(D^Dgh3BNXb*JW@`F&$xCjroJ{ZlZC0ARvwi#4ShHlALho2W-=QLoL%hv_2VH#wy z^Fs+3#OXYU*~=sJiUV&#y(d4j^ZR`!z6J19;?p#CPZX1{O;bCr*t7j@I)ui)|K!B9 z)&5hJrL6c}%@eG*{Bdl)Ie}*`iq=o`{*4VdGyf7dwAC%JSecW-aPukkeC^%Y!NYdrKhW{LpETzV6*c94I`osA?uPvMF3x;NVw5R?^2#f>i}jh@IMfM_J*W_C z&(;ArCI4fJpD`_%ge%4HpwIpFy%75S!WmeeD!g&+j;X$jqV1^59K_E4jvJ;%;Wh&vR$a zP@sU?k!M~fufE1b=W2CFFVm5yI3*g6*~H}?hdRMAd4tt5ix3kBQ5$D=v&=2E1askE zH-#d%jj&t>6V~zx>be#vyNHDR^dYR-rzsO7Jwxv67DLi4bXnZrz3HHc{gM&ol^2K9 zzVJe0^To?kc!qnv&mdIzlQ55tz;m06cLQ>Ip~Snp?H7D{haG1(KFKcq%JtDVj9bUT z^>z2N?xlSr@ZX*~CE?9KOWd#OMt_vW6TsvqC?-?K2s^bW<&OVeE&qvZLN=c<$K$xA zbPoP783Fk68QrrIvXQOXx7Kt&0|OUQMTuopVkYPnnv#uXTsp6hUVj`E@kc z;PRsZSK}wE(N8KGw#Jxx)tw>RaKgt|?J_R;ME{SLu%||B zohhiqk3U+8GDzsf-O~?+4Vz=F1FlT_k-g;)+9+p??XO}kd1BPt3lU1!1XkytL>zSF z_ilToR|01!KxbXxmN(z*!dyRphiCJ)sxXy>b?~5DAidE|Bz5VXta|sr)4G6Y%gb#| z>fCovwA`AFSa`tlllNlu&aK*1^pwTx({oQ%98dbYc}WvNE=Efjx0=hljGu!>h!!;$ zT=FsM&j+jWUnR5ImVY1Fbv`~ZcJs^hGH#-v>mSFitC!^j)k6Id)CMbe5J@_ErFb|b zYhx(r(t?iRyhj{JCjZ%-PW~wKYXQUNXBOGtbWvcTOX&wnF7Taep< z<$6i-;Cec{%f!{B4o6=Asn-cPh9?Ofe}x5r3A~rJ20YLZPvJ4sM@ws*K*<7rHger? zB=DnFx7m-LBn&jM&{;IB<1Q@swut=m;uxWSzLIJ%87TW$B`G%l{E^%>fzgbK%ITHQ zSDvkmML9G=5A>6DbryM4X^;6u(VNGm@mx2s5YcVo^~LgTQIXzZJ~$e3r$hfOw3pa# z&f&yKA9#By>}Nk4_Uqu3_VSiG@X#3eDsoPf`;_d{mXd#;4PURUqFW7MX}U`!L(%y_ z?_R<32YBeE?qNdjfutWEc^m-z&S6%#gmFlwJbYz}0I=y3`O!o=a7w_4)roPv?S1JQ z06^H#_}iT{;(E9n@hO?}d(kO3^x15`LcXkBnlu2QoWeR(%e~W|(doQgiLauc-cimO z`s}m}4^37=W+_QRZc<^~A1O#yEGNQ;YADvfdrP&|4;urgZA^m>@ctEi8rA@Lz0Y!m)#J<(D>iG#9t-ArOduA}rqK&d3qcO}G+ zh}6Y^%pu@T9uSFyhf|pI!9cFtF&D>=u^fdtAXZ|^88OMB4rC;Bq88K+L!Dg1Yja01 zuE!cD{jbqN)=wxp8&P5!Yd*oI90Fo7@GSv&7(Y@43BWrM=v_n<1O7uG=tF)?%q#8( zm!ceup<67h0rFA!yre2ZR3%^hCvG2b7I>W;{aS$Kndw~<4NuNPqIq3HGCg7SHBm4O z_Npg&A@r8`b$uVIS`-p+IgCT0BjsPPz%YOs9jUw@=X4#uYAh^+_rvq~S5Q;%#?U%J z)~2w#AP8h#N0ZEAW92>Ldx?oYB!H0WDiDAt>6sqa6fMStR6)yP)+m6fQTqaN;q{Wg?*TmU#5T7Quo^fL>RFCYUTc3%%nQLF<<$fv8WYcR~!^UP4 zRdXk3V%KjB4edV2O|4C;T}f##yk=)^2Pfv4IOh@+a>oU2+$K>_eb=xM_U~b=-+b~* zc9UKgqM*!~M7?)GpCg)eCHf3H=XR0ztzU(woC`F=3&gG$#TCTY;DJ+M;ki6$u`??< zIXJu<71+mawNaQI?v>S7ENNb3*OgOF&4sEHrzl~q8!r0Job{WD6^ zxdHc~OTH77Ai|-G?n3%1xp0z}4aracPk|MVOYhfA ztqo^AgJ*G!sELt}(BCSSFOHQqsW!IAmJqH=Mr1B zQD1$H0+_buQ-Fq@NLI6^idK-+s+?RRQ8u2F6*4Qe@9FoKsg0*5fp}Wg(NmM~d;R4u z3hpoNhXxgZr)ex&M3|RG;0*xgB@eD8*~V<eMNxsB9X+G>Qg_}m<%94*P?R5 zprN5G;dEr4e0?RO=yXyE)wpqz)+Vk{yJ1}0uL!C*I|iE4+(Dr0I#QR0%maaeOROWc zUVE(0&->Zc1_Im~s)R~viZ8XD^t%L$L{*si>ZPjrV*?e~%43o%6x7T8wNi7nSTBWw z){#CJ{I9C}H$Em;Z?1=2$HXP0VXy9&!bjp%>By6HG>^Tbc=sWize!~(p}PWCQ&3C2 zMr*EJ?Ec|UCF0s;?*reu4tMTN94h`&AU_6|?-G(VN^9NN=)WA&mepAP zPq^ovl6Ue7pv`dEPAuZaLZ5GhUua0z=6;ASv5og*Z~i<;DRFa%sBu*6N>}ROQFN_W zl1ibrmk|2B9Q%c5nW(@k>jQ&!pL?tOAI>?{^vXZ#WV=_O$;zn^3la)-ZUQ{)^Z@g= z8McDyyrDYbOLF9n%te%iVq?ph;R0HJHGRnGsBcIypcv`2R6;+^ZF12c_z1V~^^`T$C%YX(-Qr zlniG4d{haBQX*{oXkLbOASoRA%inzPvGU-!xJXHK6lz&!u$Xv*p*7J>DHVrwlu;gr zr8SHuj_+%mxuv0&!wZzBC&yOWE1u+jZt!q;~4YAc~tqqc$Ckp>vx^Gc+y?by=ad#I<~Y#dHwgWa{FjT6KPdE+6wq~}7q zt=>^6G3&hYPfzAphtm{i$@t+G_J%V$tS6)E3u_*u9!%$Zz0mw;FM9&q8${`*KQ5Gc zaW-N-k#kkxt6~`ZV{Yg{0hnfplmaB*R#Ncn*g2jgx*mg%uGspiq( z^U2wVW#ff>Z&;nUZ<=qymj;B z4vjvAnYoY$ynVf#ZvM)G{pI6yH8)($S~NHkchVAa)GqYTm{%;#n*N!DFgmU7q-`Qe|T*1y`;ZRJM1Q*ZB=XN-{AY-+Yxb)1c?t-Mn}5&h5dd_!C; zb-F?JEY0AN&A?|h-{yc%OB(*!7cOp(5g%RVaBAhir{Y(hx1>M2vqx+?K67CW`)AMGQCin*`_nR{;O;=5 z8ESer68zM$RfVnI}+y&umZ!_O>fazd5Qz15BZ1heT{`4nCKEct z_&y88ESIL!yLEn^>N|WpcbJ}WcbqyCe&-%ObT=^Zph$mEAdv}df&MN%9GD>-Ube4# zw3Tc1e4PHpCvVfoHXX^#Eb>7{ZU8S20SD@)pv<+tN4stj;ZJn_;g-0+e0~_zf2T91 z!BXctw}{h05@P#)5M1tvGMe;$IZ^?*@iYkS^<=61Mvj}`pO??L*$VzyPkgVAakBZ( zS{m<8BoF{vEI|0bu-pGjmK1Uh3&Z!iW0_>hUmL^8k|-F?JAxT@>z`WO`pqh$qbgcQ8IZU1W|Ae@Bf;YAc@MdUKl3~d{~uXW?2BCiySec8KMrw~hY^9gcQdY7h8#Xm z1N*JN#9h8}BZirFYh4!q3fd}`(PQBczT9@iN({O02#%%F;-S(=4J+w5`8}}*@uJ!h ze?hx;QA}4x%G6n-Z)mjv&qzTi<_5_tT>YJJ{No#N{feS z>QI;qYl0g1SR|_%H5OD4!^EQXoK~PLJ6MT$)-8Q1k<;(cJx;>A&=AhL22>Fhs^mQq zPRJHYB+K#mRK@cI^?Ic6Zs994^tyXLz_k59i8NN0LrG?e*6Ch~;Ea<;q8b0DWTuHE zh>1_X{MzjL`)G3p`_sqvbk5WlU; zh4BV)J6$b`Zi9_ zxNNl~X-zlQb@)yDwq;+j2yA#76mg<*>7C1o_Lq+RzrniHWIM)bP2)Mp7`&a^T{0Z_H*Em{L5=#dRjM?<@0GyMKA0C4e()K2# zv;hcQLQyU#zar83bIYSETm_}78R1_#jLN@0?9I8^_hloOKhv8uf%6*%(so*G z)D`Xz?$OS1MSm{^kE8S-Ugcu@n04XE_S3(Ej0YO9$M9L$G2`G_PQd)x-9I~z9*0X` zNxJYzVe#km1JifQe{TF+Pirmti6Ri;Z+NU|hDX}}C31!S`aE&8gU~}jui-fqsECtJ z`de8>aiUR)x>JNcFa$07ryd`KB@Od-e@%Fn^%}hDlfpHOy?twV3gSRA%#^kf(AF`7 z-iNeu%%GFhM62{$Bnw$>q@WrTpd1e+9?*p$1-Fc#1iFL~NF-xFj6i8VdOBTrq-@=c zlpt{wl!m5gGZN$y?vudYn>?HvqM{HQAnZAtqU|FkDNc;X>Zzu1Y8XMSJfWw}hcl9I zONnr(>dL4v;{k;g+bh}{p$drIwn zp0@A#3+Fd=%oujL0Pxu66)<^ZM)Z)otN~}ohg;ZyD{LWnL&?I0Df4PCxd?!+@&%o1 z|1Op*iV9N<1f~OQBw1>{%R(H@Y*W1XAv}*M#g2NlQ}W?=`F{tB)$MWBkO-6^FU*G9Y^Y!gYP? z$ku^zjfWo4W3fkDP&HD0p|lU95CrWiO|XDyQUvM6U;44yO#}A`#wA&!PVQQFze^CT zU}#_!HveBNUiap_2EfM=i2fqGJ(7@bUE7{RGZ4SKqM9t^U3{)kS<+{Bah};kFATJj zMaFv7GKja7Y|3L5r~pIr!BAWPHYIl~TEyt@Pb(@GibP zmG;3-0h0KOFLxGK2UrMCg*+a=H7y-`#8wj@wMn>=ZO1NWNP8?A0DWi1vWvb861j^l z-;S*w`Lkb}5R-lwe}5w-HdK`}NiIg2<4;p9GIW9_WwW0o*7SVnz43NH$^v+}EzaKG5+UzL&z+ zrS(`Z^42qHn-2~Mr*IyWMt~%#CrO3t#&q4>MSUWnPI7JUjIKe5pI^-1pAXw<01k6u0lyREYMbLvi3BF+e^WSW zR$`%7D}C8K=`PHpwG%uTXfPD=!Na3Z=T?7Ppr1|eV%|B9uNq2QW5e^S_wvk7-1Vmt*Sf9ulHR5ny_yr3|?w6mvWw1L=Q1?OvfP43a-K> zzjkn^VdqUT+g(><=uY-O^M0FDAtHTtUvuFKPguFV$(}Ia7S(!ne7>H87u_xQPFd^Q zP7+J#Gsp%8mvcPIEj`-@P+Ff!Xx@lzc%B*blh)7j_V2WxM}m4^&_qPQB|dwH)*d!LeT74PRD zkNvahW*pPqi{-feW~BHSBy9C$>+F|K^IeG{K`r0+a>3_*oIG>WNB#7F-0^+4p?5Fb z3Smxf+A3Z@bIXi*ok}~ZpTBU$vXz|;FDdaVOcT#-I%EXzMNO%i1ne2vpLXKFaUVC} zw)@Bq2QbJm5MD*3U}A+q0FQ|4rvoe-s0BvQ_wg8fcFc*o7^MvZ;0GsAXn010qn(B4 z950X7IH(B5FW!t%kx$S*h;Ifwb$sHP%~i$N1b;pNPfM_sPZS$sKib13UL++tJ8^w7 zh`)=2KdDJ{mrr_zcdIy^be)v6&+DtahRn@Px&bCn@cI4bPrgG+jQA7;^+}E-C21um zM}Z{u`2+#(xL6<3#f{`B9DDKv$s#QA;vvjjh%;;FU3Bz>uFnwtv z?X^$(GeP6$q>Onm^NoBuqCNd9m}#4kelU@KV3x6EX?sm zW@#4YYs#mfitY&c6)P0w^%dnV6y*9ACme+r*G(2wEfi*=ith;(l7xzzeT!SoOX^XD z!C|Tz6txFMst-{R0a&Rly@c*u`hW}@FH(zvl|Cs_lSP+K`9fz<5XP^P2byK0D7D$m zk{7;ZFZ)VfE|kpmm5%$CO%2iHJw3zx7MP1jV3Q3iHHZO&0&h9#J-|SvGH8^@Cjgom@Ifrb;YQN9)V@f0v?! zD}HL0swE`k#A;FP=Q&>{H3-8I;cdB$qX1UYUtfVUcICsm!JBEY+>Dbap)(>LoL zYSjM5*QRdOxp;Ds4eKacb*l)&ie~+LVU+-~3P- zxxtUjhOKW=Z0y(qYb+XLeN6g88waKuOKEx!6q8^$vEhCYMs0KnZlX6dwJbJFFQQC= z=2^w&7Z%Mg{hD7h!)^`DOH<8nx0)BWnpR!nyZ!FGUj&z#VYh~s&r>a5T$%;bbj;uo2PqvSD)bVyQ&*`ohtbYNb(Lb6YJnCrI?H`eWDEf=wiIbb z>`h`NIDPT%u@7esGaLX>w&wWe3;f=9f;YT#M86Fw2 z3lF0pE2mkU|MYG8b=y%O`~bp^-ue=YuqU$h4S)z7BzTErbrY1q14`5$0NLL;Q5F!sG3E(_iZ}M)>rIpSELXWW};LPY)U;{)6Juc|Z zbR1%Q>0wyp;G{q5voLUpI~b z0dSCZHYQWa{D3C5TM3+B=4F~w74#6=9TVi)m$&jol0-!=fM28R%IrNL3I=*pcYC->5Ek?vCp1*$ z55$@FC>h%!jc+}^(w>nz7(FoR7S(F|7b3kfs^18gCUhRUF#T%n$<*FUXs9xw6{J3t zz>R;ieCR?&WcULCR-0Ohw|8)VSn2y{~*C_cmR!FUWyD_f#1L* zulY}YRphwtIs{-4g2dsAREQ7;!Owu;Fw=sR0d@?+9tSyl8Pcze5MG%E00d3>iBJ>d zA{N1qhrES6>G(4|{bt&3cY1R0$Y#$oQvu+~u+`HUyepO2aR1A`ak-^T ztD&eEtn-<{_zaS9z@Gn6M<6@k95uRe6Cs6t#I4`)V+;6KI&?VrAb~NqIq-;u$+M$% z9>=vFYIU4Z0xTQHS5y0b2=gBk^9dh-O3|Qx*Jnw%XJ=enrFL7L|AJ$U@!5na?lgM9 z3OtyCbfeQzgI%V($c8Lr41VgQZu1Oa{AL64;mMRO9?~2DIWCImx;$(t_M{_CyghZ; z{O{a|DB@8GcyV`lacL^g0uTmX@)JN?#!E78I+@Vz>Gra}bfkY9BHBmM)X&ft%5(|O z-rhKVr#U}5Fz2LZ{(Dl!ze9@sCgq1+Eo`9QQ7Y`s8bjdET{2ioI|C z(anJr{g(ZsrUwp9;GfcG7P~!Z-GKAuRt%@&8UqAowtGYr4Dp7A}s_+wd@p# zrWH;vrm--J{ycD^89oqOly#f1)0zBc`G^9{L3HS~16|-?*Zn1y2nsTg($&cQc5aJ( zpLXmDey&-0dP)>=kqGH31#ozXYE-xX^pqfV+S6?r8!)WQ4h(*N>DfGP)HHnb^ySTx z#{gyS+uNz1&C`zfW8LJEuFVy$DwunVhBAT{(}V`;3|7~`fks0#)q`hQ3(trr4bJ9GGdgVqm~`&dQfns9hnN) zDuGddmQJT`6OqdV)_wVhhH5VIUNQlsl(+B#~AP5`)-dGbxKW4uQh+&y;-&aDr)BGow zk6(tkL@)d4P9q49kKCq@FN-}?>fyYw$A1GNcwC^Qq5iC(*l&7@xBblHz55g_sXQ9A zOzpg=)bTb0{P5?0D^vg895Yn{RJ4JV)K=Wp?@Yw5c`KYvADB-?=&^nG5*?lOZ{=F) zm@N5zI0(AvKU(o`eW>~n`}v`nL%APWWpNi`Lrb^z!d*@53E?T)T<`{}!bJdA}t{7=u%ZFrGpbNx@E z+J9$-4@v#taV``)4&wO^d}#SE2l!Wx`S&_g{9fz%noJOPIevct8vf^Me%s&8ichXr z$nU-$Y1XFYbtZ_=p;C0{&`G|n*8lV$eA@f(=szxyX>pHJiIPtsCty?le=P2$Dj_6l z&HdWC`i91)=He4~s~FW;NnX zKdm>2G7_P}H8i=7%Jq#F8QWhnPTtEw?|lDp@Uv$3Md8hmqyMzG!!9P6aGf;N)g%9Y zUHzg+6S`-vEE~v^K^8pa*Lg`b3jo;UKQUBCY;rIr9^mB_40pO1^4B4Lp&pVYrm-@w zxhns$nqTcKYu6{scZ_>xIXvm>JZa(@{vlCm(p$+?{*c|nrEjw=Vp>5glXV|%Je6|t z+ujYAqO&+_TU~jxDq%)U)e1f)6z6l@(o8dIo8c>uZ#t)*9WX!HC_f~m7qzh){JC}Y zB^7XCR(t`gvI);3pI3`LpT%MVb0tqGnip-ord>0=R!ohhya-NVAA0NgPRbT${7Lne zw;T~PSsC0r5~@w-lybd$Nxe!Idi<=`-0p(yxEg?o3fua0O6Ln19+tKtpHY`tB4)tc zl(75ADF)AA6wX2JBOT99sv<5+a0|VM2?ytPB18j44Ut@;>FGpv&QWc zNW*YoH|!pf+la`W6{$@D$)dH*s`^r_+m-h)YyfvAG|FjA5>Os?VyNnBc$po8(+vyK z9V1AYdN~Y__3|hWQd(LZ_stm$r=Uc#n0qrxC>6%4cFj$nGMXHfF6fbm@vy-FMMrK? zStVj_)q6Ep5UjkAl-v3rIneS4GLr&E>d?9Dc#;AHDCN;Wr}-Q>;R^Jk_L6EIvN@$7TxN>5)`;m-W>RJ-X<~f1l1YMs8f#(oyja-B zHe@q-m$kG|r=Is3=f-&`*Mo#$^Uct`)4*$oHYfu)?kM*7acd;}4~yfw(jwr|n86=* ze__AvJto2?)gK)?D1j6+GQyB!;k>EdMymQm6LHx>ivBTeBXnhzYQu;L-0pz!$tLoz z=9N)3@}v=5>la0zThmgZ+|qi3pz=7Q+TE0ki#?V((-Am}gWlgoHhG2eFoQ~rG$M6lBpI5wfL4e^Re*|-Xm zn~?iwyBjB}h?m4u`(PA$qzp5Zrw^duf>fJQ38}=u?E@ z)IV=P0N~0R`hP@Mhxq-TK%O^Z_UdBK=b_?QOmGR-W2TvMwl@U~@M+Qk9y++{c+d?F za0up%T1D-pq?2ONc57r+3tQ0VdjbneH4`M^5~R=x5OqqTxOyBcbZ)p=qY`=|4R?%P zqZ(sROx*ISVhtUH^0N$0)brY9<y!1@WpD104(W(@D7S+OCGFU>avheOU_D7Hz!ojrX=FTuOzS zfEL9gE(v-{{;MOQQ!vcLMjZFqA)?-uqw~Otr8NvI8hXJV!X^VkP%J3sFZ^xvr&4zr z6)e=><6=d$^gLceS&k4F5`%Q=CS*>WG!qVmKR=9;r zC2X@d3MasBdC6_;ew}tAk#h+a(mv2o&P!yBx?1<)uJb^=nvpHeMhHh+R)JC zL#Azda$(5Iu&ECrnI2}!on+1pJR}GYnaM($n0xEOIME@DWZ|`0?wd--vL&c~s_l#H z%3%N->0>M#h2Z5gWOr{aEm29;rzQ37e(&LL!`@=ZyZAy8L9Myi+yt|h6v@#m6Te`R zx`mFn`>1wSg=%qRoPqkU6mw(1uEI%%C~dfV;RGSO=@RHp`pPC5P2^ivP$4%?Jg*PU_A!SwqV5ZFHQnzd=7dGuCIwuSZ&igKb&cuUx*{H zXzf+`z3BJmpH80W$fU0sA41MdL;@B$8lQ zLP`+T3|IiyX|^HamB&lVVv%qaW)R)=uDIp8a7F z$RyufNjZ;6yQHB;9G}MzZn)FWjuE4T=5Q47gWKwuJa)d4Hg;-h*q(b1mmpi}{*X*a zx%-{Sau!^X(mhK{82K2VZDoSdS&Y*KVo`tWlm>(WgAKMtre_*LQjk#kVUqI>4zyn_ zvsb;vtOxj?nI!W~Bf-FamT!k=cHHS9q;?E}6(!=eR1moHXPK`vxXb_j5P6;=ww&@T zR2xc(Py5MNmG%-H2aJ8Szkbzn`|$!Bw2=k-*;&HI-l~12rQh`E@S0o;DN{-EL-SX6 zu!Wka2!=OikO0TzFbUO#RW7%!IGb0yg=%@9#WF^sy}hM z68qbxPq@4xuRCCL+HLg(oI!4ds9*uqPAH5YH?Z*Bn{=Pql(umb7fe zFf6hSu6bjKucXJ8$BEdWrbK3Nh3vApw#SNX#8$|d2!LED)v&@!=O_8#pPzO|^tcwU zxcYCg{gNQ{MCl}nScbOWf&olNcF4;U(Rq3j zo%Y5u&}$QkPFSe1j3=`}B1w0Y&h`9s+VPtS;6y!wkNhMY^ESN;kDf$AN5-SbyEf@S zG>050Q5~L%c5tFc3seb0>UgXGAAl*>p$Z27@G^;q*=6%RP``LYfXbgg`R95tfF<51 zrQCtZS~`WTx2MEowXQyQ8>>9YUl*Dr; zVloEM1WJmll+qmrR;^MxG4z&_TDn$mSP)kFa#rYv7q{H6^FeVuK5#gMBt0sK61XRJ z@dK}sk7$F&nGC0M=-dckB~i+gu&{O`6EKqmpsNW0xf%{quN|iVtJ09w?+{^iL(?;0 z$e9bm-V`ksDDVrIheJUELW#%}%oJt5mbO7sBctsp()u3hR79i<$c4>DVr`txTtEor z$WX|?1Z|Xfp%vqDZr_-v_?XEF}eGg^*py#Wuih7^cC zoILjFc3yWM;)n~ImnT$0tkua{1Jfvup+@K7fLT)FrO;})iL?jyfSV!>%%27(kvOj! z$9J004PHklf*Frv8Gv>S{SG8o+uSsc)>8))4zFbeBQD-7PoFT|^>zPOR2K5ye9RbB z$DOvuWQgqH-8*$_CS!CeTo=rAEB3j{VOmfK zuUUL5{2N!mN?5a6vAwBQu4L5_5vrgls9S}dJtIfT0&by+xvN}`+>&~%_mVfc9ACkb zu&#!uwd>t0<5YnmqiPdY?b$<6#z5Nxs$GzsQ2(9(PY%$;r|l~&1fx{W`oOZU-CM6d zN|eRKkTD)C{f-$l(+?x4C<{=8QH#3+TtuSe5`b^7z~oRA90L)-13#QHX<2|-urVFv z$xaMv!0Fxb0GJA_i?Se!pw6rsXofDQBKYZp5kSl=h(kPxzIVCD$evTv< ze6DVtm4HS1uHF{@&{T)DY>#EOZtF$hCzvlqW<-7RcXQ;u#0CoN)Ft>2zg9BV_^4m= zrx|F-M`QVXYqpPVJA%fZ$_I0mWEW{WAKRKuY2b-$V;0jCbfw_YQrkAVB@Yd8jF;|p zL3tUWE(fE6zPA#L&H)4LO8)Iz^tK`fhdno&$!eR{66fnFl!dU6Eep%}`EY56b5^V< zZF%2wE~qYEcI(fm^OmSBMRxEO>N*h_UXLdOxrw2Ol+B#fHOdLC8oySY^4hlP( z!JpSfLBmu=6H%Cpf(W3wj?EW)FOw;Dck0AvGauTl6&hfaE9>z#y~35M)CQDx-jy8- zQ+JWRX_~(5H>Pk|oJS2ThidgUptD&WzHZ}}kL-hF#``ns;h*1oztXSPBs)BKZ>bpt}1ft~n52o$cwa^Y3O0=Zu3rm9H zQ2=+s#jD>&yMobD&C{?fwMX`Qz45zU*(G#K3AXOp%LP@nr}%`=@9J6!2-SAlUo56>DsNICMxBjPbpWb17!3)BX-&qeD*Qnn`HkB}(dj zMAN`fTiNqCvB+JPzY?`u$KZEEhA4iZtbtgq$H;6F@;u!~o^ieE00@&E&Gkjz;J>ar zIJ9`vZH60unbww_cnJCdDXlICg!abFVBwu6>==nkH@cHm&O&b~8 z#Cmz6{kxn+1IwFlVt-t28x!;zQsqw=0G3Yjw!_%fg1GeL&%k2H#0csea139FdZF&#hy*a4XyW$+d? zWCap#)iWhfhwT>S4Y=fbLp0Ph($e8u)1T|<0nqfJSfR|G&~&P;;;iibrZAi@y}@r{ zJBsaf@!hy~pe4_x-WYisUn}xm@QSIXh?lRdnKX^+t9ZzAXqynmh;_vzs!ddXzXYd3 zk@vn?(%S7|g7JpuiO8ccBFfC}T^HZ_#kl%m&9&}WBq=dtCB(cc-Kg*p@=Gi?L6}zq z&AJf>{&Nnz8GH05mOJ(lhhQwWna@;2Gj@pYo3hkR<>%!uW7u>PrbnNH&4b}Mp7#Q? zA0#uLuaFQ+GcFv~VL7le5;C3*1;>U;`K0lvU4M8H8AFMCyP>#d)*F46m=4tLR`FMB zsK`hVp{q}Cl!5HePkhQpaIHVaC5n}oOxZ)j zWN~OGg<(zr`Ep}a8=b#m0>M&B>eSm473O93U|7a!l@G(gWAAp}f?zvr!AiA0S8_Wr zKfLGkLAu|OF7OmpWM9WJ9Ug0Ot>E@PkW>$@48fo1J{<8a@F%QSw=2X*dyvCdgakd6?cQ*X*Uiw;yV7`k)mk$*S#-m(kK<)%EiV z9?FZAsP46^raGK9(<Gj)c1@~~oJ+5HtG0wN}NGgsiS58lS%eihQJliM%qcPeKo`s^=F^$hZHdfH< z<5%jr&b~3QCXPKOj>#;s!;bGkPHth2Qg=}ow$L;g zI1|vc8y@CzzN1|49Ne&I_k2YUB)r&8-QMuhxM4i@TbvfkIDwVt2w#L-^PmIRXxq_)K`V%k%5blDJ{Z>jT5D5l*8(z{CxIFB@%Xhiftw zrMZq~SM4Ky{Boc=9JjTfJ9{YuhiDQo{8En)UN_|ioZ@6&87Jl(mFOQPUgdi34V2aj zelX!@hDb7MytQM_A|J^mYX2IdCXO+2h~bC@{;UlBD1i1$B#AOOo_LIG-BX3|&7{a{ zUi;?=HNEdC`5mI7p0l+K4xjb>HQ|1uFLFN#q4?206aSA$NlXNA|3{V#8=2qOs1y7j zSyDmawIk@69A`5AIx+v!Yj5fCpYHYjQ+}Jn<`@P2K8ByGe~G_FBuS}pB6VY0OS!3W z!!?S1aIoRcZyljBdB$+E2l<*)-kq-DX#zrW@@5_@rG{6}uJDQ=ryL`(QqtVkU7%I)2~fnLzQl9njCn^m&b4CTDbm zy{~PpbD0UEA=vcAJ>!^+=HfE}i(US;A%P|QpY3~`dxoR^?UgUr`MfOmVsi?--04-r z=~it2_1SRn@&STPL)BKyP{Ye`?gHE(HRX4-6GeZTl=4MK__9;bdF?xIJAG7NU$~P% zqZ5)%$-~d(Wt* z-gaMirq6^HddJW^1W@S`dJ!<#C?W>1P$l$^p@$xN$AEMY0wPVs015~qMN|Y-Py_^2 z>|o))^R9QTv)9MZdOi8VZqG^$HWYk_Lp>3rMLrQ3Y%U zq}?UI@&zUH0J5h6qdSWCUzqJ4cCt4SRjM&3r?FolrU+&=+ECf+=UuJed;lpSw-!j2 z65s#{#jCqEZ^^5<8wky@7lA_Haw`-VyMqN9#_8zMC(FWn_TLq`yLk^6;V-_Bg?n1` zt(Tr3CM6U)UUpuu2wl{bhhI&9v0mmg7? zOrrqS{^y_t=Sn)!0g+@VwV^7&oL1Cf`1VmXk&}d5C^3?io{SiUkh+vW=9Chp5{8kZ zn#IyGC${(!6$6CaO`xFz?ohF?!_HQR&cQnZnm*|%lC_@TPLj3Iw>o#3oQIx}CAmKx z{yZ`Xl9dRKeg?xTaNzU@$=`mh_kq=r;AH=lg8VP$3ONh_!f}3f3I%PPvD1G0Xy7yd z>Krf8NKyUU((UBkfzNVABL4kmeq>lg{r@tHo zu12HUz6GDY-qo#i8~&EUsVkmGSg*;kk9uE!{o`7bJ~z#LoU5IJXi>WHYT{kyOm_6g z{!fpiKXu9X>VeB;cOh)bwWQup`3rGLUmpJ}Y&&=28n`=uAt(07V!(9l&nx9Cv3qZF zPQ>l6pKAZLzt#R9VcT~6-tP2?Ykz;dZjb%7_i6eXYqb-g@fX4h+p-EkxSR~(O5}KU zzm;F`O(tkVPT+e~`A3O5^e?j{S0WB&1P)`P)Eexa6!$15%drZjIYNk^2i_E&L8E1elnl-%FLG!H-q`5SCKM%fk>I0Q3 zHPq?TBb)>oEA_k zqi`b41}^s{sr>LIr3>ie2iBeGNtt!30WSuf1y(b9ck0w%q?%dScNX1Ksn=*K9(M@J zD;e{v*NSX7F6O#hI^SCVQKre-(IvQi`ScR3(FraY7F@Arc8>ii-V|Wsuz=(~94-t1 zfJz;7AHV=YK)kT9u&Ai0k&%&^nHf|(=~_Zd`2o(0rZ>4ZFZA6hu;!caJBw_0C5}ZR z@E@l&|8*J-90CfUb3h8~w5+hO7VAq!TufVBUQSd;TS7}&R9IL+Sor9_+(JrH!g5DM z534Kuhh9iQPfG8If`Ng7GG6=Nk|7&?b#VuASqm}oATg2CI6WIFLkCGU6KOHB)ER3r z=hI@xttGsj#3FpeEv<1@rzQVOFQoHty^w#Xsz4yR9^Jn3L}!kZ--I(Nd4bo}3vp;P}&G87mT{BOxn zow_uO~_{*N-fxsm(x3ojOvp5=C^)g`Tr7vlBhV2Qkj0`C*lSC?2_df$Jvy{!KE`%m+J zR_7?UW=g9?h5l8(oP7^iXt%S z!%zBbtO#OJamts5hQGAD#KGf94um~G;9*v<$gX}w(3VQ;arLeejSctAG0H1@3CHk; z*T#`yJ~tHP=1#rku&D%xD)cPg%y-~K5oIlIGSU}RWXv+s?0$r9};u1{Q zlW650VN{2D7qFJlRb&H;sk;l!$1-CmqVkFPT|>9t}r;r zDmoFuPhQApyepz+kPe7~d6hyBXJyPpZu6$gu8+8%(0PP=!Cs*8{+(p0d3~MGYU$p1 zp-`Sim5eHMMh^HU88jkpPYAK(?R>dve&(1QWz6}OSp*J5$9YrfDQ+g`1K31Lc+*ao z?SqBlaz2W+3O1}f-HDEpbDGyNJkpY0YpaPk^W{JRf4A{^OSr}|8h{44{aDJkI=P`B z%Le|eYb%4#DBqBCPj?qCD;rWg;p;L{+i~gO)=qi>6Q!i7fzv>VS&`tBL!D5(ydXEl zSRNX;lbh(Qc9mB)&)$uvz4((`C&c61VR{{h)*}L}bW$!uE@etjS*puE*Epr{$s1zbetC+GCuGse`8Z*@IU z`+e;8hD4N9fMwgnQV&Y~k8Ho->#5yuLhXOls9oqk%7fDCf4>1L0e6qhdj|jg?$Rgh z^X;J0X{~EHx!EK5$I@*Xwy7n*dojYBzMlraq^hhK>cVHG21yYunmx}x-GH2C3K+PMB=lIp{Q-}T`!W+AsRXl1 z-YbCwxP?ZjNr))7{%nGgod&md#e>AbJu~+6vmqCg5PZ|)jOl^(=yRDiiUhMXu2)be z?*bIcd$#5L_csB?o}S0}EK;zbt%{X|LK_WQo3pyAKvGoJ6*IdC!;2$ae_KDbd|G0{S0 zKCEZoP0u`DlyKx*&Ao`tFZd`htG@00XGo*6>-cQm;_!{pI~(Q>>7(6Q>!*}dlb}JY z&P;YGV4LuU&D>|M>Q`c2-`6IS_+MN!k=sb$&BRO$H!O|TY9FQ~?4rhVkpC5ZhVSfO zgsP|Uyu_lqqDH8c`s}ka$bRdLn~f7^iflj;Mm%a;583~UC~(FuH0I~#+L?DL?HBlV z`7hatL*-9RdLYjpx;vTWO&ob_aCU zeD_wQ0imJ#LLugbb{FdysJ8zP8QHG3?W|Xls`hC#V@D{RBDq|x91~S0sNP|@l)`;u znO{8M$=<`c(VyN|^;4pmY?LEwLq`%;(nT>is_xTOh-(Lj)<*o;LFBjDZmJjORaIkH zvT!Hu3aCo7Y&ris=y~IaxEVW@h0KH;#|DAV;U6i7q;Qg~kQdC^X_9;Lqi6s8INM8{ zEp_YcFypiT{g@}<+K7m1ZDQ|2q}Gp{{i2$kJNhPSH(%{^;^i!N>m=j7BM&nIdgz z4|Om(<<*`*iQab6h<(M-QLQ@ns6kJ{a5BPLP(#=B(Bj0RjzXk}!+YE{XsVpjZHv$P zBJr2sgjTJ0G_|Ad2{-q*-gc8cp}4i>6ddyGSxYD;{`|c5!C=Vq%7w0W|KmGZj~Oq< z?!2C*O{M*nwTOMOJKpII@qfF@SQ-I3vdnXf?r)wE(Rp=Lj(PJ=z^&i&k``Z74s5wl zU5+9mr+XA$y&Spn_0FB@i7w?LVavs>a*0nIj|xtkrJU1Vdil@UmrDhIF}U}9+-1v4 zL+@5S^XH%Ia|d{1#9uu*p|PO)BmpDW!7?etnB%NYO1%L35godxBoCRa8N0c(XCojcjHG>IP61c z%kS8?93D=1L;0E%ys@Q!#4kkqmsb(ut+2)LB6*&#uLcb^r&c!FQb)g4O~2h-QjL1_ zJnBh6B7sXS8-(xBQJh3e&e5NH^DS}T{|>&~nzB9lSrguzN`XiS)ug5h8MzwOG)tN= zHy1io@G>Qg9Sm2DVz%)!o%n4>(vUv6Y5aPIPDG0%h3C)MO7Bf~?CEx{kAdM%Egt@)x& z9`Kv9(y2Jn09HpIk7zg<9=i*}g8-Ur_RjsNrtgpLLxCnCRqN26e?Z^Jh6^||A?`p19kE6nIk;C zaDCYs%_45#V$Zcur?h@@8b?A#hPK(k+6rKZgJduPL&o96m8^j)j*^<;BemIoiS8-i zvhyv@K8s*|6rc8ny?Po+Nr?)t*8T*y-(J&xl8|`CF(<7vK4mPmix6O`5s5}Xo<8T& z(9ZdK>Il3vBU8}f7ZqK;5j|p&`&HWSu}4-+5AE7U?l3CvqjX-8NuKbF=rSN*LD5jj zIrrGxyv8~sUm!~=!M~gVS?m#4cGo%b{+Lm44t*@#{Wkg;Qav^q{i|5W;k~SRpJDDQ zp8HmThJ%UVzI*vN?Ra>ehP$Qk>3H&?aJ>MX9Gc^-Wr-5%3+R`!&q z*dqSgsWh447wOsFI8~D^#B-UCla;?57Puz_ezXG}`fnY?8{-wG@X?4#`ZyZmr zx{37+`JR?c?K9&DQD1+;7;n~W2-9}6$z}wU0HLr4I1asTnMz3 z<652zt0YsJO%YAi+FmO|zNMA8)O9)8Qnb9FxN>`ETzly&TaGK-OlCR;kX{h@}9F9Jq~xe+>Re~ z*-iEYm-o0vcSry3IqBQ$soZ_)xMuofSJq@NMY+c!8fAd%z1Y&1?F*-F_rykbTZr~l z9Pc~f+fP&OJ?Sf&!t8vYRdpwXepJaJAqtfyq@1vK0de_G`U0E^Di0}uJoo`T4Tix% z5I6`YaR6YYnJEK2BW4p_Vy*pMu03+R9Y8iO7J+R_CFs=`ojJ`Y1#;VP_ zizg3a0NBIr!8gkHrtb`Fv%%g+-+j6bI4ll4Ja_k(GUR2(;LP#C@1lbU(jXoOd98f! z>F>e0jC(7`nVbegOD#;f-2oV#^+e|G($JH0gUHN*2cp9e`kKTKrxA!@i?Wn1zQhS7mjTHNzSd1P0zZqPA;L0$9&z67+C_ zV<#ok*5kq1tr4R~)w3%_jlwn3(r4&k?5H4BjJrM?6X=qu$N0?#HWisFfx5TBb*pAz z=CJpUsc%JfuP&QgCjEkLP2``*=uGp87cCvT!KRO{+USlSJ2O6!FVRDPu}?+8k)jRhHTg8yEz1@Ff9mDL;XA1h z@+m;qKxX(O*qRfXjRrFyM1wQ1-eUCnIgodzg<}`s-31N|b|&@do$alUWTVDT`k)^! z!>*29Sb)A&a0st09(42BaBdbqCKb>0Agg+|>c_k&h9VfL}?9m7aYK%fASF(f{frvO28)V3wOn|%(fX899mQ;GZm z4`6x#a4PHmT@}<;G0Y4Hcnm#RF9y-rgJ+)S0msUx-X(_(C~zwUN29xOCjMwm!zY!y z$$1^)9-Aj&lH=((=S)3xD>r=NcuU3^*AybP1Sfio(MX=`FT{xw0Ox?D#R4MrFd1cx zg>0#yAvEMw9LiY(@R>pOpGTjWh3| z9OSktI_ra9^X}NKM$ zQG0j6-aB*av2GAI^wNP{8FJsVQ@`o)ts9+mR|BcnR8msv%atO!i;0H3gg;u36Iege zI^}{ksY4vTlC#SJ@JP%J?ngt4q08SM2ZrxVc!Z2Q<|rrIf7qV34ttcdXRfF)T86 zh4plSh9Go#>?F9i*>rQWV&c{baQ(r{l<^~)7nIQKba@PI)2C!xqjKZ6mP_YmwYI9O z=0g^B0U4-JlTUYhpAWd*;(Ste^Rz)G6|`t9#E}q8?xr9C4Y{o}5_?3aG|}rr8fA_h zg7PM!*o`$u5!;>OfCgzEN@%HhdCLvoh(dBbiEHfsh*%GW!Wf(R^hLzzM}O+ZxP;k1 z&Q?hwpOX&Lrm8M9yGDCTK4)h0*F|i6HGnUfzy(Opj45#SXOp~4R21Wjx}1Q6t#ou2 zsC4}uH%`Uj6SCf=$M+OspzNN!XMOo-vdX$ z4Vy5xhv^#aZQDX`MWVRAr7`EcbpQo%%>w2eL=A5L4qJjl`4d4MHT3#Zl#D5Ny3ro# z@&3`1nRlIbwcMorh=9Z?X-VmpQF4O2+h(`QPregBMGkH1#0K4>jGcX3JHoEji3PmY zC%Qj88je9fsF-}GlRdjqJMk&>)!uKr8?W9d{MFt4UCsa=oiON{9_=Zj(#3 zN;dfURp$v-Jh(SDPe_f&3hkkhOjD5S6nf}xE@2S%Z3WC58>2~Cf5a&UtyyR5=_Tx} za=)|5mNp$Wa}K(ATte^cDE!5(v9U5G@1huIzRm1>)1;aK?>V{Y#*nxlzusyTA0K=JPLb{qraK+t;S)oC_Zh!v6kxd*#!o>oK1pn{JeM!d|%er;0+j z#M$JH^RaV7qy)IG6)ql)Ut`T0LT=R6RKc(Xcd8&uFO(u$ zj&!z`i_@Ddp_7}QRFN`fO(x!kQB6D4=~bP2IAK$!K-;HLCQCx@{l$C-6ZG3;e2LDR zT)l3uOZnzXif`d^AICkCMN*tErI8P$tZTD^QxrFH1%iav3iW)tWXqi6Ufd{hSftA4 z3D;9E)?DuFttru0^WMnTUG5|peixj(3^D);pu!=Jf|d87^i zrU`9BuQ)SzhjYZ(+wW}K+IDpFU&ss`6$yCMaTGJZ6gV!GV;l5P?rjSNkZ*q!G^uuP zAPZ0$u??O&`r5#jNAJ_4;OT>7|FDP5m~h#J%vv1E3YoKBc@*;G*3R}}S(_7fp-<0V z$of9*5HNK_N=uN3fOaB5hRqQbsu&cG!rE-g3gM{`$s|oCgp-dmZQo^KSjw#WS6906^Rf%jA&ir&h80AVRtcg!uh|>RDft=y zl3^o#9>OV+AfeJO6$gDgPUDZGUeJVAbT@Md_AztOWfK%1S&uZB-7r{nItE$S3iPKxm60%p`aBr!B>KwCPRm6 zuo0otlAp_}*oLKMM(sgUzeEGPvNVUM3@86Fb z&$lI`A?2scPzpvHz$rqOSX<};%|DEDPZIdH zr7!;MdmBKI2Zzznj=HNMgKW&5<#cm@xo0JSkhmyY{2;&ASqc!bBbGBBuiWOJmhR;X zQ~$-}>|RBW`6fP=+A^*bFEDfiWqdM_Xt>H~p4i`7>x^{6&smzavV{rk&ZUsGgQvZq zl`Qhr=V9Yao|s*QX4y-dPpVQ*U=kW%1uCYw!ZYV!gg^|BP`+R;4x)YCIw0U6ulTFQ z=v_Bs6GwwYc-g#}ihpjq!{)iXuiZcIy$_wRT06%JN9_%++gYDq_7%;>MaciiV&nRw z%%8V%99tjz^3rQ7TfpE+2sEaCfiQEQU!^+kgqQs{{M2i@c(l8Z-Tn#ud!> z#zQ0)cz$RiAA9w1(v_E6`W;V$*_>>XyoCdoPzSk&QMk3ooD+-sz3vlkRLxmjN7`nL zWWD$l;rp?^VRmZ!4fEJ0zAnehXD?qZC~c8Yztu9G$2pw;3?>_P<2aRlxigAff6?Yr z$w_6~4I@yGc!RBL^RGdf{@=ivM7gO=tKTSz(*q{@bT9D9)Ksbz)%V5yUicxmppRw5?S5`f8LJ}1xg{N3m$S8_*XL+E3UAKx4kJm^!LTCT2Rv(bV5YK;1L)iza` z8p-A{CGxJZI_r)rhiy7h3tE_J%dE5Iudvbena{C$NOJ52d0Y@m$~3KW48S{oKldFjzKTyhd;pMZWL#<9hY!qXP?U6wu0c5;vn1LO_e$GJ*JVF~m(oOVSVM5l=3_VTN#QK;9lNyf5d?yf%wQ<^8#e>$ZD?x%F#N_s zp5330!l~a4`h?EhkAL=Fp2t48Z1jd{Xwl) z)8+SbE!r+Lx!OU#!0_b}Ygt(@@nqf7D_07-T&YMhm(}?jAtu?iQM2&l&-0`5*Q~fA zOxV2Q=_vBuwZj)qfsawpAx9_Cm9P>5z(-6xJnrXX3DML6u6Q~(FaRV0s%VBmdg)}{ z(y^f?UHAdQt3e@x?w=Lx0UVc{K}seg(LziIehom7o~)vfB6130+fC3MXR~WeSw>#Q z==@7B)X9LTFrcTkIee+9Jx^06u&J?|sn>MaFTXqTJt3uU26`2wrZrMCK(_ra8gGE) zHX=3CDy`5fZ3vr|zw)o?8jFW;<00$>ILn)GWEaM=Bw64fHyD5}i`inyF7R+x99t_q zt%sT+o}ZS7L%rk{*CV3{WRTUK&`+ig3t?1eP?HNNdm7q{fEp^vcw&{smrsdl#QW5N z`V_c1nWc5$)|f#ZqX3*l@CY4NLrEC};2;rz;m&5!()Dl<)+`{;1c||!+zwfPHxF`3 zsO-^5;0Oa5Ku7w~vNIWIV;smT%ZdcV-H2Q!L{!8s(nS`Q5RUSrfvO~w@60ta7SJZ4 zV(BRR71q@tj78N%F!IXCC~PFkm2@@`EB+V+G-s}fJ_M6K=cQ0sw2pY#3|a;)u7d`4 z6hPILJnN=B(#*BcnQL|{xtfZ(x_$ZnyE*3`7P2Zl09-n2a1336o8yWu3PZr^0_#Xr zCN?01X*UEDo4~tv43Ot{`UNfGIv3 zL(jCwq5`n6RMsMap^9FB`}O6qQ{War#jpbEDjjA)1%rusha*8W6ZKpdOqxYYq~(t* zfhXOXiK7-gX(I5z?0#KTz~^@5QVbK^zBAf3-8 zGXV#W0mSQ`UU0b3ONF+%2^H=Rr`KwtoQn_BLzx(hxau>@uki3-_;!G$aI80w9R zS-$TpW^_T20sBGCSqx%t@Ty530>WqD+GLhmCpVT}TQ-9lj>t@k&spuu0|6k|r97Qf z_46T0sjNW(3#2w)zwwX;qc;J#?9&+3-ad>(sS78kyNK8sVoOOA&2GO6w-VvO3{)@? zWl5>dVB|=a6(nN-zC2_oQxaT(8{#4EyN&LcnmZFnE>i0;me(U5s^HUBFc{mlcNAJOe7EPpnyQE ziy_xF31@;cH+g~Ln?4M#{)|0M2=8vvGZFe+W9G+wT+|8>Ll!ScZ=KQw%*o<@M6Rx8 zz?+Uzi{S7V$z*3%`+GP4Tol)H0ZkX{Qt=SQZ3cxe(D4{hKX+yyr2q>zY1>yu^{z0xIzWLA>4g zMv#-HT|Yanu1TZKgu0~;p4|2>*9iFy^5U+uD}zT! zZ3!&=?KgW(NznivZuAiB@Wq%AGFq&_Hhr*1A3YEaKhpx@XYN!JVOAut-xmYNn{^?% zGSAq$+;=Wu=mj9q#1Ov%LR??)wL8Jr?!wSmtkJZ#=7f-Vq%Oplfs|)9@+S84MAaq` zV4T0}=hN?HQ;|3f{@43)XB42J2VF@O3~$W;FQJh%aRI;|CI zixCIH&!^fg-U&834einDAA}G83IcWOLd+DnvdF&-ylc>!YKvXSlYp+73(Ghkaj^c`q;+z6H|_Zf%L-M-73-<5X1u~ z4LApEKs=4s?aj=?J$U)1Ayf%;u|;c;N5l9Z)Hh?!&+EUdQgf0Sirf= z3!u&^E4e4Wtb0ZIezxE$gi+Svi0-sfne?vqB6t7PV3K~ z(~Pr$$E?6sogo-z|9eKp5eiav0t{L~XwXnd%nd&8T$guQmz1)^&ebcuZxSgj9$GFk zODmiiLhjRmi!P{L-~652;xpFbYQ91&tK4@076*u*r>X0q#r3zd<{fh9WAYiwQ+o>! z^xh+2SlGAEaB|n zzYp7B7mrvOO(qqDl9g4I41Qc?N%9(O0Q(WLsY>x z3&_RujT}rAd1hHv1akxSgkBVLKM9yNyBp4L+lz$8$lkRIKYgUayyKMFs3SDh{HTna zpN7yNtuO>fUuj&naH2aaGo8oeoVt#>c%wY(;=CYK-Q1eWZ;p#3$%O6{TwivL~5IlcU@ag;y(txxtHgnJ|N zWoB66^{75(h$48UZAodQ!}KcL->p*JT8MH`TZDs0k)4AX?^3agZU^<>ch?QuDk&28 zYj9@eVo&w?JUnYx00!bX?x@EtxYD{i*Wi0~Ik39T&U;>eNbX`k?^9+90)H8h7mKy8 z^9)NXDR z1*Mlh1dwVw-ZmJs-M|oGLteEk=@p^5hOw_=PCDq&dZBvzCH%w6jY}f6(0(RlqK0D! zxo!Vp%5D0Q*L8rr<}vw{Ad+c4@ool!^1t=*gFQ-Xq80$wQkge6)UzNfD6zhp_Lhx2 zZ*ekR)8ZErc5h~`?bD9Lw9jK_7;TqI5PI|&`}X0NwYHC{*HQ38=u)-ogJ*3GznOME zGi$c6aKS;_!pz#W%sa!(1I<^CSUB^vL0wkPo-%R{mR|ic6DK+f)jjMt)D5mjBRKUm z*LC5wn<)F4(Jdg^OC+B_;f{+!>ER211JA$zc{`-@KJFSyfX=Bm0rU)euD0kq%AD_OFCN3-Jg%Z$L)s^5fHziUW?MsNbf^tGf4 z)KK2Y@^8p37!*bd>G=wICJ#>YjToqgFtkF?SRQo>2lNKQs-A?ok3Eqgg&oa2mP|Wv z+X$QHgCg-^NGv2Q9Gp~#{sUwA{r)R!n~|B7t!;0p>l<#I2#Ismjy;rJb)8O58fLGT$N>@%J)|Iz|pb_q`dvC~J4sU)eu}4oA0a_aHx`$U%eF}Le zOcw9e-cs+Rs>OyLaFYt}_zCDvP-peHp2|OpGMIj8HyCaNc>nEw53G!FP<)J@Ia45V ztCeo|I5`N+u`KxE&WR5lw8wc;`u-s$LPTXdab7vF-vMiJV))pOhnRB_XlyJYz&BC* z;-*RUWnC!FhHQqqt^ZwSAtB$?1h2;Bu@8<~Kr>5g*!`Kqg)FfKtUH0&Rk$r+4A_K- zOLk$30A+@l6Qzz9qT-42pGkOUvv`}-M4n0zq+r?{F>D`|v?rbVaY(X|t2Q_Py<~xK ze!Q1vkt%Q$yZ+0#QF8kH@hj)2`a^53hI<5SaI9GDsI>)eTYRg@Q8eQaM7>ZdC=UcjVSbT0d!_-t9hBBHON_0GTNHMBQ=2vqmmE~Si|?wp;~ z&%prMr?GD+FjNT39F|v63bGrR0q-Ou26e4Cbz4U_72_prsBnEV=J<`2mG?}k19p7+ zS%CK&Zj-LaF)UH<9A7vNu)(*em7e`uBJ74vQ5#kaD4x<9_+x8ZUfEB>oVMOpn--etlC{dR{yc@?~3h|bjg%;Ad@ zPBl&?G!Y~b=TCwKt(QMoa~M|C0MX&{JQOHqz%X2)SuH3+Izag#P2_=wCiC@$@^d2u zDzjflQuW(v*UK8$L5&x+#csR(Df29CR1!(_ykSypevP;S-(UrAB7XO+cxcJV89;ME zGKBr%%h_b&?01cq8vxbwEnC(6K6Gy^sNkT`jtrvWW`!gMx2y}gwl!pVx6GJZ#B={I2e4iqoWpIca z6!$sZAC297OSDsoK>d`IN+k0_CAI+Vy?2sF-3Sstw+Q*I2QNP*r1GHbuz=yAWjbd> zW7Yex@sTG-l*7%KiMr%e03c-`!zqc}cx{Nxqg4(A!Y~9&L&-Uv#{B_S(h z?5+t!h>TJ=D-CY17)Kf$rLL~1Sy*{{h&g?}d#tM(^$wCE{#1cYv&=!%KB6WF38+l#S zU1W|4#AQKZ8f#;BR)(%t5VAvds&&Tt)NdU*NafI@=JIA^Q=~&y!MuKnRKGf;xF*Xx z2Ew9vn5iw?CY=8aVSyxOMoIiy= z)mQ0RhcKneX3JXFO?-yL{|Hwexv!EbI`6LgM;C6`I}e7z0T_)k_u~=dDyH$h9hV3` zL+(wjC3a5Z;Uy|!w@ai)rj~P@|LDn;HgEpFW!*JT9Hc35?!brJG$Y>v?mMH;!o;rE;?P3 zd*k1yl*S$$EU7kU`{D$3dr|FY7Nx7d*NS1gHqci+%?_mo$c z262%OTUjdJ#>6nDW@L(v%SF(VwtoL#U5RIgYi!zjLYn4 z7H-#57}y^=YAacD=x&lYdt{o7XUEF2gCHUmNjaHUl+m#KLMWmjSwjGdECVh{nMVQw z+zwabDs)UReKsMot*9%0ioVrt->@GUIn+OIIYn;R=%??(gbnULsknSw-5?c^7fO~$ zB~p%&{jb-E)k)kYnu-T?T)g}~m&1_!o$S-ZR-&>7CO>;$eccly#Kdt%kDIGh%%J3V zSNSj6_w=80cw}nDH>i)Oh_HK4S`Qa*X7I-f(t$vUtE6m*salj^U0w^b!lMb z>+6g^vlY0kG6ORV50+;oHM=~7pqGkDZ$5{6w`|PCX}6!EU`CaqkDHsN+dbUCIvkqG#hYYg*YvWlZUJ!F8omEh`ISAf|0mwp^`+(SW$9vbH{1^)16|dwTBl_U$9gSd@ z5t}p`QcXKwbYb%s;^tht#5YDxtU|@utFXJuZk^iCIhPUb%lT?(CfDF@>WP@wE!N*g zPaMQmxV6Wma{seGBQNBunDS@++-vs=G#mO&UG0F3lp9PZ`U(MnDqXq+;HZu$6PlLD``s}9&Y z!3EIJ3ot54P+GXQKYSvTH4DNt4FOmI9Tvw#`ckfPor=|WN`=7=O|}~0&9)Q$340h>Rcx$ ziY@4|qCr@1)fP}sEah4{F3xo>mn~G4dO*y@^(lo1=Vsy*<#fT*1R({Xq=w$qhRxIj z9gxQ>{lYA@&{!}L%)v3C5!C`a@&Y)o^u!239A5Y(LT(o)#8L`NlaocQ!0KF5GhgTQG@l3k+!K{_6WPdG=4pHEAc5h@f0g?$2L z#p&6Hozs)Cg`PZV*JdkD&s1dMg?}y-y6MLJPQdBaD$jDm-$7ClYxr84l*JVZhzK1h zlLGYUC_Or+pU%qCc5sJsD$%)pLeP5EoIZ2`8#-TeHMdK(uu`?~R`nsJnnNx%IFTBQ zE36+e=iEYaGQ9v`d9X+cKb`W`BJ<640B1bZ3JqW>f-;oM>e)(3p`=`}%0#JvN*1P4 zs*D>EKZUBUGip3^t`Ci=LrazK&caPeig7FO?$4emX~;z%s4f7z=u&T&TYt8r-aB31 zubJ zxz!MeX$7Nsn} zhCDUU=bHD)F6M@M>WJLcVFp~`cGR67XZOsfJSrn5X}r=s*36!i=-#@- zxSv;4S30383|UiU^`wm6f^&TvJmCMz1ke2Mm|!VkssB3@%mRY(ni`fmqSkof|05t+ z)zkj}6A-Lvb4t|NQ~$pK!L|;k{8J)#3(qcsz>b|73!T>Ho;cvKq?M@x z9zEG49v%KS6HA|VKY#gJ`tsGcz5SLSS+7?UA7sxu1&?J(9S-N|R0MDq!}|6}4X2Th z{Af&qMJ7NF1ON`+Z{MNZJWLQPrV+QS(D^KdCS&8X=G6JFR>U)C>(Rp#G|QZ$iQVuC z>TCN-O^?34)SU}Z{qP+jv#x@vM0|LZLF_51$Kt#RJgvs>ZD0Z_7+l5qz@rowl>=1L za>H!l02W$yXh5N~Z1hiG8SS$+Iv z>Xe;CizQ?zNP&|%#Hu%w0K4X6Ap-KCR+1&A3{@ioJpUU9m?M>#OSam$cdmYU(jjI8(5s|d)hVg}#i45x*fTO{?#TVM6C#z4&@ zKP9I+<619Ub&Tn_Hn?8*tdlZxYm1*nm`~iJ`8Y3N&C2e{v&>Q}1>+TIbiIk7B5e=3 z)CpI|x>hkek-{l6fX-ad*^ZcTL0PIE<&)b1F}%4)1ukpW-aQGsoT4CUV@fQa)ZpkT zDG>iaU107Id-#TT13}w7558GZGD7?ElB$;*&Vt9d1$9pr$N-!wyEP-<3aV$^rNSj{y)Z3TdiSuT|Dm?GI*N60 zee%K~H8A{M&rfNgSB5$gDC@3)*M-j~AHAsxsfo3#&QSiPY5K@8Lb3UJ*RTDmoKJCk z9lKwDeK3>@W_7x8m+RVx(I3jlk2IFuc!P2N(|Xd`pGECH-P7J2`LbBK{YUGu@XdD{ z4{oV(E*Dqvu-MR-6%eN6uAD`j7UbN;gr93ICr3}S5B$_pe10+Ihk|X`L!(O{_W#*+ zE&G~QDt|VWI&@3;cl{J7zzQ=hW*WODoOUQ9F7i*P4`{%Kf+y{^JN>-O#CK%Tz&eQW z^v4QGN4yx<^6h!0`HA}C6+9tCP0~F0r?}>efWcBP76bIrP&X=CnGQ?2?!AIusD)Ch91 zZysl+cIQ?Wl3uTm&fL4e#Tl;>!F1}L6=C$KuEs^|q#jG{f_b-k+NX^x-YFIfwxJ|a zg1;r}Ynz8qAzW!6fdGQGky1==)MZm!zMWf^xT^)`cZm5$ z#ZhBDM(zMN$5wtP&tHCw2*#5kC)rFzHd1*VGKM)SUlz3h=zXVbS=2464T_P5JIBRE z&ri4Kz4R@6+JYR&nfQGoz7N~>{tco?H|#8Ihc(~DA|q$$J{xelHT4{q2}J9|7L%7Q z2>b!a2rUk@;>nzr8ye1}>(&=pcwT+WccDBzcd0znJ>ZLk2=L**^hU9(g%ZsKCX>kWvlAn@<=P| zl+c@k$vn(tiyS^%!{crJaS1*6N`y1!vH!-Om%AlI3=n<;BJX6A%@G_U(Y8-*qZ& zgry}NOvAMlf@5^v8KVT~x`)!Jb7Ws_l`NCBo#8pRN6OFcq<5a=eVBQg{&jd|TvUWw z=;@_(s&uu|Wv|;}E~tNpy8aM$peVCrr&7Nzs8ar2f%;;|udp)0huAM8lfs^e=NBUJ zMk_CP>I*K#3!Lz59X{XpJesv9_3>hE&FgEK@z3vVz_eAmw7W-sah*t{eN&?$Iqg_& zX18W;Yfs(s4|2LC0kYVliRsXGGkkYntdX>VKck_ zb*HXS(8_ZZkhM(ZYPn&Ah%XqVfAH>T^26)k&mkXwEJUm*CPsd)pqIXvFF4l!sp!_} zclIQV`c?cODHwD8(>tZ;{%L8%&uf_VfzlN#vYeNHOQp%@v%aIZdX;1B2NQ)Go^^p_ z)(d8&C%$&=dbZEM``Y9XzFCIae^`!;_xsxQ!_eN#^mY307dKHqslN>mSE@cmbog>2 zwm|IGT0moH$l+AR&Y^UB!mEG&3NUzB2?_LhL$n<1Y^OYKXhomO><5jySiM*JkHIgy zJ3R>>=W;hs;B=pe!*#Gw5XRT@i?h#oQg?mWA%#$=e*NW2BF!qU4KHL&11B)#)mtcx z7|7_pD|Osw_^m$s3fIH&>tpw#pGV_StMO*d@qajB|DGq(&mcNY;K*?%5bY#``WVuT zFbOq7GZEu!&E!ZJ1w=e^GxMg8q!C#%V^JuC3_*yWipD|{F`jxU<{hW_aRaB#dZftP z1X{Fot~45QPVl*Q1m&^N5bwp)WxV)e$|I83A_#mJn>ip@AjG0<+M&`?RH78std$D&a55PtXY`qJuQSYjMGKZ zFBLC@+-718&2b=TN=Qa`EL*ObL?6D*xPx$@C+o;g2n6Xw>b)Tl(iQ=o#o!dwm6adP z`Q9-QE1OTNSE>hcbGKsL4|D6^2Dvrs7h7?l$V|uPP9a~+^Fgsk{+IN{bwpB9IAcha zOE=2Z5*Eds#Bay#e93%X8YOBPf21uqa3P@tm%TP%4A<2cS`!zrxq8hxu9T1|8B3I& zO$47U*c@P0JT5>B7Jj>|sPT?`?K`upw5a=iC!~7IhmrJrAM^GBs+=gy`6M1J$adoyk!(h+GOSh)+JDfYNtA4y2WFz}{s~ z#>8tOi$x@eeRUbdw9+-s(kkB@L~(ja)Vo3wV_1fRKC#xi_%o0BOmUi6xrumLm3rw< zT$x2nx}ObFLtFR9H(7!llK+`_iLS>B7xGvC>!>H??7J1m=#(_9Nt7AG4OH0_TM^K! z#T>x>(>mD3IzhB9?1z~aKfXAPTpV9pxmjG1C~J2lP}K`W=jw`j_9JMM+E&LllNzEA zZ0yQ;O4fBs*7*Xj2=Xvtn9lgdM9OHk7sk8~&^*wU-3(x>Fp1oRI*w(ssiXZKo8yV>W?!qI5bnfaO&81)JYqhrH>iPIZhxLR2 zl?E+vyNoF3ud5RIbq=62Omti3CR&M(>vg%dqGMWJL3GWn*;;iyT}`2Q1)~ z30c578_6piv-O5^+QxzPJ(3L!bHp~BGjmZ@^z8Zb%xWs@4XIxno;7jktcQNWGD;K) zBe3%c0Gt=2jG#98@27g{8R9Auj?wYokl`^%pm`f|5}|fY&GY(xa?Q7(@Cr<%Td+w* z^Vwe<1C4OQGS{Z9lR%hzG^$miwWJFu&-lffIj0*hQNKW_X9%DibW(}9wlJ5pWxtHZ zMW{ZiJ@h-EhiTW}0tVdL_3-VX&Fw>N8vR0728B9?Y&-4^x7(_>&&)w+SsnNHJLcxv zAIf*$spxoG(N2eNb#O2uCUKq1S?!x`kj=Tymu~GnZS9k`?c-Tpi-BEFDmn+|Iz9z< z_PYUxLLIM$yB;%lJ(chJJKXtVxNASFW5>2jp8_1OGp-RghjrbF(#!btT$8rL-Ih|f zj21n_XU)v;9j4$JC*-!O0UmC)2)Do|OX@?|`TuoE2?A3qX zE4tfvp48)7iL!R@HUHgr#jeMvz305}ZMXOR5|zDJP(OD5w)=d)>F>U)!u`<-w=Y!o zh0fFabt?OO;-Lx8dm=0QqJS3SA~hqGXZfI#d6!;JHSaE?tVW!adkw6 zJYwBDGR-p5^&XgRAEvbfw-iPevPU}<#wPTE9=nkqg|Qiy(S^$4I|`t#?9l;zK!rBe zVK+Mbesn{4?9s?@-){zFF*bK~tTTIfc>c~k;n6mhkp=g=Pu}0MeidiPWN@H)%r zggd~60)7dPzzs$@9}Mqh-{oc<-E$v3eop%_a(8@wbYx_N_5EPkC7Jw@icq?4L)$@9 zkgak%Ni_Yp>$63*RToXSXN)^nS7iI~Q?vG^-ee!ZEFVx95Ma&vkx(T8ntuVTd4Ai7&XHTA6S z0qqtMvax^vMgl_r_N;L+L>ice5FmEkI0G8wR2+hfdg|3xB)b@>$9`74e)g#x@^SN= zv0uZjqPc@5A3Xx(mK3O4aek=~B?1eo7heZ`*PjPg^89WTX zY*G>SA=2cLDg)cqd$_0YXq6QZT86cs@Z_mif*L+r`=dYK(Q*q7uq+Px*iYX&;JLzl zj{z*x;RMDwG&BvDf_2s&)DTSa7Mu6(N#D~5o~bbusMlLtl-4dU>#s=&=$*9`0_hXXL*o_ ze<3IKI0>F>UCGF&6O+j=)_A2?YId1Ts*0j#r{k(!r!cL8m55I9M>;V`h!)~@8j{-= z+^}@gplqW6>;5hDB!k)g5{W=Pc z+6EZ!zT$vvnAiZ3f$vVx7k^)5P}X{!Qk}+O*45|kjESEeMZ|M$=*`Y_-)W29dQ(Vo4c%i32A{I*SPGYZT&I?K zk^Rkv>>GpV+J&mx9-yzrZn%)ViogA~0FBci;5ZEt^_94)_@My@F=lziYl`EWeH6lLz_$h9%r*IZhxX6!QrA*pouD5M2dT7!7()yn;MS%8ibEfn%F-oJ8MwRL=l)4?x#apPS2>(YNIUpgY@ zB67iRA(oE1d}I6UQ!fHtHM@GU(hCs$iVDU7%O0#Pwtily@3*wS1?T9H)MqkUr+UOd z7wt8r33-*+w`nKG6+46CcnIPX0r~41HGl=lk`4pvWN@u8@pa-N8h|37coiY|Y;IS^?uWf4C8`T4!8tiA7AtQRHpiO?GweJj|iv8XRy z+l6pt@%|Ifg%+O2aBgaan+Lw=fk11lg9KZ7Bj6z~XHxZ+LiKI)c8AD|DS=;|$&~pf zdYo-#Ae+xp8Mf56!8syhIGg$RYiyf}*J|tE!}7j2XxX{upx%NG=E!xI>~P(%?772_ z%gLWV2^b|bbL`wt=T%Q))$O@7m3PYhPL6K(tGO~=`V~5>Q1{!Jdb3KS+=@d#ccNQ@ za_72Q&{C`Tqpq=^-+dnqoBdeG9SJ?yo=iSHgQqe39pOvcY zuTNz+!}(2-xaiH<0f|`P&Yo1dDD1eQ(6T?Hk*Gp94Zx*+d2zg5ZhGgGSf*ece{+R< z`l;ryYxH-xBK|u&bJDqPhyLn0=2?iwLTq5Gcv)6YfOvUaTdQPwl3qY-fwJj-YgPnv zYiql0L11H7Klpt|9u(D9-!E#q-_p~@97LU9w+rf?63q_knNyw*>Rm8mxzY2Fd9hja?d#Y9tIQ4MaLS9o8LK&shu3NImpqVkx^(seWocanMvUE z-%gM`E|f`}$$zU`LO3Gl8?>x}YOzwJNKShwhs#Iu;(Q%u)vJqFVr~-oc3pzO>$<)&oB_MU zY-#d|lTmterDa~x5{MIOzz4-t@+_Y-0Ru+*aQFb9h-GcEZv8*T2@VGZ9;3Jd)b#_jv|w&(Ou8)*oYkKP$jucpD(NcnQfWb^zK2 zp_%Np)q5KJYII=nyEnnL;7m8BAFDvS2HmF3(TF_nFU`bF>3PIv$5uBNl!lmXDuQ9oDvLOR1yRnUY7@xwGmu@JtNAk5oNB|01TT^rAL zK|SX)VyL&O79#8flAjwfLXRGu5ia$wpo{%bRDv33@beUA86*LWEx2)C7ywyO`%#K1 z#94I-w!eHDbP@VCGH&&r$k8H9iZ+gpk4aHYePc(`b!1Fi06sXN%MyWM7NpUBP+jgY zU0SZ>L!HtdbDdIhqf|O1?D8n$Kqh6}5I)2%j~WgX(RI4|b;CtNT`S`mPoR1y$JD6x zxIG|LzIN1ycoJ?R=k+s?lY>0-6aZol*ap5mgD zw5PBhF>qmkNqU;VJIT5sLy_U}@@RbO=64`X>jMg@-B80%L0-s^1B1LDn=qpSAI8&t zR3R@bC*Dl9Is{AbR0@a%aStI0vgX_1M(fQ3stXBpP+XOY4-)U!MSQl&rS6PYaqFWB zXxRHgRtQ$Rn63Q$s@HNpYu1)$vU#(p&u$AlA-p_B*7Hdg1AQMYgW?r<$Vbman_rA` zb}g-MKa1)cNldpYIDG!ftG-=UD&PZi=ox6k5kvQfvDN(!f?V)M`u}#3dN`%Z%(_En z(h+?zp>VFQCpXD6)e{RrKY3rLaaB-h^4z=kYI)bZY3>Ay#OOY0Q29~Fljq{9w=%|z z6_-2GzoewRu0X5^q;p)Pz4sD#z9WYNdTkyMOd2t|SA8&5_LsT^ZVIH$pQmf(HQMbQ zEY4VbcP&AcC5C2oBV5$oOf(9Q9YXVREfgq819)y6r^Tha`yhlK_ zcP8fSQn(^!?%noz#DXzP`C0*YHig@Bb{&t0X*o}^6balfeeJ=e{bNuq?Aes#rHkBh zECdnXMliSVRZqBg)3wiMa(w&AL`d*-TkPkxRqv?c7V934zM>nC}=lxDni z1nJyufM~n}v0XUBQYqCt55uILbKGjQ)1j>!;P0YNYz3ZNyoum@c^l%w#sWjrs+KPR zkUYY6hoU%C#w*mcAp#0p+~ktM0bJ(sP*{NZyAXZGq@Ss>|FWDru}x7eyVqqK`@D-bNJk_c(}(P6Vl z00A-6rax4NFCO?ZL7&?{e6IN{ll?Ps%TIjcdw-Pl9Y+7?Czs-PcYfSr77550-(KKY zPOn>Qk2Svdw}E>*r7oT$PcCVf`w>H8FgBQdi~W#ST)|3S^w|?PBIDpD=6(d7o_Q~$ z%W{gKW^4ApBB20LtK7~%ss;lr4jNQjrhqv*?49s)*&COk0P5YXN+7}3DN@z}7SqXcEh#niAO#9ooRYM9CPjTP?vx8bft0G-lB!Qaf`OD5OW*{2 zs)04p!k=g^07#T6b*U1q_K2quX-=z(_9P@7B?jUU1G&nASg}xE0zzXEa(^OCh>AoI zAo>SD3m$2Tg?h@SF__@cRm8a%WD-rlU=i*eg9xC)@1F^%pm--Tx{oNtOahF-Y#NJY zWY3U7turzXQq!<(nva=$K#)WVi5-VfAw!Z#nTRdGF&yDh22r8HqH*9d8o10_zix?i z3z7Yio9JK-@jrlt(qOu%OkhhWZV#M@f%B#-m=NH8x1CgR@bqz577ZLlh0P-1ARJ^i z2JWz!Oj?gLLOW&g>xhC>LWw>q>y&>{Dn9QN z1!&)cddFsBP_Rgf)6fc3Kro#h54Av-dNa6OGDI~75l+tWpd|_y0}1pkCL#qeCFC9H zkW#5x3FV|wQYHhy?mK|ssPLh;4Bi(45K43@nISe+_lJl>Xha|$9_B(UW~eBQoA4OREXP&4W7D#RnU;wJ)roy6iT08JnZYy?zs+t$u;l|~)sY{Wn{ zXnC=&rGwfxT#mE(kwCvIA|f)Ym4vuXD$~jbP6t4u845HC{LfHbuWP{DvMe;ZGLs0A zn?sCdB0&2$Z=(QKLIpJzemn~#9#o@ga5|hB-dtYEl2!keRM+BC>ps_bFRWHB0?Od4 z!WWAJW)LgZl}~glzl|5qBmC3|-NNq?$8+5$S$f3Xk)jGc(!xEzeR`y>_9(P>%VsO{Wh?j3^$0&#hM~c)-zJJJ zCsj~DGG~*T$m*#yki;eA2Y$6Qxjs-s*eP|S5E^8x@Bhn383DB3D@Wg5B^EH=L>Bp} z7>JZD!_Nl=S1K_8w+~T@rVLV_mgYH+G{HfGT@V@vl`Ue>lS0U#nEqS&xeeRGK8BDThaA%>(JY|SM;|(lpIWv4qXt0xJU&2u$ z2>?}}8*3|7*;NA&V(>^ZgmGL4X3ROLut)M)&+B^f$-ph$JPRvG%vGnSy85}Ok~E;V ziCX%h8Of%I9AS}1SujJe)i)UhrKnK=17WPcru31*RR{))9l8i(FGf_w)G^~G>M4wP zYNB($F$^0gPB?d)s3nWRh+Og{E*gu}+W}jc-{I=H*~WZOZF&p&3%}O1aYzVPTE$_jw$3$Y#KnO7}$cCxBB<%dT#5C=5E2g07&d2MAHPMg@s39 zCf*KLb<9jh;BSa+kUdervA;kh7T%90$Lc!AxWZ))a*4Z8$kq*B%ZTw9IPnAZ&aa}I zJu~wNm{v4=7BNc-WEB4}{+6(;{27`nS(N~9wSl0Hiv~@h2j!z_*c*yixZ&b>*@F^6 ztsASEGa={+5DF5x#RLH$sUG>U)`;F90hw7aTX}wDhhS0#B71aVwY6x<0CD|8Wu?Kx zn^Y~r)D_JfV}N|7KY~d(TF(uKvx_u#!O(48!68AdI>6($JHqj} z#eWfEpbIsi<)6Z^2)RCeA(*ds46$a0>!M5l#v-a)ORfTdsOyvINWj1qs!yHEn$36I zdRFxg#wflB5(B)(7$1=agE^StwdQncyX3FzI5MP4h(&k_`A-7v8`HJYJ?JROKs~g^}~lG zdf7j&2-XF}n(Ivm!_h`jpuMJY{&+uj>r+0(*qN4i+W~Q+FvO+*jQ1x$XYR}47cN_~ zTK96l*|>ihbN_9Y!g&|8KG&@;K84Ro7*nBd7gf$r3Oqu<(0Y_1MAl0sRiSh)WvG`d z+!0kTEz(=W4n(&K#2!GVQT5TN!eTbyr^tev{8va)o-vmDz0!Ll=7xGw#f_8+1EEhQ zkLprHZivv2atXj?oo{E1wn~3ORP?s}hxS{KkCLFTp|p!rG<#$<C!-toVI6GBcvQd!^Pqn9;LMr*?Gw)82R0}nrUKLiI5_O|p4HyR{! z1>j)R;utXC-B>XIjBS5>Q$g8!AI6LC@KJ($kiUMOAU0AN3o3X>LX)5zKoUw{-tL$Q z&Gf*xWX{y<qCL>jGiH%ymVHr7Ae1Vvo+O zDu6X1NZLQzP$`;RfVp2Cbxn^K;M56-)R6{~f`K|(i8NiuymA>pBn0c1jq<8g0FZX> z+@==reMk+(Jb$U=@@XPs-0fRSQBKWpBuY4dW}3eP2bg5MJhba}N+8+R=XknF41`yn zif|#k-bqmu1_e=KmldG_EG5uEhl`l(e6~~%&S_tq)~BQ?%+|QdL4Y-C zYWly^?UclFa0-hH+VL@pJ^h#4lrGml60sBGUyFI}*ZE>3MqE$7TiJ9yYDcOZD>nVn z-4JYU=nErQ-?Yj}J&1kJ46y2loED?~Dal?A=zRH|f$}a$nr5O@mEYuqS0)w6*(vmw z_wZY499)vQHq5>YYqWUIRf=;IVK&iupHJtTx>jw(p)2>@bB5aZXc>l5RdQs1txpQ+ zuB@NN9Nz0)vH2vaJhMB{o3>HAxR)j}kdQ6Cm5?!CH&G;>o*th6rBu}GJa70}`v5j9 z4FP*~-^P+t%?D$YtAic~qIl6X5O=clwjRVEZ32>XJj>@Q*S}W>(M#Cf$~d3AgxkI1Lz%j@0{aX&A8 zX>i9S*HZpngYqYfcY5KA-BTj;V07HO=Ga)b7M8{2!2Q;iriv1nLJKverLE>$i);6@ zz;>eYMoS>dvcuclV*th?53!h${SPL%=Yf`cYuAFM!pFWR7p{K1y?R-pR$M3W{l|f= zbcIiYud?Plv$;OdARU27PEVIfpI$yTBc6LS)M1I8Y&X{lJBVr^lM^G*xP&L(L7eKq zXTNP)tqMQN-M#6#(`X@23upvcsq)`So0@D(2Zd#wY<|r;)z8=W4DesXgPzYM$t={we2?S@=Q>P3hV$!6XJ6jCB zrJf)ya!+JneCvgXr_SvcBFgO_Q$#pCUz(vJSDk)H6gs~w3y8qw$y`n}XP-)pTXlk8 z%)Wbnsw~yOOb1Y0?G9kjykud|I@=|y_qTSt^e^KPKx%Nb4ku?_2=>=EkQVJZTnba=*hd25sHBlERK>s`g>h@b+B4PED?Fe;E}e-JFY!dl6F4AN$CTZCywoqk8}7eq zuERGC1JTi2>>&c%QdQ$Hk)rg#${`Wpf;U5(D$Xw4YkzW`mb&zZAg+(zQGH2GeFKQ6 zh7ru*CK7NNX75Y67>sBZE!FSfzTiXd2_dPiA(@x8NQ$m0Z}T3>NM{@2`wDX60RpPT zX9D*kN-!8uB7BsbS?6!swN9SYZ^;#LpRDhi$WN8Tb#uF$i}z(Y-M8%W=6na10B(Ls z^(zBlqp}TpF1Q&B4N6XOL#_y8NX8ndmQ2lg-6zx}p!JF-r-e5ah*)C~ZGmBEk0oGm ziWJXl!eeL+oD5z@=>D8i*Z%48%~HI#=%CE?(&diNS2gI zM%SBUmI7dYrv(O}pO|oY3AEVU6Cy;|rWj@a206bYXWY_zLRk6mKyOC&=@~sq!|=xU zl7gz(r@)1_NM6|GVYl*TH85);<*Mi&@JyfJr+n$Pg0Hs87@d?wzg3thc*YMGPI|u^_8V=x0ZcJqt_P)?Jm3&j?>0`&}`RAwa=fbYW*bC?32dFcxA`cSwWWm7P zN!h}i|HPVI{o7leAcxa;D4$Ojc+B@N(W|a`4K+}BBckmH{_I1Anehrj6smnCduto0 zXs^gP=j_k@LDZ|-No6s&j?vrcr_ z8J*^-lE8_xNE}!g%me8L2~K&c%w2b@bf$7;?(rjod^zYZaWiOv3CQ@zI{t4l79vm1 z0|esE-TN*UIbm?+Dg65_z=d2g5~is~dtDPFZ@d0QiI3=FmMSb}b#u46-Dhz4eN-9)^!Yvi6L;_vF*zY_1%UGEO^gVuoA{x(2 zRF!2l4L&*g^Vy(R_7j;|YRO~UkLtLWIW{e-HtD0cQIynE(uxOlH|`9$s1;aTl9GL2mPzWP5+fUM zEa=&JCxI`8d=Ap`fb2gKcW(Uc!=5~)YfIlPXY%-tmH^Lj(pa8R)0uHbZi}Z9!Tw5p zaB;b0amZrQ{YB2_D~azhfE&ZTr#Vv^YoK`;`NC@JAk zTVcM=o}R9W*s{N_1tpHduHvq4tA#_#QlD~3sHHQ}oLSeW**69NH!9P?N~-EO$Tpct z9LvS~n5bsLZBh$zCNMdRX+X$K=O{dOTRg&yu&XxPIXu&SKR|;s<>M8=lEfrIzPL=` z)GSDmA5^r$0+U5_M^1oit`GIK7EpYnGz5;*(;>~6f)%K|t`aF2|CDSr(Y_nJYL)C7 z!z4-Oa;ODMVKa^P00tQ>hU3DS0AggWY%;+phM?FDl?1ZhQ`6iJvLpdU(__{i9N@7g zGH^~~P}(w%Bp8z*DUm^5QJm~!R`zAgp;>Cank62juBN1R@1*x1UT>C=U$T~5nL$Em zvTH7~FI-qRXQZOG)7@v%&)1Tw#JJdIxTHY9Mg}n(MRc|1V#0u_D_jzs*#?72E@Hl} z7%r>YybHC2DD`xCJXy3Q=|CV&VhePVoQyJIa?j@umCfAq-(10ZY9!JN* z9dY4nJ_rYjvejaOKD9uxRavQ3S$C_ziUxVu3{hPx&^Rt&M9B2fg$6?qy@LYnSm=IF zp@D9p)^UMFY>}RBq3vveyl$Z`8DcV9VBA`$oLQ)9Q=~9dXgFJFd0gz(THvW$q}^JC zJ1)|hEijKQ)<+cvzbo<#C^niZ3TQ11UMskgS)vwOdNH;zcDB@Hw%B5g@v9P2Yl*R7 znPPdK{UAAHFV(b{$&SV)VamjAoh)K<5;?lm8&6#FwmdRHlyzPKohsS^xa%X~p|90>ASwl%PERf|PNWMChB{RS(vx7$Thc zW6{UR>PM|rA>P$bY^ql?s~^r*uLTHg3fAnrt4iOlUeT?2ky*1DP_w^QGe3)j9+dT4 zlexB2zf+jR$pq}ry#6vKtPZCbEv`nF`xpS#m2=={ZWto?T8G4cyRiBqD*p<|{uJbD zE9d(%TdA~Dsc4$xlIr@g-`(y(@OKS_& zt1-)@Hq~pi)f>dsYunbtIqP)}z@}~W>y$brp$7T=1{FN}%dNV%*m}qH2IF51=52L4 z@(s$i_13={-Q!TcZESvX^%%V-X?&wrT)p*v{RO>7H(Pq6-F}_pa9y-*lcrm$1^t%vXO+H^pzF@W(lNSzZ5 z$7RCg!KlTS9)Cd28-Niil*C)P32i zrXRS(M-K1g5>9N07H_%2>Foq?W5r7}XWKfp#ZgO$jyWU;ULtBdPAr9qzf2Os*wWfb zG&uv?G5k}u3J-SD&rTyRbDMBK?=9i~KX}~#aP&(3|8Vr4`Y(>&|Api#|GzkTZU3Jf zy}|!CN3Z9~URxq*2*ENXbAD4Y1jwIC7EmGGh-!Xvh8ai3^-+A2b|HIK+@Lze{_Rikg zs{hT=`yV`R$bWJ4rd?+AhUFo${x?T&>5ZGY)z!)jN3T+J6GPJ5*8ZQ4-oXkAWr*SE zrInA|gp8*uw-P)1=coR|(R=&ejemLE>}NTC>G#KGx`2l%+XdVPGJD**d~=P@|8?~K zD0)%5_46-%;@1O#EGfsA6#iN0)BgqLN-zS^nDlDWzhEvTXu|$# zC#nVy}BhRl6~bedyO!WdgNkp4^VJPImzisfZzN;`n`; z6gPnf=Ll&JL1Hc^0B>&0!Gmr-DzME1C2cR{GxX@+5<&Z_LNM%t4 zF_Q&Mu$GM%8;eS}&W;o6`GNGWy`}@psC&q@84RpWuZyE>B4|NY8{4TOATW)<3B#p; zJc!bV7d#|v>1vm}Y_gX43yN6#c``*zFV{)R+NMGL)a{=EX%6W~42x%2rkVea#ra0; z=P@-$gI550Iwx%dZ)Mq~sah!-gnQ}>j_Hfc3@^5py)1zgtw7>cTut}R2zDXMja+Tl zo9Z0SxcXH*J2(8Mv2Ku-aUQ*(Eh!ZHM~qQ2eXQ#)!ZC@52RGf1osab4BezIH4TNO6 zDrHwF#uZI7t(panX{~kl>udsgFv)thrr_ zvafVT>sTtXbX4K;Nco9Yf+4H@1sOIUjNMf64b1bM9v@42Ia+Rv+v^f_ji7t1rJ;v! zR7dEIoKEJ3zqUKiYHCGbEE3Jl6#yjbmoHMd%MyiU27XIDWeV|=XAB>j#(zMA?d;HT z>OZro+TdHV#S2CDiWHH4TQwTgundD(7J1$ONt~$zJ+V;Aii-r~tOhloJ$+jB;n8K; z4e`ggD>D7qOO>2`@%1zv$CYK7YoyTtJ5wM(eLOPkWtyO(T!wtyYVI1N*KljylveSFVBcQ!90&M;p6de}B+_ zN8Dulxy66F?L~W#hPs5r!^57RFN)1sknb7V`)>!&uNxmh6vb3?R0chjw771YMG!)$ zG76`cCsPy-I$kRUAq`3F@G0<4Z9GmEb|tX zLL8U9z@+Iv#$%eAKA|qWj`#u|IwYt0Ws)Bx)yz?R>blQ zXG-Nc8Hmq}?PyD05Dq+tO z%tk-+iTgiM9^mYCPauE^RTe6V$AUQJWv=Ch%kg4Y=4P3?ql{1NtR&Rl=ENLUkSODV z&xRHzI^SMiw=dIttea^x6t22Jm&W8{$@EXC=1Z`pI=Q8iu!)Av@Kz~Ymhpv| z&bs!+hZcTw%XURYO?i9otdf6?nm@?((dUJN|CRU}T!XuxfPN&}($71gZnvC|e0e_Y z$~lGfdYFIhGQux1gY4HJ!7nTb>UIL>UOvyKkPQ19+x$a?xiYEV z)C-e(Bq6E^To=Q_%!SL)rnD;wn`CO(Qp*M=d`g5Z#FT!mkId;P`s_WBxspARl{hS+ zc~nlUPCyHbtzP!ktDXWPBE{z`u+ZEO7WjpstjGPqwJQ;O0tt4bUG~cT#4>Ja#i$hV z1_`#fL9-i8@+9yYA7}I{xlo5wkDarkMn0@}_sk~?|0fv6?3j$fE|9m`bWQQ5~-aSxK$Q$B8uEh)i;gIjF7 zXI=Ns5%7tu%p%cY_Q1x&+da3HOd_%`a8px7QwT(Hb3!-XI%s%q`_YvLr9#XNq2kt9 zSCeN2GkJq}spApvw0v(^_gAWdVpO-N;jufvZ-|9*PqzTucCQ`$9)BoT~IY2f|Hc|G4%163WayE{>mS+tudkww`TSxX3R$t+ZY-r_u+W_A3 zD#CO%@q!lfZ0nyr4c$AP$?T!7=2%pxEKHL6xNk=1`#oG)Zv|&|6HxqEG2?B%+B?v$ zZ1S`%N~ij^U8=(vI_!7s=AhOY?%1GfcMqStBuWftG%J57j^|=jXV|S=bBN#-gCb3PjKB*F^qXXs`O>&%+ZSi(vQwW$yqB? z4?bR%t}(N&8-YX5`F8&f8XoHG{SUV8I;zR|Z}|ANzBX!f;|L|iiAW>l%ZTx+*K1+Rp=5k_fVR(y8joVBJTYu zHRmxLFeH=CN&mzO-x&xf+9!&(C&k{XBfv=tIcD za)DyHVV(Ofx$ld&0Wy;xqw55=X5>p}{6k_^>5d=F0DFGvb*Pk3Q z9-(Y?CoDH7U|pk{8jppO#JJ0S%f%Hh5mD5`a0mquZ}Ao*$o?rYh&*cYmrZ_rAaR>; z`1;!p9z(OeJm3tFWjNV}QTXowJs0LsnppbldM4)^uC7T%& z+<^I$hy*Ty-SR0BB+{RJWEczeX5K})8BLjEOd<+PT?bczXC4ERk?w2M_xQ1~b zz`ubdzC*-3R{ng4B<(72Ugg-i0g>a)$20W&U!I0MCMkH#?`XWQ!dGW#kJzj=ct_UxpPiX;Q*M5GQiQ3vJ)fkN92xL z`rp@z-Vx7oQUUo`FhnTG!_s!Frw!{0zf*FqPM5>tp*A1@NYXl5R9x<+AXnowg|fd< z#MAnZ?8%Tjm!>4Wsyb+aANWPolqmS|%jC)j@7q?6G6;DkvX^vg+P$UhU++aUaRih; z&r_d-=nhA8=GHI5>!QwkdXin4DNWGvA-DZBtNAPKv3G ztXia~P3AF$OAeGNebkHB_ABaUkW)RWh0LU~kEhta8_{Ld?i%fG1-Z6Lt$~W= zCfv9(IP$!Z*$q)fLQKt|%94Bf=5!8tR?av}z5Gylezo}hM8noEfn)AbNBZlXt{1u3 zhMbshJlax>Ujn|+_`MB4e(vanZlp(B7)h;UsJ(oFUjm{4vmYypH}DOV3_r7&B~X5m%Q z((wFU3`PGH- zbE*T7?p&GbFeU@+?G91(s~_Aucy~H?rnU?BFM3214xMZiam^9=+KC{izG- zQ9A?i(!EJBeW&jYWb^dbcnnm1>~*mlIB(cj$J3i1(-*;WJ=gGh5l>&N`i*4izMO^h znzl^cd)56|dd5I`aKEy;r8<{v7%21V(o#2TM+stK8amu>aKrzX-8=jryLT8*f7`ju}Q^Z@z6G7RKG2Z66jQ4Zq^KiD%rz&~JYE2z;j86e16Q-Wgu~cysO}uyNxi zN+>P%tc&EGLhJbRdjIQ;P*^IPT3KRY*nso#QWK%iHKHw~FWCr9LYnVW{dA0C)E z@90;K-RS3l(bY=WYrC6@>%;PaqmsN#wmK8fWa5F*zdSdkVn_8^!&<*@8E4;uFvfU{ zj_Jl!jIe6jrz(XHcKs+~k=U<^nsZ1-Ec6LzxLGq#em%F9&G5OF{Fvxoa&Q09J~3;7{`o=-CTZUxC+g&`>oAS zMsM!`!elQy?~Xx#^w4kJ&x_g*?%!kkbS?*?h3OBtgBfh02f|tC?)AnlJdmUF$kR43 z>V*`0;GfznK8-^7qDjwCCk0`#=bMXx;Xl6<#NR$DAe;at#B?6pi$6gm0WfzxRw-Wd zKoTh>6+{Dh5eyVSVF|>c@vOamft1)8`0FZuxC#Jc?GGY1B$Ipm5P+1dpp3E8=8K{q zMxd$v6?R5WngJSQB~nx2BQmaGOw>tFR|5c+c^rML!#gW1(dI%}dgHTeT(TD{HlT+# zNpij4`&6zBX32h+oEGiEM)LYr2%wKKb`HYRUu)m$ZWt9fbtfg2e_*!sKVQo@moY^3GA z*;10S3BE1#2)aEi8Aic2bhsNh!D@5n%V__+-jn+Q<|kCx1<-XG{>lz~I_>UiFa0qv zxn~53T^zsu2POpgHu1r=%N7c_)2CQqLH6a>*tz01bZkofO@o%6#kL7sv{`#9G8_%T zdL;p;2Csl(-yogaS4y#ST(x)mO$n6(x1xy(&{73Q5J4A|m2oc~$3e$0pj`z8olk(+ z{MXzOrclNrcc!Mi1$_AI&7u&1=8$)7abxUUuqj8{%x+28bMF01P{T|w_=HLdE0PiT zw2OXv{l}|9a(a}tbQxp*wMLIb4mx}k0W6->|C(+akFt5SKalcdGEDF!`%MHTJ=zuB zH^QAAe8anlf;(qS39(RL;geKAM~4F6z? zdwU>vLh73N){@&Fr*T96o@vQ+bXrC+J&P8PmbWB*i$j;ZdckvOwV1a0jVcXCP8Z=d zV) z-xD1@-9s>5N#Q@o$z%r*5+AW#61$mMj|>;6z+JC%gG)KzD~Fv1z-H_A ziUGsUKW7uNxoiw17VmAr-Cs?Z4WoTc#Xmpz3HmdqkDC0D3g*1Z z`=+PWzf$uD6SnrXW3M1v7rmo-%0O1|#i#dCO={8Z=!eBVRlZM7aFqgwn#S{90Zi@5tJ*O3y@TAn$b_a@TlpYaMP3?g++1MWSrbgx%q2{hiI^&f&R6Y+xY_%!BdO1HhZ zBL&O170>6DX~*1O?lRvaP-_PH#H%jGXmxro2H|pkDre1%m za-!p4`r3qh=<0L2wYSp+wXhY(4qv}ZVHF2Di4|vtlkD4jnorjqj$6B58R18&iqBdj z-23+aew+W6T#!Ln3$gP|hZw)zF{}Kn^lc7&)qqO__ZT8~mNO;rj(y2T4WCUu4?H{F zZ2IL>MPb+KT%cY1r=u?H#~lU}noR~SZI2r+IE(-E6X^+92;cpsMCQhq^`4m!^HZ^r zkt_6*U&{Vt^!`|X{>x9`@57zV?;jU#<(ZglZ++kT_;=ssC=LW%q`>AQ=rKP86~Xv8 zr53pqxP!H4%7%@rXBvM~dTp9qe9K}&9Fqji5V9tE@#}MEuF?8TmRBaeP9-tpV9AO? z*51wu?jQOh74nR4&ep@#D@damcsBK1j+w$>1I^UI?_7cL{A@%1-iMJ&S*~K`%LVSx zt+%-bP}RmV?Ygqv*=n7B4Mi6@Yb$ld+HG@Z3&KnM-orKK2OEo{b6c0`x>8b##gVU6 z-qDQ;R^DFL;i#U2WU*YEbAzF+O68YEGgixJuc%9PM+(}S=uVvyt2Cb=Dc_8WSLLeJ z9gim(D$TT1TM8+C{!1OEQ|N%Q8+DOtm7yh3O7vJU_vNzjDL>y#&pMmtlJKCZdd382 z^;{i8%YUU#se(pSf}H&7biJh~037;y?FJS4sk0p%YG7ss5B;!I2)>m!)UXeL>nbqh z|A=Xz$Euaq3vM;(U9lMzk>({Ui=WA!94eWx+kg9q)6m6n8g+6KR{I`=K5=+mVDZ%Hzm49o8Ta4^Vb4z|@cn$| zm}mcU_g?vLS}HyLgmSX`{U8tDz1dv+BxvGE`{|M2IM+Ye)RH=Yp)m;Ufau=nTt-svs5 z3;4viEgK>i?_F~=rD({VqfPE)M`G`M{CTE;TmQ0xCZKn8uNev!;S$o`ru=R2;q<}w zle^v5t{c#(Ol^L2B{>(=0_RT}@;(fF0Gd;zy$23M(Lw37i zF_Fi@6!XdXjz|+l%lZXP5bpc(PrOQokO&>~TRjCTYYM#yp~GCUBSO6lT|o^TPZo?R z;!H=p^YlcES&&fl+1q9lnwhC85Rv548+_+XlK}!jtY;u4>?J=BtG&*+g?QVnB|pdV z_bzx+da59P9cF&NUdf$0(Nax|C9=kZ#pd*le~;u737$fhrPc$(SQx;CgtY+x+Tw^| zf1_-lS4o}mBo(p$$-VSLo2f#@&H!QCQWfFAPbq5V1vJk3*>R59%44dY5=2h>fl&Ij z;;Y$>Ym}7(3TjJKV0qy>cU}W>KNo&&hubKVs0(~p9{H8?yBa^-QjcX;9Rnb`Tkmh} zrV*kB)tLtQK6ie{Q4q1o1hM5-BSST_C=dFm*!BsE&_qy$?fPAgHQ7k{kXgmdy>lq# zNo%axwSolSWbTgnbmgaS_?Np|7NpMKJ1Le_bR&BdaikSeR`50LM%5@ni#Ao_4>VWB zHX_5Nrg&b^!oIl@G*U4XRbQ@*wVSg4RCHpUKTu*>lw@CNaKExm+betG%}uE{`1rk} z?fupsyN!N=*Xo`M`qi)Khgm(;@d}BElV<9=kP#qf@pB|U*dQt$eS6`@gPg@9DsRZm zy02gICqCR!*ApnSxO18)=sqxtvBX2sPd;b)cii#e{;YQ*88ICv}WG1=N0% zr0IC4eM+7MyZ)HlI7;_f;piGh_}$77(zEa0i_Iq*FRPrDO8wp&R4PddQZZSbQY8^~ z8LscL6Zq=vyv?|t$@G&iS`cuO5{JHl$Ouz*m8(W&pYJV_kJ1%TCE{f?#)b+Vl0yHe@pEs(2Bb|s!>2%}Uk|V_!qv~Wlg_oz&dMszJOf+< zN7yTQ^1Hh37P^jz=}f%)s#;s%oIB6>!cKX#yS7(}ukZO#EDBdejjuYn`{II&fHv$` zqvpEDs@3H(*!Z-JD}xhP%)JZ%xq$D@P36MJh=E zdH1Bvk#LM&VLw3hQpDJc$kj_c!5k2$`VSX#U6el945kgFT_tC5>Pq{N6}=#?*>UwiMVG- zS~Y|h7l73xC5X62D_XXLptdoOqb^*>hD3n|Zmi-K$@08ds8JfB+df=pwSdpVjw3&( zIJ_4$iS+3A;hWE3H=wdrQz6uXIEQEcz>G}lh7hxVQAbVX03{Job}dbB7=XN&x82or z3-QQP}#>rQHx3UlT{5CB~-amDZ&gn}=uP#o9o9NvB{Id^!A3_L@ksi6; zLQ4fE8~}{cY0+Ru!&kxFc`%k2=aTr&@H>9mkRip#WoU<2r%3SFqJnp6I-*g27a#*D zia9M(SAz3}qCd#UwQ;QgOG%9L4h~$nb#PyLePR8%*Ab~v&OZum$KgQJ@{t=B!5xZ6 zu6;kb_Qaq~7kf+F{7}OYeh?UKIHcNmNDdox@qP5!WZh4rG3Uk62q6425fGurME4{K zi-ezd22hKhq&b4@z(y7hV%)Mjjm5V6oB{^>6TQ>2};vK+&*Jjas*>VDp5!DoA6!t=^ zO7<9)KeGj2L=&zYL0AjIx~M<^2yhABzDU#|Iyc5aSG2(J+`yL%^*e|bOU%k9rNgIF zZ&PzushDwBm@j||VIrTXp!;V9t^nB)i-?a3|C-BS?hYOZ4)!HI4?YbIXXS7=D?!Mx zaFU!o6LW}L5R*_?G;ahs?<6z!B3aIX2x>8D5lo~k1TZ7!W7YQ!nzt2iWQ{cV? zK4CoEpMgrlp@Nt&E~&d6fpVbykH5>^#ZQNYGxJjk1<-@Q6(Z{R9QQh+teG$s8;~39 z8c^UT0kk>!U+F8j2>Rhm3@OM%B*9=}$}5`%_POVyF>oataLOjXhT2HO^92urT2qaX#m2X-SsH7NLi5?W z*HLd)VQja0CwDMtEyp6W#oT~*n*o?pP%-#_6?d%!TEM1K2LlMxVE$YZGzoBE!Gy8M zbWAPYrZNx@Ie~_sHUMLpm$O;*)0PFMc!<<03?#!1aBU6OL0zCtpOvFA^-tUFafcg_ z1i2w^n?D%7SiFYJ4r4`l;>L{fl3hwY+w(7gAb*5nHA$-0)a zn4zwY-s3?476C&NB#WM&hK21Rok$~H(@?)=WtY8_*<*LFr*);qVz%dK47EwPGaTr3 z%Ib}`?rpHS=BAE0K6}9SETBZ|9t$#zUaaovB3Fpeh}3=c{ndxQ>TsOQS1%doJTMEm_@}|Iu|V zaCxP8cmqdbkcNdd3=CE=2C_+m4ct$M=5sKHYaTt;gBf0i2bj(=g#>%^CbWBx?%~^R zY6Qn8up6Sq3D1aK5v;5i1ISlv{HccM&wfqX!~%fOn1ydCrXiDTa^9|Fy$V2|azh_g z!`$+1OQQ_~gqvj)q!Q-lMrPqxDsm|X{c+)H=MA_#EA(P&TrQR%Pass&LXKM7`+h(d zABPI|5DImScNT6bO@JQvcs-{O0;FP<|Ma`jwDf5^YAFpE_X9mEz{kD<7<^?hqr8oP zEz}46W6*nJ(GR)jg7nd^QWz(jp4x?*WsK20Y?Cruh+FQeoz19S5YXp^b2f1eg$%=$ zo*T=}7G)ZHcAd58)OzyjJl_(v^h~Ymao%7im9seI^*Mwdnii7K| zBGU+0**w7E#kNpV~Tt2O=lK z7xRW!k$@X&)D6}kQ~Xs5wrdW7VL^4c+xIu*(xQ4zR5`SAqk>4%SSn+3x(WDTbkAHG zeHV82uZMkds{MQq;@xdscfcXs*Khlr!`}cG7pA@Y5ro-u`?%g)5Cp(YGA)&+W6h1e z9z)!)BYH5PMTJD3XNO^3Ch|;2p&uapL44v4Z{uXk<+?ar*}IhV37mB+DR+NH(}(j@N~7mGW&^6u#8n63U_t@Saf{Ec zO2Vfmk;gm6wzB9~=%~n-sHa9)Q_kaK_h*u4{PjDD#`De>=Gv!FF?qfa{++K8Q9_H@>UMmD;r(siTX zS&aWW5jy0TdK{XLfEthAt-NEx`Q{p1?|)z-&Xw$@PItTeWZ!{4J^GKAt{=e3oFVsb zydW$40t+U!iU6@l?h=g1MR;off9z(3{dG+)yX*NMcK6eL@J2Z@oPqMgKAgQ*X&?(I zq2UI6fF}lSPN{3~MOnpO-F#8`a|;Yrqd(PebFm+N&%-+|31DzFd!`U750|pA6$yqY zlh1%P8GfLKTV(-P*8>Whj0=>5;PEV^g2PgOc2g3!+r=~NIzgi$y0j+B{-);C%G=Z9 zsB6{*#zAmZ{?cfYmG*D27M(MvzJzmlZ^=Zdy+R`yv6I?&qPz9}Huz(>@-Fv6bi-A| z!WRB`Ar;SR>jdcjH0j#o-;F#Q`|w37?rs)6;INLNb;-Fr=7)<#uVY;J_yYwfk%#u@v_a&-~-x@RkO1kGJ!toG{~lwvfe zHiEETdJ0UA&T?8swez-@KA;c#$py1NgOZ=Om9wU9uD`V@K)kdxec;P*IX&=z7BAq6MZY36^c~TT;=T>^c??%JUzO`Q+96Q^i z^D1kRki&H3-FTs{* z?W+8}o&yrs6>h?&`y|B}numwpq++fNxi^NBZYd2unJ(#AU3k~44@|Eiyc5Q=jm$I;gS1AY-`_kP)!x&+xPI}1S zZ;na?$VMozUz~6_-O$>~cn}5=Tnr_;tXlOSRw6$x=LaeenLf@#oN@ur_y970LwA$H z;WQIfEOZxRA&>O^9s#bi9~BLp#k@hC!o%aRKVtO2O*+5_faakwKx$fg`o6d@F2H-} z{{XxKx&HuO}uq z{_sGt{Z=j1PGf;u9=iwXe6=A1*>`ibZn52@7R=v zHc!DLTD6YB5rBqo%|)lKzbKCpyWrmI4z3T_P+Jvx&4yKEobISyR(G9Ou%ADR7A}nu z-eKeeZ_kcYQgujkgTinM)F4i5nHiFmXtp~tmzxS=#JK)0C_%ZS4AI!dD|qJ`g7CQ7 z4yAXepivDFGrYGgbMHyw9OC?~k_Q!eQ=%4u5g3)8AD`2%86IAKGAXS7(A-8y{q)c# z4xQ&xkP2ay(G$+H&{%87aQY*Rs>*F{gtzn z$9^g_$M;by4ICcV=y%QZG`f`rxDg; zkY?Mi{)4}_%l=WkZ;K9Mk8VsTm1?|WI;HJjN&&bArH`O#UyF|)Hi@brwd?)YZbQep z?z4}KF&BV?F=jNWDFs>$7eYOU=#W$6t6{Jwngr z$b%}_m!1OZSS#sA{(KeB`vU*`$nr0Id4b<2Vg{<8imS?F#s2*B{SDRSey6-)$_DaW zZ$FM5&7YtrV zL(iQ#y;1Jmg!=IJDC*``MBv|DUwW>K{oxy1xRCSy_G=~cF!DV6J&n zla!5zM}lK?ZzT7g#u_g8DP5GfkGoZe1i19KK*t*yD8LjMl}$p<92lMB-IK1%!9ma{ zZdgkt9YptKM;Z~vqF*qKbVMkSh)9^gIl+`%Hc3nWp7r-j2eQyOd48R5a1|OAtt+!3 z$h$Ho9ZJ6zg7f6pv>1iWbRCwv^2RZW_{Kz2k#~vDlaD(;B9lhViq-2%HOHRaukseI zbj1@o^VVxu1wb*v)uySC6(r7V0ys=Qb(AzF8iE8Q739-(&ZYCeqK=z)cH!b@C$P-3 z3_WHoWx{k+DrY*)MlCatk0~oVsHkkH(Iu{2#>5_J9XY)%bXs$9%o|JB`dIY|=|C70 zEJ2%E{I<$^Aw_vHkOEhn7)9+^FUl{IZ+u+dBP?rZeZhB{$9A0ahOcbXRAP-@uU#bs zygjFYUCN+G{q*FMeT#B#YOT#t;SuD=B^|t|$ooXJPG?gas-1NEk+GBrU_M}Owgu>- zjya1>Ec%=uz&hyO?yf>?&;@e|xngUJm(zU-f|lC`7G+Nz(_Aa?;HrA`Qj^5FEMGH$ zg1nGu1&}mrZuolZUY%6f$!oUe-r2NfJS&kulB%|~uEb*oCGm#`5Rz*QD#dsoHx?zr z`YSe`8Z9UCJlG@vB~~{0r?rx&7e5&A3>G zQTpyP-w5fY&!Fv!v5j5{cW1lBe)6Y3Xn8r|?$+~4o}(V!xa>VRe`AezCO4b~^W%AJ zJR)V&6u0;wgpHv@t6|7hacyUnT~Gz%KWhCZWPxqPfqJQ51Fc@q`44?hOMSC^6kJR; zJvfhYk6c2{g{sOll`tpr+4Klz#f5-GoRJJopyy;o#7Dm;QLjudrThBs4q>Dn!XAm3 zv9G`@i8&QJDM_u3l2U6sq_|_P$;99;2!1>MSnuxky3#Vg~gdZcGM7QW3lm0iBThe6w^I zT3az%NtIxc@CLM2IWBX<)ynYIv>?yZ202ck1Zwv$`4Qx)H2H%88DXTy8IIp6nQ^|! z#TN>e3(vhB75s_7e>apiKejccYh%9Br`>IKyI!Pu1yKlT{&1Y+xF_J}$XD$|0p5G% z!pa$lDuJVwrp{WARi~ZG?Af|2yoz$Qz)8y&_$I>zxZn=s3t6*%x5}a0f=Xe~T?P$r z-52H$WEtLum2#hf&gz`3{5)@8b3qXnrgN_UJSZeRMJzCS zDrq@*Dx6>n{eaHTjkek zea?rpN*rC@>OPW)Xxu!LaBFDgPj4wCkODpM%hr)x5Z%RxfaA*YeUL!X(}+bYf)tR) z&jxB=zQQU|hS%kt>z|&<_%`9lF}u#-L?zBed}j$roGfwz>7>R1i`p!)5+YVq@9^Q8 z#H`F?Y>_<|YVi@O@GZXDq;JWu_dh{pwH4gj3c4skNZlmfZZ&G zqo(4=HsaH1aj7)K3thdXUy?8`$zZK0kK64a2$fP1(*C;Nv>AcfJc%PfxdVxAlo%(o zgdeEAJKS3_#zC+S9kBdwE7zWWQ=y_L=s@zulA@`P7~)Mbz=-2ox*yUJiX>1J1dxD4 z5=7KUUINAt{ZJ|@LqoWc)c|73*$s*kQOtv!gzyyChoq$wL`}Q^tFjbRCs39oakn`s z`}tnHwta6tM|7M8?-qn1g@7A<`!+|DldSh~)m!hQd+c0!EaZhSbc7;4ZWkfmaR9(= zCUUolp+LZc4Jo6F26e&Z*>NTis5&j4Mir9>#O(;sI#=^R8*ixU2Yw7^Tso!AF}dmp$cOqU5nm8v}fC7*$6&m)Bw zHYJ~whRkn>aEV9fD+5e4}afD!LOP5A>t zZSqA;r(>4~pvcL@ow9f~2w3cg?gpUlbXqSV*BZ>F31*K?w6#bLU1UVIv9T%CRxQ$=EYejiv{EfTHdm3IM<%~22dEs?lXD&qPrO~n`Vz~!&I#PgJkFu<(9 zi7Z!k%CV&U_NBe$Fx`A8vIAmv*H`w(Gn2o{xZ7@3enk%dWyAXIm=P?pAoXX0)Z#a;JgrE!DnB zwXqfx&tJ~wv_0Gs7kr%kLjkg9ZO@*HIu$j@9&+8@iaOqnI<*QI-d0!}Q@@8?kB_d$ zFV-Ezz_e`Z-JR-rO&bjS>)aLUm2HJp4H^ui8+7LD&9|}kQ+32`?$YcAr?&b=VuQUu z+S0vVeY^3Lf1UnRoqb!w3AHBwwT3flO~kb(WhqWGX}d|)9TV187r0%2!M52}tvLWw z@BX-45ewZNS^GCq7;+tsWMmm$1a7#3MUqevLWUjC>e_W#feajlKp_U)47YVNss%{` zd^hu4x-#qB#oMBQ1_MPw8>k4atq}ulo=njoBpo%abS|iUD71G!`!IKBTMxn95QmCu zk#}I7kvf;3shs;^>B??}4!YCHX=@46h{#NO?ixzMj*#d|Mi_2%xOWLhY>2uNI*&7j zy{zN?y2Mfw5dyfpi}_-RO!2mIaaZD=I0%q1A}mks5Y4E)IWI9?cdXOX;C?M?>k@2i zL^4^TODIMG$$+%}677!$5rm`<9#MU}7 zkTIG8Q0G)OK7V(Y!HsUa0_x~Bs0T^yX`7~2yOL2%kF_Bs&opLCTw^>*CS&*isdl-LuKrm!SP(>~)mCdKhWfkJGGUUssk$Fj%8vehrZpXm?#JVN_ zjpt@(NYCYt zA!gsre|YZXYB^++PeCN#sX|?TzvbLj`)Oj z#^pPhT69~$5GsX5L2tuIgYQC&vi%^FOEjx^C8yYHm z95I%mcvr;pb~CZwwp#7z(R5|k%MvX`^o&9?3Az#5ro~*i&i4ssFTSr}&Xgm2y8uBM zu~{JUe%6Ujdc*Q44DWKEFw_-FyXmiswmvy^dpdEks6^c-OY7OavI7A+mMToEn+P=$ z)2-D;#5^iO2=ic|Hy|bjLd)e^H|wVT#&7OFpnj2`DP7i@z`F)3shl~Z-tQx#^?0I- zH#aNQ?#=s;v)xw58{XIukxg9+{J)iwacl`jP3ooVNx{J2OWi~TDpOe5{+0N|Yxu_3 zzrg7Nm-sJ&tX&BJ^@oMBp1P%6f4p4385?$pS$V1*z|LKRzQb z@G#|Q(n56gu_ zOg%ML>|D`vVX2d%N+QRb#FvZlao+CP1FLr^$j$10I^y*FU2o(#pX!II)RR#o#|=-- zB_bR&7A;C0T|>`TcsoUw#@QbuANM4CPL>K2acb`LpMO+c8Z*cBCt?QtfIDsna*IzR zqD(JBs3i&dlS3Xkq-U%!^B z#4s0NSpv!@j$&yp$;v_u!8U-VZ!N5&*|ewLrPc3MiWu8F5z(}<*m=X4DZNj?c%7}; z^XukEO`(mS?fZuRBG)_lx0h~w8QN5k$B%x4p2XkW`1*0*&?64?{+C-qh8h>gByZdp zyCWn0TXRHsOd8)KSby^Bu+a)>-{_uijEi@^n(bV?ucgcTZB*ed@7Eg`U88IKAhv+= zz^II<0Ni}H`>l=4>W@;K@O-#SgoMQ>3xs4S&Gfk>i3RsO-(jG5B+)=mZ02@(8rbZe z=>K}~Y-45E^~u^zc>DYC1+k|u-v3aLUq=f;9vD1dxOV?w!j)@FTkkcrZ$0{XW&dqu z@z|(ahKy|XJ&9j**i`-(UhOH-M;f7%Tb!Y*W4|&vgo7`5MXu=Dj68nIDE^VO&h?fr zO9D0MC8+GglP>r(7jJT<-{OYK^Xyc?+1r6b5TfRfrxCilL^woZe(cw1_Wnb%@AEEm zw$}Ue4()u*J9BgA>)0dC?@xDwP5%7;^(EoY7rPn`T!QdpI+y}C+67&uqkipWQU2DS zfgL4K#k2F!5f?pz>U4LtCi^iN{lw3{F7m2 znbJ~xhH(7gXf`&M$gFMqDQ31dXBB;6^7I=32L}$}6DMN4{x(S5`E5U)_&e*e7{v9? zAGiHUzw2=aaYWQYqN1v`KgK}BOY+U&Moy)w1fakCJ9UtF7gw zufI{&D~xm+AugsOmmI?px{s> zPrNgpzW-QCKfhal52WCzgB~9s1WY+gg_QIJp4-14eZ4 z5>Gj0HYy#g>F;cin&(?Vq(EPUXzcg*M{d67w71pWX?hL^PPF#X-zXj3_p%FsJU&oY zrFBs8h+P}*vvXoo(s;9Pj`R~>J)N7`VZldtw?C=4-f4b??I^_}(98;Jnhy2qNznY; z;PT>^>z3QsWO!f`28wO|0@k97#m6CElPXUnXP?&=3N6zrKPbo3bilsD|E>I8qeX4? zU-Ezl_+1pLqGA$-Id|!+dBx`!>3)njv%t3Z9wUK22h8+OpXfJGoY&l=+jrd211u6P zA?-Hv-??z{VAx#fArN>H{ph$w(W$p`3Ijg1nkT%@UZ#okr&39jBqbgj(%f+Z5J(xUOK@YjY|dTT_|rFFyBX&+clzIAMBT$Upzcd#$%#*c!i) zBEF--8aK*s$u)gVczxu9vIqI$Bal&wx>AI{CE{kO(@lS=a#!v77E5pDD^BDS+EQ_Q z`p>~0ZNkF44~#n8^#f#SL8BE1<#O!Bw4Roj#Bf9?KPGdIm3!o~wc-0G?mMqW11?1TwHTo-+I7g>{$uzOS-Z`r?s>=~btu$DuVC&tr zdWg>XAo&XVKIHO+2Yy*MjBIW94Bp={d>0-ux_ls_`0=PybECE)=cDdL(a=9>tW;1eH66s7XnKZkZAFf*lz zzx(1JlAz(JsM=?7>Q=HvsCcYI@(_n|F^L>rk3-7%CVJtJO4K0zfy7x{++T6D`E2qI zA@V*ke3}qlQiO9)rBn$wwScIv1>*e?0ZXD#u&kO*U$wPn&F+A(^GMlY4n<7stVWIVU zkR$?BiF-Ri&ScS3YG^R~vP*F@(ICV(b|QUQ8KVs#C(5!(l;lJ%g?1E7RY6XbWgh_e za!&+eXs9qeiW5i!#Tt5vW?F0iA3u*X&vn>ZfOG?R6z|Ul-KPzk_J731{~1EZu-T?qxdphF&=2>E}S%u z3FXHY&upeYWQVNOCuxMm#-9(Ca4XeT@wv#C}5O6ndOw4%;uA@ zWe>=a0Y8!YQ6L733M0XT$tV#VoV$hMJR`@0k(Nb-de4Ep0F<$!zMEE@N-nr(3Y46~nE{OERBB>eKo{I%;o264NW!L1(vI#&+Yj#?B z@)){mRJCeq3+;9{FjqgLm%1opjYSnif^bIR5lTiV6K>yt@}L86Ic~`z^xRB($%DCyn`ZUzEh{=R zDjM-g51Co)(n}?M5t^>D{1WtTUHXs<{YiPPv|cqul235n{}#GYE`xr;HixZ>z9{Cu zpbvVJxUL9zn1JFo5grU!C>bSyg+()rtR_qLB-UT`1VZP*E0Ps|M=Fe@(BW;(b@Z%i zeC38tzKBgiXhy?NmzYbo=;Qv44$+Bjnc1>y*+&ej^8FJFE6N&3A)k;i?$AdN1+Ilb zSw_KPX$UL}p;`fO8SE9`rh^idMYzj%4-Y#)fW7jE@sUFgqP)(N4n;HTl1Odj z3g9%YGv8IaoN7ciAl|g9D`RIu3NrJ_S!QNXN=5sC9_CN;Z46+M^M ze&T$4DTxLfjMTHk3`H`oy(g>bo*TcE&nw-N;FEed0JO>~8y(DE@Nbmm!RZ(Z1;;e* zlkBAoHoBeYys*Ooq5Y6sKHexYP(g;Isz;1oM+aq4Qq?rd-y8aWWW<+2ONrEq8-o>g zNfiNQj`s#-W_=5O_O7|~+S&OWn&(YfJ8ORZQU@xg*drmZa|w2??N7-C3PyA^uM@z>!_$6H;nU6FaZn<2+}wpf;0#y&Crbl2$DLaNXXEw zLpKcFFi5AQv<}@!Ns5Akl!1kXe0P4kXLrx;Klk5z&$;Ku`@GNdd2;bsrM{KZmh}0) z#m(6Nw!2cK2iBB&OSbDe43I-g{o^jZk59Tuq9KOTk7keiorCfkl55I~28zRwlqv5M z+vmM~184EQ*-{VO5kS)f@`_a1b`j#N7ums1%OG6zmm^PwF2yuI{;2P1zco_+%d^wX z6prA*^}ga0rp8-b-D#BP%$ey$xH8C0>FES=;M|}Wqg?BYd72T=@E6ktCvnQHV zCUDd!#*ulkaZs(h5BsW5g*%gx7HPjRkTvhusGn0r%8dveio*kj>(qwG+#p-z=qCNu z+V%`luj)<#x3FOirNJ~potp9pHh<8)xQ}b9E{8H8K7*KI&9%y{k#VR7B@Rh{nd=YHr$H!=h%< zN3Kd!9Ufz;q^4Hx=kw#0W9u`1hN@8d z#Dl+y(i$C%62&IE4(E1)^8Q=x2%UcM@bCrb>vRQi?0(~fckzovLh4g`B$5J2R-zpc z8;zb{e2k;;vCWWAf~96CW8wHo-G$?6|LXo1oZ=YwlY=Gw_$MwBtL0{dbr3hBYNnm}Han7v!H#f}YH z>NuVB5}2w;b*}Q-SW^n6@Vttm>&}#VZaK@ytFoCvdbRO$Xz#d}?ib}H-^PH~#FQsu zSY=>nU~3?GBm+fFszGv5022xFPjqu;zZr0 zH~q&ORdkMWBv>c~_JAFt-BWEualS@UHl(;iSD#m7mZJ1`s!yKphA);9&FG9g9@*m^ z$2Whdn0FdJK0hCrcv}7wWGj;)&Drw z>`RW$>0K9MULWamRcQ^rA-Ak7KO0L!-+L-_7*9%cZ(%pqg1eJacMk)F@Z(*phXOwb z@`+LEN0YrgeSXM~Yp53kPd`Q`9KhojlIK1v9Bh~i26U?;?qjN>x2rvIPR1kE(l|JQ z^Qf3obL%7hBTm}2xw|xk8m)un(v$h_+4j!U2wd9dD9b)s{EHuFd*DaQ=jYxV=U=6) zU;MPITSq!dqw60?L1E*~)X=*&2b3BlXCwiBL^zrRYg3F^B(AREKYS3{{eqaBc#Sj) zo?9$g@_-Ir{d_;hSY1Z)vUX>U{RbATg7kPcGFZ;^(AEF^8w5oipm2AYr(f((y!GAIVYG`VY|mlbI6AkpOT3T0mDMt+Uc;K`roa3l` zCR)m4L(9Le9Lpva`GrMZrgpwuE7_OU>K1!RB5RKNbgi`QME0!)n}H;`hHmOw<@MPg zxdU)T52Y~Hx?YHQ_XkTQpLDJp0_hAQVN7pOAtHK-v_)=W>ut$5%e1Rb7dCD+rEn=d zoax?ro_kMpe>0gQYj5_8!MSnVGMiPjEK8Dat(i7)fv#4_`5~%r=|$x*a3exztwneA z65ro*l=81${dQqL)pOyezPmGARa?J9$QxvY0kM`29OJ(Cs!ubNNu|~-DbjntIWTzB zap%KkU%c3F`)|MH2b`+YpX25Z%ENwiG2)5&XkZB5Vts>7{o!OQi#Dr*-yH{T{dQCD z&-MupaYDx6((vCqLUF{9h+ll{f^iP~>@tm2xhAKw_z@8QoZe-DnyOq54~y=L(~o5S zxfF%m{20f6BdMvzA=5yjz&M;l%D%SU zxf+#m{51EA`$5vbrb$Dvva(dO*p>OJR|7woSwCoEuk9^gi;du9y}oRc;59^Bq*Z+T zsCl#D$=^k@2Tu-F!!1V=>S-h^k{L!Rw3oS+S|gwdMs0#oQ!x};{+7ir5~5CDpWrn@ z4Wx$5#Ap0oobxl?;26ujZ}(M<8eVLjztNh!XLA-&Y&he1D34tLE)s2CzPd6!*`nEb zSUu~@U`;4_{3j)FW5=zb!&=LBmKG&+r@((xj;ZO2Tm8n;6CBe7qATLjrY;!VWc2fL z^zQnrLkd@9Vg5$u&AC~Fh7Eh`?bZ|@pRN2d8l-Lc<>usr!m_kpvFaPsy3r{?p|2l2 z-p~*Er~)Cn*XKQAuskX{Q7wC{l))?a<=Lh5vnMq(V&>IE={chZoTh(+^*T1wBI-OL z-j-kU2%q<#aO<+EGoqa{v5YG6Xnm+c_ItYJ*T>AqXHWKKtKT~K9m&_O-Yyyd?s$Z4 z_a*+jYI;tw6uyZ`%mnf9cE=b}@C^R*!#wqZ5EW$-GJ`;OC+&6=BP;>RCy$Y^%hCF`z*@y7%%F|jf68}ps=a3dCU{My1ms@ztxxS_X5L)GLkTubq zB)Fm$iJ9R{9mc7mQi`Dr zpq<)uy{Kzxl)@DBot;?4c?Y@~r7Dp_5)G)BnZ~6%n)fNXSD!W(gt_VT+gjgzsO$G}gwg3IjgHN}I*x3KW;VF;yNS9Wa& zPQujbPxe6QR57s7l%qp-Dx7P@&Fq@Wl-dRG(-MYd^Cdq%)6a$C73bH!*QMa<6D?V~ ztE=_sOWz$|y)Hs>xPoVRAf?WE0I11lzpV7bL!iBQ-AmU`sW!KUw(km;=bv^m%g1_P zGZgaAIT~%mM;bi1+UIX@o?dvEV?}Jc-;ux?_*B|q;RJ80i@N5ZM3^7u1!175MRio% zG@d41R5G;02ey2N#^jli5HQM${a?IP`LjT3Degyd@N`1gpz(vaA=c2WBrBrU zI7lh~@fB_oW8WRa;6N#Tu|I9>W-mEO-H;eK}d z=e5T2#TLSa#>BuP2c7%?!_q44`;vpoVR-Rm@Z4z9Utz(8vGX8xqmZrW2>07w`AtL0 z5>M{9a5-vu=GXPo_>hjHpVMr<9nn?*wrz@&A?zlWT=~9Na91x>b*I%_%vg!R1kLj% zuaC3AzGkpxh%TdsChl2kNpRFo+emRt`LEFB{$s^S-2H0)Qf4!4oc_R1%REijtNrq_ z=fT`B%V+EpJKODHq!RHfON+D-Xw$p?z?d8XSX-f{YF^bET2Z91nse5uc@{5fZ z4eCD++V_OAWih?)Xqr58mC3Rhu66p>j9Rd+dzK*k8aYU9PacZ!0q&AY{jZ!@CmZ;2 zTxN1?Vt46kxAm~){Fo1kd&DCM21G_>96!H$_4jx;-{w46QX@LTp&hi0&$}SW%cgeu zpL^KZp7r%=xzOC6k3{cxS%-pJT6{Jj-4OOI8n)J7G4_mFu5nGBxZVEIT|Kuhxi>!& zL~mBCE-7@b;NP;!hag{{NY~yrcpvCKr9I0p_ds~ABY5!jsrFK+o847~&sr~jx-8+B z-iIt4UE1Zp_qFl`Zk6WJ*L-Eq$9coyX|iRpU`JVLj&#H0yzSl!2K=ZVq19T^IBrb> zP>@Av9)qx9#occeK4rpGryG2i`S~ z-@4{L*!VuZ@Y2`lX4lfFKu}#@$X1L_e{n-I8(P^Hd%n^WEH=TzrTtY!skY)*Nov9V zSVhT;w!hytu1LODZ`b}7Z58syDJ$f)nnv2YZ{f4*ck@DR9YIq!OVaR0iD4cR)=zHh zRrmkuHC+91u#=$tN#XD`YPdvaknPz+hBEswt=m{WT*DQE?T5>;U6u?J>gb9k*vuV-v>aFe`?q5JrduIXgDzXNbqa@ zl>|@{wFXn9@}gCIAfaUS@loBWQFUrVB$sp003z+0bka|3eDzh|^q`c9HT~?{#Qb0J z3;76qcQVjoRU{Xejng{~1|v^2)&0-YpR=cdkfQb%B2QZYo3RAGpZ0b6X-5c6C?fsg z8V{58rO!jm(J{JNa%NO57=_n+sizmxp$iC;t`s1hx?;BE*xTddG3ECe3UE#Ash{;S z_J2xLf2Vc9!MkoD+bgrWMoc;?4feiYsJ@q}t3W4^NLTgCXE7>i)l~?E%(`C@MjlHc zorI}>5s{lD7IxEqaE68hH*JpEXa=z$@5Qy`qt&A>*odP z=SLUhl`2T43g=b66c>9B122+6P+aW*Hw)jOC zh~Iu1O5RC0ho(%>ER$qrOE43rG4rfbp3;V^km2t7P-@-nDTj#;R$ZBtd;fRY{W|!k zTV+2(%0i%I_rtOu`ealu`D3=O3Kp)1B{NKsIkn2^70Ve7)VV^-E+vt5$YhYgV}>Ls z%^$2Xk^DQc{Nwks%Qlbyt(S8rmDALh3))nG4d8TzWU6c_8%pN*^BC4!&a7BTb%jZA zR_f6{7MdzMmk+JLg;LK=7FR64R#>Uy{&>s<$@~-DY8ih|7q^)gzgAG9wvt8+Cd!yT zwEG=<@G}*_=~`-AhGoNSUt0L%El{n{07XkqBq+M@E)oF22(?ts9vuJy10ZU4D88^Z zIaC$B4J3t<(n9P0T&ZJ_s)Z-kmU7k=Ce>w50aQ$1L1C>Ffds|ZmC=GKX+d$E^;Ji; zP<%sXVSTH6ofH58aCLc{b>*}T3GUR^Js?%Fu0E-u&!9fLzOLn{c6_QnGqkaS7Sv4J zG+8*nwHcf2QNlDd95gO+<8rDLa>wB9A4XDRDihE=2RPEBA=6;bzGVM8a$z4Z# zJ%MLmtZjvA?-212a&Y6!%9IjgTCZOCU2P|v&VWFw#!v|~FcJ-Nv{N@W1}=z)g}0>t zZ|Xj=3S&dQ(7Sk*j!T3~U(_jEqrwzN~te+MvK+`8S)O&P2HP))P%Y(5j7|kz#+vL~1hsV8L71ixZ;Xkqca|w&6Unr(?5XkSgS=|_>N^;M#^Ed zJOQLMKD7zbSwIEdoFq(J&e*0YC4in?9QS7P~EACG3r#nl4D`2!dJdirK;QBF8Nu|~h96ZOOgQ}@z zD{B?oLGF{ZG-AL%4$=j~kT)<>QYTu}@sUe6Iu8q2-2_i$#cxW*<(xq|K zR7>3xJEIx{Q=|M3H7G}h)rF@Q;unGoCU~$UES{< zvjx9l=n}wsO9hV4#MBywwU<$I!8$GSS=fMR=GeFg2IINWd%#j(o3z}uGtl{#k>gc2TL?9Y3{BSZ)>gu!*zL(Y+S3(`tT>& zG!Vk7+xY;Jw{vBK9{vCiea^j>M;T_?HDFv`mx2uV<@dghrGJD5EKtNIE~1sO0=Hw% zcryQ>y=d_?@@~@vO-cU%VDeU=tdL;vfMmkegnTet8hSEZgiGc2H_)NHI_^Q%bfg}A zH?@3<^dTF#ZLj+STgIO21@k}{iRN|VaBwya&;s`)wrzy}PsU@B)!yDhPQHYx%#Ron z40Ky^Uq>Kc@NDrnnbeQiwUSMmeM}U$X~O4U7oIHB@|BpPbj*2xuG!A9;FtZWD&|zN z)VLcRZo2cErk7@g9wGMV!z;$!Qsv)U-1^qErAQwNta~(d`pOIKMp!)`wCP>x`Ro9a zp>oYXv;(@0RV_i6eQYkvxC+;x1#E!DHc%>QJhZT<@f-B)Mv<3{lj&W;an zn(Sh5J9R=VwA)h12tF#q%s&6(1W4g>oq$Rl2__H*L_y|V9z(hhxF-*4T&Wic_- zDfgr9<_`aBFCTm)rg`Nm{mIN4va9>E^VzrY^ByZl%D9uiY4!O|ZFrT&Y#SQ@V9jA3 zFAc7?*1RagM$_`#GN&$l^s+<(gwjY0RsS>F9v$2tGybWyv&8nzqDBo3o>0hdV7pmP zZPB$)eo8V(zV&XZB|s4wC0XluHQ=T4e<=X)jXlPgyhfL)+JL{#WWyXR%YQlp-{ z&726CK3g(}`w}T%DVf)}H^U-DP=5V_T)u~T0YE1aXV>%e<7N)cOXx{Y$LBZC-ff{! z{oOtTkF2Mx&j&h>Rg2FY#U+yadVd_N2{TL9eUzX4^tumu!mb!1FqbrT&+<)z${)WE zG?AZA&s84(iat?VeDU+UcB4&X8>_m!`t2!y=R;YZK>F(k7@3%n3nL85C-cLxtgcky zmfJExi;>4Ncqi^+(gcKAF<}i7t9(G#WE3t$JWi4EP2gj`@*eRvLFns2dAf-2FTO<8 z7OS@;KG^-8STTm4ic|#&>xwvOUv{S)&LKoqqKL`w%1pJ)gxzG7Ir(=Cmsb#uDe_=p z{sMWy`>uIzrF!pEZ$|xc$n-9qh(=>FG{>1aGC5o_tvEUPbNN5v_83?S74}P&AJ;l0 zTb~Bs&pvmTxc@GjZ*JW&Co_uHJ=U#W|8b4w%J0Lf2Ay8Vy!yvBd==sE>yH_AT$Acj zh12Tx(+KZromxUZq3=~)nfr4@YJPeZdMRY~LO!t)ZH0?`b@cXQ6l0v|gYMaRhvuG= z;$#V)&{}G0_fz#Tvj6jx;phINjj+$XzdjW`c@8W!==T0uY93rMy%8 zDDpDOQd8JrTia;talp#s-z zvjzgr8El+V12;T8wgOkY8%hFK{f0@`p+4_af?kKe@VdShG;Vxj)3XQ#qK~NYirRAI zYQC{^SLoB}R`#3OA6v;X4@34yP6OTBnZrE44ocqTbs|H|Kgqu-x-=KO7M;xVXQy3F zHDtGPx>RX3<;|zRpX1GWZ@lUJ=Jo4CYx3)!{h|Hl@OJ~#|2lVCpYy6f(=Oc{*mnLF zFDoP=H_p0rQ;4NA>Q>DYRb0{`aI)r+Pq}KzpwjG)C7Nheq_opJ(=`ttgES7 z8m4|=TLxxZyYQdFNhCUj3>9({Kk0G4Pty?#;(j8Le%QD6c2>v zv-NWUoccbboc^9(@>cOlocv5VLlA-$aH*1eAxxqh*pubt{F3l&yPP?1Vnk3egX>2N zTn&FswHn35r#HjTTsAQ(5$Yp+^4C!pm?(Y^ZM9Y8n^rHa9=#rlOL>mG%)PHSt_Y^Y zvqAYyT;JuhYs{t+iwpTG@v$QG0MnIP4OT2Efd)ezl*lk778eDv#+s937+z zZ}|+@Mp(03rcl(G#*#e-biHLli-66rpbSAP%fVu|{Fv!~2?DopvG?`PK}GZ2P=%L= zvnHxwt7I%-m?PcxJp(XOhT4xdm(qrknVo3k+xv&Ih7@M#0pl@>!IcExJ?1`(PHKx z!QW^vQ|=<^(YF!cBt*!GI{krEB#k^-{=X0IG^HdEzyi<$qeMVa>ZPC&YaVO9h|im! zF;@j{w*XBNfGlRKE-(jVY;|yf3;?^}j_y}9wSJ-i@!)!7e^kP!5D;)j$nIyuFP9hq zgO5)zYh~FL6%Cj-z{60PZ827n_Yd6@v|xb+^uOE?rN2RIrERo)#P{&hN%KDsvw%xi zK(U|}Fk1e?aHE9=Vs26oLfkI!v)GMkIEh4vIzTdbg!$$YV|l+V142X}J>6+*u^1vv zgoT!u%(a_A*^vy)Sa+TcEL3Sevg5qMngWgzO%TEpf#Z*q3t|{oy5QgS^z2VyQYSIA zl|4u{yx;Aj?HF6ZY>-)O6pa`$RaUJWa*+TAit&-O3BSQKEdWbl%RNsPEW`wVHJ}0q zy59F2nUd=#`|2Cw-$*9<&wbyAby4HO41)P#-0z7OoL9hoisGE&F;QV6CYg&?=;{7y z;b8?ZO?z&p1zy}`n8T{<=ud+U zjnOW`%-Z}4m2Yu_9DNZW5iid;F!)dd(hTBq!EW>_iynK-B6X_*N^HZmNSxDi|4jmvIDi-!LkUTCG46UFEEwQ{sfIEE z#s=G_{N&*1m- zFID%4R?SE6xqh$!AVLV6QJ+j#S9=$NS%Tqq6)5+zf`gNMZM4F}cX0z*kmU-+q%8S@ z=yUnCVTEER<&q26J>JPBYsTNzj9;%%s#%hAZkJzvC%0-YKclH6h`pYgAAflL(MOWT z+h}*UTSos@6VHPJy($c|#2<%is5k%*dWmD#PQ$9@8Cl*II9!RhN zcA?55oVrv8J+UdA2_*1GvSupTMHE+ISIMhgyy77$Rqd!LBfI{I1WrD>RiF< z@ojs3xd8Daz}1OR1$hL4Orwc~3rTV6fGk{3q4Z<|I}V^Bf#Sw+PPrgslIzc_u6eF; zlW>4%+tsl;j4lB5VK1y(00A8bPJfW%S4i}Dx1QSo6+lhjg1a~$cI#Z;{jU@6Z3p$! z8>YYFv5$5W#S~b`-3Gfc#$4KfU;<*fQqQWzAhA;KvJ~&W0PsQ<2>lrujkY=L$Ws4d zwjX1h!jhFVqGyU9NSTBmp9W1O%TX_SaC;mG|8xmrTS@t;7V zF;G7;{1}!l3Zj-)gdN7-2j2@bqYl17_Lv^RqP9=e6?^+C0^@Jh_j~ryNZbe3e1Hb{ zrswl0B%i-P&AU9{JXXDSjNPNsJ#`_I{2N{6qL=VJJCg`-k<4N+?yKQuWP@ccv|{;7OnGf9x7l~*Ta}5< zIgdmq$rxJt|8&a*rWhc!$miCN8Ge+pfgm*QI^4ZF@b3kDHWfqU$7UIiZ;U+7mWs|PdRzxvu8+;Q)Y2cw+Nfpa@Hg0tta7X#wF7^A%>fi2H{Lrs* zJVGhcBE!hiidZ<7fN&+k*-eqESk&J3`NLlgZv!munHD{Nrg{Bzt zYs*8mOur}u#{H>J;%vyLJXRpWyiQ<&ClKSOK!pKAC>m>xL1^IM=GPI|0B@>?J#ilF zM}nQahtUxr6TMJL9NdSN(T~t%q7L^3ylpWEZ^F$eLSqR9mO^@x z&1wJ~GGwaJ$NkA2z?=2Ox5IBksWi??WS~|{AuaKG*GqH z_X~g);O$3&YPWC)oD-mi?uh>0+$dkT+KF=>zSVmhcC-dll!6W>A-As3A;oQ61Z^1UOYhv_64(;*bJ=oj)VsV#!crF7kdIlND`kgNRoB(=J)sRzAg6 z;xwXchsM1QrbywH!@&Zua9A>84|p2d0tLv-8}2X>Q3PR=3Wh|?oiq)(Bf)4!Ljueb z4e>an2_|3KYk`7Kmf(MIBW18)FT^r=`0(2tl>+m;UYf$>|;C+mtT)^jsBB zy*b_XM0gIS=dNL&BBm2PRm*AmsGb)8E6@GzQCB=?_iMVgG9TDScj!$K1OpN3gN5gX zA-*3qcpUXc<9nh=fCfd%Z<9V04fUFYZ&m{SEj0Fc>b25%lN;l3{d*@6CcxVl123Qj z(%mJ%egCt4|M8%D=X+u>&>*roZ412Awm(a>ZI00YV7?DKPxAo%^u%_MnTi^7DZgri zlCaUKiOUSL)!LjMApagv<>t%JfVj*{+^~h%Pj|-`A^2ZCdm)PWs)T4-?o_pvsHDA` zM;cVoqk8jQIA?ko&$@|U(=rvGD_};GTWlMX2i@p^1BX#C`5Xw??qLQq{-&d1UGj-ckjo9@9_95gquA z0wD@79~)8a9Uu=-=tOIIFV!p_SKRPKeQr1XWF%&OowC1Doz>bP(>`9 z8^GC)A(vW>Atr1cM>JmB2n;u*$7b+?RO6@!LYwj=n0C;8y~&3Y!ruG99tWp?*Q}P- z2n$CXZ%BOV1$GSJLByNlI5>MR&6z1fa>Ijn>e27{j}i!tA01oliH##k;Kx+Xtnzcs z#?d_dF__T!#s>0>+xy+lkm!q^l_{=u#qZLW3};mv<>V2=45t9_tz`RqTG6hQw}cJV zg!Q~zjr3JcZ8QekGAYvd_s^HBYEq&vz8grQnoC-&3&r0TulsGSug+z*S|aqW2W>sH z>4F6_xtg=UY!7^lIdq&ZzjuhFakRuZcE!;=({o@TT8Ua3GvL4)7ftHDgU>s?&F2q3 zukSjI$vM#JIDfwEpm%DOh&2fCFXMEWl zmW{tRVy+Ya_VMj_fka2E1C1ayeYRz()wo^lt`2L&YPC!@4SH}mDMof1QGg^)upB~K z#sxL=I0dh*kp0WQ4N>#__Uw`0@-Fg*r6QDx^XC|fNRzXI%?fNpr3Zcz@m)Nxn0!2z%1VPJX~w7P zWkeVheqS0-H&A#@I_;EBb zeasdD=-$W9nmLRB!j7YL$N(gYxpm72KPntu8?$0SL(Vz2seu|00j8X~m))^5PY3wH zMBDnXb+fF@z|jO`%*9{gySeBkR*V(CsrIGtxB#_==X6H8<6t4~ZR5It028%e>-~J) zuomWUy+h#{Mel%xM@|t6bVt6|JGpEV&SkJYisDyx-4Me#>+lizgG>N4_z8mNxGvJ| zh408j@e=U5MY^LV2NXp6)l(l|3u3-p^U&WBynRkn@}P*ab5m;k;u{V=-jMoV!^5Gm z`D|~(e{^<@3WhDW7I|wQWY9#uyFYF(UvFieDw}i0Mpo(?^-EBQp{SR0KC6n0i-SEp zC=Zn8Er*9_&JV8n?Un3bmODS#rU)*8FhKlseLsh|w{@mmd?n5-E;&Fr3$uR2iO-_G zXdU!|p+w^PqLF05{ac0Z&6BQ051t`~%nVq4)maVLh1M)TNsU^7txQMr%M5U_dCcZl znK&S~2|4?=q4rfVklVK$XfB#E>0nE|LF6b_uU0uL3xFHXZdO|Fc(F7Cgnh|sg)h%n zVq8nC(J9;7D9Gte8^iNmlfR4wdwY)C&5*;r7g+E%LThG22N4>uKBLRiGdsLPi6x*l_sqb;6RaIht>5b$lI*^+aF&dY^=+* zSVP$ev9}tUr+(hHv1S!zjE@J45+J34~rhHD^fnajc>Fx_19*ybD-Jc+DU3y zsc&e*J^^Hh#{fMB^+9l$lypi!!)KG!hqqQRiF0Qb*+B2+$H*zZMd8FxjBJ4i(Sa;t z&J$c-wV9fno2KpFF|n1d_VkPB;!DcQ{+YBy@Pj9&;Psmt3CBvM7~(IizoY|~oR+d$ zCf)t<{5n$zw|a0%LS~I>kZc1nP6{%6<^xgD(hEIrm;fWy)t6sIntm}XRC-mTvh~q1 zy+c0bJ980v(o6Y6Ipd>Wn%yAmgHSqkBpTPH zB1a=>fdzK5i9kES<=l*q?D*I~Taj505W!{hn`;q?tXfqjml2n3sU#w4-fbX*?-hKv z8p>=`eya#OBS=dc6KQNkTW3=eyi23a{OduZsH!r}M z`CDiOiRl@|&JKJ~EFdru>3R_~&I3Dvshojf3IsfZ(R_-S7T!wDEsir3Yxt#Z5Go}< z^a9w9Rr-#B4=P46@Dpg6IE61UUX5Zfy8uPd(;-TJY14hhwIsia1n)V<$y}YE-eHZB zQ^5-Uox#C*zEgntY*+a?bPIxIhgyLkc**_u?42WQxNUyb%$Nc%0uxmjN`TzZ{4)6E zgaSPWh#-2qN!%kq2H(58$21aBtfCwZ?ybZ!yw^`ywyHwc;O;#m`58%`3@SFpxQYEc zgxE%Xdu-8bydr;y5(`N+w4*ITjXOW(0sGWyiPxJZn)46Hfwr`_ z%JmTS2ovOs3=LK&W(;(7ics~IQmI^JVS}VJWIHBX*Gmc4wXoLvUT(P6;ZCE%qvK~7 zTfgnRzud0)@(BiE##c)Fvc6X{BYC8bPCN>cu;4&f7n#p{%@Xl$XS}uFW5sxMFypki z#_qdjsmo^!@mg>rLw*E%>_Z>Os@-XxGy!!9H_w~EGtDE-esLsxp6J%E!zpwwa`$?b zGcvtSJ&>tCkC&aAue=H{^lp7Pwv$QR)=1Gv42QLzWoo20L|z1=KYIi&$)q5BoC zcll_pHEBLH7R=f^3_zuTyB#`22#Mm~>nP@?*r>>-*%NE^P7LY`SOM}x(4NaBNZjPE zF$E8AqrOf;aRM5<82Aa_Y~j21_flMMXIxIlL@j*Y%Z6PBDPhiC`K*NZ;@*?d(6Dbu zoap@pDe?hgScQzI5i5WjvXV~z7G)mK*W;>w-esGQ^LVoW2%K(KXx9&`_1V)!z5-S*}4wC+*KG#?FO^x)uW z7k!oZQ^_3RcoCEC$(whMQX0bd#NvZypXNV@P5hSeHiSyO<1_0XHZ{aYeZJ}YQ&GmM@6siGX7ot z79opVyTpmXL1bAzqNFzUcIqO9z*3dp$|EBg(qztR`=Wm?n|B`9$H=Cli6C*qKvbGq z;cynuUzMWnYM;_?H@gP*FOTo6-+J@sd&3*SR`2J3&r?MQ;nXNxxH z-e|Q6AS164?Fa73K709yb6?yKhod`*tRKAdOE>Bb4(>*R=Sl%mSo=h@SRD)Tm(Qci zwMe=7=uv5&W_7;1H%vsjtpyR%I1N-9#(JfS7N-Z_<%3c+9F`@pA0E!zPIJ-MnkT{T zDj2d>MZ5%#j6DIP*=;Yng>bJroL66YtNT#(20*(K+Elfc!!2p zwJ^RRSdZtYgkYGaiF9Nln50Mdw?%TDowj!wvOtN^ae`}6Qh{wo6(Te`i2E>sk^6=K ztQGh=n6zAr+R#MKouI$qBEGgTsBH%UuCi2^>uM_xLfv5hLg@TgT>{iM@DX|mmf*~*{uW?pyF`nYXrS0g zT;uU4!nE+vkQUhak5!&!qUw-RuH5yJCIpwBYS|%XJ$!ToP?z`{dlZQ z5CNJM0E1;yNiAi!L1}%b=*; zHJRt78cx>)M-<0NMLQ=_{=}GiOc~%*tP&!*f#g{3Z$$Gnd{cluwom-YdLB``F@ZMqHkU0?xsg2(8Qj!nRcwtPuZ} z=sDl<7Ex&BDDVq08gVDeA2h<_(CPtrcn}Hxj~_77SD*c+EI7h96qgg%0(`D8deg2V z&B=dOF2K1^dCv;L5uB{i;8_OXm4APX-tbE&Km3VC%+jz+(Z=TO6*OJ`S&2>>b zvYb%=+!?m+4qT&YXx#uIYvn;Hip6CGyDfbqF=@vgIp*cDu`ls?80MLFU_VzTL~ z44)X7*OP38NO1G|hAbA8Aqf#eF!+p(x4f8 zPZe3NA(yUL=dfKG8nyq;C!;$JhyB(^us_-O$;EMzmKK{l%*uE_Sh8^YF6Z@3!-*W6 zC<>T{qc4}Te(N-CpauA?zb!_i{otqON1lcrUIPR@TU$YIZ3|nk{!fyruPa)rcNy>I2fIJA1W_Rh zWw|m;@W1*G;E8w zeF|LqT^Vi3M2Ec>$LhvF0uV%=IRnICrrZBP+F3Tm@px^zXBc1@Y#_l23>G9n2qAdz z;1FCB0t9z=2=4Cg?iSoVxVyWDU;#q-?ff6BXKS~1Yis*Oe}b;AI_KQ?b-6cSOyE7y zQZhEb2ug7-wx{OgB-G^eXllMW(a&-(DGBSW-{Q+#va#(lN5=2+n>$m{y4sygrHFDA z5}i`+O+gZzc#kP$W}O71`l#XEB&XPk7`c2l5K|k-ufp!VeJc|-PjUF{CQ&t10hJ`-Euw z_8NMX9}N`ANd+zXHJRNpSM_)ROTra8qSBzNKYfN+{f@NU9We$nYS6c8c)vK41FJ#K zTVHd90R-II-hvL|4R~4r4s{^%K9B=Hsd;#hoOr)VxhV#K0(v9QGua~lByBHN-k%We zOf%9Ye%e8l79=F`EYD~lr<^kl4tPTVe-zbJJp;E7*e)nQk}x)tE+a<+URe*L#|N@R zuxe^APwnXNcYa3SJd)wqp-?PCN(THpJQN<2@Z~f#Q$z>JLT94vm_*QzSE~(LN^bi0 z&Gb%|bPGYb%;N%7Vn|gc*GqA#XtDLp;c8jz24+$;-4SUcx?nu;Z+@kk?D1$}3DRx= zfdIMIPqZqHD)Sq@yTIaMW2X0>%;RNd0MO06(eSie{fGMJ!l#IW`pb-hs2Wm)RK1?_ zckjqfiz$u=*cd1XkNEX7XlxO*@Q+@Rk7mA==wT*_^F5`~ifjuB zG$zE^BC6aX=|CZ=M0w%0^$ch0`8Wz9bBnlAo}_Y{7-x%@ZJViMo6j3UXtjl4-G&S7 zRGDvc$Zx;K*E3iYRv&C<TS}R%dtl zO-&@KR~oscwAM#$cnJVQY;c7Q`E^4;a52@dg9GfK*Lm0wI%>|h#cf=rY-@VG|l?JIsMXycP#ANY-YnC&J)GnTHY zTmG~~^|arLxm)0L*z1&P>hzLM^V7-cguvM>>uF!d>712jzrg9V*Xh#JX)n(Cs{HwU z<=MX1`CjDtR^<84`sw!5`LFTwCgPyo>L2>?9Tv;f5|CI7}UcLW$RmCC2)+Hm-c_sAis(kl~ zr}L`Z|5`5U>SgwI8;6wi>uX+I6s4+b!Hw(BKd+@IZ+HZ6^*XP`J8!tHuRnje{cL?L zM|q=$`&;Upp{U@kx!|?aKR52*uHx#A1SX`dJFnG0{?^C6lbg8q{HL@k|IQlsx?JoA z9^K__HE;ZP3J=Sf9c%6H`29D87#SOwN@!6rXCUV@^lJ_TU6+s=eyo=L5a~srX7e?4 z`hzy!2@XOW0SC$X0QR&5=CtCtUE;Yo;2a7G`)km>-Eq-Juvz_AjhqiDl@R<3fKFkS z;XN3i?V&buh;gD<0qqF|ZVvf=0lzU4)pT-o|FAm1*FUg#=*N)Mzk_Y3hLK=f5jTfr4&98O&VdAbhHvQU3|2qYGU%lDgjGZT=j{UE! z?P49SxctN$=eqvRFkA|+$EC~t8Jd3{IXOi9>||!%v$P91p50xYY*^z70XF~|!zS|Y zVzTLD!r1u9J~yU8!NKuE--iElHEt?jVx!`%Kys%;JtNHIuEZy8n~+;_he9cnFP?-A zhudNFo(wzT9P=hS5hpHOt6JF@eVZYdJRF}t{O&f{jgi#x--(swJVJtPy$U`diP-xH zGpq^|#TY54qdhOhK*s%KgG5&vcNHy7QXQPR4=<9w3^39=MLZhsXSnQ_9Au`-Nm2X# zL}kn|a~(51%vtzV5*cZbQ*_7%;b$`SjtmSbbRX|;Gzt}=K0Yd{lw&$B&QFvs^*u{~ zQifXUL+FdE2S}AN3g^vEDw^yL0elm3VSf~0myJ54%q+Dax}tO_w|tZ{OtErO{MDI8 z_%t!2u|#%`C8-2pQ&Kt(x<}|}F}0T09ro~^wVXDbJe_O8O9f}>@ zp8RBX>Uf3Rgb~SN<6fDqpp=5%VQnP9GsTNLpXZrh^b;HNv-Mz{*c`R{?7MIDJ*rt; zrjr(tfBMeU*hVsVb*cNhDQ}LSGEKC@?Q&eI<@9PIRL7ic^m3RP-QHV(=u01uwLjg2 zLMO3NfzUSz$2krA1-~{^6Z31|5;YRqB3cPcrzFjyirZyU{IhpadR1m`KOcy@oG-b2 zA!b|g_*DE;^L{ok>a$;d_z$6X)X@$^NiF#h}wG4}IjCo@rs z`@?+g2FD&hKkUlY9TAiB#H>Mieo+^%OXEl(NZxHd(M>ifZzt>xRbL_dknhnyMQ zE)~zCt2Z~)T=!Bd%Ou-=Enf9M-mWfm@UugUroJyw&RAHKIjv;;eJFSQ`SfSy7H)I^KesQaQZgjhnl{E@RI__ZfXnfS#eSiv-(r`WaD? zG+GfV=Y`*MtQ=^LLu-u&n;Qu^+4!f065JLATAFaZNduFpnXy-n-^?Zpxfi;L9wupM zn5k_1O%Tv&xUje^?&v@x3P;7cM~}?ZnwMn%+1<}zjnVCj?RQlivt>B8uM*Lw8k@P~ zYC^H=CGfuw4RG2WLU&H)z;?jEgP~bCGgKuJeQL2w=)VEfhrj@UyvTq80RVtNAQ%`J zgoK1dL`1~I#7Lw%DJdx#85shBc>Ve{FE1}YKR=S2E+8NvC@3f@DypEMps1**p`r2l z^XD&LzUb=e>gnk@J3D)Lcz7dkUH<+70RhOXNO*X7PEJlB{rB(R8yXrK8ylONnwp!N zTUuILTU*=O+S=ROJ32Z#J3G6&y1Ki&dwP0$dwcu(`uh9(2L=WP2M33ShLCvj;o;$t zk&)5S(Xp|y@$vDAiHXU{$*HNS>FMd2nVH$y*}1v7`T6;Ug#{$Yd}(QEd3kwdWo31B zb!}~JeSLjnV`Fo3b8BmBdwY9lXJ>bJcW-ZRe}Dhr-~dTIKRP-(K0ZDyuCA`HuWxQ{Zf|dY|Neb$zM|!|J}5)Iiocvx1*yMS?a*;uZ#JbVAL@3FU=iL6m zg66>T(E4V^*3NG6!OiT^$>~Z`vhB~YNipFx_2JBJU0gF2MdNU_3hjT6`{E?nCc4AQ z@zpdLP8J)i&by=>IID9%gfkGCermFsmT+$F!(irlT_7ihYa+Q+T$v{t4d;n)Fk+t@ z%k#54H(099;4=Cp>BnVkqW+1OiyFzXEL>NcvN|YN~9(~`F5bvQ7$wG;4?`&SbO;I7^Q^O+}7EcuT za&E}Se$3#T%H>?SVsoO^@hrbPp0}ZJ~7;FyLbO(?85Zp~zHN z$|##GaE7@-FHNn{f7e>IC# zoXt{)qJ>UF$dn(?H0VA|CzmSaD9AGz7UT{P(tNGm?lY~Ra7xKfZM|GBqr&x$F3ta> zl(fqyzDzNbuN{R?+;r9k7+7%x%P?e#d`l z{GvE4sl#GS;FTwz5X7(T?a$wri7m&b>J;B&ve#E_^`90oC!7b~H-=mHrjH!oSLD2f zmEHNzc=5#M6<~PX?U{78ZAfQf#O%L`TR-JMtLBLr{7Se(_N&W2J8A8;%TikA4|tE>&OMwu@lgh_eZvpexGLPGZdzjWMWJ1q z)uLl6FHlfE@%ywp>)(yVge(2sKC|pHkaf*5(k(kxq0%E5DLVTYg5$4K!vXEbx1$q& zpw4(&p5uI`WBpRl<9VMMUCnKCmBv6V^)v$kTl(Blz&KBCdpJ@3Tf(W}uWj2WBKfbD ze!LM;bf9@iFYaKSo|LJ1n-4Y|qJBUP2>BMiL+k!D|32wvCn8@zAEvF&Plsb3qq=I4 zB4pg|v8E6&CI1svSbZ-{D?0SzEj>oScLv#U?0BD?e~#w#C!F z|BHr{8>oogfJUlxiK zV;!E~Hs)H0;bc`^(}_@(%4p@vm53UqFp6G3sT2#?`po^IUdMvTyo;@M7UeIIaec@T z=)Q8lv@`i|kAyf8#%5^r5M%U~$mcrVB(A(#8mq@pz$=Zda7Zv^`58J|l{@3SG4et$ z>qo2ew0@|qwgunS^2ff+U!K&TUp;%^2|H+4t+g#+{-Z^rlB45TsT^xsf1#2423eTN z?2%4dJthi`ghL$xi)P|bktR+IJ)vS@if#C)SS+VggDL`U5*>sIZ)Dzg*HM*Qkwh?a z;R4x0?pY9X5the@FiP=%Y^fQQyyEDUZ(c>9E&8C(H2uSW? zoShbJmFG^JH?%>UMtB3^IcTiKK6s_o1S0!!y)U(FD0n9W-+Tf9(nH@I{<=ws)MC{y z%nKVu1(cUS7tpsiq$s>BJNcxhITGQAsgmu>iIm1L9D*aLRyU%-?1Aq#g|WSnX8Uje zgjlSsODA2rQF4LK%T2+}vcou%>3ZMuvtywbGa=Y~&{>Ill2>ehU~6l37rym%jM%KJ z^R>;OzhzQfy5jk^OxzuH&Sn^OMG;t;*ikg6hwf@JI2FJRG)sJN?2moDyv9)=;Sk6Spr_w?y`}cilW6OpzV&7D1QE| z>RGxbi!xL8w!Y!p?+FXug6|C<4_Z-f=f@e)_V+GstW1CZsao;cbxGDVqcgtKe zC>Uwc5UQQ)IPa)8fpI~%Ub8#H*(j&^;w+)jX*-MNwpMfGGA_uyF{vY3t0cls|2KIA zrnN$^42g2`&g!n>9My~dxW%LWwmqrm_cK4wtXpPRkHxGxn{ah*a*E!sZ_dB+r;)ng zqp#PbeL5U_o1#=Q{&X8B#@{f-<@Kp%{{4<~Q65K4#Z>oOoAJ*RHwzziKIO#i4=Ca) zu=jhh)}A~bdb2jPlV#no#Aw9~jC*);3Xas+*ZsVe=E?BHagI*9%#{kFIXy73TuvoE zDXDbg_$jsLy_vif;dv*x_1V2zIpd(2^5lBRSn*q=_ED+C#4JhE!pQK;Kg&`tdr&*Z zdd*2gc8|UMe^fZFptql8BsH}Ky_mX-6PSZ(-&UujDF}J|O1YM_f(1&P|P3FKW zkHDtR$g4Hb%jJnkje^GWPTbe6NQZq;@#vRt=g9Wv`CGt%*)=;ef#^U%*(!}k>jfRRU#pZAFatZ$r43xf&-u^|ZNBaRz zgDT~mKK0JN4Qh`4yN=4i{yhgDd=35SiS24RIB1=5=+a)ON?FX!#%)ikuF1j8Bqyo%K*W378zOuc z01Vmw0{Q20GoVa{p&;1PIQ_z$?M;8PVAz0OOoE7_fruSvUa(Z6MxeeAh(aNP!W%S} z?C)nl@?^O0>cS4->PF1p0ZsV|%#I?t8ewwyplyu^ylUXH15vP_kJR^|lf_7ii^%$1 z$AK%;H|QQ3J&|X`ASey1D7Q0SQYbcc^tNR59~YV<`ao9(*IQy*EYpaeiyH0Do^kde zKDIIE8qu+Kw22OyEqC^X;Mn_O`WN^y2UkMY&i=o-qc0YN8Ge5+%GQ5}dAAff! z7=5PnUUc?Ld%fR{a54uEIH*>0V&0RITSI;cu^Ak-t3mU4?NZF;?XF2VYZ5{14Zwv^ zlz(`Nm{OtCy!sCj7CUl;V8%ec#Q)z!Sd9M?VZHpnh_KWVq>@zsFD|T?|K-9WVV3&e zy0G5JsF3}a3+scJ`hU8x6y!ddYD-!Dn+wb3-&|PA|ILMEZ~q@ItYC-#y$j1FnC5>G zVY&W)i?AyHClOXh$M^rE2n#viA?LXNwVWRppOBc8oRXTB{$C=j!lDqk2eP7HURD0B z#_L;ceeL&V8*{NF@a!y}_(8E}Wn^6Bb^ruN09w()ihpE^ zgP&m|_l48=^=eg%-Jv&?1#K?AY(gnVecp8RN-$R&upt!{mb^6V#d3u3gtQR4Ua%d< zOXaNWa1p~@NN-L?GBI0*E8cLs6lFR73mGSpdPfHJ4!48zJsIGMAX}F~0pvFz&5bR^ zBGy>G(OI02-$YjOGrK(~&5bm?DP~m^l~vbm`dNO!Kuqo~WVHFJxXxsz!Oyv@V#Sg) zTi0OIz#L6j$w-M}^^~K_}6X7_{&c|nYt`iq#S~LeHvLf^_eEytls6P5R=`3o10p;yma{0Cp z)O7@^#)X(d2aleQEJ3xnzAG57UPu_s!95&A7T>54$_{?I5DVd+F9aF->jn~o6!;Z) zo&8*Z4`wnSy0xB@nz;HXs%1(PJR>mSA)vaRqM?bPTt6g8P_)S2r#h7*FpiT+b@>?j zkq{scA%*X+Mv1)CfWZ!4p`srg)T&cV4vdZtbUFKDt=L#nkUAM<4m0kGeqfKG7=TBd=3sguJUABwrYJN|kz3*l^u?cc9 z8!8q5z8u#}2z8b;i>13=)*+-i)h?07X+(+xbjr>;zIT+J*NNh4S52(zmpM$0vY$Cr zHP_1gtmV7wLTOc%VPWlQWMbebhfsINMq-ErtY*TLgdp67u zA*oTyKp9}0peXhWLg4V+>Tb*7La}K(_-zOGb|4=P&rU2o&i!7pai!~Sg!TFTL6CY! z^I?*@yxU>6cI3lxf%EvoPFj&rFlLbXl!{Ko983S2uL;SXb8rHE(y0o1d?7;@abcny>O>|$HkRMjFc4uL>^ z|1R8*8ln_nydY|iEgWMFF@nF5LMAHXawO9EP zNA*(=g7dFs=eMAKEeaKPqbU|(KKik;iPgA3PQWhQ|hveeC`6xE4{Oq^EZVkFsxgmm@v`K5=c zLYf7EZDw4Kw&2eY8Ul7z4x>Pq;dig!DqOx165F`WlaP)1C^=hKH0IMSxbtIF9Pc7! zvMrF0Z8s5Pcpn3Dr{FFS@RaStdl6R%D@GKRk}s8CF_grNNrp(P8I0Csx!q-{l=TU3 ze>!0JobiLAs719QFyWQDt%#^7L40fI2bm^NnMJkOc=x_hwZh%8$RdrJn2K^ai30&> zy;PuM2(8f2F;FleMN<+QjXTb;zb_Cp4P7?p~V>^D zdXtH8=O?k$lTl-yZK58=^WM+`#V!;zNlWvSx?HIkBgU`P6Jh&TnSWZ12((>Wh+dwB zHIg66Tl)@}sn@Rt^b62)R2E56dv^9@EOzD{6yZ^8U!i0*7|pssN&Se(!OS@eEGc%J3@ zb8Xkj8Sfjny1#_Bt*!8EBd3@6lYZ!J?yIHZHPxsY>#|>oTSGd2x07X9%lm6?LSO!N zp{o9AM&v$!8i>)e)^4G|;IX}f>f}WtZ|U%bTPaxFLHW)2nTvMYChbDizyTSG-am^y zHUif*5^n-iS048{iA0A@Bd;alg`w)WN7!|J=~L&o(#_VanX9L4+q*Fx^6_6d?17f@Me zCHBU;BgfD{Wn%MDtp=l;sBI8hyl^&T#FGn=Fi%zR+)eUac6Q`KVv<}?*fu?p@>f@>LIx8R`?|%G{PnjD>u~8Fg6Mi z*xMC4<_NY^aJfA+noBS=CbD_Fi(Xua<}QlcqYwW%ABFoPj_V+99zDEk(k}pxZY~5h z)kPPY6nI#Ou&@3XJHXKfDGTHD3c~n83>H=*)H@7`>H@Uyh%k`^gMO%6oEU8AE;iu%#&1`}(4WPTBHf^aJ1DRi=@k_r}!p7%-Scl_RG1 zY~F;v(}-qmiWVn912mJrrP%qDg!%EH1*D*`XhfsBM&}`709~}8-U#=u1RxqP)aAC= zd|jZoO*#bQ2(7_zwI7-hZU0Ta4A24btFowc}(1FNgBoXJxR4`SOjVI_< z(t;A*5q1sTS}3$yF8q00Xcy|It`56#v`Jwr^ln1vp_|k&ru|h*0-Te=*op$pif!GB zLt#bXfnMjX7!)la8~3Yi*| zRo9P&yJBJ3Y2K|WNV;d|fq|$FPAVUZ+D9%~ttzJ_tJP0fqdnlhV zhWhXnJhT+wr`A}L=E=8czY8r&&Mq?i74W^0n98O+R2-m{Q8_*?6$*42moE0Tskt4l z$qOyxHZKkw!ti8*3bq8?8gbQZXA8oSKtY z3g7=RjXZ7|R%?n;sPtaU%Z{$ksjjaj$d561lKxQBY+8eL-^@J}-ZIksQT%%onX}Ib zhV(tgR&xu}i6^y9Tb3@Eex*9UtlXXqtE&SgDLL3)x4+aVc9;N!?+tA8}WEakvCVJWpXzvy10|NjI3hqbJQeM!IWagakdh zEAPn$C>-e6!)*6HHj}(@s835nl$V7j0$iWUlHd-nu`tfet23!;FA4H32lT5`qwE`c zb4g8Q$xB7)8)B;yH*b1HR>_6aHE~BP&q__T)Ovx7zRcr3{qmZk(BPP8hZ}Jyc9-*} zVT<}HId+>YIepw4zFcvw+pyUcBgd*P0_`JW_ z#HUzwr6{{*7`%j)%hVRV1Lx2e-GDCRHHO8fqIIET(@c;vC<$+&Ge zJ01ePK(m~LT3@4B(?Vd`L&Zt`5en5~s>6MV044;MLGX{>(+*qrzIP;HL2A9E>|<7> zZEuX~?$U?jt1SYRV!{v^3_>A^lIW|F<8&CGP5+pyk!!>Mgo+;jFlp@jJDR_E(D|^} z_ziQ&w@r6^AU^y;Tnhjek|SIvA%eMpC24`OE&jh}AOmz=4$e#Ml1C4G-w%JU^f}zi+3^^bmQqd4}__&ME2m_opo)p#{ zj>YC_R#GwS#hXMC#Oc>E7j|YJJf^pRiB|Wb2Q}1a=M{9idC1p$skmr1kOq>E?&ffj zu~6QVWAkHN;m3-2xsK-Y!v`0q$5PFTzS@ix9`zMC;e24l#M;Z*O9&8J2F1R}uFFF= zUNJpP!#Z|fr>2_0B%1h(W{d$DSoO5uUi)(6-g%qW$<(spe>AtoIYh`c$K$lz*R@IW zW)Og6%{pyJwdt(1Z~U$J()hU>lDQQEuZLwospR$Xx>oz2;2;)$LO3fYF0;wyYX5-R z6q@*^UFjE&$ciYy2zL#7{bCT4ecOS2(ZST>18?WD(~gzdj-*$ykZcbu(unVT$E#*L zRB3Ra4Tr{T*ScnRF7?YNf#FD-BE=5qd)7UT$6Z6!IjZ2k2B|FbhrL9$|TY zvhyt^Ze57A-Y(GCtGzFr`v!9!tX>;$jHv?T4wQ>_L)Z88#h<` zY{yqj9x;T;P6Bm9*SuqCT91Ftmex~fakA_XWu82RkDt_MpiKT=$fc#VPt#)=XK6);eY` z&e{FVjO6)R$P&iv84>mwR=B%CDl4rvf7);8%B{!5kvuu^7qxeji+Vz6kdHeQR(a8^ zZChSAYgSlAj2q;)7udBwrvKE_LXUIC&tDIvjgx%b96O<+v=SN*mdZX$?>-pqYWp~U z#oX~zk{SD_bTeVa)jA6;nP4zw)RtHAC-m2CPVcdvw{&C@Zfto2%xvI$9KAQX=t#6< zkX621|M|xa1kc0?TGlbO+GU~wpvD$i6!_G&Wpf$Yb%_OTrFJ_R@7SBBxD=U=x-V%w zU0*wwCs+Tu&==j)@bZ3J0sJyDZ>U3dc>Kqxmrz#v=ddV8!#R89j|U-e2Zt!Aq5Mz7 znulT1EDoMU_Ria!kH-e8f7HUDeq{yU#vX7pAB3&u9&tQBJpEkp{$t1WFqF01GEp{M z@BBnhDUglAi5F>=ew6a_&v?RLi7M`A<3HKcMnRMhDc>JQamN;Me-3)Om1GYgwVHWc zC;@rs!)p<-<0J!aI4wb6>By6OJPW-y7Y^tpP3{hYith#&5AW`vY@Gik!df~C!GJUI zN^6<9g{GFa3@<<2!^mFoJ*_aJIfY@0qg;q2u|MSg#>}ohaJm!^(oY4P8}pQDv!fRR z%gL9$#iy2$A}pkUNA(?^SEP=XkX7dS6Aon*jE33zTT~T{YH;D_20Gg&LKH$krv+im zp^>U5<@Fe1%<2m%?h|SYe)ILEcC*#l@jGUfYUD7nxrvhBP0lMTJ2pu}+v69@eF#B^$hw2p!=*V&l&ooFSUq8mS%Lzd4;aj1)rdSlSS!1J@tblDIfao- zvM^4T@<Cv+ys5$FocNW|ic;4z*axX}Oh|ESRf-9GE~cv@e`22@LD`#rKS= z2iY1RSr_0{Mt#D0NPib&;-}NA+@a`a zfaxMgjNu)Xq;B*x_!2(wo`Nus3$0#3FQJGS9-sKe>|oDHNzPDJNW<`hRw^TB?REs$ ze(*@7-c#;d8tr#2AqVsp0W~}FK@kqCPyRN~OS;G{6edw+Fh&&zF^rJZvuyhY z>a~J=Nr{ZY$tlr-qSye9!W7zA$zWlIN(`wq*V?<>;*Hs*7-Hv+&@wuk2E!8h@1P6( zFLJ?lCh-7PPLQ`Ks?1<@4sA39TwAK|3z-2coPD3TDP{SZk4(jz&|CGJl{GInnSWa= zj0Gy1{B2K~F9()iMG1&cqHvXPZ1!U0iEa9I@ZKL1gP5Zyk6I>4!mAsg)oft%GVc-_ zmB(Ng0u%a3Bc0}NO-w({UrT@b#qe&@#C+(WP-Z0yGSXY|^+bir^2g-Zr>lB$js>~V zCrP{nvRfG0pd8FBO%w$%QV~nPMe`E0b_1e}W};S8gw^dB0M7{o&*w-Nx3q&`aQ4 zI46nk;YdH_ymdCZmE4RUmQQtIPp6S4k3qM%+O1#PD|&yu&J1@@-SW*WJJ+dCi|x_2eMz+Jy*8RSI8czsAm%MCcK`6;4!8Y{x&&bJ`?{8R**!R((+&XcCf8 zzWjlPX*<-n)IH@_F>sq6W=Z=gc0OAbTdVJHeeFO55@4IsIcK?4xS^>X}uj*Jv<-;X6?_ zhf7PKINS2!H%_PJpkJx(-kvu*m^zl4q4tp^DN-^NOaAit*W>gQo5nX!k`_uI^4fwa zKHLbgiB%_Wq3kj|(&8!GNkl9P_oFV_^86_fNpl~WWu$GEQ92ZgG;!DeO<2R(_vVUf z@LGlaL$mx}EbHgfZRquV4KJQC;}g)?80^VzepEiJv!hxxW_2Z&S21{PiE^6x;(cJ3 zi&<`lJ(CoB664f#!nBo@2Rb+1RW%;%zAn0V@;_L*N@&s7x-(xjB%fVP`Ga-S4eazq zr)F#P@ZaXuAu*3bz-(45NSv?~q!0z0eXkc^r01F*@AbjkO}{#CVr$k>rR(j9t(lQV zM&xPJ@Y~PBD$jv7S`%57uDqJFud)fK-)_Zb?=OB;D43s^HwBBTJhh0Hr)&w0Q6pG7 zBcoB!p#7j829Sr@IRHfn>929Asa@BGyc*4)nkQ9k9iSFZ^_=Shhv2G;JJl0~nu?5& zvW^sf$KzcyHCDaKS=ctsw4u_tSFv4@R7$9C>&N;s*g_(Ma~^`aySO#WxDsZ=+02=% zyNmM-^n&&y`Sf3PNAt3Ub+e>5N^6zC%e0=e2>OZ~b4wBSkySZnuJ%i2Ln2Xj6kgge zi~w7yS`8&)BNEKil{0Ijme$WeVk!KC%#5hAzs~KnoG8rdbt7w>H$V9fwll*n1NABz zlokawq;?=s@MHtdx8KN~QSM?zDtndqvKzay&rRDy-B|xgUCIFpmJfdynwoDwCtDl> z$L|kf_@&+_78q*Ui=jiGI8@7^R3oB+we!X!7*Mo&naqqz{C3ty*!5Qc$vImxP#`qo z2eOTsD37Q4iT_=CoVFQjsFkVL_nkZyiBTex@!o^+045vwMQC;!&vTRKO;adv$O~i# zzL2Y1R|J>h%$tJS8y$DkC!cQ2530dC9aDK-K!0W`uk1FHjPnjxsQpMe$_+jJT)6o4 z-(&Q<&AIHrdRzsTBkib%naY=rMV{^Eia}Zny#tPArfVmkMpEayU)~mGjF}q{xz9@3 zc-NJAo@fe^&6Ni_mVWzdY8m9dJX-0{7*Sy%{muTVG4DN93V+bd4h2!J>r4f{mC+nciIp1C=+zL!-4{rQE98&AA)%XEh~d!XSQ}(f4kt>SzU#pw?p4{ z-j6F*+GWvu?g**#4*j!w9lfx6!1K*@!j;vbh^T#!WUyttpaZ`|nf&-87w?Z=dHZzd z)f4+ol##KgUkQz$4!H~IMcl~-og0_N%09o+M(Mx^71+!5ro=S(DD{;}nDM!U$Yjl7 zwo4-92z1Rx2+;>X&_lo-;_VG$k81zP3tT^C26chiIsq6l0xfTYAJXCe@J#pTRSjR)%!a`448isj!A`d&Bw`aj^#0)M#hXK=|zG0n#6_eSnWeF-^X-><1|0*q`#^@~2pZ=uR^?>SrG`z9k?WPZtu zCgagG8F%HP|JY_`EJh#bVIF4>c;Yb$kg4&L91!Dle7Td$1dZ{L)WFCxAoQmXgxk89 zLIL3I=lp8Gf*Uq34&rtRaOB3*Y%+T9qA!aU=qq4>FxOCXs3tMnpvvtdw3@^dpz zDdA_xqKOePaiE`MpdnSTpCqRAP;lr_h!jY78C7TdgAneXfs|iJ*5tFIChhQuqwsZJ7!sw1=HU&lX-0Vy4XM|Jr4@?>BjOt3IGgJT zt{TF9crb{SC@~#S&QtvTq%w;)zj8Iiwtzr;#mOHw0qg8Ej)v4VHX@K=kY~Tr`E$Aqzu-Pt1l{yS}81{<}@|Tf_Gbg+30$&L6 zEDqz@IYCZwHGmln*m|Rb6>`{)v)(^Tin&4maDh(j$HXA6BRmwN&w$GnE#N7Z^<-j_ zMSX8}hIIcq`*(e#jf1bNPqq4qq{w=F|Q1*3A^qL9=)=gmTApr{;?!Lntn z?S$<4CRR9P(Ojd0q9GqbW5h&-tOGwO@?so4Ln|+3UDH+6%rEtKF;p?jW^y($af5Z@ zk#qjS2D|Cm=Oo}uqibEbG}oAHC_EcDj(b*w7McLFopf?}Amc-j`whdGe26@j0pw}u zTWPW+01>Ok2frm6JuY^bMB~%V5D_A89)@AE5m|Lrc09y6T$FEIAmeHmWCAu7HYq9W z1f{vsrBN92cn4@5<`6-ZhjKICR-Sooj@Ju<#bJyO?0FbI@FQ zVZYwh0=hQvqOxM$T2aMkEO=jfTVN5}l@49B6lE}uFk7ohl=&YJDTJQXB{l;ojK#f- zJj}-a4KYq^r7X1x0Wb4ws=DHAAi^yhqqcVAdH&aT)et_3&RvDTyz1*8)$*e13cNLS z*&*5|*m2G!72YUroAsLRFkMm@CL+UPvZPEG#l9L1?WjSwBu=3u7F3HRdxFi^2SFFX z(o8LUmc(qu#`q(a*%H7JV=sRFt5MagE}|7xSOk=S-k9+eW+T;=@j|AtKo?Rfm0djY zoUm2qvrM&70VkBq|65V%(R8Wc_tsV!v{v_qk zBL!l+i6$ikdJ~QA{BIjE!BiN1NxRr&dx#xYkB>|-9OQ;5`4A1kVPqm4Ur}s z^k)UzSOJ|$3fp|LYY`Sx%_mh$28fYTKoVoV1ZzG^W9`Q5eSwG8Th_pz%WH9ht)m%R zAq2e3VP0cneAb9M#BSR%1w*5c>(B}y((ZdAcds&6C@IcP^i(7^bFJOzD#`=8wA{XQ z@b-5M_j$nMWrv8aTFc~$(P`2E!5`@67w;;nMg8`T*;A_Ci}qL>^wjZj{|bZ;n~<84 z_4+)jorv~U0pZRTQQLReIN2zN$s{NwII|!&cvr;9UEciukV5wm=m-bfCepTeC}sSzl z3{alIooWXSa?ItUJUDWKa4CHcpNH;#lj zC60aUX370N{!LoPp z2}i13N*$gzG~G>5ew`%1#^sAwC#;xq4;Z4GMR!7=+ijx5;eee`tMigbZr#+Yzu36* zQ_Pl=eQkmQ(P%M0ka%OjP9fjeas0@in+F(U9PP|J3dm^^m$-Gp{gdu!I(5`M%EIAd)L#<;_);gy zQncJsT*XoX%MxGLQsmRwQcC+$(%901irW4USHADk3226r@2+z?g^oKJnz72j|)T zg5PW3>vLW2_rlci1swj(5sReaD@J0gHv@oyA$vcdPyHUq3ne@#gnm?*X=V@B81D^+S;5jD~(l zx#;4bw{QRLyq!PJK;K|Ij$LTkc|X{~=w(~j%XnL#!4QA?{<-$Y_P?dyVi$E7UIu?J zJfxHhZs6DR($?=kGn~oQ+FjPx2{ie$Y^b!NFSc@FV411qykc~5#dvqwaA3t`cg2!@ z}$@> zYr*eU^lz?uwyvEYSPQzj7I9)VzIDY=Y1#M*hn&03-RIBT-Xcp1BXcsNbHp}eaT~>T zkV5tiS;9u)>y6vYjbd_4N%=-$W@KJwbe-5n&Bcx8fz8_1&C1=)@*A5K<&hoi8}+Rl zRW~;tILFlPZVg`C9DcVoa$>Xl-R9VdEo$rL9Wh8z-DV&AChgr;$BCV~o8bGI+fA)I zb5A$*eDd;Jw~NHKUYyu0U~VkljI7z+9?INoX5ZN@XKvS*?-rfd-5l8YdGYh-8#@JJ zTXW7a&&zj4Z*IKP**z@(yjuRb;KXN8))xHV?(B)(*38e3o%a@7A^+Ze=6k%GBQ~F# zs2ya`yK3dsoWHyt_)7lX*K-H26=TykP>GrBbj3^G&IWwzH&oDDJ|~q`c>312^BmuG z&+F}aR-d;s%A(EZV85F^`)+Yf)$7Vdz9Ls8)>jt;e%NOHD7>xhH2-p4>6Iz))8!u2 z{?bp6&+-*T4kMu#O>Q|~JNc6k@H6n_K34Lp4#m|^JTY1rErVmvk3$~`NEn&yq8J|f z6dIRvMg)Ur&;ZguAnqhuBwIRB92~I39l)_)@)0=A%*iTn16Zj~#V>>Sl=o{sQEHjmgI=mQBPfJch~u$uGxCLQFe z^&hr)m>uy?1><+$V|i;TSO)tq`8>LULjb4%;J6m+Dwrhz7k=<5>>X&ZPZUq7{ zaQU3DdsgQr7-(HxHhrh!c47)Z0VL$Li z&w2967o5MY?9tV8)YLbJOq{J2Udag?jb zF}&%2Z}UslgV*%xwjN|Y?0vcahvCS^@%%}%fVjnN6XIaLG~22B0+gf?aE>*UeW_o* z5^LFm02eX2Do1W$;EhVBbWbG$5Sd>tB06+h4Hu7}Ol4Pf4H96-Z8P_g-4tFCMW0*w zJl0-*=v8{f6(b68CVck!1U}Bh;j58!{mpB5yGBF)4 zjvFkxCRAokf?YB=0`)>!gUnA|Qlfr@iJYeD@>qJ)K4Rs#I&O0d%^g$_II;6j45@$S zGHze!h?kNySC#*imlp$HJXdu;xWw0K=o`BqL2_uwk{qL#VqUsr6CaeAO}_+!46Xsj z3GVKzC0Hdo-WX27=pmDkQj;d_gJe#t%JBPGk;ia zn1L;%a-bq1_%;%M@VccDH%CO21z6`hJ%K}9NoK-nn2M%&K{~=6!@SF3yqsD`LPK*Je40ucI5>|5$y$zH=5fkg}2z(OST{!tF_bm zTpPdkZuI}G)!b^nKhzY^2OykI^dC<3B+z!yP62%|MWxT(NJ!bD&9OQglf%Nl4Id6(+<8Esw0Irb3+?WGGkh2JEtaFXvq*! zy*^#CkoR^c?9Egkb^K-sQQ~8Z0P8Sorhvbu#I-SHpsVY8>Lvb%be4x zn&^nuwLJRN^cut7R~HV5i`P`$__Z0+RIYKZw)g3;?T4>#L~qx0Ug;860eKnmG>m{L*cmN>Mhgeyw zadv$qc3l#QU2mj_P2_3tqU6knGCFTS(ut7xdJ>^8s6~#6Z#}*QmRN=kraw8XPaFjo zq^S_W$OAfAmOjW4E07=t{zB28)#b=Q#!0e2C!5Ap^0;9}#o?SOLV1;#TLKUT-!ExK zOCPyM)eU6yIMXkD|HxhJZE(7rmgeccEJ(I9IPIB}8P@!fBa~pIFcz4q9pm^#Awo+r zF4^Oxo7haBiuN2%56Z)-8`x1xIh%o#JYu&>6p(-ejDdtC9*Jy~5k4ylTr5kxgmga* zhHlG1_m0IWf-VE>+p9;Ok54kvd#0xTXij9?CtjitN+}Nqer_KRmBfIzMZuuiL4#`Z z9Gsra5Zof7aEV=tqV4U1jAGQDwW#R)c$`TP=v7DqX(h&id9aY9fhR0^@G01;UVjq( zwv`oM@eD-OD3eYoL*-cB9ztcia__KW(sgss4hMp?axw&w91JqB-Vdp+1uBX1%XM75PO5=FoZY_^9*Ol?aA+VHHG2H^5?32;# zer@piq^i7!g8ul|68d<`F-eLa{k4l_)-#Th4K z!~j{?&^WQmC}F6}874}72y(3^L5!zC$UuE4FSl$?I#-ZKbJEiOgaMC+4 z+ivJ%0=p)2T~E}iMqGyE$R7P>$k3CvbCV@nxNGcT)|n>P)gMB`*P;TS=sf)jf7}VW zATZvTOuegtb(zj1b_{J0$zs$v4n!)B>m7-#Pm5#YosM_d=WbNN;W)0Z>o#9eCMQ0& zC?j_<(54w z2oe=FF(f>%ysjw)`fT(bwCLEHabZoU+BWrjcuHBxm($FzUt5~_f7T|8YMCJFOWwSI zv~=p}Yd-gsi&D!GTdH|)f%ylgQA?F0j!aod=dOe(5CG9Gy7`PvPLH#%ZEZxhkSmbR z%n}NFpQq&?XX0`-9P*u(n6|#O!1DRqP%nx6;#)cUmg;ZzqKrd=y4Xuho4&EpOZHi6 z*^7b`kN-3{+IPRwou(j}>Wj+1`aU0iCuc{IF*YHX2;b0XG7f6}oad;1dG$yEgF`qH z;bLSY%XoAHALy3^f&vGi6Np()G^ZRi7r0?gLb^z!+V`S1fBOGh3%@}H8pdMz*ZraD z0W)g1Op~t`k?nD{*ZOUI6gq=6>=H#s3Di!tFaWBW4KG`ZL>NcKgvZ6xV#(P63h-;M zMe;+5F8N><29GLDJdB74CdNCdCpGZd$YlekX^6Ojq^so6TmTYIVkX~b#89ZD(KFF= zWKuhs6mS4(kY&-uB}9kCv1BLRzd*jA?&M64)cKikd-Wy}?)7D#QetfU`4PZE2Mn-? za15g9s|OXAG~elUnhI%nt&bu>HTQtvqTuM&TfP|3Raq#yOqum zDwCnks%fb-NLzgp4u=YYKsgD}^HjA?N zz7Uhym6A`7emoH*{^;iRIJ@kc*5eMB-L9<8v4mUzR6BvL7f8n#XoT+p)u*q2wo8kr z`@Ae*J&OGx0JZ{_ZX2e1)KG>Ei3{Y3$5e&nGKmT5#wejlwXN0cV++~AG{n0LF(N3a zCmr6t2f50C^LK^g7&++4EU;ioA;L!*;e34Vn!1p8wUNQbU4fC1?c!MWK9 z`81=fF~~&|lszTC83Un(9w|K_>P9FlgZzA2o_%EAxwWkHI=>%sd2+IewAzA@6zrO9 zVFW73e<4Vx%kSh%Eg6{hVFX8{eNjRRscPGISgUyW{L0*a72iS`XHzUEOB zZeLv1o$%!#u!k?tL9&?1>vhK-b+o0;4VakVtEq$DsV^=C=2Y6^M8^QVAwQGJk2 zC?LHTru_(WDIbX>04w_}(tEPZrcW$T445_vs{X_RCjqnaj%45tnE<{8F1yDlUGgbz zOes!W0WR@@TEg8tItpnRP&FUO*cI|jfW-~Yvfj;mS+$@<7YdA{Taxe2DMMW^cu;`5 z<9LU6D z$QyQPU}QkdKH3AgT~ZPJngF-@g^u2<(zNq?P4s3IA}^tJoilS6$P5c6Ilu}{Ei`(nEN+W?PSmt#!+3*P0&!}6%J%f1#ckMxgAO3x z$`>(J%|cc4_C+V`vt^^bq4cQ7fMWnYuC=YEr42~GfCy@IdQ4Ax9nv&`X0x$=@bz7fp*+*)z4 z{<{LQ_de!0Aaco#tBNRcs36KO!F|aM_PkjBbpvMZOno-MBLy_ba^9)KG!~mkqnJnS z{p^;*FFgD?;^%R^X2&2b7wRa1Zs~+S9b_-qL~5 zFT)T+fq!g{y1=0^M8x$2cyt1>-4^kp;PzetLSW5@|M>%RTalLXeHQCiKxvp%q?#%L8`vgvbH`<*! z!jd?V5U_}(vO}D&4!l(4_L1fOx#$a!m}!leHHmXl0$g9+tDs?hJPyWOa{>CM#U40< z_i}Xd0dW~qlu+;eRxU*Cl-geq5I{)2o()}Qbn$)3{mL*GC^&Py*=f z{MG)|T+og>e;5~(EgKPL6r%@#3@`|<*9y^?P=o9m*Hoh0K7F^2?E&h3*$`y2(n@Bg@7lC=G=C}Q3Dc1g+r8ML+KDfr^iQ5@tC$I z%{5{}Z75s%@H4(T!nu&+EP&%L)e}kyp`^hWT>Lq&%y>EwOot1ws-bYu?jk5&RpIR$ zh))U<+ZQ3W1o>PVe%xtTU>4w?d0c8%H)PYgHpO(k_R;T;M@c-9%X7Ikg(?S7Wgrp& z6vGq1C2NflrMSup>dM{xQ!)QV)~@R8&X=)=8tVds z-U-7797{g}Rl9a%#1r~2wby84n^UuarwB*3Y^V_~MwhB4izIO^LE&w{(>l^r40J{d z<=6vxQPvXA09N4)_Kl4Vk0%ou|Gm+H~&IDuK8Ph|+U9TpQ)&kmE6TaiJ+4tYW# z?xHA}DNYqLstWFyN)irzp~{NOQD-w(#!OjOE~hfp74tozAy*5RCV5}=!wU*^Qcwb8 zgYQ!>L2?p>vr~~(=2QM|{i%3J2n`yfuNIw4G~Uehq$(UB04`ZXC~YnXpTp*pd{q_! z5zVzWejcBu%h{#k7C{N2#RU-%*vY42^AF)OHzKKnoXR&ukmPy(F21g6gBke9c-&FY zOm4ZY+0dW2HJF~^9bGpFGeO*-vv4Bki$vpYGoEq9c)UknXP#QHl&jS*%dTmeTY=9P zTa3lc!D8s}p1*V^xv}3v12y+E=hD||PGihJzBt;GxLynU^o5{fMp>z|o+o5_4zS2Q zH&}J@IEAV$dkW0o%Y_Z(vc+@R;B-u_9oHcuPzm&zt3AYa)0%0y z#oJyF$@`aw(cgSwM7BozepOlh`FI+R9ja?Vg8Yd|^q+*dO~XwX=z!(WNE+gmEK;Q9 z;p$kksP@cgvorfsiX#Pic#19-i|y!qa%H{4e*YD2IY#ttiGzH2d-4Fp8w*uF>J2+O z`a)ueYIlC(`0oRE#+Fo1AfsiW`kA`?A@Q@U%PGp<<|3p=Z{gh4fo3{RB=uFx(+}ns z7xM7T>ke`k;n$(2Z=Q)?Ral^P2ivr67gprfwgx5x=;!874_`b8#9*;jNP0zs3g+mI zSLrUIk^gQy&-{)Grdh?TjfbaT*Wpg8Sx;W?s}E)yNk|yIfuqggeIPKIXeNVmxOs71 zX75gYH-mLo{y&qM|DJ=?Nzk8{u^%5IEO5{dR-P}}RNgg3X*Wa%J-A_I5P~6sxf9_W zg!CUx5EvNx!whta1br5v5WeRNCrxqEGV_S=nP0#KJPYwky3NIGp9lmG9oAX6^Cok+ z{tvLi4gfD88YI9)8oJF)f3BXP@TZEmZ09ryDyXmFwNcpWEzEDAE^g97wwfzSz1K9*y|u0yo))%*gJpTr_Oh-+r#MBVhH| zV&v;AVJ+xqQE7fDX;M1g#~s~d4aHVc7*}ja4mvPy9$i4q(DWSWzV;)|8XTZ&jbx!& z179kORqF53t(dV$r+<^?`qtJ2YxEX}2%|zldEM%4pI|RTHh3uJ0Sw(G-ja^=97VX_ zvE1`s0-?}{AFgvoU{RA@5XNop{q(O-bI#+Me%)6yPk$7X4Mr2a>Z?AH_fiPIA<~mM zD!Yr8nQ_18uJ;pcqDY5h{kKa+Axj0|n#Tdp=7Fk9Bku|TW*{+J(j^;aZjO zzkXV+S%t1Qi|YdWUM%M`PJ8U3xn* z5{|#4@<-i3X;GA2^pHUZ>MJi1u6I*n|5$xzCY(Apc3$M)!I$|{)e|{rvyx_&QFNMu zO~joTd4<}U!Xpt@o*|uKVH&tnUHo$F)6)tA?jb67b^VK)G6Ih~+FD*;gG0i!+S_t@ zEKA%d>hCYv#(4v2hc@q=044cif8B;y7F)}U_qDRCb>p$E&Nb*v{5*@@hb3B~#ibn=-JH!UZAprb1L=_sX?4Y#(M;CG7YurSosIR9!1CyLj(*r3k=qZq7aktZ z$}FUI?7lS*R&1%s-G3v%)^y@VUzDP8R*Op-54(2H_e2`!h4l|7oo|cQ3P~MCPrO}YN zUYOREA^58>ky6(?Coe<9?Qv9y5QO#Xm=Jfn1dlXS374H#Jx|w{gsS5|$p=`e+vK9| zfNG^%F$UM1Smqh}O5QR&knqYtzG{owb3B&if2GGojPCtdce@kM?y!&z%#$t%*FcY< zBreb^5Tc>8IeOp#mH81YI!~9k2EZd}tfBrO5^J#Xd?EnWG9}-%X}@Arf}$ypbLh`l z8WmqK*i-;6lr3Ip0T-nzFoCPHgV^@Y8KQ!yM@LXYwFB$NArbGg&9Sy8wHlN6C+Fh8 zz^h8m24R*7l9FhH3;|I)Fvr=@UZYwHlWcB3Pyh;gSOE4X8s|{GMZTveS=qo^Bh>_( zCUMapzow`n_t|GZV%KgoHA*U*n_q81J^QjP^^-H|c1DErXpwIw>_C>9m%|!7ln@D{DdJVVnW1^i!6*oAX=|&$|qv|DakjRJkhvUsBaAYCv zk+`E#|4PmVc94qEh*C>ZDQ24 zXN*dYfe`1)2WIliC}oMT#XzLR!>$}v-NfZ^%_n5cwvh7$U5pfG2!{!l4&X1olrUIw z9v?IsVBxvhrOeZqc_D9@k*O}-D;qb4ech5l5XE7groZGLz^m@> zSaRhPxiflKcIv!tW&T*OoCYU9yZKvfVa>4GSLzFz-IyA9o;mP)(O(#W{aRx%yNzT) z$AiD(8VzV5d#i8xIgB&pvswyHgA=a>7a2SfM=4OBG3Ut8=ozee+qIB`!KxBc;;|Kw zIY??mY`!glh#vx(sDrtNY|@~5N-T!>3L%9ra6?W>a%PY~%-6PLD68^K0pAZ`3J#(2 zoybf&){K=d5Ku*rwsDy@OK>M4hGS?*-C~VYNAEQ;d@RR^EXlsSElfP)avQANF!zg1O;juL!4aP%8|NmS z1z)=SUapn>_NmGE+|hX1-BEKsj^`@#wyVI@sxm*PnbnOCtex({()9+i216e&GCAb0 z`P#g!D`*Hfjc%zo+|rj7Q=+hk8FS0VKu9nw5##PKzF?Zf1Dnw$C(P>$`{NLoGcaX5 z7@7`0=%vO(KlX}dS(WEq)2I`S!ZS5%YE2ahDnKZw>?eoIm5BQ#L6s%@A|q9E-v(VG zuh^PBQosi^QfiYk0F<$>Ew_YC#AX^|1_qrx5eecMW9xv0{gDT(n&K|iget2+aD>3O0o7$I7tOBhhNc zhE=czH01Y434jj@EnH_cNXSTJkOUv##5j|y0tjT0T9PHEsLfR00IYhKo~V-94+81ob;F1Q znUQY92LP_lcmo5v5_ZZphK0PlN+Cx%D)nl+(zv5KS{7B{|$BbJ($$;d!;q2eaTsqmi&~k)ZXwp7o zG}&{Xf9vb4d7q+^S&t|O9()W!gIZG(rN4_^H_XFACFq(;NPL7I5eG%s17NYw$Wb*k zkianrV!s8j3+PCAevWw=-VTUnN9S_N#WIp|e?Dp&P*zwwrJtb_K1Y9hDG?g}{`bXr z=MXAdqJCsoI5bHb?+UxZ_^Tv9_@moQMI+>yJ4yFq6fv$aJL8-3*|&Z#6^?vc%9^y` zX*mJxb>w}$m>|0NMA)G__Q&>Xvn{3vYq<8|+SbEMQFcf=m|cV*o!%MyS^i7(FRqw; zQp~?_G!zHGjFAZXtuNVJk_50M9?UXN0&svWfmBV3kZ!wmvkvnX5r3D+U6LePcpHpZ zIjh|ULH*a&ak4}B^Xr>uCU{QE*>jACrg26;s1y0|`dBJ}%7~B2?L>l*z+iZs9T8?t zjb+wFnAyRODI=fS!j3B=d&jxP#zD3O*b7XD*En71(!?XC4{ zJkgpz@eO}G){f_K2+kY>nXS2ep2)+U4XjxTHy9-(A$b$K{2X5gsaKv}`zCZo4Vyp! zA8$(x8vz9DP%%tIj2RAyU#NCL9v%!KDB~VHjaE$;8hKHHq!K1IE;TW*uDdao? zTuX^LO1Rq8Q7qY9c0hXi8X$oK&%92a3{R=iio3V+k^zlhQ~wgbIvB2 z8H4*6$+;L33KKI?7Yjk&u%*id8v{1k(MN=p#PR4DS!6bWG;N!9RCsMhf_WlQb9G2} zW3Unp9FK`jVI;>GffLEuxymr6dR84KM6U1J1@(=uyGlZ)qb=0XH@#5(;AgJ+4UibwD1{$Y{T_9TO9b# z!7cfmoPV9s96^a@1i%cL&TS9l-~!E&b2?;Eu!(RE*PJ|{G;Oc+zI=)`kbZ>(vzSj8 zI*dEB5veb6))#M*K=slCRQ+%#N>wRrlI6=L<)7sJR#VD9r3h?HGRt>1%B^(Ew@`OK z`;>p3#Qrq7dth?+_vGEr4R`;dsB41M?ZdnO7O;1GvM~JN_FsY$RucXgBbzBDSX82z zK+?o`Ix?jq0S~sOMX+FEdc%>;MX9}qIsaqTN7?q zw^h6}x#Oi4kIlW4Ks&34gH8ho3)-1?#zMnqop{HpjXzeK|6;#{2K5lZmo#cFMS(39 zYOK&8TMZ{$-Qh88VX?+xs>V3JcG#ol&!-yi#aipB8rz;)f76=aUo|e9N1k9d z=gn%uuR0Hnn(I?FJ$M&y-&*(0TF;(3pT?TVp4uLu{yNjN!Mmi!4qcnB(GV3?ceA9y zLa5GpvnEr+N!QDtBm5Y3QWj{>avcX9qs1u>rnlOon!BKgw)6=v7=l=mNQBwp!CcvC z$hH^>dc`pkplBIk-qk$jg;Wd#5cEps8qi_~p7AYn7N`(aZ=oqPb1{HHwH66Nasmw` zrQGylGE#f9>a2^xQ5{sD8x$INt+4WHG^yIlgYtLt9+~HsMugiBwdfoeYJrT*!d0mF z!eaT8=hxa!R3s|}R&~h&rx(M`=A)-=VL~i`)qFUT5ssb+7u||W!zD{ZM#p*?aVy4h zZ>8k6B_UZdb~i)RT+Fuwp<4zBZ4Y1Ohy8oHiVwG6`q_Rl`pzGA;(-)2J2J|)T~Hl$ z^js}Oltpx+;Iz1uy_O?F1{a<~;|dB{-?o;D;i7@C2(~onC`u`3I@#`X+CB$2coJ|(FX4__B<}V!=VWr3?Lg4e3 z5KWAJK$-5o;}^O=AF8}Ytrkov_v@)k>uK;aL6^wNJxDl(=x(d%d0^K2NVC)Mbtq)3 zF{@XnW2^TFe&B2S(C&FxruQvT&c4Z}zUflx7$;||VozvY=lO}gSAPAkg>}>;j)6;$ z-E)YZXBqgQH~@X&*DdV-tB4u0+%&K?Jz&<;#W~(T*m11dv1G^Z@qXIlfQrU+zk#td zo%f}WK}s};6Zi6R-|Dj6%id1t42^A@_7xBHCc#aVk+JR}#=?SVk#3HeLD3o7;juwu z0Qj`kbBGKc?{yPv9#U)`z+eYYro&IQh5kvSHB0z^Hw#v39@dQM*8zsPwjt#E6ngYP zRu@exeZ*wDS9@>Rn+~}b-kF)CBh)u&>OX3`-L3Oy_);^KrAO#(=|lDOQ8)9kkm-^0 zA|uVy;xc8OLwvpbwqt=x<4F-?%4K73ni6O-(E(1Q!Q11v`a&F7hqZ{Z&lKA#P+{uk zT%?(ajP$_JKSNH;7$Mc4J?Q2M`R$3~=1E@baUblUQy*oush1sHQR+Wcx1{6$Xq3-s zD5GdXE`73IY5D=HRJPJ!;-3L7qg(f4Chwb1KW3eI0h%n286N|ckY>lM%=-tAlmj!u z@gkGWW#jkvA0MR-Pt%_)hzJdDkI1-9q*Fp#T%IhNKmFt{*pUwR5t(`^QWEL+WWfLF z7o}%rpeJ{?pM*D!-%#Qz)Oz-J`&61zRxjF zSS_COYP0-UdNO*7vw3qWdS;yH|6Jnui&DlA*Y>2hveRd?NmTPQ@jJuE*j}EpKw{I+ z15`*T9e-3Tg`LnA{9hPR!T*U7g#dgIc2M$>{6R`k@XV0{LRv&bT~t9b0*avG8vXXO-6pF4tyDjiofQWG{&7Btm7A!Z~dY9n&Y zSVS~JMATbY=)W*gO;btDi;{wY64F7(tW8AhtwhXC#eD2UB78-SOt23nqN7BiE3MUXqx$m-;6ad(EmR?QOp0y6Lq}gPcRGrFHiKcy_d%|&r5D0 zzMh^zLBUsDoGV0+9q~ld{2fyxyhKw)g-b;FtAvEIB(P~>|1X|sL{@xYb?S}8S~q)t zig#3+NEAh=_P%Iki$Y76a%;DEX>~|a!Htxf*osH#Iky`MDXk?*k1EnS8jE`Fm6D79 z0~5Vn`=G9-w)a6}Q%7I_FgSxnEVe$ zG?gnJd*$U7Sj}bY6s*;i0t)u>(~tkbh_0=VL*G_2$U>Ie&zIg!v3xDNB9ta{rH*B( zc5-On1VoA5;8Jj!AX;(&qTe~Y0M~grc`Kf`O|ssu!~fL|ZTJJaczzA+BE?(O$f@5c z>P6>7mHZ8UK7WCO7gzH9r4rDhjVK|q{1~vrLTQ^)kw+qMv1mY;6pFM*4`Dq_F94VC zyy#mDMI$S{Up8J%^S#=4pLw||gl#`;3a%?!ZKqvrjlTvqKY6|A&8y4r@^qBuc$Vn^N40iJtVt{h6G+5ZUSAn1QrfPCkg{S9`r1Ut)iMGumD~chIkfu`du`&t?*suxv!LR zxlbRAMdi2v5Xd&2jkzb7{F@a>OA?ioqBslw5N3maJzK))Ro_?U09>~+!mCf#*LlxtVn#} zQ&&mR6B?CZ%O$A zChckFZ*E^*cKEo`@!bOn@Zu~;GDT@0(;Dl;e5W?3%+y8S%7dt=d!?nWB_|toC!#)A z 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

X_+vQ}AS` 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 w5s01w{9V zhB<4QTwlnevo}x^5r%+KL7T9U?IT2ieISusDai@qSay5j3@pBjDZ$1-eFD(Q4Lh*Y zX$_4nQ-CVL@peP~Gl?eYLlH75ca|DyS}#W#sIwoATj-<)cbMt5A0>===4zvSMbkkXNf?@)T#aW%Xn_R4ODx@4y) zx>M7=Q@6P7d`hR`%TA8lokr+~H(s`0mwagE{&2sj-J4C32OnTXqhGt9I?a7qv{j&^-2L6xZNQBT!rGaW79smG3luvKL|DDKXvN9e_)hev?<@2 z1Y(fhnJ|7BLk20z>0;k^`dKY$?sTWbj`zGDHL7VvkpKEoGg!6U%O3GkdDDWH&`Bxifcs#TC4nJ$K z@G{+iW%Iw+!ThSUuCh1};Nal=V@W^RXuG&(72yzZawLi+)nR%siXm$SBQh+u6v?hGTp(&N?l=Y-)=g;>ar+-H=a;&;Wh4Q>(tVEL3C%Nwx`NY)Kl!d-u*huqT zwWjWC>Go1DKCmn#6h?7pL3~ zK9~XYe-0uN00F5GD)29;N#G{#R4IApO5I)wA4Zxh2p3r=}_=CHntWQ?fJ5|KEbD7Yt3#SUFxby?4dX zO&~HtOG}dus$RQc^8Wy;I@3Yb>;HnP_x>xWn*85_s)_#_R88bh$;PH62^J)VWW@MZ zCws-!I9homx`d_hh9&aUwDDCoNi_XmrfO!^|81(4wDo7zcGlL^{J)#3{|T!88}j^D zjm{utX8pII>VFM+{%fUq3YY=z3YvK9Sz7L#0_Y3WNM znSO0gSBm&*3)rhvGqS0XxGysDZG5|tdtar)%`7*1d_o;v9l|K6x2nP%1JeWP#aCPd zXyOdQ9C7L>jwZLOSweRC1_*}R5Hx?&cx`T|&@4D-aH@&D9k?jlqT$j)F7o-4CD%#W z(*^i{R}RY`h%dG!vP%iG|CT0HIQ=||zm`3|_0p8NRo?xIw9X@wzDdWET*}wAOqKg5 z$#?@;=<}L@DS%pY{R98Eu~f<6)fh$-E^yBh2%Au0CWi}V2)X&k;6QxX*_`9J;<(z* zY4BkC_hHlt?;Wmu-L~GQ| zPJF(U9bTiU9WBT+YZfa|2qy$c35M7pATm?x91I3On4{_dSG@=g&YR_;+Ih6BY6+Yc zZbikMae3Os{YlSS--S*O0)q@TizDA{ zyVMeC10v-{iR0o`UOlSR|=mB4}zV#)tI>-hwxXgBLCsH}I?v%`qI!K5mbxA(#S( zXA5rxhU(>(Bq`kM8Mb4WHIK(z(%ZF!e=sEiZb(9W%r%^7^B|3<*r~X_p`pI9nI`W1 zz%$aoxjxfeWt+^`+P7Qgo-i&tDiC~fu}QtapuT!M64hAjwI9~;`rM1-x{0yD-%af~ zJNmT~>XOP*ZyzOl_>!kj#lYF~$DTj4{#BQIMs3NV>$8vTZ-~=P$1byY4l}!GqCm(H zpTeTwoM-UIfTt0`OTj;{c7G!LBOS6FusPBFiTJ@YWSJm3`D=}&%Y3|=ZMdYkMtpAb zYdP=bME6>FuuRyd6y{>=Mo7q4lBJdHrJ3X!b!f}IX7s65b_=sMb$IGZ`fJ!t>=es^ zjbJQm{D7V8iH!;6iIw2V&YJi0<8M7jhq3rA^#$ON;mQwMe3SGjYgMdj-%>_Zde3IE zMOoyZit?!b0vK@?GnvD*diV^I@!ObulNNZ~B=^-pi@|T7{on5S`Pz6F- zPlLx4A1`FOg1Q}|!AYYgaEh&w9!6qG90TxEC&TT>LP7% z+|?@#&GW;oG5B~zxw9;vx1OO^GZSyVay)y3wxuJ|g-OAm*t6s(>Pn(+rn;D}!p>Xj zD83~TLl;5(C!z@Mb7BRP_ajlP%E5KO62H(-;uAI)5d39IlhMs{+S60TIfK_fQt{2P+ z-{S74ZZQdr4_z3UPHs|JgO_gMr3T+t#4xV0nS>bdk7wmI6~@32n6u1`+9;JhU5on? znf78nBCO+i#?k5kSg*QXP#on^#6!y!mL6=V3}G?Zd0~b?sf$I9$9yDxS7;!&jxiHwZp-^s+w4!gXss2%12Zozt;vm%O z+-Q)kft;>=mjbx#>KZ^_T4<^;w3{GJU^$ReNkUXZ>iZ>$R}F}F;DLv!ggv)A6=r6X zT=9spv>cV`2kDIP`>~i$sdeOZ(FvjML#qD#sk7W+TJKb+(!A`vt{`@PSD(N1b;Di7 zA>SUWfQ^y$IwG?dF7n(HSO90T!!T!u=F|CK#kbzT5Ujfg@=^5X*X;MFtUg5wJ*8bv zo4G;PZSE_0qWu0F1>! z*i78l`HJAmq0}Hmrhg;({58kHS9W>nTs~>Ruh#g_I6RLVrDPDVt)FE%3v&w`0&ouN zB3BkvaV;|G<<~w-=>8nx?P|~KmMRdN^BXUtUd(@SZNn6+^zxo@N71L~&)C>rHV4~| zl1+~!#p&b8kec{{_{YdAo5!ySoI~4Fy!4DG4|}-rH&L#E1T^pOH^J%8iUsKzPZNjN z*-OwWKF@7q@6f3-=7)7`nf7YVgELjem(yN1?U)ml-^7hT8*Gf+#hm-z^-TKLbL=5u zQi9-KX88bh=`Rkn>B9Lt=|6-WNJI{;lm7U^{sBc0tJ>z-0yhm7e(l;flmm$vXaz9_o*DQC9b&(9M7gx&s z^qY9soa*j%ZA$M(cb{yeDJo8asD7yji>yvty)Q1S9O|EU1*_vhf+D0Bqz@;X_~65b zRWjczo{H=c>%xY!rGKce++Ji~-#Sfr z(d+wDjWUN1jk!U=6itC8QXk#6y_eWThs&)K=<{=7%NG6gO zBOy`&8};R9tmKPWr5aXV&w3SdZ?>p_1K%;dff3SotjQUbWiS1$t z4>DX6i!dO-Cr485U=71Dpcdlgr@sQ)3DM?UNCtAMN_0jp4jAfT`!#yY>{p^vTgI6! z#3?wSKuO!n_nK3TGMh`7woLn^BgASIyHeo$Q8cd86k>#f`_c;-<>B23uJ$1qD+bnC z2Lxl_sz6YQyw_vdB$8eBmFT2QLbh^6cG_~bXmrHw&oRusp%|;2Gp@euW632U5MyLy zxt?c5B1CyPM-i9&A(41hA^mX;EO0GFL_Y%n5`7L~2YErhYz(57(y(R5GzFv(HpJ>H z2&se&?B?)u&bR7e3qD5Bk#27NG|X{=l@cveTPcdu)gyW=SzjsOoe1)jBgjw`nq_4p zWPygzr^9xn98zJik}sSJ79k-Sutf-Y;O!PEsn;{5J|Q8rpvVH&DDJU@D6ZU0<`chX z66~6ZH40uJZm7=6#?q~xAnuSZHqIR!LkDz6X# z&BA>JWJ?ODAhRm3eAiGZ3y-bdvM{~_JiB3KfH1YRh!Vm=I~_8=K>l`IA;eR$gB5;gUVPQEir2NWgitwcUXl;w{L!g? z6XMSQyIjS9yamr~b|QW)tS(3>&-5Ypj1Z1{kX(vINCiOLE+%W)Szp4#5LJ>KbYQ)N1k}|m_0_E@A;D%SOd#YESu#+E%N$tedmJk|#i`155NJk=7 zd)sd1ef4|2IeYNBgqo^utC|>*hSiOlmW_-`N`{qz_fQxzOrrcArO9QWsl&>}6_MU~ ztFcts4MlFGwTv}-ybmk~YI`^8Qrwb$jMSl!jk~UmIhA zrDVMH>ahnFpHHUd{n=>E#nyaFYI)7$@}{BwOIT>VrR#JO<%?1}j|6h*J*sG|aEV;_ z)d{F^MLigMFp}ByMW0e?UL2<%g?v=Dk8)+Y-Kwq7kWTi00JM}~JElg$Z`rkxaVl%Qj zH6(EMsOA^nb+1D#L)6HLtZR^{+T!p>6;|js!o%TYu;B(x*Q zWfNXw*w_04mMiWd+lP|5kMfK0ZpK{j#n8yhDWw__^eU7G- ziQSY}U7aG&o=t5u^vMsf-Wu=^8qiP~3U(TdZtUbA8}z2~Z|Xr~@sLIZ>Gr$uZ!S;G z4NyYAo;AZrzuoPD`{?_;P9M=AnS$mX!;cIh z5tM%cR(%X;0-b$vd!Pybq%7h2sJ`QsR8)=igV@D#wQEjJsiS*5VeQBvSJasF6@;z0 zLVx1ecRkfQ6R1mV(9Bz?$s<%mp*wKfu`L|^a?#oL%R^e5^*x7pfOzet;O&X@lA0%m z{RU0lsmp-IKu=J35l48#Hg9kJ)N|HbqmBs>7unZ`kDGd%CT4azZp**)-5uaLK?F;2 z4eFyI6O(mQ-6#43i;H)4!e9S-RfhJwd$RaYQpL}5FqB5EE|{^Se}Z-1wkYXNUMt#SJBXs8S z&rAn1y_KnWGGxGORfgh3EuDo8_jlS6l@pvzCy0p%6<>p^%|WFf1W_YbyILF{ zzh@Gi&B8YI`80LP&-W2(Mc+)18{JjJzfZP)`)Z>8_hZNYiGj_>OC_X*(&cx}z$c>o z2X|@uV*dPPw;|(&q~+W8%J_C4y{L7YCC<}t-sUbj^G?pB(N_ncV=5@CG&HNRW7Zzh zrW7qs$^XdozH?_0AuOznOy7cV=NOfJ9lA2YCWvQ`~K2vU)m-%!alHNId%Xtl8TTc!F@X5&Oe7- z$AYHaQLSjE=3UnW-FUw-&tF$Jb7Zz7Bt9$O*v?D^A^`Zylxc)4Jc#^QpDwGy;axA% z6BT!=aqBIFFRlselz}ggs9QAAGya*(yO(zoYMVJa`(FZ>r-#MxquU52>{B)>5Hqj` zb9w49>44!H=*7iwZn-j3V)h6mMbO4mzO9+bs`fIr&VJ%gaRkSgxFB*0k&+&WQLw=R zMg=g4_wYYUuD4DYg?$zi%)w#2s7w6at9C+fa}QL;*W)txoSA@Ky+kb%yx$VB&IVTl z5_Ry;442_rK8d|^@AEdk7`uNuY(A_6_C)D6(ECrfd?Rt6l0^2u8uT703VvHGN_nLB zJb~H|;D>wXVfzJy=XUnQBNZ|{!Z@$AL6vLVvHKjbZ*E93Y(36^2K=g$kO z)y&u|NdI7)Xd*z1*IkB(Q-MRhnFP}$=`^yi+q5sS7bl> zV*0*PY?D6kYZsXNSY%Y1iGb9ngMXqLY@gizh4TBxfF^60jVy`#yG-)Q0T@QE$B7qi z52v11<6TBvTo=taTmJ0!FK@zVZX(ZDP2{Bwjl9!$#vhN>;TaQwYh@plGHa$Pv{LAx zs;TI8O~oW(>3O+^nUL$xjB?#l7oL+p37P*z$v4fn>1OzPhUN+`c)Nb+3+(J#xLp|k z*h^b<%VY7${Xf6=+>h3+^`g`TF)E6_GlOLI*I&jiQI%jGco&0}2_DqTR3%!4*c&UU zjj3WC;@abz7e!w9!0VvPMRGs{#iPCd@AV^*MOwS@ch~f9@z-|R#VD|fVlU0HdTHHT zC5wkFyG55@^WOX+xRe~QI0fRr4|$7_T-ZqOpFN!2CLXI+^YQvTBFUbK z`cXf(-+oFG1Cs`m`-Xm<6%l72wYbk)sep0q%=EJ-YDj!rB{j})EZqDgOVNUU(z0+A z#BW^uoG`cTcQ40klnx}u^n@KNZ^@>Gq&AMb-OBIENJIl!9BgYLo`BQ5uGF09;2IdT)K@!82` zN+NpHBRiW6QjibNo7W?|nr`L~*A*mAOW&BRA-dbY_{o(l zc|=xBN)u1kd0=V(XLJ*}2KP)f{-sY5ovA?vb=y$***Gu z=kx&nNKW9v-!F@6oe{w|)|MnN!`5)-^;zzQD|sysxb{Wnsly+n)(h_Aae}b>aT=dO z&S;#{<_zpV{tV!45zu+h{o}3RGj=zu45|z{*V-j-hTiFTK5J5PVUhLda%ctfed?gM zgP+LWNaU5ZDB<$#wU?{f->7e|KlRRkkum&u<)!ndU-u7dx$MzYK zbB(hAvp@TA+ID0HeP=x@lb|~P4DL6eS$Z*=pgI&CCvwf6R|-GKae*2w*JNKYdGjd+ zPq9(>H5ojx2C5E_4!v`TWTE2Xkl$Yu3KY+>a?x2PY$hmFj12co9F~e44xm7>*M#}Ch2KsE0;~{C-{ocX*g|Xzk zmb{N1cUgAfYSlq4wSRXVL;u`?Z?o<~uG<#| zmsno^g<)Gx|74=|hHS9a3zdZSH1(1-&ck`QW>-g?CX5mZGmX19ClY46CtwwJI zU8oLLSyNW)ow{ZGwOD#$lNSEn?m8ldD?|KE6)w~VC7eJ8v(@2Ms%9s z{fLa$#a8i;4swlzIc7~DvYB2w6?8ai<~{jel9Zq3tAe$>L&kH6G9^_vd7Gg{_~hx1u4W$(UeljmP_ z_kJ!tM1~O)WJYq_&DJ-1k6u1K`c6rSFu$Rzc%@185%x*eIho9(_ff(5Z7(C}@vN1K z$6+j;Ri}i)4s4}DUoh9i4rgf#s(fV0K+5>B2t<4m{PbsEJwFx_aq%?+n6M1Fx8`7a z`n$SXuzKw4=ZkP!E(-%#<<9v6w0cCZC4q$$hJYgMiyrq}6ye1`!Yk5C+(U4C#sYCg zYhaK%Mq^+6Y067zM>`g|h%0s?SYR*Rg1ogPKn|1bx%AZ7uv|C~m#>*2ge;XXn!x&^nH5z)tRg78cn z?GhKmIw2~2fWF}ZG3B}h+Jc+?io0EaRC(dI?<`5pzp7o!1Qqej6jhqQX!zp2LZ(E^ z34p)df3!4&Bw)RQFfs8Yh$j^iII0>q57WXyzSMXIjCxhz6O9HmB=L}tDF$Y8EGrCk z?JQIdOOPTF!?z$tRN|(ig^?nt-X$htih+)<(rwmwE~pSYF+n!@{uVLAGO4DPsD^_? zh9r4Xf#Spn^(lJFG`jK^yt)8dTNe{D1uII_l7A87O^7^|0H+JE;2v=NDEJ8iB`B15 zR?Lg!LX;WO2;M@jD<%TC^ayNB20~M02>IoOip^I|R}DWmF`AIEFn?P#lh?01+U!^7 zu-ZB}?b9!i2ofaR4$4XjtC@o`(DghQ#Lc0kURirByzX^V?Yjt6pd3_*0N0uF6YWLc zG|h^{WU?ip>4t06RNO`V>}CXmR31`5JV~b4ah*iMSI1|CWS#O+5aG6eNyzG>k9{$K z(sI_RvCI%WRC+Tj9t*#elv#$0IgJ7K0fs0cZ8KLcj?m2bWi3WK3$CCnw*|Wp%S?CK z3?nRHRiAdflkO`bPPElO;YhTC3#vpk3h?|}5O9ZB@ByzY<)iD#j&jwC^90i32|!R1 zl6^E?*M*p}P;i$6^)U#9#KD6o&?GQp)fD3RPDhOdm4Izs`WFXA4C>&c->XQVl7eR#zYZQtexWb>e z`8@2+Ed_L+`zFCH5e4<=Jo;+9oNh`X%x}H0+^#Uxp|GUBs&eWfV!nqGjR zW-^@BAX-enGQ=*L)<-DQDuQ8>(0XENa6p@~lvRbrIrSVqRxyFO3xFk0x9KRRZsUy%|Pfnm<1q&l?I zWpe`_`_+WnV%c)m{L)^$Z&p3vHp`IHQ2+KaWQzjg^w(> zo`*r7?A2a}7U|7F&%xS{$@CkMrtz8rM8i3&G)H0W2L`bf7!5BxBG5E<_&4$kjD z;6PRDLc!0E=gKPT##8F=q0ao!$2kWYl6J@mzV(1l9suY%%r+DeGP>7%qjQkD7H1Ol zX?3S!1Htc*ziug}y5&+=>r7nX=n+!MK-S=Rj!{UGH#KU(62Z6u(^0hN$)l8zAm79Q z)Kq;qUNn;j)e6d!qSwWl)f1`JP$=AuOb8*x^x;bp19sj65rRALXUgUx_4eLL9m?S? zB67f4$@=$*PH}g{sCd)CvALmg!6SGsVA>%fQGT|-4uNL489Qo6BM*OR zU;NHy_dKQxTGRzi4*cEM+QVx1gVN>psO#@emu+mpWDJw|T{!2I=N_zzt{%7kCeSZb z=mSE5ckplulp+>cf`g=d=rO{8#E0O!2o#Ev9ApPgzpd+m0mZ$Hzd@tN)v*K}td}Am#BCq4swpMgL*ZlqaJ? zlecyr%ZWLw6XayBuNa7fnC7|;_;_QU72tIlMXLZGDC1o0BiTpoXC964#7Qi6&em1W zA4i>N;_$MCk}9|-%7CT8AWKh^oONZ5=upw&UERaNBR?LQd(8|iyAgVE z!=F)rn=B4;cbIc?Aju*q-faMuIshr*a(*=eN(pifAkE`c>FH)hN|=-{FHjjdMno<@ z4}1PIOx88>!3$PqYFJUQejf!0ZVKBt*OoIjDt~%x&hAB&b?oOVCJ8JwqY2GI7)y|S zu{w^7>3k7ZSpJHw+td28Tgip`rg6oWFV{8Z=RGq+vet-A0_5MH;c&;y#mTQt+ApMD|2Uy}efD^LeE&7I>Gj`5+(jV7ck?ym@9Ps@ zgDQF@#K4%|iaxp&$t-O^%Q{;CJ%usS2Ue#ro~?x``maxzc%C4mhC&%GXm(a2zro&e z`SOaVF-fJpJ^N;=V&Ew?_`fq+6W2z*L-cL>ZhnMzSj^m(o*mJeQIicH8=W<_nfa+TbFXol&PkESl$hp3DuyXOkx8f+uE;rrsHq zz8hJewM%;!%Jgpd#We!ooHyS)C(nff+TXdnC$nWA-{G$=koFdCl+NGvoDb%k*Z4SB zKQVW=`CY#Bf(E64>YJ4?@u4MR#@2I=9$s!un>R3;_m+NFVbfguBQ z-p4tbY9zTz$5q9RSH|aPUNJ8fs72^#@`u0T2hO6zmC2dtXa@})(!-jc7b7}q3{+hDas;%uN zK5{c$b<=`*-8TJmIBmsx1+pFM!Y}VA`fiK9e8{I0CS$(McVwSJv*#p(Mc>(%%WPv| z4yrgv*^<4e&Q7V!PPG@PoO!#vY@5t~H=B9qQVp0cqIULgXVC0RWwr%2b{;L+_o{w* zZXEW+cBhE{ZkyLmO8RzU&32}$Bbk4f+`olQ_>$Vc(_~9WT6bC^x7D3?%K7&ORO#>C zQLpV*neEP{y~q1I*aX^cr}2JwR822O5b*ZQ=7(Ep=d)v-C!f#uV#_3Hywfg@?PBMNP+vVWhk z{F~&#_lJ=`%F_>()DG@l-?mnxHk2LxOyBvo^zG79>Tt{6v;D2-`vk_%dNezE_{R8WHO=^!XVmxV7YALoyJVK*G@0+IE!oiKe?isegWs(zfBpkhedztC z`#(U{*MFY;Pf+#Q`ID#>=&<*H0aXv6&*`A*r`P7eS^`M)1t|K(n3B$B|> zB#8nafIg;wOa&dkQGO%~h)*eivY8-w8nX}Z&;hs@1Kv@)wD9_$zfVuJKnR4YIxCO> zKr}R%iT@>Qn+t_N3QEh$iTvE;>IXHo|CzOI#+kJyyj?=xGehns z0tt=(f~qgOJgZMJ*jhtzm$F(|0c-%&j^OYDcALrrzUE-qc8kdA@doj%HR*O|WFc<7 zk*k&E7Qz1UFfE{@d1b|vhH2|ERHfrt$KgB`-doTGZQv%{w)kTH@^C;`r zS)T?judsjJZwps@WM+_y|B)sd&#`&gc{v&(lDO<~Df9cN4SgAK+T~Ub?j^#y#3xZk z_~hc?#h6*`ig>H#KnA3k^%hQASTWWDBt9Dd=Dbikf$_9h4_DG9>+fPFAfd@lE*Z|; z+%OD+zo8A|#b>G` zOjWw+K63!^8SL)6ZIKe^Tv1dQ^zQN<7&p5tp^W#gY&_T`U>Q`#1-+%s!N+c30spzO zdIwJPaU<2Rb1!q-6p&{)GwZ8s8g?WMC+k=}gn9hf;;Krq`L;qN(lE%%rLO35;G4eq z1V}Z>J&6}tg+`k3g`zKJ-}|o4IY`Dx3Qf-c9yA0Li!Cqqm5?Oe3?{XAvbTQ6nS0v; z_qbpvh_KzpYu zy5~QAJN8N7l(&Cr;DVEa=i#*Z`O@xJYJgzCyn?{hpHn6WMqMAhPxt?ru}4>Qy*V$i zjEqfUa-DnFanl`f`g*|V8#W7-3a;~2kK7Qt9HYOrKj1300a$ z^rlaFDFeK|zS~au5S-d#u*mT&620I~1fL$o zF+`q^W=bVPMSBL|H%T$S+L!+YRS~!Fv23r%5Z(D_uoy}lpNb&Lh-(ld-l zD!&A273=cWtLwL$??`4fUKZdu*BC-h(kb^S#B&p<1-()YBmb6 zXp=!qS^yuA>Kb9{Q!a?fs`+uDiNs>^T5LU^Uys`X^^g8F+D0&^zU@s%pgKm7Cjqe& zaw_ta-UFx<8O-wwmwO6R&0?t^YkrFWqkNA>*^2A&Q2g>JO~O)+#|CD7rwS;h(GuR< z2I%$ng0{yGSfKib7B%1Uh91{QRTLVyyZPsT{QiKYhuiRW7cHxxU!_(yUun|p-P`cpV< zR8d7h3m_vH#QZ=-saoe0eD$xh0Fb+ZL!eGBiWj8!55MCw7?(lNv>udY4G=i>zhB0ASuJ-0#KC-0@Rnnn_wUdRP%7uGq^W$UgvxiYYy1lmf0- z%`+E{-{t(R)zA(hWV?&k$eLb|*Jur4x{U$YKUEI)5V8A0q(;o=pqO4#;xk9-wp8ck zYG69K@!Wk7;~40Gd)QwGa1jJrV#ZFtSsp!aeF<<@i9J30m*M>4A4c0uFZ9J5-cFt2 zh$7{f{--|Y!qnFCpWx2+C+eHo9-?w2B3`q+ZM=Dn`2w;-?BXdW{X=0{d`*_t_ymEulYE^O!py?M{`?9^HZFY2EJrCVjsIfF zxqm@b<iJ9?bRI$3T8MEb(4h+mYZ z#+)e$pAZ>-nL~h||H7!GO~c_pyy~$6oeuM9zZ_X%0|*oRZF-F0w1AP|$NN#>HTd=8 zbG*e~xsOghyXl8`60k7E(F!I_;Kw-{mo5-;@F`@z?9rEj2b%LZelL<1%NY zHjI0e=ecA`z}4kObobP`{w!wy0=CE0#Oo?ri+h0Z;!EZmK92>k*Y`^yyug_y2N`AA-if0+sqqNr~#q-e0s(=WnFWlX&LvGX4vTI!zovV2uWfxpw4RUdx9Kjb-! zxmuEl>$=k zTi4a3Vx$vzm_J`u(t})ik4@Tf5wY@M+<9el39bB+i%!oqwB-u4(cOI_64 zOYpY}zGAhJLwP>(1+mJOsKPGTAqBb!0~krr00P_>usN#rl?_3-Vc>#^!pg+ZXTAsn z3j8!y_YQ^*-$6sD4DM8hu%M{7RlaNk%z;$zw^h&xYVZvgy6EbogRzMuMG0DhKvxF<;>mk#%iRpM= zs3k|8OR$55i?3LmNg}T%l^B6Z48kQ6Ws@InCXS5w&4i@Qi^bO^07fKu5Pcvy02Ne6 z8i*y_6uZiX1^tjWL||cRvY-%)T#xm+K2w_jXN-s1EpukaNSUCAUw`i930HCcH zdTs%Z(uz#S+T*#9Z1}i6jBY}_Fc_PPKZXH>;KSuiUm!82j<~rMeVIMr@@Q7QQ<@id z{%3d+MjfJo56z?hR;i$RS!4F#{A?^8g-Or0%Lgff2uet$WeC|WKSVsgEg_bqR0t<} zQ$Kt#Y05rwN{izj_&8PHyC_-rpnt}7o7~|CB0(CE7^hiP3xN^E) ziknBENDxL>gpr+ZIY3tDLSCjoL1CzQ`SRI!iM>c<8pt+*a<8@B=Jf!BqbX_#W1fdU z{n0_Y25(nX!6?F0dBy;Fy3e-pY}v(e)R{b-?Eq2^2)?Nf`RNni>QqQxwtRsAdPbuv z<`C&-7xD z*cZie{6=7=l$*Q zyU0`4g!5Dzs4~f7H(Y@jkpX{zLwBrbngK;`tb0yR&d*(7z^CU^V0OnC9tB`(HZOq! zi!5d|!N>=z3 zPcB7jbh@t7wb&;I0*oPsFF;4_iEPUa1RZ)e5zNO2=}%?2Oy~UUEIE9jTKNs$E(swx zs5c@vkcJQJ4iSD20Sw65L4e6!BE0Q40yz+52m*96lMbeW@y86xKXq}N4Be!veZc01 zZqiwII7=t^(HwI)HV84$E_?ZbE?Unl*b#W62gpRJJmf zlr>V8lP&K3^v;5_`(-a2JlmK>`7?9uTDanmQ>ATzuXH!u%IV z3&Nt{LDty*kG_hQBq6S5GLuM(A{&8%u0&DPTB^oN^!y9U_+VY26e4NSOa!~D5%!njhSHNT#$BI zc9%-~i*vYiOFgD|a^%X#yeyR3Y|%3^AY=3kx_4UOC{e|J1pL|>2puhZ+3+e9B-f_} zb}$iWjO7+fJLLCVt9i2tRwsgIewf;Zam}TvoYmqOyQ-i3?0LyDr#RXlY_0G(8}3&Q zSP|7DP_Wmp+sVRN>r6QE8N?X_cc#IwFrnswNM$93FeaSK6X`feBt-{u_nE!80=4ae z^G+DP&9n@x>9Od1OZ9b&t>o5;A^|?dsa0BBC5Cs}KEIPmmhXFPxyv zoI4lh5U(sl|D!?s*Wgd80HNol2B*CDnqBs@U+asOUZmI=h7NOogz<(Tj;Rby?hH=N zAVQK5xBR(=tvEUrp&J8{CGCTaUk6FVq4&iR_c%G=j2ho5E_+sSZu)6~A5iH+mCKvp z%ZHmPR4!GPZ&@YwSxvfWUaZPHoM{Q9PwL{k2dJ8*qN42!HHvMHhT?30oOQQlI#58PUKJ`IqK)*&io7?T>y=@BeLE*O(V^K%mm%n9S-Ek18);+ zeEkIS=CI93EZY^;Ns-99s* zA!eaLfP zthAjO^DB%UHvdt6w}Jzj_@~82h2w>f(B@K-2Wn(s>wJ{_Nc9kLcKxY0%Q2=dN%@Rf zx$Fq4EYACQkajZQXTr*&u{O`X&iOB?1?fWihD3j>J>fZLus>VP%>kB3;4|pXseFCr zRJ=u2DSGcS)OCj04uQm z6ARaqGUD&G=RyFoa;Y#SL;jOm^747t;F#Xav@Z%pTt`tN&l!gzZUkF63e<=L9NoCh z-lHFhUoX}i3r>~o)Nr#n0`gM$N`!G#HE_vkfU)_Q#j_q&Gzce^3evaZ$Jt>|Bb;$A zFv4BkR^XyFLdA*wyx}{~Z^kBb*ppAsu0bN0?3W2`diq6FhO7OfFh1J4a%idmM%|PaENr-(W;o}Kf$p;|tmg2|KCB-!Sbal4N-2dY z*S#2WW|-9>NFJ*Ota0FGn(S^`>HQVR%a!FrsnrkqtGg+rt7{`~aon(|+Ej*f)#`t; zk>IA(Pm8Z?#WZmW(!jcH%_fWo3&uSMFZD8Y)2%)070U7*ateYxfk>y1pl4k$76ONc=CEK+F>iP!|i9U#Zr+%`No*(&0^ zB~70 z_J^6wJFP7B&6_z<7$JUu4XS=y@UttQ->z$=U>0p~<_ilzo4K3`QX}@pVsVkZ$20SC zj74x|o5Q4-%A8;{CyPTPiHoVhA~%=Q}jB7WSv>S6WHaL0C!w&sxu? z^}qiYRCTUNd012Pu)SSM1<}{Md*^S&gMVs*dF-q$p9V|QdIKtUf(-8E5`4*fdi;)B zQ4dw9`)vCmrGDH%7{V*%(nTJKPL_vh*|`=z9?VpQ^jd$=DjmvYgQ}|gPg%nS`k}x7 zOlm3q->_{+ZNW*HIsJ4vr_L;Q&Xp$)FA|#;dp!k@PRfyQQ|i*2$Y1bas@Dfk?wkyT z+*oA2oaKyb59YStfEt>Szd2CFZFo8&qx5XpkU18*-In&?E+!Il_rvT<@a5 z0~Zj*TMINWEH8m4(!Kq?*r~D(u|Zy3Xw|ZMf%K32>Sq48BZj^^-^7OmxP0`%zPoqs z@a5rOoffshPPjy;1iPu45a(j%8Z=R#EJ4yoo62xYkP)!}#=TqeCSctyi4rI>ajk4S z)h+3I9E6Y6N-7%fGu8UpGoD6G5ZM_b7RzYmn3qSzs}Ax->*S%M=&5i+ zIVr=9uhNl~HG`Gd#v^Hl0>OK!kNrzo)^h^qP+CTUe#}u5K`@5VcPL==xKjb>KMyhy z%N(8~^F%cA1CVg$RxCP#EvPb#C6=YYK}ve%(kefd%_QReCwf~7{a4SU{2TkCqywNb zaH;cFs2&L)D1AV}n=QWLX(&(Cr?1y+6a>7ih{rpAd%RPTWO8yDYS|v$s*|2r@`QGs zQ<_<=1+=3O5(0i_s-JIwqKFLxhrh9%roy3KPxFv}Abs&xQE?JEZdG=IoI%s%_9r@u zg?%d0`ZY4phtqK*t07zjo`@bUHAql7w{LBvlYUynUQ=S=l!v=bPV?9ybDYLbL4X;MYUd=G+|Lv)gB$w7-z4UKf;ctF(D(9~_VBhp%N!H}r}- zguY2oEcSL_{j5sBW1>x4)!K}8F5A{R&_R3@L!6Q+$fKObfAwAQ>BUaoz;djlagc`C zA{QqF%7kv*gR}0^^66f+Tlf5aqb05RCg~gAOfK8yTILRFh*@>*E8y#Rwj6&6_-Oh3~r4 z91LJW#Kh)fchW`~AN*fo!+cCi7|un+`tI=l_!CA@ChAo838}6^-rLEyWDHum)G1|} zSjR%XU>hj9C^f*;OGW_VezH=Yn4WLNAOJrxXY(m&s*1^<$9J9)Bx^E~La}1f#iz05 zYANcL3z92!2?B|H+K;=sVPIzL&Zc+3zikEiI1vtMT?@shRto2qY@Xfh!rH_mZ=Zm$ zs1-g+$vw+oMCp297-Pe2>YAGjieWWoWE`-h`U-e=mtjnC!5>guSFFCiG;Y70IO=68 zw$4a6`!o6xfPyUJ{G&l50)>a?B*0ja)E+CXhIFB7rO2xRZ{$Z@@b&#h;t__iN0cpi zLieIkoQ4=BE2fdJeYez3Nt_$9iV=YUzf(1YC`<_Pc~PQboyodxB)n*L>yXm3_hXM_ zd5{;@vEszRIKkAP2m^E$Izl5lEZmPDI`#4Lxm3OCvzhQKI`Lv_hVL&JHoz}68S)h6 zy+hPBYU0=9>_@U}{R5F*7FS9vl2!s+ zn)T>1@~C9OStK9fP)VHULk}1(QDJPo_{x{gbsSKN;ti!R`9GYf57WHS*w=^!iJ|k) zao^Ac_ls2T8Ocdf;|;?F?j=a|fPHvcf|9J&((*iqEqJq^(@^iV82i0{r&^37bVoze z13t}(xd2n2-YM~EvW{~IKPP95q~dK~n92js6Y1TgT}IR3__nEoN6pPGjOZBy3L}XT zD~U#)21ukZY6pcsoLodrgc^5SkP0bCFm&gsW4s&j< zx`rV8H;4DMX1%yeTPFwYN^hpPue7Ob~iIsCuQZ@to*xX5ZK(L$Ro1#w7i>OzZrhm;(DKh#*yWw+DM)?g1*DY z=W5OMlb!hM0X;>Xgyx1v>pZtIPM_;BXl|+P<34-~wdbAhdj*4-(1)GAZlS~~nqc<&#k#pJsw0fQ` zia2&U&(5&5J3Pi%hy|HH32U_kqCj4A93@1M$Z5iz3|TL<3;(ob%iuoDba-47I21 z_Fqi><;sl%T-2e^pTo(=@r6*Ym!|>Qs2Hp&j>`c-9ZQKnI=NiFr9%?pD-3~9to~- zFI)olqL!P8Z;rR?b6v(It~Axb8l~qs>(0fk-Xc&ykiO zip!d?_{F7+TU>QP*EBzG&1CB?>ZF3vIR^g1mpf!yrLZvE=bv)8{cnf$_kB}q!^I5R zyT+Hl15??oFAHi+Wa(V++)1#;NC4C@REZf`vgw=G2lHtG{(bZ%TL=EgMmcOou*|@v zibUJaFv&fyE7|8&G;E;83gfZ}M=-*If#}VUwyF336m;YfJeK#$y(A*6Gzh#{=KC!R z<}UAh8535p8?Y(jE%6m=galyL;FY5UmM~VLEI=C(S?nGq$BH|+6P(8k{U5Q)3RD{j z1>yZzf#8+W;8J32ei>=-YxKQ6&kx&(2bwX*{8Xol04og@i!}e8RBmekY6MWCm7p<5 zO6&x*IiA9f!x}Rw(IiR=ni9VUi6T*`XlfRk8he;S&9I|n_fzs(DS3EGiY_&Af4I7zJmT+|96HgQ}D1=i4$a9m_O0mT@IF!;+eL zSugVvN9MV^nO3=(jux3Wk7YTxW!~0vcB#lPZOg(^v)rf|(;{5(Zx6(lL$eY9M;uso zH{ynMn%{0jzlg6~0@xmfg`0zKAmg>N*;+~JMSKpZE+>x>=(dzv!AsFs7CtwFD=05?-@8Y{rMw)6%KdS@=O z(*h!Z0~w(5Q%mTt_Vb?R=6CDSJC-3G9P|dT2i|nZLUKaM0r6i`@J#_K)iB<}XqUzO>Q51ak-zAAS?1|JGyt+o!({ zrW-IGeQhh)$SvrpU;qyJI~4_O%lSX_9=23GYzTh1&_-Xke>5gq#QU4k%Tdr1TqqGz z_|&4XGdO=En4?Ya;lF{x8H<8GYW|uYozEekilRTK=IbgHPEIl~m5;hP=_`-qIP*DOLAc(Zm6bwOrY}b|PE6)r#N(6o) zK=zwpmdt_Z5!Fyh)cBsAXQtvt>pKhhtm??Yf?YFGJ(4Wd!g*_XGOVdw0 z3E~nFZ&rh%0T{2BxwmiR)##wu_z-7jOKM_rOdOeT!RMmCTU6GK`zAC(dcl=Ph4^Cf z&G2KHPuz>0{=4bz>fc~jO_LH$_pQIhXuk%4<7>h)p7)W!-0WfZx{49|xN-Be@W|V} z?e}N$>N4jWI^Ngjm)k6_y!%o+`*zY}@Nr37H*2d9e$nsC@GM$;?+1_SQ$(_$Y2~JZ zpW(3iS@%~0OU34ua}}5V2^jaT+9|32PQX;L_NyR2h(Tk8-}0<#b?D6#FFr1_TqyJR9Sc_W%AMa%MLeG< z{}D3uQHtl!mGEGPLOnOWz}127D;7&mI|ce=YWB^rp`W{NBa0f{heJ~>t}z3*4|zmp z@3jB=;1tF4zT`u~+q37T;_Ydz3B-wH5-w5k*ZX_|xHL!>&unwg_I@&QJ>TuSOqu9^ zE=F0Bq0{y|3lyHyy(X!rPI5?|Ry{vD+$_P{{4d^rA+%23xJ^9(PbST@?9V3%usK`P`nj`GW* zEa|l^r`x?78~wLQ>dtbKKA1}L9I}~D#cPj88=|G9J3MWr3HqP2AG@E2_dmKHQ-qhi zO!L5(U>Cj&U@97n8yCI4?xQ7Xucz)RhqVcCE>tvmytJ{D;?ppVT9L}fZzwK36wjUmRx|}r=VE?G|8#RA3)v461 zmWg=8O{gX+qc^?0CPS;A-i`@Y=~zA-_|$SMV#q~XQZBo+<#Y9&`r4~gSm%zXR|oG@ zRooeTQj$NvE1&o>5Ux`Ep2?<@>?+QP-L*oT@ENww-D(=+-hQIl;Q1qQ#|60?(&Tu^ zQ?nZ7mv&L`x%=2f&35g}oO(5Xl~W2AehWKmglg~n!4VGDdD7-W@+|cZG4z!J+*2>J z$*Ot(uYZ0okE}$L%%>W39RC~{U5Q^pX%V*PeP#o-NA68jKTaN;b<`P%e0yR1&FIEw z!BIUio`?(?$c%53>C5$+Vw;_|5A{=#vTfC``FL6yt%ufYRzI%hH!Fdjb$1SVu@bMX z>?M@V1aF8dY177cWKSOaB6wrxKK(Q9Y4_3@3?Vt(q&br@(5@PXyKt{N?&z`7lj=^L3Pa5x8_H_zA?}XQ^Aa9IvHL=GdiMgpX=` zOL+fqOXo?0psv!3H9lJovhW<@$hvL*RGje4quigTu&X*%j(njDZvyepOy;?7C7)odX}HT7fI009 z#$68{I2nhj(6#VwGBXe!#8^+bCRJ${BW=+9K>_WS>qoyFBNUn!T3v zSZ(9#^YALmM^&7O`jdeS?i{N$*`L!lKDadoU+pXW1-U7@AHrdo%DEj>c-vj-7W%5z zagAL5j0vlQEA{)5)(`Z4O`kxST=etxE(;o5)Fp3P9oextcc^U6Mys^H!*no+5j;=D zZ>z!pEpZUeW1l>kFN1o2Z!m*mf9}|+;xw;n`WVA}Xi7Ud(FF9__p7L&Koo48$1~`) KwQ&ppocTWwDo`8% literal 0 HcmV?d00001 diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/grid.go b/Godeps/_workspace/src/github.com/gizak/termui/example/grid.go new file mode 100644 index 0000000000..49121411f7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/example/grid.go @@ -0,0 +1,134 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build ignore + +package main + +import ui "github.com/gizak/termui" +import "math" +import "time" + +func main() { + err := ui.Init() + if err != nil { + panic(err) + } + defer ui.Close() + + sinps := (func() []float64 { + n := 400 + ps := make([]float64, n) + for i := range ps { + ps[i] = 1 + math.Sin(float64(i)/5) + } + return ps + })() + sinpsint := (func() []int { + ps := make([]int, len(sinps)) + for i, v := range sinps { + ps[i] = int(100*v + 10) + } + return ps + })() + + ui.UseTheme("helloworld") + + spark := ui.Sparkline{} + spark.Height = 8 + spdata := sinpsint + spark.Data = spdata[:100] + spark.LineColor = ui.ColorCyan + spark.TitleColor = ui.ColorWhite + + sp := ui.NewSparklines(spark) + sp.Height = 11 + sp.Border.Label = "Sparkline" + + lc := ui.NewLineChart() + lc.Border.Label = "braille-mode Line Chart" + lc.Data = sinps + lc.Height = 11 + lc.AxesColor = ui.ColorWhite + lc.LineColor = ui.ColorYellow | ui.AttrBold + + gs := make([]*ui.Gauge, 3) + for i := range gs { + gs[i] = ui.NewGauge() + gs[i].Height = 2 + gs[i].HasBorder = false + gs[i].Percent = i * 10 + gs[i].PaddingBottom = 1 + gs[i].BarColor = ui.ColorRed + } + + ls := ui.NewList() + ls.HasBorder = false + ls.Items = []string{ + "[1] Downloading File 1", + "", // == \newline + "[2] Downloading File 2", + "", + "[3] Uploading File 3", + } + ls.Height = 5 + + par := ui.NewPar("<> This row has 3 columns\n<- Widgets can be stacked up like left side\n<- Stacked widgets are treated as a single widget") + par.Height = 5 + par.Border.Label = "Demonstration" + + // build layout + ui.Body.AddRows( + ui.NewRow( + ui.NewCol(6, 0, sp), + ui.NewCol(6, 0, lc)), + ui.NewRow( + ui.NewCol(3, 0, ls), + ui.NewCol(3, 0, gs[0], gs[1], gs[2]), + ui.NewCol(6, 0, par))) + + // calculate layout + ui.Body.Align() + + done := make(chan bool) + redraw := make(chan bool) + + update := func() { + for i := 0; i < 103; i++ { + for _, g := range gs { + g.Percent = (g.Percent + 3) % 100 + } + + sp.Lines[0].Data = spdata[:100+i] + lc.Data = sinps[2*i:] + + time.Sleep(time.Second / 2) + redraw <- true + } + done <- true + } + + evt := ui.EventCh() + + ui.Render(ui.Body) + go update() + + for { + select { + case e := <-evt: + if e.Type == ui.EventKey && e.Ch == 'q' { + return + } + if e.Type == ui.EventResize { + ui.Body.Width = ui.TermWidth() + ui.Body.Align() + go func() { redraw <- true }() + } + case <-done: + return + case <-redraw: + ui.Render(ui.Body) + } + } +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.go b/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.go new file mode 100644 index 0000000000..1db5434965 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.go @@ -0,0 +1,68 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build ignore + +package main + +import ( + "math" + + "github.com/gizak/termui" +) + +func main() { + err := termui.Init() + if err != nil { + panic(err) + } + defer termui.Close() + + termui.UseTheme("helloworld") + + sinps := (func() []float64 { + n := 220 + ps := make([]float64, n) + for i := range ps { + ps[i] = 1 + math.Sin(float64(i)/5) + } + return ps + })() + + lc0 := termui.NewLineChart() + lc0.Border.Label = "braille-mode Line Chart" + lc0.Data = sinps + lc0.Width = 50 + lc0.Height = 12 + lc0.X = 0 + lc0.Y = 0 + lc0.AxesColor = termui.ColorWhite + lc0.LineColor = termui.ColorGreen | termui.AttrBold + + lc1 := termui.NewLineChart() + lc1.Border.Label = "dot-mode Line Chart" + lc1.Mode = "dot" + lc1.Data = sinps + lc1.Width = 26 + lc1.Height = 12 + lc1.X = 51 + lc1.DotStyle = '+' + lc1.AxesColor = termui.ColorWhite + lc1.LineColor = termui.ColorYellow | termui.AttrBold + + lc2 := termui.NewLineChart() + lc2.Border.Label = "dot-mode Line Chart" + lc2.Mode = "dot" + lc2.Data = sinps[4:] + lc2.Width = 77 + lc2.Height = 16 + lc2.X = 0 + lc2.Y = 12 + lc2.AxesColor = termui.ColorWhite + lc2.LineColor = termui.ColorCyan | termui.AttrBold + + termui.Render(lc0, lc1, lc2) + + <-termui.EventCh() +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.png b/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.png new file mode 100644 index 0000000000000000000000000000000000000000..655ef435f468f210fe79d371256395395c6facdb GIT binary patch literal 139361 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�Y!9Dj_@FPs=GNpw>*xDIpVY7X{%T-QOkt?ziZ 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

o4u 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
9p;bss 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 z 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 DLvTMK literal 0 HcmV?d00001 diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/list.go b/Godeps/_workspace/src/github.com/gizak/termui/example/list.go new file mode 100644 index 0000000000..d33a3616c4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/example/list.go @@ -0,0 +1,41 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build ignore + +package main + +import "github.com/gizak/termui" + +func main() { + err := termui.Init() + if err != nil { + panic(err) + } + defer termui.Close() + + termui.UseTheme("helloworld") + + strs := []string{ + "[0] github.com/gizak/termui", + "[1] 你好,世界", + "[2] ã“ã‚“ã«ã¡ã¯ä¸–界", + "[3] keyboard.go", + "[4] output.go", + "[5] random_out.go", + "[6] dashboard.go", + "[7] nsf/termbox-go"} + + ls := termui.NewList() + ls.Items = strs + ls.ItemFgColor = termui.ColorYellow + ls.Border.Label = "List" + ls.Height = 7 + ls.Width = 25 + ls.Y = 0 + + termui.Render(ls) + + <-termui.EventCh() +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/list.png b/Godeps/_workspace/src/github.com/gizak/termui/example/list.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca08c079ad499db0da1994074e5b3fc6b767c3d GIT binary patch literal 37227 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 literal 0 HcmV?d00001 diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.go b/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.go new file mode 100644 index 0000000000..a32a28e0a1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.go @@ -0,0 +1,50 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build ignore + +package main + +import "github.com/gizak/termui" + +func main() { + err := termui.Init() + if err != nil { + panic(err) + } + defer termui.Close() + + termui.UseTheme("helloworld") + + bc := termui.NewMBarChart() + math := []int{90, 85, 90, 80} + english := []int{70, 85, 75, 60} + science := []int{75, 60, 80, 85} + compsci := []int{100, 100, 100, 100} + bc.Data[0] = math + bc.Data[1] = english + bc.Data[2] = science + bc.Data[3] = compsci + studentsName := []string{"Ken", "Rob", "Dennis", "Linus"} + bc.Border.Label = "Student's Marks X-Axis=Name Y-Axis=Marks[Math,English,Science,ComputerScience] in %" + bc.Width = 100 + bc.Height = 50 + bc.Y = 10 + bc.BarWidth = 10 + bc.DataLabels = studentsName + bc.ShowScale = true //Show y_axis scale value (min and max) + bc.SetMax(400) + + bc.TextColor = termui.ColorGreen //this is color for label (x-axis) + bc.BarColor[3] = termui.ColorGreen //BarColor for computerscience + bc.BarColor[1] = termui.ColorYellow //Bar Color for english + bc.NumColor[3] = termui.ColorRed // Num color for computerscience + bc.NumColor[1] = termui.ColorRed // num color for english + + //Other colors are automatically populated, btw All the students seems do well in computerscience. :p + + termui.Render(bc) + + <-termui.EventCh() +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.png b/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.png new file mode 100644 index 0000000000000000000000000000000000000000..9a4252616fb8f753ca79a34bc0bf87d0df17502d GIT binary patch literal 20075 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. All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build ignore + +package main + +import "github.com/gizak/termui" + +func main() { + err := termui.Init() + if err != nil { + panic(err) + } + defer termui.Close() + + termui.UseTheme("helloworld") + + par0 := termui.NewPar("Borderless Text") + par0.Height = 1 + par0.Width = 20 + par0.Y = 1 + par0.HasBorder = false + + par1 := termui.NewPar("你好,世界。") + par1.Height = 3 + par1.Width = 17 + par1.X = 20 + par1.Border.Label = "标签" + + par2 := termui.NewPar("Simple text\nwith label. It can be multilined with \\n or break automatically") + par2.Height = 5 + par2.Width = 37 + par2.Y = 4 + par2.Border.Label = "Multiline" + par2.Border.FgColor = termui.ColorYellow + + par3 := termui.NewPar("Long text with label and it is auto trimmed.") + par3.Height = 3 + par3.Width = 37 + par3.Y = 9 + par3.Border.Label = "Auto Trim" + + termui.Render(par0, par1, par2, par3) + + <-termui.EventCh() +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/par.png b/Godeps/_workspace/src/github.com/gizak/termui/example/par.png new file mode 100644 index 0000000000000000000000000000000000000000..a85e64415b3d45546ad1037193aec7900b09aa5b GIT binary patch literal 65773 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 literal 0 HcmV?d00001 diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.go b/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.go new file mode 100644 index 0000000000..f04baf5706 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.go @@ -0,0 +1,65 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build ignore + +package main + +import "github.com/gizak/termui" + +func main() { + err := termui.Init() + if err != nil { + panic(err) + } + defer termui.Close() + + termui.UseTheme("helloworld") + + data := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6} + spl0 := termui.NewSparkline() + spl0.Data = data[3:] + spl0.Title = "Sparkline 0" + spl0.LineColor = termui.ColorGreen + + // single + spls0 := termui.NewSparklines(spl0) + spls0.Height = 2 + spls0.Width = 20 + spls0.HasBorder = false + + spl1 := termui.NewSparkline() + spl1.Data = data + spl1.Title = "Sparkline 1" + spl1.LineColor = termui.ColorRed + + spl2 := termui.NewSparkline() + spl2.Data = data[5:] + spl2.Title = "Sparkline 2" + spl2.LineColor = termui.ColorMagenta + + // group + spls1 := termui.NewSparklines(spl0, spl1, spl2) + spls1.Height = 8 + spls1.Width = 20 + spls1.Y = 3 + spls1.Border.Label = "Group Sparklines" + + spl3 := termui.NewSparkline() + spl3.Data = data + spl3.Title = "Enlarged Sparkline" + spl3.Height = 8 + spl3.LineColor = termui.ColorYellow + + spls2 := termui.NewSparklines(spl3) + spls2.Height = 11 + spls2.Width = 30 + spls2.Border.FgColor = termui.ColorCyan + spls2.X = 21 + spls2.Border.Label = "Tweeked Sparkline" + + termui.Render(spls0, spls1, spls2) + + <-termui.EventCh() +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.png b/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.png new file mode 100644 index 0000000000000000000000000000000000000000..9dd7c82b1d3273814cb5355ca61d620004f05a15 GIT binary patch literal 43431 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. All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +// +build ignore + +package main + +import ui "github.com/gizak/termui" +import "math" + +import "time" + +func main() { + err := ui.Init() + if err != nil { + panic(err) + } + defer ui.Close() + + ui.UseTheme("helloworld") + + p := ui.NewPar(":PRESS q TO QUIT DEMO") + p.Height = 3 + p.Width = 50 + p.Border.Label = "Text Box" + + strs := []string{"[0] gizak/termui", "[1] editbox.go", "[2] iterrupt.go", "[3] keyboard.go", "[4] output.go", "[5] random_out.go", "[6] dashboard.go", "[7] nsf/termbox-go"} + list := ui.NewList() + list.Items = strs + list.Border.Label = "List" + list.Height = 7 + list.Width = 25 + list.Y = 4 + + g := ui.NewGauge() + g.Percent = 50 + g.Width = 50 + g.Height = 3 + g.Y = 11 + g.Border.Label = "Gauge" + + spark := ui.NewSparkline() + spark.Title = "srv 0:" + spdata := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6} + spark.Data = spdata + + spark1 := ui.NewSparkline() + spark1.Title = "srv 1:" + spark1.Data = spdata + + sp := ui.NewSparklines(spark, spark1) + sp.Width = 25 + sp.Height = 7 + sp.Border.Label = "Sparkline" + sp.Y = 4 + sp.X = 25 + + lc := ui.NewLineChart() + sinps := (func() []float64 { + n := 100 + ps := make([]float64, n) + for i := range ps { + ps[i] = 1 + math.Sin(float64(i)/4) + } + return ps + })() + + lc.Border.Label = "Line Chart" + lc.Data = sinps + lc.Width = 50 + lc.Height = 11 + lc.X = 0 + lc.Y = 14 + lc.Mode = "dot" + + bc := ui.NewBarChart() + bcdata := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6} + bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"} + bc.Border.Label = "Bar Chart" + bc.Width = 26 + bc.Height = 10 + bc.X = 51 + bc.Y = 0 + bc.DataLabels = bclabels + + lc1 := ui.NewLineChart() + lc1.Border.Label = "Line Chart" + rndwalk := (func() []float64 { + n := 150 + d := make([]float64, n) + for i := 1; i < n; i++ { + if i < 20 { + d[i] = d[i-1] + 0.01 + } + if i > 20 { + d[i] = d[i-1] - 0.05 + } + } + return d + })() + lc1.Data = rndwalk + lc1.Width = 26 + lc1.Height = 11 + lc1.X = 51 + lc1.Y = 14 + + p1 := ui.NewPar("Hey!\nI am a borderless block!") + p1.HasBorder = false + p1.Width = 26 + p1.Height = 2 + p1.X = 52 + p1.Y = 11 + + draw := func(t int) { + g.Percent = t % 101 + list.Items = strs[t%9:] + sp.Lines[0].Data = spdata[t%10:] + sp.Lines[1].Data = spdata[t/2%10:] + lc.Data = sinps[t/2:] + lc1.Data = rndwalk[t:] + bc.Data = bcdata[t/2%10:] + ui.Render(p, list, g, sp, lc, bc, lc1, p1) + } + + evt := ui.EventCh() + i := 0 + for { + select { + case e := <-evt: + if e.Type == ui.EventKey && e.Ch == 'q' { + return + } + default: + draw(i) + i++ + if i == 102 { + return + } + time.Sleep(time.Second / 2) + } + } +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/themedefault.png b/Godeps/_workspace/src/github.com/gizak/termui/example/themedefault.png new file mode 100644 index 0000000000000000000000000000000000000000..23b574f966df6fc125bd005ff7558e77ee3f06b4 GIT binary patch literal 105508 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 d+OgULNoXW!K9NaT;I5>o36eQR;1(V$| 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 z zJ;z!0m{tsN&gye%sG)^P+5!{7(X`MXb5LDN#^$gFM7~_%!FWRRUG;UcdGr7Ea7GmNm5npe$knjLToKyv0+=b4LNj}I} zJOPz>3(<5R0Ri-?2DC7fT!QIuA#t;FEUqE8E@Va-=Ij#!OMEgZD_|%Jfh@fgJqwx( zry381mtiQ|7 z3*dg`Sz>41oj2^aV-f1=jT;gx?81`SSU1W(@G=6k_TXHihPFST?uXL0xT6gbU?V`x zaaeusrtDvvXQ!Tf`FvY?kX$DAM<5TlBAb5TwBQCJ<7TpMY#2J8vhn#c9k4gbVz&yQ zNtTj5q9KnO^w$s{rPamg-Q|D6SgOs=-ckQ}A|$iZ9Sr#1;w`2f9tsv&=BPHgJdKKb z;Z%9(mNm!k7@PeXF~z)~X+UFtpa(yc;!9;IhXpkJvZkrb%~Bol;zg!9RK6zOuBhxZ zkeX}!c!AB;J*y4K4H}F9GHlq`5GEH`(x<(*uv>$qA%KoM|^+yCTsr0 z{?Ryb4;{n%nCsTfkb*~heJEdpCW>6ViOiIdy<@gY{Y$4V`R1D;?OI+lFu@{G$Stzr!&S$0UFZB__%iUj_$CZv-2lbPX@qn7?gkMM>H`o$tl`k(wi$;h5 zJ84x|y@E3;DhR#n5A!;l@=i<4O`MJP+ial$u7X7xwlw5GMl;F78&tu>F4&AB8_zPQ zS84Vy%5$!A62(2WXpmr!ME>REjI6*wGFD~u9^86N2cxVZ_gLf$oCfL)`S>A_-(yi0ugHka5W*>f|M!H z_uXd7j@!jy-+~u=xs|A=FFO|MYm0KWzKl1+QCvJ0hBGQDZE+ zBp@F*B7Cp+-8N^1M7|~h@(>%vTTJe4Tm&wVn;qirsJ<_`TJU=E$w;p-A{Bb##=zaP z>w^2EybRP7&uiRnMMbV_3i?NPjugr@$@e$Zrw*Sp;jS^|#|8NrV~%yR`HxVkvR;x+V@&fh-12U9L~J&AMq!~bXAKby0!V(gC8liI?DQOðv=!6U^mTE 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%0D5>u1d9GzOhxg2< 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 literal 0 HcmV?d00001 diff --git a/Godeps/_workspace/src/github.com/gizak/termui/gauge.go b/Godeps/_workspace/src/github.com/gizak/termui/gauge.go new file mode 100644 index 0000000000..986f4f3dcd --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/gauge.go @@ -0,0 +1,113 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +import ( + "strconv" + "strings" +) + +// Gauge is a progress bar like widget. +// A simple example: +/* + g := termui.NewGauge() + g.Percent = 40 + g.Width = 50 + g.Height = 3 + g.Border.Label = "Slim Gauge" + g.BarColor = termui.ColorRed + g.PercentColor = termui.ColorBlue +*/ + +// Align is the position of the gauge's label. +type Align int + +// All supported positions. +const ( + AlignLeft Align = iota + AlignCenter + AlignRight +) + +type Gauge struct { + Block + Percent int + BarColor Attribute + PercentColor Attribute + Label string + LabelAlign Align +} + +// NewGauge return a new gauge with current theme. +func NewGauge() *Gauge { + g := &Gauge{ + Block: *NewBlock(), + PercentColor: theme.GaugePercent, + BarColor: theme.GaugeBar, + Label: "{{percent}}%", + LabelAlign: AlignCenter, + } + + g.Width = 12 + g.Height = 5 + return g +} + +// Buffer implements Bufferer interface. +func (g *Gauge) Buffer() []Point { + ps := g.Block.Buffer() + + // plot bar + w := g.Percent * g.innerWidth / 100 + for i := 0; i < g.innerHeight; i++ { + for j := 0; j < w; j++ { + p := Point{} + p.X = g.innerX + j + p.Y = g.innerY + i + p.Ch = ' ' + p.Bg = g.BarColor + if p.Bg == ColorDefault { + p.Bg |= AttrReverse + } + ps = append(ps, p) + } + } + + // plot percentage + s := strings.Replace(g.Label, "{{percent}}", strconv.Itoa(g.Percent), -1) + pry := g.innerY + g.innerHeight/2 + rs := str2runes(s) + var pos int + switch g.LabelAlign { + case AlignLeft: + pos = 0 + + case AlignCenter: + pos = (g.innerWidth - strWidth(s)) / 2 + + case AlignRight: + pos = g.innerWidth - strWidth(s) + } + + for i, v := range rs { + p := Point{} + p.X = 1 + pos + i + p.Y = pry + p.Ch = v + p.Fg = g.PercentColor + if w+g.innerX > pos+i { + p.Bg = g.BarColor + if p.Bg == ColorDefault { + p.Bg |= AttrReverse + } + + } else { + p.Bg = g.Block.BgColor + } + + ps = append(ps, p) + } + return g.Block.chopOverflow(ps) +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/grid.go b/Godeps/_workspace/src/github.com/gizak/termui/grid.go new file mode 100644 index 0000000000..5f6e85e761 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/grid.go @@ -0,0 +1,279 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +// GridBufferer introduces a Bufferer that can be manipulated by Grid. +type GridBufferer interface { + Bufferer + GetHeight() int + SetWidth(int) + SetX(int) + SetY(int) +} + +// Row builds a layout tree +type Row struct { + Cols []*Row //children + Widget GridBufferer // root + X int + Y int + Width int + Height int + Span int + Offset int +} + +// calculate and set the underlying layout tree's x, y, height and width. +func (r *Row) calcLayout() { + r.assignWidth(r.Width) + r.Height = r.solveHeight() + r.assignX(r.X) + r.assignY(r.Y) +} + +// tell if the node is leaf in the tree. +func (r *Row) isLeaf() bool { + return r.Cols == nil || len(r.Cols) == 0 +} + +func (r *Row) isRenderableLeaf() bool { + return r.isLeaf() && r.Widget != nil +} + +// assign widgets' (and their parent rows') width recursively. +func (r *Row) assignWidth(w int) { + r.SetWidth(w) + + accW := 0 // acc span and offset + calcW := make([]int, len(r.Cols)) // calculated width + calcOftX := make([]int, len(r.Cols)) // computated start position of x + + for i, c := range r.Cols { + accW += c.Span + c.Offset + cw := int(float64(c.Span*r.Width) / 12.0) + + if i >= 1 { + calcOftX[i] = calcOftX[i-1] + + calcW[i-1] + + int(float64(r.Cols[i-1].Offset*r.Width)/12.0) + } + + // use up the space if it is the last col + if i == len(r.Cols)-1 && accW == 12 { + cw = r.Width - calcOftX[i] + } + calcW[i] = cw + r.Cols[i].assignWidth(cw) + } +} + +// bottom up calc and set rows' (and their widgets') height, +// return r's total height. +func (r *Row) solveHeight() int { + if r.isRenderableLeaf() { + r.Height = r.Widget.GetHeight() + return r.Widget.GetHeight() + } + + maxh := 0 + if !r.isLeaf() { + for _, c := range r.Cols { + nh := c.solveHeight() + // when embed rows in Cols, row widgets stack up + if r.Widget != nil { + nh += r.Widget.GetHeight() + } + if nh > maxh { + maxh = nh + } + } + } + + r.Height = maxh + return maxh +} + +// recursively assign x position for r tree. +func (r *Row) assignX(x int) { + r.SetX(x) + + if !r.isLeaf() { + acc := 0 + for i, c := range r.Cols { + if c.Offset != 0 { + acc += int(float64(c.Offset*r.Width) / 12.0) + } + r.Cols[i].assignX(x + acc) + acc += c.Width + } + } +} + +// recursively assign y position to r. +func (r *Row) assignY(y int) { + r.SetY(y) + + if r.isLeaf() { + return + } + + for i := range r.Cols { + acc := 0 + if r.Widget != nil { + acc = r.Widget.GetHeight() + } + r.Cols[i].assignY(y + acc) + } + +} + +// GetHeight implements GridBufferer interface. +func (r Row) GetHeight() int { + return r.Height +} + +// SetX implements GridBufferer interface. +func (r *Row) SetX(x int) { + r.X = x + if r.Widget != nil { + r.Widget.SetX(x) + } +} + +// SetY implements GridBufferer interface. +func (r *Row) SetY(y int) { + r.Y = y + if r.Widget != nil { + r.Widget.SetY(y) + } +} + +// SetWidth implements GridBufferer interface. +func (r *Row) SetWidth(w int) { + r.Width = w + if r.Widget != nil { + r.Widget.SetWidth(w) + } +} + +// Buffer implements Bufferer interface, +// recursively merge all widgets buffer +func (r *Row) Buffer() []Point { + merged := []Point{} + + if r.isRenderableLeaf() { + return r.Widget.Buffer() + } + + // for those are not leaves but have a renderable widget + if r.Widget != nil { + merged = append(merged, r.Widget.Buffer()...) + } + + // collect buffer from children + if !r.isLeaf() { + for _, c := range r.Cols { + merged = append(merged, c.Buffer()...) + } + } + + return merged +} + +// Grid implements 12 columns system. +// A simple example: +/* + import ui "github.com/gizak/termui" + // init and create widgets... + + // build + ui.Body.AddRows( + ui.NewRow( + ui.NewCol(6, 0, widget0), + ui.NewCol(6, 0, widget1)), + ui.NewRow( + ui.NewCol(3, 0, widget2), + ui.NewCol(3, 0, widget30, widget31, widget32), + ui.NewCol(6, 0, widget4))) + + // calculate layout + ui.Body.Align() + + ui.Render(ui.Body) +*/ +type Grid struct { + Rows []*Row + Width int + X int + Y int + BgColor Attribute +} + +// NewGrid returns *Grid with given rows. +func NewGrid(rows ...*Row) *Grid { + return &Grid{Rows: rows} +} + +// AddRows appends given rows to Grid. +func (g *Grid) AddRows(rs ...*Row) { + g.Rows = append(g.Rows, rs...) +} + +// NewRow creates a new row out of given columns. +func NewRow(cols ...*Row) *Row { + rs := &Row{Span: 12, Cols: cols} + return rs +} + +// NewCol accepts: widgets are LayoutBufferer or widgets is A NewRow. +// Note that if multiple widgets are provided, they will stack up in the col. +func NewCol(span, offset int, widgets ...GridBufferer) *Row { + r := &Row{Span: span, Offset: offset} + + if widgets != nil && len(widgets) == 1 { + wgt := widgets[0] + nw, isRow := wgt.(*Row) + if isRow { + r.Cols = nw.Cols + } else { + r.Widget = wgt + } + return r + } + + r.Cols = []*Row{} + ir := r + for _, w := range widgets { + nr := &Row{Span: 12, Widget: w} + ir.Cols = []*Row{nr} + ir = nr + } + + return r +} + +// Align calculate each rows' layout. +func (g *Grid) Align() { + h := 0 + for _, r := range g.Rows { + r.SetWidth(g.Width) + r.SetX(g.X) + r.SetY(g.Y + h) + r.calcLayout() + h += r.GetHeight() + } +} + +// Buffer implments Bufferer interface. +func (g Grid) Buffer() []Point { + ps := []Point{} + for _, r := range g.Rows { + ps = append(ps, r.Buffer()...) + } + return ps +} + +// Body corresponds to the entire terminal display region. +var Body *Grid diff --git a/Godeps/_workspace/src/github.com/gizak/termui/grid_test.go b/Godeps/_workspace/src/github.com/gizak/termui/grid_test.go new file mode 100644 index 0000000000..cdafb20524 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/grid_test.go @@ -0,0 +1,98 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" +) + +var r *Row + +func TestRowWidth(t *testing.T) { + p0 := NewPar("p0") + p0.Height = 1 + p1 := NewPar("p1") + p1.Height = 1 + p2 := NewPar("p2") + p2.Height = 1 + p3 := NewPar("p3") + p3.Height = 1 + + /* test against tree: + + r + / \ + 0:w 1 + / \ + 10:w 11 + / + 110:w + / + 1100:w + */ + /* + r = &row{ + Span: 12, + Cols: []*row{ + &row{Widget: p0, Span: 6}, + &row{ + Span: 6, + Cols: []*row{ + &row{Widget: p1, Span: 6}, + &row{ + Span: 6, + Cols: []*row{ + &row{ + Span: 12, + Widget: p2, + Cols: []*row{ + &row{Span: 12, Widget: p3}}}}}}}}} + */ + + r = NewRow( + NewCol(6, 0, p0), + NewCol(6, 0, + NewRow( + NewCol(6, 0, p1), + NewCol(6, 0, p2, p3)))) + + r.assignWidth(100) + if r.Width != 100 || + (r.Cols[0].Width) != 50 || + (r.Cols[1].Width) != 50 || + (r.Cols[1].Cols[0].Width) != 25 || + (r.Cols[1].Cols[1].Width) != 25 || + (r.Cols[1].Cols[1].Cols[0].Width) != 25 || + (r.Cols[1].Cols[1].Cols[0].Cols[0].Width) != 25 { + t.Error("assignWidth fails") + } +} + +func TestRowHeight(t *testing.T) { + spew.Dump() + + if (r.solveHeight()) != 2 || + (r.Cols[1].Cols[1].Height) != 2 || + (r.Cols[1].Cols[1].Cols[0].Height) != 2 || + (r.Cols[1].Cols[0].Height) != 1 { + t.Error("solveHeight fails") + } +} + +func TestAssignXY(t *testing.T) { + r.assignX(0) + r.assignY(0) + if (r.Cols[0].X) != 0 || + (r.Cols[1].Cols[0].X) != 50 || + (r.Cols[1].Cols[1].X) != 75 || + (r.Cols[1].Cols[1].Cols[0].X) != 75 || + (r.Cols[1].Cols[0].Y) != 0 || + (r.Cols[1].Cols[1].Cols[0].Y) != 0 || + (r.Cols[1].Cols[1].Cols[0].Cols[0].Y) != 1 { + t.Error("assignXY fails") + } +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/helper.go b/Godeps/_workspace/src/github.com/gizak/termui/helper.go new file mode 100644 index 0000000000..80d8a02788 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/helper.go @@ -0,0 +1,66 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +import tm "github.com/nsf/termbox-go" +import rw "github.com/mattn/go-runewidth" + +/* ---------------Port from termbox-go --------------------- */ + +// Attribute is printable cell's color and style. +type Attribute uint16 + +const ( + ColorDefault Attribute = iota + ColorBlack + ColorRed + ColorGreen + ColorYellow + ColorBlue + ColorMagenta + ColorCyan + ColorWhite +) + +const NumberofColors = 8 //Have a constant that defines number of colors +const ( + AttrBold Attribute = 1 << (iota + 9) + AttrUnderline + AttrReverse +) + +var ( + dot = "…" + dotw = rw.StringWidth(dot) +) + +/* ----------------------- End ----------------------------- */ + +func toTmAttr(x Attribute) tm.Attribute { + return tm.Attribute(x) +} + +func str2runes(s string) []rune { + return []rune(s) +} + +func trimStr2Runes(s string, w int) []rune { + if w <= 0 { + return []rune{} + } + sw := rw.StringWidth(s) + if sw > w { + return []rune(rw.Truncate(s, w, dot)) + } + return str2runes(s) //[]rune(rw.Truncate(s, w, "")) +} + +func strWidth(s string) int { + return rw.StringWidth(s) +} + +func charWidth(ch rune) int { + return rw.RuneWidth(ch) +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/helper_test.go b/Godeps/_workspace/src/github.com/gizak/termui/helper_test.go new file mode 100644 index 0000000000..6d1a561302 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/helper_test.go @@ -0,0 +1,58 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" +) + +func TestStr2Rune(t *testing.T) { + s := "你好,世界." + rs := str2runes(s) + if len(rs) != 6 { + t.Error() + } +} + +func TestWidth(t *testing.T) { + s0 := "ã¤ã®ã â˜†HIRO" + s1 := "11111111111" + spew.Dump(s0) + spew.Dump(s1) + // above not align for setting East Asian Ambiguous to wide!! + + if strWidth(s0) != strWidth(s1) { + t.Error("str len failed") + } + + len1 := []rune{'a', '2', '&', 'ï½¢', 'ï½µ', '。'} //will false: 'ᆵ', 'ᄚ', 'á„’' + for _, v := range len1 { + if charWidth(v) != 1 { + t.Error("len1 failed") + } + } + + len2 := []rune{'æ¼¢', 'å­—', '한', 'ìž', 'ä½ ', '好', 'ã ', '。', 'ï¼…', 's', 'ï¼¥', 'ョ', 'ã€', 'ヲ'} + for _, v := range len2 { + if charWidth(v) != 2 { + t.Error("len2 failed") + } + } +} + +func TestTrim(t *testing.T) { + s := "ã¤ã®ã â˜†HIRO" + if string(trimStr2Runes(s, 10)) != "ã¤ã®ã â˜†HI"+dot { + t.Error("trim failed") + } + if string(trimStr2Runes(s, 11)) != "ã¤ã®ã â˜†HIRO" { + t.Error("avoid tail trim failed") + } + if string(trimStr2Runes(s, 15)) != "ã¤ã®ã â˜†HIRO" { + t.Error("avoid trim failed") + } +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/list.go b/Godeps/_workspace/src/github.com/gizak/termui/list.go new file mode 100644 index 0000000000..0640932f2b --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/list.go @@ -0,0 +1,104 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +import "strings" + +// List displays []string as its items, +// it has a Overflow option (default is "hidden"), when set to "hidden", +// the item exceeding List's width is truncated, but when set to "wrap", +// the overflowed text breaks into next line. +/* + strs := []string{ + "[0] github.com/gizak/termui", + "[1] editbox.go", + "[2] iterrupt.go", + "[3] keyboard.go", + "[4] output.go", + "[5] random_out.go", + "[6] dashboard.go", + "[7] nsf/termbox-go"} + + ls := termui.NewList() + ls.Items = strs + ls.ItemFgColor = termui.ColorYellow + ls.Border.Label = "List" + ls.Height = 7 + ls.Width = 25 + ls.Y = 0 +*/ +type List struct { + Block + Items []string + Overflow string + ItemFgColor Attribute + ItemBgColor Attribute +} + +// NewList returns a new *List with current theme. +func NewList() *List { + l := &List{Block: *NewBlock()} + l.Overflow = "hidden" + l.ItemFgColor = theme.ListItemFg + l.ItemBgColor = theme.ListItemBg + return l +} + +// Buffer implements Bufferer interface. +func (l *List) Buffer() []Point { + ps := l.Block.Buffer() + switch l.Overflow { + case "wrap": + rs := str2runes(strings.Join(l.Items, "\n")) + i, j, k := 0, 0, 0 + for i < l.innerHeight && k < len(rs) { + w := charWidth(rs[k]) + if rs[k] == '\n' || j+w > l.innerWidth { + i++ + j = 0 + if rs[k] == '\n' { + k++ + } + continue + } + pi := Point{} + pi.X = l.innerX + j + pi.Y = l.innerY + i + + pi.Ch = rs[k] + pi.Bg = l.ItemBgColor + pi.Fg = l.ItemFgColor + + ps = append(ps, pi) + k++ + j++ + } + + case "hidden": + trimItems := l.Items + if len(trimItems) > l.innerHeight { + trimItems = trimItems[:l.innerHeight] + } + for i, v := range trimItems { + rs := trimStr2Runes(v, l.innerWidth) + + j := 0 + for _, vv := range rs { + w := charWidth(vv) + p := Point{} + p.X = l.innerX + j + p.Y = l.innerY + i + + p.Ch = vv + p.Bg = l.ItemBgColor + p.Fg = l.ItemFgColor + + ps = append(ps, p) + j += w + } + } + } + return l.Block.chopOverflow(ps) +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/mbar.go b/Godeps/_workspace/src/github.com/gizak/termui/mbar.go new file mode 100644 index 0000000000..9d18c2cb43 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/mbar.go @@ -0,0 +1,233 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +import ( + "fmt" +) + +// This is the implemetation of multi-colored or stacked bar graph. This is different from default barGraph which is implemented in bar.go +// Multi-Colored-BarChart creates multiple bars in a widget: +/* + bc := termui.NewMBarChart() + data := make([][]int, 2) + data[0] := []int{3, 2, 5, 7, 9, 4} + data[1] := []int{7, 8, 5, 3, 1, 6} + bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"} + bc.Border.Label = "Bar Chart" + bc.Data = data + bc.Width = 26 + bc.Height = 10 + bc.DataLabels = bclabels + bc.TextColor = termui.ColorGreen + bc.BarColor = termui.ColorRed + bc.NumColor = termui.ColorYellow +*/ +type MBarChart struct { + Block + BarColor [NumberofColors]Attribute + TextColor Attribute + NumColor [NumberofColors]Attribute + Data [NumberofColors][]int + DataLabels []string + BarWidth int + BarGap int + labels [][]rune + dataNum [NumberofColors][][]rune + numBar int + scale float64 + max int + minDataLen int + numStack int + ShowScale bool + maxScale []rune +} + +// NewBarChart returns a new *BarChart with current theme. +func NewMBarChart() *MBarChart { + bc := &MBarChart{Block: *NewBlock()} + bc.BarColor[0] = theme.MBarChartBar + bc.NumColor[0] = theme.MBarChartNum + bc.TextColor = theme.MBarChartText + bc.BarGap = 1 + bc.BarWidth = 3 + return bc +} + +func (bc *MBarChart) layout() { + bc.numBar = bc.innerWidth / (bc.BarGap + bc.BarWidth) + bc.labels = make([][]rune, bc.numBar) + DataLen := 0 + LabelLen := len(bc.DataLabels) + bc.minDataLen = 9999 //Set this to some very hight value so that we find the minimum one We want to know which array among data[][] has got the least length + + // We need to know how many stack/data array data[0] , data[1] are there + for i := 0; i < len(bc.Data); i++ { + if bc.Data[i] == nil { + break + } + DataLen++ + } + bc.numStack = DataLen + + //We need to know what is the mimimum size of data array data[0] could have 10 elements data[1] could have only 5, so we plot only 5 bar graphs + + for i := 0; i < DataLen; i++ { + if bc.minDataLen > len(bc.Data[i]) { + bc.minDataLen = len(bc.Data[i]) + } + } + + if LabelLen > bc.minDataLen { + LabelLen = bc.minDataLen + } + + for i := 0; i < LabelLen && i < bc.numBar; i++ { + bc.labels[i] = trimStr2Runes(bc.DataLabels[i], bc.BarWidth) + } + + for i := 0; i < bc.numStack; i++ { + bc.dataNum[i] = make([][]rune, len(bc.Data[i])) + //For each stack of bar calcualte the rune + for j := 0; j < LabelLen && i < bc.numBar; j++ { + n := bc.Data[i][j] + s := fmt.Sprint(n) + bc.dataNum[i][j] = trimStr2Runes(s, bc.BarWidth) + } + //If color is not defined by default then populate a color that is different from the prevous bar + if bc.BarColor[i] == ColorDefault && bc.NumColor[i] == ColorDefault { + if i == 0 { + bc.BarColor[i] = ColorBlack + } else { + bc.BarColor[i] = bc.BarColor[i-1] + 1 + if bc.BarColor[i] > NumberofColors { + bc.BarColor[i] = ColorBlack + } + } + bc.NumColor[i] = (NumberofColors + 1) - bc.BarColor[i] //Make NumColor opposite of barColor for visibility + } + } + + //If Max value is not set then we have to populate, this time the max value will be max(sum(d1[0],d2[0],d3[0]) .... sum(d1[n], d2[n], d3[n])) + + if bc.max == 0 { + bc.max = -1 + } + for i := 0; i < bc.minDataLen && i < LabelLen; i++ { + var dsum int + for j := 0; j < bc.numStack; j++ { + dsum += bc.Data[j][i] + } + if dsum > bc.max { + bc.max = dsum + } + } + + //Finally Calculate max sale + if bc.ShowScale { + s := fmt.Sprintf("%d", bc.max) + bc.maxScale = trimStr2Runes(s, len(s)) + bc.scale = float64(bc.max) / float64(bc.innerHeight-2) + } else { + bc.scale = float64(bc.max) / float64(bc.innerHeight-1) + } + +} + +func (bc *MBarChart) SetMax(max int) { + + if max > 0 { + bc.max = max + } +} + +// Buffer implements Bufferer interface. +func (bc *MBarChart) Buffer() []Point { + ps := bc.Block.Buffer() + bc.layout() + var oftX int + + for i := 0; i < bc.numBar && i < bc.minDataLen && i < len(bc.DataLabels); i++ { + ph := 0 //Previous Height to stack up + oftX = i * (bc.BarWidth + bc.BarGap) + for i1 := 0; i1 < bc.numStack; i1++ { + h := int(float64(bc.Data[i1][i]) / bc.scale) + // plot bars + for j := 0; j < bc.BarWidth; j++ { + for k := 0; k < h; k++ { + p := Point{} + p.Ch = ' ' + p.Bg = bc.BarColor[i1] + if bc.BarColor[i1] == ColorDefault { // when color is default, space char treated as transparent! + p.Bg |= AttrReverse + } + p.X = bc.innerX + i*(bc.BarWidth+bc.BarGap) + j + p.Y = bc.innerY + bc.innerHeight - 2 - k - ph + ps = append(ps, p) + } + } + ph += h + } + // plot text + for j, k := 0, 0; j < len(bc.labels[i]); j++ { + w := charWidth(bc.labels[i][j]) + p := Point{} + p.Ch = bc.labels[i][j] + p.Bg = bc.BgColor + p.Fg = bc.TextColor + p.Y = bc.innerY + bc.innerHeight - 1 + p.X = bc.innerX + oftX + ((bc.BarWidth - len(bc.labels[i])) / 2) + k + ps = append(ps, p) + k += w + } + // plot num + ph = 0 //re-initialize previous height + for i1 := 0; i1 < bc.numStack; i1++ { + h := int(float64(bc.Data[i1][i]) / bc.scale) + for j := 0; j < len(bc.dataNum[i1][i]) && h > 0; j++ { + p := Point{} + p.Ch = bc.dataNum[i1][i][j] + p.Fg = bc.NumColor[i1] + p.Bg = bc.BarColor[i1] + if bc.BarColor[i1] == ColorDefault { // the same as above + p.Bg |= AttrReverse + } + if h == 0 { + p.Bg = bc.BgColor + } + p.X = bc.innerX + oftX + (bc.BarWidth-len(bc.dataNum[i1][i]))/2 + j + p.Y = bc.innerY + bc.innerHeight - 2 - ph + ps = append(ps, p) + } + ph += h + } + } + + if bc.ShowScale { + //Currently bar graph only supprts data range from 0 to MAX + //Plot 0 + p := Point{} + p.Ch = '0' + p.Bg = bc.BgColor + p.Fg = bc.TextColor + p.Y = bc.innerY + bc.innerHeight - 2 + p.X = bc.X + ps = append(ps, p) + + //Plot the maximum sacle value + for i := 0; i < len(bc.maxScale); i++ { + p := Point{} + p.Ch = bc.maxScale[i] + p.Bg = bc.BgColor + p.Fg = bc.TextColor + p.Y = bc.innerY + p.X = bc.X + i + ps = append(ps, p) + } + + } + + return bc.Block.chopOverflow(ps) +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/p.go b/Godeps/_workspace/src/github.com/gizak/termui/p.go new file mode 100644 index 0000000000..e327d74897 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/p.go @@ -0,0 +1,71 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +// Par displays a paragraph. +/* + par := termui.NewPar("Simple Text") + par.Height = 3 + par.Width = 17 + par.Border.Label = "Label" +*/ +type Par struct { + Block + Text string + TextFgColor Attribute + TextBgColor Attribute +} + +// NewPar returns a new *Par with given text as its content. +func NewPar(s string) *Par { + return &Par{ + Block: *NewBlock(), + Text: s, + TextFgColor: theme.ParTextFg, + TextBgColor: theme.ParTextBg} +} + +// Buffer implements Bufferer interface. +func (p *Par) Buffer() []Point { + ps := p.Block.Buffer() + + rs := str2runes(p.Text) + i, j, k := 0, 0, 0 + for i < p.innerHeight && k < len(rs) { + // the width of char is about to print + w := charWidth(rs[k]) + + if rs[k] == '\n' || j+w > p.innerWidth { + i++ + j = 0 // set x = 0 + if rs[k] == '\n' { + k++ + } + + if i >= p.innerHeight { + ps = append(ps, newPointWithAttrs('…', + p.innerX+p.innerWidth-1, + p.innerY+p.innerHeight-1, + p.TextFgColor, p.TextBgColor)) + break + } + + continue + } + pi := Point{} + pi.X = p.innerX + j + pi.Y = p.innerY + i + + pi.Ch = rs[k] + pi.Bg = p.TextBgColor + pi.Fg = p.TextFgColor + + ps = append(ps, pi) + + k++ + j += w + } + return p.Block.chopOverflow(ps) +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/point.go b/Godeps/_workspace/src/github.com/gizak/termui/point.go new file mode 100644 index 0000000000..c381af9a4e --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/point.go @@ -0,0 +1,28 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +// Point stands for a single cell in terminal. +type Point struct { + Ch rune + Bg Attribute + Fg Attribute + X int + Y int +} + +func newPoint(c rune, x, y int) (p Point) { + p.Ch = c + p.X = x + p.Y = y + return +} + +func newPointWithAttrs(c rune, x, y int, fg, bg Attribute) Point { + p := newPoint(c, x, y) + p.Bg = bg + p.Fg = fg + return p +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/render.go b/Godeps/_workspace/src/github.com/gizak/termui/render.go new file mode 100644 index 0000000000..d697d0aea8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/render.go @@ -0,0 +1,60 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +import tm "github.com/nsf/termbox-go" + +// Bufferer should be implemented by all renderable components. +type Bufferer interface { + Buffer() []Point +} + +// Init initializes termui library. This function should be called before any others. +// After initialization, the library must be finalized by 'Close' function. +func Init() error { + Body = NewGrid() + Body.X = 0 + Body.Y = 0 + Body.BgColor = theme.BodyBg + defer func() { + w, _ := tm.Size() + Body.Width = w + evtListen() + }() + return tm.Init() +} + +// Close finalizes termui library, +// should be called after successful initialization when termui's functionality isn't required anymore. +func Close() { + tm.Close() +} + +// TermWidth returns the current terminal's width. +func TermWidth() int { + tm.Sync() + w, _ := tm.Size() + return w +} + +// TermHeight returns the current terminal's height. +func TermHeight() int { + tm.Sync() + _, h := tm.Size() + return h +} + +// Render renders all Bufferer in the given order from left to right, +// right could overlap on left ones. +func Render(rs ...Bufferer) { + tm.Clear(tm.ColorDefault, toTmAttr(theme.BodyBg)) + for _, r := range rs { + buf := r.Buffer() + for _, v := range buf { + tm.SetCell(v.X, v.Y, v.Ch, toTmAttr(v.Fg), toTmAttr(v.Bg)) + } + } + tm.Flush() +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/sparkline.go b/Godeps/_workspace/src/github.com/gizak/termui/sparkline.go new file mode 100644 index 0000000000..c63a5857fb --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/sparkline.go @@ -0,0 +1,156 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +import "math" + +// Sparkline is like: ▅▆▂▂▅▇▂▂▃▆▆▆▅▃ +/* + data := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1} + spl := termui.NewSparkline() + spl.Data = data + spl.Title = "Sparkline 0" + spl.LineColor = termui.ColorGreen +*/ +type Sparkline struct { + Data []int + Height int + Title string + TitleColor Attribute + LineColor Attribute + displayHeight int + scale float32 + max int +} + +// Sparklines is a renderable widget which groups together the given sparklines. +/* + spls := termui.NewSparklines(spl0,spl1,spl2) //... + spls.Height = 2 + spls.Width = 20 +*/ +type Sparklines struct { + Block + Lines []Sparkline + displayLines int + displayWidth int +} + +var sparks = []rune{'â–', 'â–‚', 'â–ƒ', 'â–„', 'â–…', 'â–†', 'â–‡', 'â–ˆ'} + +// Add appends a given Sparkline to s *Sparklines. +func (s *Sparklines) Add(sl Sparkline) { + s.Lines = append(s.Lines, sl) +} + +// NewSparkline returns a unrenderable single sparkline that intended to be added into Sparklines. +func NewSparkline() Sparkline { + return Sparkline{ + Height: 1, + TitleColor: theme.SparklineTitle, + LineColor: theme.SparklineLine} +} + +// NewSparklines return a new *Spaklines with given Sparkline(s), you can always add a new Sparkline later. +func NewSparklines(ss ...Sparkline) *Sparklines { + s := &Sparklines{Block: *NewBlock(), Lines: ss} + return s +} + +func (sl *Sparklines) update() { + for i, v := range sl.Lines { + if v.Title == "" { + sl.Lines[i].displayHeight = v.Height + } else { + sl.Lines[i].displayHeight = v.Height + 1 + } + } + sl.displayWidth = sl.innerWidth + + // get how many lines gotta display + h := 0 + sl.displayLines = 0 + for _, v := range sl.Lines { + if h+v.displayHeight <= sl.innerHeight { + sl.displayLines++ + } else { + break + } + h += v.displayHeight + } + + for i := 0; i < sl.displayLines; i++ { + data := sl.Lines[i].Data + + max := math.MinInt32 + for _, v := range data { + if max < v { + max = v + } + } + sl.Lines[i].max = max + sl.Lines[i].scale = float32(8*sl.Lines[i].Height) / float32(max) + } +} + +// Buffer implements Bufferer interface. +func (sl *Sparklines) Buffer() []Point { + ps := sl.Block.Buffer() + sl.update() + + oftY := 0 + for i := 0; i < sl.displayLines; i++ { + l := sl.Lines[i] + data := l.Data + + if len(data) > sl.innerWidth { + data = data[len(data)-sl.innerWidth:] + } + + if l.Title != "" { + rs := trimStr2Runes(l.Title, sl.innerWidth) + oftX := 0 + for _, v := range rs { + w := charWidth(v) + p := Point{} + p.Ch = v + p.Fg = l.TitleColor + p.Bg = sl.BgColor + p.X = sl.innerX + oftX + p.Y = sl.innerY + oftY + ps = append(ps, p) + oftX += w + } + } + + for j, v := range data { + h := int(float32(v)*l.scale + 0.5) + barCnt := h / 8 + barMod := h % 8 + for jj := 0; jj < barCnt; jj++ { + p := Point{} + p.X = sl.innerX + j + p.Y = sl.innerY + oftY + l.Height - jj + p.Ch = ' ' // => sparks[7] + p.Bg = l.LineColor + //p.Bg = sl.BgColor + ps = append(ps, p) + } + if barMod != 0 { + p := Point{} + p.X = sl.innerX + j + p.Y = sl.innerY + oftY + l.Height - barCnt + p.Ch = sparks[barMod-1] + p.Fg = l.LineColor + p.Bg = sl.BgColor + ps = append(ps, p) + } + } + + oftY += l.displayHeight + } + + return sl.Block.chopOverflow(ps) +} diff --git a/Godeps/_workspace/src/github.com/gizak/termui/theme.go b/Godeps/_workspace/src/github.com/gizak/termui/theme.go new file mode 100644 index 0000000000..c8ad947560 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gizak/termui/theme.go @@ -0,0 +1,84 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +package termui + +// A ColorScheme represents the current look-and-feel of the dashboard. +type ColorScheme struct { + BodyBg Attribute + BlockBg Attribute + HasBorder bool + BorderFg Attribute + BorderBg Attribute + BorderLabelTextFg Attribute + BorderLabelTextBg Attribute + ParTextFg Attribute + ParTextBg Attribute + SparklineLine Attribute + SparklineTitle Attribute + GaugeBar Attribute + GaugePercent Attribute + LineChartLine Attribute + LineChartAxes Attribute + ListItemFg Attribute + ListItemBg Attribute + BarChartBar Attribute + BarChartText Attribute + BarChartNum Attribute + MBarChartBar Attribute + MBarChartText Attribute + MBarChartNum Attribute +} + +// default color scheme depends on the user's terminal setting. +var themeDefault = ColorScheme{HasBorder: true} + +var themeHelloWorld = ColorScheme{ + BodyBg: ColorBlack, + BlockBg: ColorBlack, + HasBorder: true, + BorderFg: ColorWhite, + BorderBg: ColorBlack, + BorderLabelTextBg: ColorBlack, + BorderLabelTextFg: ColorGreen, + ParTextBg: ColorBlack, + ParTextFg: ColorWhite, + SparklineLine: ColorMagenta, + SparklineTitle: ColorWhite, + GaugeBar: ColorRed, + GaugePercent: ColorWhite, + LineChartLine: ColorYellow | AttrBold, + LineChartAxes: ColorWhite, + ListItemBg: ColorBlack, + ListItemFg: ColorYellow, + BarChartBar: ColorRed, + BarChartNum: ColorWhite, + BarChartText: ColorCyan, + MBarChartBar: ColorRed, + MBarChartNum: ColorWhite, + MBarChartText: ColorCyan, +} + +var theme = themeDefault // global dep + +// Theme returns the currently used theme. +func Theme() ColorScheme { + return theme +} + +// SetTheme sets a new, custom theme. +func SetTheme(newTheme ColorScheme) { + theme = newTheme +} + +// UseTheme sets a predefined scheme. Currently available: "hello-world" and +// "black-and-white". +func UseTheme(th string) { + switch th { + case "helloworld": + theme = themeHelloWorld + default: + theme = themeDefault + } +} diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/.gitignore b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/.gitignore new file mode 100644 index 0000000000..836562412f --- /dev/null +++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/.gitignore @@ -0,0 +1,23 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/LICENSE b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/LICENSE new file mode 100644 index 0000000000..be2cc4dfb6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/LICENSE @@ -0,0 +1,362 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/README.md b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/README.md new file mode 100644 index 0000000000..33e58cfaf9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/README.md @@ -0,0 +1,25 @@ +golang-lru +========== + +This provides the `lru` package which implements a fixed-size +thread safe LRU cache. It is based on the cache in Groupcache. + +Documentation +============= + +Full docs are available on [Godoc](http://godoc.org/github.com/hashicorp/golang-lru) + +Example +======= + +Using the LRU is very simple: + +```go +l, _ := New(128) +for i := 0; i < 256; i++ { + l.Add(i, nil) +} +if l.Len() != 128 { + panic(fmt.Sprintf("bad len: %v", l.Len())) +} +``` diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru.go b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru.go new file mode 100644 index 0000000000..5f1e8a1af3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru.go @@ -0,0 +1,175 @@ +// This package provides a simple LRU cache. It is based on the +// LRU implementation in groupcache: +// https://github.com/golang/groupcache/tree/master/lru +package lru + +import ( + "container/list" + "errors" + "sync" +) + +// Cache is a thread-safe fixed size LRU cache. +type Cache struct { + size int + evictList *list.List + items map[interface{}]*list.Element + lock sync.RWMutex + onEvicted func(key interface{}, value interface{}) +} + +// entry is used to hold a value in the evictList +type entry struct { + key interface{} + value interface{} +} + +// New creates an LRU of the given size +func New(size int) (*Cache, error) { + return NewWithEvict(size, nil) +} + +func NewWithEvict(size int, onEvicted func(key interface{}, value interface{})) (*Cache, error) { + if size <= 0 { + return nil, errors.New("Must provide a positive size") + } + c := &Cache{ + size: size, + evictList: list.New(), + items: make(map[interface{}]*list.Element, size), + onEvicted: onEvicted, + } + return c, nil +} + +// Purge is used to completely clear the cache +func (c *Cache) Purge() { + c.lock.Lock() + defer c.lock.Unlock() + + if c.onEvicted != nil { + for k, v := range c.items { + c.onEvicted(k, v.Value.(*entry).value) + } + } + + c.evictList = list.New() + c.items = make(map[interface{}]*list.Element, c.size) +} + +// Add adds a value to the cache. Returns true if an eviction occured. +func (c *Cache) Add(key, value interface{}) bool { + c.lock.Lock() + defer c.lock.Unlock() + + // Check for existing item + if ent, ok := c.items[key]; ok { + c.evictList.MoveToFront(ent) + ent.Value.(*entry).value = value + return false + } + + // Add new item + ent := &entry{key, value} + entry := c.evictList.PushFront(ent) + c.items[key] = entry + + evict := c.evictList.Len() > c.size + // Verify size not exceeded + if evict { + c.removeOldest() + } + return evict +} + +// Get looks up a key's value from the cache. +func (c *Cache) Get(key interface{}) (value interface{}, ok bool) { + c.lock.Lock() + defer c.lock.Unlock() + + if ent, ok := c.items[key]; ok { + c.evictList.MoveToFront(ent) + return ent.Value.(*entry).value, true + } + return +} + +// Check if a key is in the cache, without updating the recent-ness or deleting it for being stale. +func (c *Cache) Contains(key interface{}) (ok bool) { + c.lock.RLock() + defer c.lock.RUnlock() + + _, ok = c.items[key] + return ok +} + +// Returns the key value (or undefined if not found) without updating the "recently used"-ness of the key. +// (If you find yourself using this a lot, you might be using the wrong sort of data structure, but there are some use cases where it's handy.) +func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) { + c.lock.RLock() + defer c.lock.RUnlock() + + if ent, ok := c.items[key]; ok { + return ent.Value.(*entry).value, true + } + return nil, ok +} + +// Remove removes the provided key from the cache. +func (c *Cache) Remove(key interface{}) { + c.lock.Lock() + defer c.lock.Unlock() + + if ent, ok := c.items[key]; ok { + c.removeElement(ent) + } +} + +// RemoveOldest removes the oldest item from the cache. +func (c *Cache) RemoveOldest() { + c.lock.Lock() + defer c.lock.Unlock() + c.removeOldest() +} + +// Keys returns a slice of the keys in the cache, from oldest to newest. +func (c *Cache) Keys() []interface{} { + c.lock.RLock() + defer c.lock.RUnlock() + + keys := make([]interface{}, len(c.items)) + ent := c.evictList.Back() + i := 0 + for ent != nil { + keys[i] = ent.Value.(*entry).key + ent = ent.Prev() + i++ + } + + return keys +} + +// Len returns the number of items in the cache. +func (c *Cache) Len() int { + c.lock.RLock() + defer c.lock.RUnlock() + return c.evictList.Len() +} + +// removeOldest removes the oldest item from the cache. +func (c *Cache) removeOldest() { + ent := c.evictList.Back() + if ent != nil { + c.removeElement(ent) + } +} + +// removeElement is used to remove a given list element from the cache +func (c *Cache) removeElement(e *list.Element) { + c.evictList.Remove(e) + kv := e.Value.(*entry) + delete(c.items, kv.key) + if c.onEvicted != nil { + c.onEvicted(kv.key, kv.value) + } +} diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru_test.go b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru_test.go new file mode 100644 index 0000000000..b676cfd9db --- /dev/null +++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru_test.go @@ -0,0 +1,127 @@ +package lru + +import "testing" + +func TestLRU(t *testing.T) { + evictCounter := 0 + onEvicted := func(k interface{}, v interface{}) { + if k != v { + t.Fatalf("Evict values not equal (%v!=%v)", k, v) + } + evictCounter += 1 + } + l, err := NewWithEvict(128, onEvicted) + if err != nil { + t.Fatalf("err: %v", err) + } + + for i := 0; i < 256; i++ { + l.Add(i, i) + } + if l.Len() != 128 { + t.Fatalf("bad len: %v", l.Len()) + } + + if evictCounter != 128 { + t.Fatalf("bad evict count: %v", evictCounter) + } + + for i, k := range l.Keys() { + if v, ok := l.Get(k); !ok || v != k || v != i+128 { + t.Fatalf("bad key: %v", k) + } + } + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if ok { + t.Fatalf("should be evicted") + } + } + for i := 128; i < 256; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("should not be evicted") + } + } + for i := 128; i < 192; i++ { + l.Remove(i) + _, ok := l.Get(i) + if ok { + t.Fatalf("should be deleted") + } + } + + l.Get(192) // expect 192 to be last key in l.Keys() + + for i, k := range l.Keys() { + if (i < 63 && k != i+193) || (i == 63 && k != 192) { + t.Fatalf("out of order key: %v", k) + } + } + + l.Purge() + if l.Len() != 0 { + t.Fatalf("bad len: %v", l.Len()) + } + if _, ok := l.Get(200); ok { + t.Fatalf("should contain nothing") + } +} + +// test that Add returns true/false if an eviction occured +func TestLRUAdd(t *testing.T) { + evictCounter := 0 + onEvicted := func(k interface{}, v interface{}) { + evictCounter += 1 + } + + l, err := NewWithEvict(1, onEvicted) + if err != nil { + t.Fatalf("err: %v", err) + } + + if l.Add(1, 1) == true || evictCounter != 0 { + t.Errorf("should not have an eviction") + } + if l.Add(2, 2) == false || evictCounter != 1 { + t.Errorf("should have an eviction") + } +} + +// test that Contains doesn't update recent-ness +func TestLRUContains(t *testing.T) { + l, err := New(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if !l.Contains(1) { + t.Errorf("1 should be contained") + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("Contains should not have updated recent-ness of 1") + } +} + +// test that Peek doesn't update recent-ness +func TestLRUPeek(t *testing.T) { + l, err := New(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if v, ok := l.Peek(1); !ok || v != 1 { + t.Errorf("1 should be set to 1: %v, %v", v, ok) + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("should not have updated recent-ness of 1") + } +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/LICENSE b/Godeps/_workspace/src/github.com/huin/goupnp/LICENSE new file mode 100644 index 0000000000..252e3d6397 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2013, John Beisley +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. + +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/Godeps/_workspace/src/github.com/huin/goupnp/README.md b/Godeps/_workspace/src/github.com/huin/goupnp/README.md new file mode 100644 index 0000000000..ea2c155a12 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/README.md @@ -0,0 +1,14 @@ +goupnp is a UPnP client library for Go + +Installation +------------ + +Run `go get -u github.com/huin/goupnp`. + +Regenerating dcps generated source code: +---------------------------------------- + +1. Install gotasks: `go get -u github.com/jingweno/gotask` +2. Change to the gotasks directory: `cd gotasks` +3. Download UPnP specification data (if not done already): `wget http://upnp.org/resources/upnpresources.zip` +4. Regenerate source code: `gotask specgen -s upnpresources.zip -o ../dcps` diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_httpu_serving/example_httpu_serving.go b/Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_httpu_serving/example_httpu_serving.go new file mode 100644 index 0000000000..d9d9daa936 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_httpu_serving/example_httpu_serving.go @@ -0,0 +1,20 @@ +package main + +import ( + "log" + "net/http" + + "github.com/huin/goupnp/httpu" +) + +func main() { + srv := httpu.Server{ + Addr: "239.255.255.250:1900", + Multicast: true, + Handler: httpu.HandlerFunc(func(r *http.Request) { + log.Printf("Got %s %s message from %v: %v", r.Method, r.URL.Path, r.RemoteAddr, r.Header) + }), + } + err := srv.ListenAndServe() + log.Printf("Serving failed with error: %v", err) +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_internetgateway1/example_internetgateway1.go b/Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_internetgateway1/example_internetgateway1.go new file mode 100644 index 0000000000..29e8adc8b0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_internetgateway1/example_internetgateway1.go @@ -0,0 +1,67 @@ +package main + +import ( + "fmt" + "log" + + "github.com/huin/goupnp/dcps/internetgateway1" +) + +func main() { + clients, errors, err := internetgateway1.NewWANPPPConnection1Clients() + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Got %d errors finding servers and %d successfully discovered.\n", + len(errors), len(clients)) + for i, e := range errors { + fmt.Printf("Error finding server #%d: %v\n", i+1, e) + } + + for _, c := range clients { + dev := &c.ServiceClient.RootDevice.Device + srv := c.ServiceClient.Service + fmt.Println(dev.FriendlyName, " :: ", srv.String()) + scpd, err := srv.RequestSCDP() + if err != nil { + fmt.Printf(" Error requesting service SCPD: %v\n", err) + } else { + fmt.Println(" Available actions:") + for _, action := range scpd.Actions { + fmt.Printf(" * %s\n", action.Name) + for _, arg := range action.Arguments { + var varDesc string + if stateVar := scpd.GetStateVariable(arg.RelatedStateVariable); stateVar != nil { + varDesc = fmt.Sprintf(" (%s)", stateVar.DataType.Name) + } + fmt.Printf(" * [%s] %s%s\n", arg.Direction, arg.Name, varDesc) + } + } + } + + if scpd == nil || scpd.GetAction("GetExternalIPAddress") != nil { + ip, err := c.GetExternalIPAddress() + fmt.Println("GetExternalIPAddress: ", ip, err) + } + + if scpd == nil || scpd.GetAction("GetStatusInfo") != nil { + status, lastErr, uptime, err := c.GetStatusInfo() + fmt.Println("GetStatusInfo: ", status, lastErr, uptime, err) + } + + if scpd == nil || scpd.GetAction("GetIdleDisconnectTime") != nil { + idleTime, err := c.GetIdleDisconnectTime() + fmt.Println("GetIdleDisconnectTime: ", idleTime, err) + } + + if scpd == nil || scpd.GetAction("AddPortMapping") != nil { + err := c.AddPortMapping("", 5000, "TCP", 5001, "192.168.1.2", true, "Test port mapping", 0) + fmt.Println("AddPortMapping: ", err) + } + if scpd == nil || scpd.GetAction("DeletePortMapping") != nil { + err := c.DeletePortMapping("", 5000, "TCP") + fmt.Println("DeletePortMapping: ", err) + } + } +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway1/internetgateway1.go b/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway1/internetgateway1.go new file mode 100644 index 0000000000..be71855a9a --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway1/internetgateway1.go @@ -0,0 +1,3957 @@ +// Client for UPnP Device Control Protocol Internet Gateway Device v1. +// +// This DCP is documented in detail at: http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v1-Device.pdf +// +// Typically, use one of the New* functions to discover services on the local +// network. +package internetgateway1 + +// Generated file - do not edit by hand. See README.md + +import ( + "time" + + "github.com/huin/goupnp" + "github.com/huin/goupnp/soap" +) + +// Hack to avoid Go complaining if time isn't used. +var _ time.Time + +// Device URNs: +const ( + URN_LANDevice_1 = "urn:schemas-upnp-org:device:LANDevice:1" + URN_WANConnectionDevice_1 = "urn:schemas-upnp-org:device:WANConnectionDevice:1" + URN_WANDevice_1 = "urn:schemas-upnp-org:device:WANDevice:1" +) + +// Service URNs: +const ( + URN_LANHostConfigManagement_1 = "urn:schemas-upnp-org:service:LANHostConfigManagement:1" + URN_Layer3Forwarding_1 = "urn:schemas-upnp-org:service:Layer3Forwarding:1" + URN_WANCableLinkConfig_1 = "urn:schemas-upnp-org:service:WANCableLinkConfig:1" + URN_WANCommonInterfaceConfig_1 = "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" + URN_WANDSLLinkConfig_1 = "urn:schemas-upnp-org:service:WANDSLLinkConfig:1" + URN_WANEthernetLinkConfig_1 = "urn:schemas-upnp-org:service:WANEthernetLinkConfig:1" + URN_WANIPConnection_1 = "urn:schemas-upnp-org:service:WANIPConnection:1" + URN_WANPOTSLinkConfig_1 = "urn:schemas-upnp-org:service:WANPOTSLinkConfig:1" + URN_WANPPPConnection_1 = "urn:schemas-upnp-org:service:WANPPPConnection:1" +) + +// LANHostConfigManagement1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:LANHostConfigManagement:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type LANHostConfigManagement1 struct { + goupnp.ServiceClient +} + +// NewLANHostConfigManagement1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewLANHostConfigManagement1Clients() (clients []*LANHostConfigManagement1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_LANHostConfigManagement_1); err != nil { + return + } + clients = make([]*LANHostConfigManagement1, len(genericClients)) + for i := range genericClients { + clients[i] = &LANHostConfigManagement1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewDHCPServerConfigurable: +// +// +func (client *LANHostConfigManagement1) SetDHCPServerConfigurable(NewDHCPServerConfigurable bool) (err error) { + // Request structure. + request := &struct { + NewDHCPServerConfigurable string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDHCPServerConfigurable, err = soap.MarshalBoolean(NewDHCPServerConfigurable); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDHCPServerConfigurable", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDHCPServerConfigurable: +func (client *LANHostConfigManagement1) GetDHCPServerConfigurable() (NewDHCPServerConfigurable bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDHCPServerConfigurable string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDHCPServerConfigurable", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDHCPServerConfigurable, err = soap.UnmarshalBoolean(response.NewDHCPServerConfigurable); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewDHCPRelay: +// +// +func (client *LANHostConfigManagement1) SetDHCPRelay(NewDHCPRelay bool) (err error) { + // Request structure. + request := &struct { + NewDHCPRelay string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDHCPRelay, err = soap.MarshalBoolean(NewDHCPRelay); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDHCPRelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDHCPRelay: +func (client *LANHostConfigManagement1) GetDHCPRelay() (NewDHCPRelay bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDHCPRelay string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDHCPRelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDHCPRelay, err = soap.UnmarshalBoolean(response.NewDHCPRelay); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewSubnetMask: +// +// +func (client *LANHostConfigManagement1) SetSubnetMask(NewSubnetMask string) (err error) { + // Request structure. + request := &struct { + NewSubnetMask string + }{} + // BEGIN Marshal arguments into request. + + if request.NewSubnetMask, err = soap.MarshalString(NewSubnetMask); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetSubnetMask", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewSubnetMask: +func (client *LANHostConfigManagement1) GetSubnetMask() (NewSubnetMask string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewSubnetMask string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetSubnetMask", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewSubnetMask, err = soap.UnmarshalString(response.NewSubnetMask); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewIPRouters: +// +// +func (client *LANHostConfigManagement1) SetIPRouter(NewIPRouters string) (err error) { + // Request structure. + request := &struct { + NewIPRouters string + }{} + // BEGIN Marshal arguments into request. + + if request.NewIPRouters, err = soap.MarshalString(NewIPRouters); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetIPRouter", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewIPRouters: +// +// +func (client *LANHostConfigManagement1) DeleteIPRouter(NewIPRouters string) (err error) { + // Request structure. + request := &struct { + NewIPRouters string + }{} + // BEGIN Marshal arguments into request. + + if request.NewIPRouters, err = soap.MarshalString(NewIPRouters); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "DeleteIPRouter", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewIPRouters: +func (client *LANHostConfigManagement1) GetIPRoutersList() (NewIPRouters string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewIPRouters string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetIPRoutersList", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewIPRouters, err = soap.UnmarshalString(response.NewIPRouters); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewDomainName: +// +// +func (client *LANHostConfigManagement1) SetDomainName(NewDomainName string) (err error) { + // Request structure. + request := &struct { + NewDomainName string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDomainName, err = soap.MarshalString(NewDomainName); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDomainName", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDomainName: +func (client *LANHostConfigManagement1) GetDomainName() (NewDomainName string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDomainName string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDomainName", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDomainName, err = soap.UnmarshalString(response.NewDomainName); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewMinAddress: +// +// * NewMaxAddress: +// +// +func (client *LANHostConfigManagement1) SetAddressRange(NewMinAddress string, NewMaxAddress string) (err error) { + // Request structure. + request := &struct { + NewMinAddress string + + NewMaxAddress string + }{} + // BEGIN Marshal arguments into request. + + if request.NewMinAddress, err = soap.MarshalString(NewMinAddress); err != nil { + return + } + if request.NewMaxAddress, err = soap.MarshalString(NewMaxAddress); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetAddressRange", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewMinAddress: +// +// * NewMaxAddress: +func (client *LANHostConfigManagement1) GetAddressRange() (NewMinAddress string, NewMaxAddress string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewMinAddress string + + NewMaxAddress string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetAddressRange", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewMinAddress, err = soap.UnmarshalString(response.NewMinAddress); err != nil { + return + } + if NewMaxAddress, err = soap.UnmarshalString(response.NewMaxAddress); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewReservedAddresses: +// +// +func (client *LANHostConfigManagement1) SetReservedAddress(NewReservedAddresses string) (err error) { + // Request structure. + request := &struct { + NewReservedAddresses string + }{} + // BEGIN Marshal arguments into request. + + if request.NewReservedAddresses, err = soap.MarshalString(NewReservedAddresses); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetReservedAddress", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewReservedAddresses: +// +// +func (client *LANHostConfigManagement1) DeleteReservedAddress(NewReservedAddresses string) (err error) { + // Request structure. + request := &struct { + NewReservedAddresses string + }{} + // BEGIN Marshal arguments into request. + + if request.NewReservedAddresses, err = soap.MarshalString(NewReservedAddresses); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "DeleteReservedAddress", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewReservedAddresses: +func (client *LANHostConfigManagement1) GetReservedAddresses() (NewReservedAddresses string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewReservedAddresses string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetReservedAddresses", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewReservedAddresses, err = soap.UnmarshalString(response.NewReservedAddresses); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewDNSServers: +// +// +func (client *LANHostConfigManagement1) SetDNSServer(NewDNSServers string) (err error) { + // Request structure. + request := &struct { + NewDNSServers string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDNSServers, err = soap.MarshalString(NewDNSServers); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDNSServer", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewDNSServers: +// +// +func (client *LANHostConfigManagement1) DeleteDNSServer(NewDNSServers string) (err error) { + // Request structure. + request := &struct { + NewDNSServers string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDNSServers, err = soap.MarshalString(NewDNSServers); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "DeleteDNSServer", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDNSServers: +func (client *LANHostConfigManagement1) GetDNSServers() (NewDNSServers string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDNSServers string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDNSServers", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDNSServers, err = soap.UnmarshalString(response.NewDNSServers); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Layer3Forwarding1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:Layer3Forwarding:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type Layer3Forwarding1 struct { + goupnp.ServiceClient +} + +// NewLayer3Forwarding1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewLayer3Forwarding1Clients() (clients []*Layer3Forwarding1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_Layer3Forwarding_1); err != nil { + return + } + clients = make([]*Layer3Forwarding1, len(genericClients)) + for i := range genericClients { + clients[i] = &Layer3Forwarding1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewDefaultConnectionService: +// +// +func (client *Layer3Forwarding1) SetDefaultConnectionService(NewDefaultConnectionService string) (err error) { + // Request structure. + request := &struct { + NewDefaultConnectionService string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDefaultConnectionService, err = soap.MarshalString(NewDefaultConnectionService); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_Layer3Forwarding_1, "SetDefaultConnectionService", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDefaultConnectionService: +func (client *Layer3Forwarding1) GetDefaultConnectionService() (NewDefaultConnectionService string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDefaultConnectionService string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_Layer3Forwarding_1, "GetDefaultConnectionService", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDefaultConnectionService, err = soap.UnmarshalString(response.NewDefaultConnectionService); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANCableLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANCableLinkConfig:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANCableLinkConfig1 struct { + goupnp.ServiceClient +} + +// NewWANCableLinkConfig1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANCableLinkConfig1Clients() (clients []*WANCableLinkConfig1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANCableLinkConfig_1); err != nil { + return + } + clients = make([]*WANCableLinkConfig1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANCableLinkConfig1{genericClients[i]} + } + return +} + +// +// +// Return values: +// +// * NewCableLinkConfigState: allowed values: notReady, dsSyncComplete, usParamAcquired, rangingComplete, ipComplete, todEstablished, paramTransferComplete, registrationComplete, operational, accessDenied +// +// * NewLinkType: allowed values: Ethernet +func (client *WANCableLinkConfig1) GetCableLinkConfigInfo() (NewCableLinkConfigState string, NewLinkType string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewCableLinkConfigState string + + NewLinkType string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetCableLinkConfigInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewCableLinkConfigState, err = soap.UnmarshalString(response.NewCableLinkConfigState); err != nil { + return + } + if NewLinkType, err = soap.UnmarshalString(response.NewLinkType); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDownstreamFrequency: +func (client *WANCableLinkConfig1) GetDownstreamFrequency() (NewDownstreamFrequency uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDownstreamFrequency string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetDownstreamFrequency", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDownstreamFrequency, err = soap.UnmarshalUi4(response.NewDownstreamFrequency); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDownstreamModulation: allowed values: 64QAM, 256QAM +func (client *WANCableLinkConfig1) GetDownstreamModulation() (NewDownstreamModulation string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDownstreamModulation string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetDownstreamModulation", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDownstreamModulation, err = soap.UnmarshalString(response.NewDownstreamModulation); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewUpstreamFrequency: +func (client *WANCableLinkConfig1) GetUpstreamFrequency() (NewUpstreamFrequency uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewUpstreamFrequency string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamFrequency", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewUpstreamFrequency, err = soap.UnmarshalUi4(response.NewUpstreamFrequency); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewUpstreamModulation: allowed values: QPSK, 16QAM +func (client *WANCableLinkConfig1) GetUpstreamModulation() (NewUpstreamModulation string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewUpstreamModulation string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamModulation", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewUpstreamModulation, err = soap.UnmarshalString(response.NewUpstreamModulation); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewUpstreamChannelID: +func (client *WANCableLinkConfig1) GetUpstreamChannelID() (NewUpstreamChannelID uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewUpstreamChannelID string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamChannelID", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewUpstreamChannelID, err = soap.UnmarshalUi4(response.NewUpstreamChannelID); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewUpstreamPowerLevel: +func (client *WANCableLinkConfig1) GetUpstreamPowerLevel() (NewUpstreamPowerLevel uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewUpstreamPowerLevel string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamPowerLevel", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewUpstreamPowerLevel, err = soap.UnmarshalUi4(response.NewUpstreamPowerLevel); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewBPIEncryptionEnabled: +func (client *WANCableLinkConfig1) GetBPIEncryptionEnabled() (NewBPIEncryptionEnabled bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewBPIEncryptionEnabled string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetBPIEncryptionEnabled", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewBPIEncryptionEnabled, err = soap.UnmarshalBoolean(response.NewBPIEncryptionEnabled); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewConfigFile: +func (client *WANCableLinkConfig1) GetConfigFile() (NewConfigFile string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewConfigFile string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetConfigFile", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewConfigFile, err = soap.UnmarshalString(response.NewConfigFile); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewTFTPServer: +func (client *WANCableLinkConfig1) GetTFTPServer() (NewTFTPServer string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewTFTPServer string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetTFTPServer", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewTFTPServer, err = soap.UnmarshalString(response.NewTFTPServer); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANCommonInterfaceConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANCommonInterfaceConfig1 struct { + goupnp.ServiceClient +} + +// NewWANCommonInterfaceConfig1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANCommonInterfaceConfig1Clients() (clients []*WANCommonInterfaceConfig1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANCommonInterfaceConfig_1); err != nil { + return + } + clients = make([]*WANCommonInterfaceConfig1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANCommonInterfaceConfig1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewEnabledForInternet: +// +// +func (client *WANCommonInterfaceConfig1) SetEnabledForInternet(NewEnabledForInternet bool) (err error) { + // Request structure. + request := &struct { + NewEnabledForInternet string + }{} + // BEGIN Marshal arguments into request. + + if request.NewEnabledForInternet, err = soap.MarshalBoolean(NewEnabledForInternet); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "SetEnabledForInternet", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewEnabledForInternet: +func (client *WANCommonInterfaceConfig1) GetEnabledForInternet() (NewEnabledForInternet bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewEnabledForInternet string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetEnabledForInternet", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewEnabledForInternet, err = soap.UnmarshalBoolean(response.NewEnabledForInternet); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewWANAccessType: allowed values: DSL, POTS, Cable, Ethernet +// +// * NewLayer1UpstreamMaxBitRate: +// +// * NewLayer1DownstreamMaxBitRate: +// +// * NewPhysicalLinkStatus: allowed values: Up, Down +func (client *WANCommonInterfaceConfig1) GetCommonLinkProperties() (NewWANAccessType string, NewLayer1UpstreamMaxBitRate uint32, NewLayer1DownstreamMaxBitRate uint32, NewPhysicalLinkStatus string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewWANAccessType string + + NewLayer1UpstreamMaxBitRate string + + NewLayer1DownstreamMaxBitRate string + + NewPhysicalLinkStatus string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetCommonLinkProperties", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewWANAccessType, err = soap.UnmarshalString(response.NewWANAccessType); err != nil { + return + } + if NewLayer1UpstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewLayer1UpstreamMaxBitRate); err != nil { + return + } + if NewLayer1DownstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewLayer1DownstreamMaxBitRate); err != nil { + return + } + if NewPhysicalLinkStatus, err = soap.UnmarshalString(response.NewPhysicalLinkStatus); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewWANAccessProvider: +func (client *WANCommonInterfaceConfig1) GetWANAccessProvider() (NewWANAccessProvider string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewWANAccessProvider string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetWANAccessProvider", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewWANAccessProvider, err = soap.UnmarshalString(response.NewWANAccessProvider); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewMaximumActiveConnections: allowed value range: minimum=1, step=1 +func (client *WANCommonInterfaceConfig1) GetMaximumActiveConnections() (NewMaximumActiveConnections uint16, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewMaximumActiveConnections string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetMaximumActiveConnections", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewMaximumActiveConnections, err = soap.UnmarshalUi2(response.NewMaximumActiveConnections); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewTotalBytesSent: +func (client *WANCommonInterfaceConfig1) GetTotalBytesSent() (NewTotalBytesSent uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewTotalBytesSent string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalBytesSent", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewTotalBytesSent, err = soap.UnmarshalUi4(response.NewTotalBytesSent); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewTotalBytesReceived: +func (client *WANCommonInterfaceConfig1) GetTotalBytesReceived() (NewTotalBytesReceived uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewTotalBytesReceived string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalBytesReceived", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewTotalBytesReceived, err = soap.UnmarshalUi4(response.NewTotalBytesReceived); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewTotalPacketsSent: +func (client *WANCommonInterfaceConfig1) GetTotalPacketsSent() (NewTotalPacketsSent uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewTotalPacketsSent string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalPacketsSent", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewTotalPacketsSent, err = soap.UnmarshalUi4(response.NewTotalPacketsSent); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewTotalPacketsReceived: +func (client *WANCommonInterfaceConfig1) GetTotalPacketsReceived() (NewTotalPacketsReceived uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewTotalPacketsReceived string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalPacketsReceived", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewTotalPacketsReceived, err = soap.UnmarshalUi4(response.NewTotalPacketsReceived); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewActiveConnectionIndex: +// +// Return values: +// +// * NewActiveConnDeviceContainer: +// +// * NewActiveConnectionServiceID: +func (client *WANCommonInterfaceConfig1) GetActiveConnection(NewActiveConnectionIndex uint16) (NewActiveConnDeviceContainer string, NewActiveConnectionServiceID string, err error) { + // Request structure. + request := &struct { + NewActiveConnectionIndex string + }{} + // BEGIN Marshal arguments into request. + + if request.NewActiveConnectionIndex, err = soap.MarshalUi2(NewActiveConnectionIndex); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewActiveConnDeviceContainer string + + NewActiveConnectionServiceID string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetActiveConnection", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewActiveConnDeviceContainer, err = soap.UnmarshalString(response.NewActiveConnDeviceContainer); err != nil { + return + } + if NewActiveConnectionServiceID, err = soap.UnmarshalString(response.NewActiveConnectionServiceID); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANDSLLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANDSLLinkConfig:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANDSLLinkConfig1 struct { + goupnp.ServiceClient +} + +// NewWANDSLLinkConfig1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANDSLLinkConfig1Clients() (clients []*WANDSLLinkConfig1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANDSLLinkConfig_1); err != nil { + return + } + clients = make([]*WANDSLLinkConfig1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANDSLLinkConfig1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewLinkType: +// +// +func (client *WANDSLLinkConfig1) SetDSLLinkType(NewLinkType string) (err error) { + // Request structure. + request := &struct { + NewLinkType string + }{} + // BEGIN Marshal arguments into request. + + if request.NewLinkType, err = soap.MarshalString(NewLinkType); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetDSLLinkType", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewLinkType: +// +// * NewLinkStatus: allowed values: Up, Down +func (client *WANDSLLinkConfig1) GetDSLLinkInfo() (NewLinkType string, NewLinkStatus string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewLinkType string + + NewLinkStatus string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetDSLLinkInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewLinkType, err = soap.UnmarshalString(response.NewLinkType); err != nil { + return + } + if NewLinkStatus, err = soap.UnmarshalString(response.NewLinkStatus); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewAutoConfig: +func (client *WANDSLLinkConfig1) GetAutoConfig() (NewAutoConfig bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewAutoConfig string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetAutoConfig", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewAutoConfig, err = soap.UnmarshalBoolean(response.NewAutoConfig); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewModulationType: +func (client *WANDSLLinkConfig1) GetModulationType() (NewModulationType string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewModulationType string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetModulationType", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewModulationType, err = soap.UnmarshalString(response.NewModulationType); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewDestinationAddress: +// +// +func (client *WANDSLLinkConfig1) SetDestinationAddress(NewDestinationAddress string) (err error) { + // Request structure. + request := &struct { + NewDestinationAddress string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDestinationAddress, err = soap.MarshalString(NewDestinationAddress); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetDestinationAddress", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDestinationAddress: +func (client *WANDSLLinkConfig1) GetDestinationAddress() (NewDestinationAddress string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDestinationAddress string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetDestinationAddress", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDestinationAddress, err = soap.UnmarshalString(response.NewDestinationAddress); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewATMEncapsulation: +// +// +func (client *WANDSLLinkConfig1) SetATMEncapsulation(NewATMEncapsulation string) (err error) { + // Request structure. + request := &struct { + NewATMEncapsulation string + }{} + // BEGIN Marshal arguments into request. + + if request.NewATMEncapsulation, err = soap.MarshalString(NewATMEncapsulation); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetATMEncapsulation", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewATMEncapsulation: +func (client *WANDSLLinkConfig1) GetATMEncapsulation() (NewATMEncapsulation string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewATMEncapsulation string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetATMEncapsulation", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewATMEncapsulation, err = soap.UnmarshalString(response.NewATMEncapsulation); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewFCSPreserved: +// +// +func (client *WANDSLLinkConfig1) SetFCSPreserved(NewFCSPreserved bool) (err error) { + // Request structure. + request := &struct { + NewFCSPreserved string + }{} + // BEGIN Marshal arguments into request. + + if request.NewFCSPreserved, err = soap.MarshalBoolean(NewFCSPreserved); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetFCSPreserved", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewFCSPreserved: +func (client *WANDSLLinkConfig1) GetFCSPreserved() (NewFCSPreserved bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewFCSPreserved string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetFCSPreserved", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewFCSPreserved, err = soap.UnmarshalBoolean(response.NewFCSPreserved); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANEthernetLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANEthernetLinkConfig:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANEthernetLinkConfig1 struct { + goupnp.ServiceClient +} + +// NewWANEthernetLinkConfig1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANEthernetLinkConfig1Clients() (clients []*WANEthernetLinkConfig1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANEthernetLinkConfig_1); err != nil { + return + } + clients = make([]*WANEthernetLinkConfig1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANEthernetLinkConfig1{genericClients[i]} + } + return +} + +// +// +// Return values: +// +// * NewEthernetLinkStatus: allowed values: Up, Down +func (client *WANEthernetLinkConfig1) GetEthernetLinkStatus() (NewEthernetLinkStatus string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewEthernetLinkStatus string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANEthernetLinkConfig_1, "GetEthernetLinkStatus", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewEthernetLinkStatus, err = soap.UnmarshalString(response.NewEthernetLinkStatus); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANIPConnection1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANIPConnection:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANIPConnection1 struct { + goupnp.ServiceClient +} + +// NewWANIPConnection1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANIPConnection1Clients() (clients []*WANIPConnection1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANIPConnection_1); err != nil { + return + } + clients = make([]*WANIPConnection1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANIPConnection1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewConnectionType: +// +// +func (client *WANIPConnection1) SetConnectionType(NewConnectionType string) (err error) { + // Request structure. + request := &struct { + NewConnectionType string + }{} + // BEGIN Marshal arguments into request. + + if request.NewConnectionType, err = soap.MarshalString(NewConnectionType); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetConnectionType", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewConnectionType: +// +// * NewPossibleConnectionTypes: allowed values: Unconfigured, IP_Routed, IP_Bridged +func (client *WANIPConnection1) GetConnectionTypeInfo() (NewConnectionType string, NewPossibleConnectionTypes string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewConnectionType string + + NewPossibleConnectionTypes string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetConnectionTypeInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewConnectionType, err = soap.UnmarshalString(response.NewConnectionType); err != nil { + return + } + if NewPossibleConnectionTypes, err = soap.UnmarshalString(response.NewPossibleConnectionTypes); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANIPConnection1) RequestConnection() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "RequestConnection", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANIPConnection1) RequestTermination() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "RequestTermination", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANIPConnection1) ForceTermination() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "ForceTermination", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewAutoDisconnectTime: +// +// +func (client *WANIPConnection1) SetAutoDisconnectTime(NewAutoDisconnectTime uint32) (err error) { + // Request structure. + request := &struct { + NewAutoDisconnectTime string + }{} + // BEGIN Marshal arguments into request. + + if request.NewAutoDisconnectTime, err = soap.MarshalUi4(NewAutoDisconnectTime); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetAutoDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewIdleDisconnectTime: +// +// +func (client *WANIPConnection1) SetIdleDisconnectTime(NewIdleDisconnectTime uint32) (err error) { + // Request structure. + request := &struct { + NewIdleDisconnectTime string + }{} + // BEGIN Marshal arguments into request. + + if request.NewIdleDisconnectTime, err = soap.MarshalUi4(NewIdleDisconnectTime); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetIdleDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewWarnDisconnectDelay: +// +// +func (client *WANIPConnection1) SetWarnDisconnectDelay(NewWarnDisconnectDelay uint32) (err error) { + // Request structure. + request := &struct { + NewWarnDisconnectDelay string + }{} + // BEGIN Marshal arguments into request. + + if request.NewWarnDisconnectDelay, err = soap.MarshalUi4(NewWarnDisconnectDelay); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetWarnDisconnectDelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewConnectionStatus: allowed values: Unconfigured, Connected, Disconnected +// +// * NewLastConnectionError: allowed values: ERROR_NONE +// +// * NewUptime: +func (client *WANIPConnection1) GetStatusInfo() (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewConnectionStatus string + + NewLastConnectionError string + + NewUptime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetStatusInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewConnectionStatus, err = soap.UnmarshalString(response.NewConnectionStatus); err != nil { + return + } + if NewLastConnectionError, err = soap.UnmarshalString(response.NewLastConnectionError); err != nil { + return + } + if NewUptime, err = soap.UnmarshalUi4(response.NewUptime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewAutoDisconnectTime: +func (client *WANIPConnection1) GetAutoDisconnectTime() (NewAutoDisconnectTime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewAutoDisconnectTime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetAutoDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewAutoDisconnectTime, err = soap.UnmarshalUi4(response.NewAutoDisconnectTime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewIdleDisconnectTime: +func (client *WANIPConnection1) GetIdleDisconnectTime() (NewIdleDisconnectTime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewIdleDisconnectTime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetIdleDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewIdleDisconnectTime, err = soap.UnmarshalUi4(response.NewIdleDisconnectTime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewWarnDisconnectDelay: +func (client *WANIPConnection1) GetWarnDisconnectDelay() (NewWarnDisconnectDelay uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewWarnDisconnectDelay string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetWarnDisconnectDelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewWarnDisconnectDelay, err = soap.UnmarshalUi4(response.NewWarnDisconnectDelay); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewRSIPAvailable: +// +// * NewNATEnabled: +func (client *WANIPConnection1) GetNATRSIPStatus() (NewRSIPAvailable bool, NewNATEnabled bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewRSIPAvailable string + + NewNATEnabled string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetNATRSIPStatus", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewRSIPAvailable, err = soap.UnmarshalBoolean(response.NewRSIPAvailable); err != nil { + return + } + if NewNATEnabled, err = soap.UnmarshalBoolean(response.NewNATEnabled); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewPortMappingIndex: +// +// Return values: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// * NewInternalPort: +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: +func (client *WANIPConnection1) GetGenericPortMappingEntry(NewPortMappingIndex uint16) (NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { + // Request structure. + request := &struct { + NewPortMappingIndex string + }{} + // BEGIN Marshal arguments into request. + + if request.NewPortMappingIndex, err = soap.MarshalUi2(NewPortMappingIndex); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetGenericPortMappingEntry", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewRemoteHost, err = soap.UnmarshalString(response.NewRemoteHost); err != nil { + return + } + if NewExternalPort, err = soap.UnmarshalUi2(response.NewExternalPort); err != nil { + return + } + if NewProtocol, err = soap.UnmarshalString(response.NewProtocol); err != nil { + return + } + if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { + return + } + if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { + return + } + if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { + return + } + if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { + return + } + if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// Return values: +// +// * NewInternalPort: +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: +func (client *WANIPConnection1) GetSpecificPortMappingEntry(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetSpecificPortMappingEntry", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { + return + } + if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { + return + } + if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { + return + } + if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { + return + } + if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// * NewInternalPort: +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: +// +// +func (client *WANIPConnection1) AddPortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32) (err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + if request.NewInternalPort, err = soap.MarshalUi2(NewInternalPort); err != nil { + return + } + if request.NewInternalClient, err = soap.MarshalString(NewInternalClient); err != nil { + return + } + if request.NewEnabled, err = soap.MarshalBoolean(NewEnabled); err != nil { + return + } + if request.NewPortMappingDescription, err = soap.MarshalString(NewPortMappingDescription); err != nil { + return + } + if request.NewLeaseDuration, err = soap.MarshalUi4(NewLeaseDuration); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "AddPortMapping", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// +func (client *WANIPConnection1) DeletePortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "DeletePortMapping", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewExternalIPAddress: +func (client *WANIPConnection1) GetExternalIPAddress() (NewExternalIPAddress string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewExternalIPAddress string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetExternalIPAddress", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewExternalIPAddress, err = soap.UnmarshalString(response.NewExternalIPAddress); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANPOTSLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANPOTSLinkConfig:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANPOTSLinkConfig1 struct { + goupnp.ServiceClient +} + +// NewWANPOTSLinkConfig1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANPOTSLinkConfig1Clients() (clients []*WANPOTSLinkConfig1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANPOTSLinkConfig_1); err != nil { + return + } + clients = make([]*WANPOTSLinkConfig1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANPOTSLinkConfig1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewISPPhoneNumber: +// +// * NewISPInfo: +// +// * NewLinkType: allowed values: PPP_Dialup +// +// +func (client *WANPOTSLinkConfig1) SetISPInfo(NewISPPhoneNumber string, NewISPInfo string, NewLinkType string) (err error) { + // Request structure. + request := &struct { + NewISPPhoneNumber string + + NewISPInfo string + + NewLinkType string + }{} + // BEGIN Marshal arguments into request. + + if request.NewISPPhoneNumber, err = soap.MarshalString(NewISPPhoneNumber); err != nil { + return + } + if request.NewISPInfo, err = soap.MarshalString(NewISPInfo); err != nil { + return + } + if request.NewLinkType, err = soap.MarshalString(NewLinkType); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "SetISPInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewNumberOfRetries: +// +// * NewDelayBetweenRetries: +// +// +func (client *WANPOTSLinkConfig1) SetCallRetryInfo(NewNumberOfRetries uint32, NewDelayBetweenRetries uint32) (err error) { + // Request structure. + request := &struct { + NewNumberOfRetries string + + NewDelayBetweenRetries string + }{} + // BEGIN Marshal arguments into request. + + if request.NewNumberOfRetries, err = soap.MarshalUi4(NewNumberOfRetries); err != nil { + return + } + if request.NewDelayBetweenRetries, err = soap.MarshalUi4(NewDelayBetweenRetries); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "SetCallRetryInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewISPPhoneNumber: +// +// * NewISPInfo: +// +// * NewLinkType: allowed values: PPP_Dialup +func (client *WANPOTSLinkConfig1) GetISPInfo() (NewISPPhoneNumber string, NewISPInfo string, NewLinkType string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewISPPhoneNumber string + + NewISPInfo string + + NewLinkType string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetISPInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewISPPhoneNumber, err = soap.UnmarshalString(response.NewISPPhoneNumber); err != nil { + return + } + if NewISPInfo, err = soap.UnmarshalString(response.NewISPInfo); err != nil { + return + } + if NewLinkType, err = soap.UnmarshalString(response.NewLinkType); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewNumberOfRetries: +// +// * NewDelayBetweenRetries: +func (client *WANPOTSLinkConfig1) GetCallRetryInfo() (NewNumberOfRetries uint32, NewDelayBetweenRetries uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewNumberOfRetries string + + NewDelayBetweenRetries string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetCallRetryInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewNumberOfRetries, err = soap.UnmarshalUi4(response.NewNumberOfRetries); err != nil { + return + } + if NewDelayBetweenRetries, err = soap.UnmarshalUi4(response.NewDelayBetweenRetries); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewFclass: +func (client *WANPOTSLinkConfig1) GetFclass() (NewFclass string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewFclass string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetFclass", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewFclass, err = soap.UnmarshalString(response.NewFclass); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDataModulationSupported: +func (client *WANPOTSLinkConfig1) GetDataModulationSupported() (NewDataModulationSupported string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDataModulationSupported string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetDataModulationSupported", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDataModulationSupported, err = soap.UnmarshalString(response.NewDataModulationSupported); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDataProtocol: +func (client *WANPOTSLinkConfig1) GetDataProtocol() (NewDataProtocol string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDataProtocol string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetDataProtocol", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDataProtocol, err = soap.UnmarshalString(response.NewDataProtocol); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDataCompression: +func (client *WANPOTSLinkConfig1) GetDataCompression() (NewDataCompression string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDataCompression string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetDataCompression", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDataCompression, err = soap.UnmarshalString(response.NewDataCompression); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewPlusVTRCommandSupported: +func (client *WANPOTSLinkConfig1) GetPlusVTRCommandSupported() (NewPlusVTRCommandSupported bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewPlusVTRCommandSupported string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetPlusVTRCommandSupported", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewPlusVTRCommandSupported, err = soap.UnmarshalBoolean(response.NewPlusVTRCommandSupported); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANPPPConnection1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANPPPConnection:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANPPPConnection1 struct { + goupnp.ServiceClient +} + +// NewWANPPPConnection1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANPPPConnection1Clients() (clients []*WANPPPConnection1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANPPPConnection_1); err != nil { + return + } + clients = make([]*WANPPPConnection1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANPPPConnection1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewConnectionType: +// +// +func (client *WANPPPConnection1) SetConnectionType(NewConnectionType string) (err error) { + // Request structure. + request := &struct { + NewConnectionType string + }{} + // BEGIN Marshal arguments into request. + + if request.NewConnectionType, err = soap.MarshalString(NewConnectionType); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetConnectionType", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewConnectionType: +// +// * NewPossibleConnectionTypes: allowed values: Unconfigured, IP_Routed, DHCP_Spoofed, PPPoE_Bridged, PPTP_Relay, L2TP_Relay, PPPoE_Relay +func (client *WANPPPConnection1) GetConnectionTypeInfo() (NewConnectionType string, NewPossibleConnectionTypes string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewConnectionType string + + NewPossibleConnectionTypes string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetConnectionTypeInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewConnectionType, err = soap.UnmarshalString(response.NewConnectionType); err != nil { + return + } + if NewPossibleConnectionTypes, err = soap.UnmarshalString(response.NewPossibleConnectionTypes); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewUserName: +// +// * NewPassword: +// +// +func (client *WANPPPConnection1) ConfigureConnection(NewUserName string, NewPassword string) (err error) { + // Request structure. + request := &struct { + NewUserName string + + NewPassword string + }{} + // BEGIN Marshal arguments into request. + + if request.NewUserName, err = soap.MarshalString(NewUserName); err != nil { + return + } + if request.NewPassword, err = soap.MarshalString(NewPassword); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "ConfigureConnection", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANPPPConnection1) RequestConnection() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "RequestConnection", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANPPPConnection1) RequestTermination() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "RequestTermination", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANPPPConnection1) ForceTermination() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "ForceTermination", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewAutoDisconnectTime: +// +// +func (client *WANPPPConnection1) SetAutoDisconnectTime(NewAutoDisconnectTime uint32) (err error) { + // Request structure. + request := &struct { + NewAutoDisconnectTime string + }{} + // BEGIN Marshal arguments into request. + + if request.NewAutoDisconnectTime, err = soap.MarshalUi4(NewAutoDisconnectTime); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetAutoDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewIdleDisconnectTime: +// +// +func (client *WANPPPConnection1) SetIdleDisconnectTime(NewIdleDisconnectTime uint32) (err error) { + // Request structure. + request := &struct { + NewIdleDisconnectTime string + }{} + // BEGIN Marshal arguments into request. + + if request.NewIdleDisconnectTime, err = soap.MarshalUi4(NewIdleDisconnectTime); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetIdleDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewWarnDisconnectDelay: +// +// +func (client *WANPPPConnection1) SetWarnDisconnectDelay(NewWarnDisconnectDelay uint32) (err error) { + // Request structure. + request := &struct { + NewWarnDisconnectDelay string + }{} + // BEGIN Marshal arguments into request. + + if request.NewWarnDisconnectDelay, err = soap.MarshalUi4(NewWarnDisconnectDelay); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetWarnDisconnectDelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewConnectionStatus: allowed values: Unconfigured, Connected, Disconnected +// +// * NewLastConnectionError: allowed values: ERROR_NONE +// +// * NewUptime: +func (client *WANPPPConnection1) GetStatusInfo() (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewConnectionStatus string + + NewLastConnectionError string + + NewUptime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetStatusInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewConnectionStatus, err = soap.UnmarshalString(response.NewConnectionStatus); err != nil { + return + } + if NewLastConnectionError, err = soap.UnmarshalString(response.NewLastConnectionError); err != nil { + return + } + if NewUptime, err = soap.UnmarshalUi4(response.NewUptime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewUpstreamMaxBitRate: +// +// * NewDownstreamMaxBitRate: +func (client *WANPPPConnection1) GetLinkLayerMaxBitRates() (NewUpstreamMaxBitRate uint32, NewDownstreamMaxBitRate uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewUpstreamMaxBitRate string + + NewDownstreamMaxBitRate string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetLinkLayerMaxBitRates", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewUpstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewUpstreamMaxBitRate); err != nil { + return + } + if NewDownstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewDownstreamMaxBitRate); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewPPPEncryptionProtocol: +func (client *WANPPPConnection1) GetPPPEncryptionProtocol() (NewPPPEncryptionProtocol string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewPPPEncryptionProtocol string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPPPEncryptionProtocol", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewPPPEncryptionProtocol, err = soap.UnmarshalString(response.NewPPPEncryptionProtocol); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewPPPCompressionProtocol: +func (client *WANPPPConnection1) GetPPPCompressionProtocol() (NewPPPCompressionProtocol string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewPPPCompressionProtocol string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPPPCompressionProtocol", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewPPPCompressionProtocol, err = soap.UnmarshalString(response.NewPPPCompressionProtocol); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewPPPAuthenticationProtocol: +func (client *WANPPPConnection1) GetPPPAuthenticationProtocol() (NewPPPAuthenticationProtocol string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewPPPAuthenticationProtocol string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPPPAuthenticationProtocol", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewPPPAuthenticationProtocol, err = soap.UnmarshalString(response.NewPPPAuthenticationProtocol); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewUserName: +func (client *WANPPPConnection1) GetUserName() (NewUserName string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewUserName string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetUserName", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewUserName, err = soap.UnmarshalString(response.NewUserName); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewPassword: +func (client *WANPPPConnection1) GetPassword() (NewPassword string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewPassword string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPassword", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewPassword, err = soap.UnmarshalString(response.NewPassword); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewAutoDisconnectTime: +func (client *WANPPPConnection1) GetAutoDisconnectTime() (NewAutoDisconnectTime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewAutoDisconnectTime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetAutoDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewAutoDisconnectTime, err = soap.UnmarshalUi4(response.NewAutoDisconnectTime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewIdleDisconnectTime: +func (client *WANPPPConnection1) GetIdleDisconnectTime() (NewIdleDisconnectTime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewIdleDisconnectTime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetIdleDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewIdleDisconnectTime, err = soap.UnmarshalUi4(response.NewIdleDisconnectTime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewWarnDisconnectDelay: +func (client *WANPPPConnection1) GetWarnDisconnectDelay() (NewWarnDisconnectDelay uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewWarnDisconnectDelay string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetWarnDisconnectDelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewWarnDisconnectDelay, err = soap.UnmarshalUi4(response.NewWarnDisconnectDelay); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewRSIPAvailable: +// +// * NewNATEnabled: +func (client *WANPPPConnection1) GetNATRSIPStatus() (NewRSIPAvailable bool, NewNATEnabled bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewRSIPAvailable string + + NewNATEnabled string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetNATRSIPStatus", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewRSIPAvailable, err = soap.UnmarshalBoolean(response.NewRSIPAvailable); err != nil { + return + } + if NewNATEnabled, err = soap.UnmarshalBoolean(response.NewNATEnabled); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewPortMappingIndex: +// +// Return values: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// * NewInternalPort: +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: +func (client *WANPPPConnection1) GetGenericPortMappingEntry(NewPortMappingIndex uint16) (NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { + // Request structure. + request := &struct { + NewPortMappingIndex string + }{} + // BEGIN Marshal arguments into request. + + if request.NewPortMappingIndex, err = soap.MarshalUi2(NewPortMappingIndex); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetGenericPortMappingEntry", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewRemoteHost, err = soap.UnmarshalString(response.NewRemoteHost); err != nil { + return + } + if NewExternalPort, err = soap.UnmarshalUi2(response.NewExternalPort); err != nil { + return + } + if NewProtocol, err = soap.UnmarshalString(response.NewProtocol); err != nil { + return + } + if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { + return + } + if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { + return + } + if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { + return + } + if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { + return + } + if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// Return values: +// +// * NewInternalPort: +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: +func (client *WANPPPConnection1) GetSpecificPortMappingEntry(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetSpecificPortMappingEntry", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { + return + } + if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { + return + } + if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { + return + } + if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { + return + } + if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// * NewInternalPort: +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: +// +// +func (client *WANPPPConnection1) AddPortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32) (err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + if request.NewInternalPort, err = soap.MarshalUi2(NewInternalPort); err != nil { + return + } + if request.NewInternalClient, err = soap.MarshalString(NewInternalClient); err != nil { + return + } + if request.NewEnabled, err = soap.MarshalBoolean(NewEnabled); err != nil { + return + } + if request.NewPortMappingDescription, err = soap.MarshalString(NewPortMappingDescription); err != nil { + return + } + if request.NewLeaseDuration, err = soap.MarshalUi4(NewLeaseDuration); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "AddPortMapping", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// +func (client *WANPPPConnection1) DeletePortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "DeletePortMapping", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewExternalIPAddress: +func (client *WANPPPConnection1) GetExternalIPAddress() (NewExternalIPAddress string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewExternalIPAddress string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetExternalIPAddress", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewExternalIPAddress, err = soap.UnmarshalString(response.NewExternalIPAddress); err != nil { + return + } + // END Unmarshal arguments from response. + return +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway2/internetgateway2.go b/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway2/internetgateway2.go new file mode 100644 index 0000000000..a5892288e4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway2/internetgateway2.go @@ -0,0 +1,5271 @@ +// Client for UPnP Device Control Protocol Internet Gateway Device v2. +// +// This DCP is documented in detail at: http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v2-Device.pdf +// +// Typically, use one of the New* functions to discover services on the local +// network. +package internetgateway2 + +// Generated file - do not edit by hand. See README.md + +import ( + "time" + + "github.com/huin/goupnp" + "github.com/huin/goupnp/soap" +) + +// Hack to avoid Go complaining if time isn't used. +var _ time.Time + +// Device URNs: +const ( + URN_LANDevice_1 = "urn:schemas-upnp-org:device:LANDevice:1" + URN_WANConnectionDevice_1 = "urn:schemas-upnp-org:device:WANConnectionDevice:1" + URN_WANConnectionDevice_2 = "urn:schemas-upnp-org:device:WANConnectionDevice:2" + URN_WANDevice_1 = "urn:schemas-upnp-org:device:WANDevice:1" + URN_WANDevice_2 = "urn:schemas-upnp-org:device:WANDevice:2" +) + +// Service URNs: +const ( + URN_LANHostConfigManagement_1 = "urn:schemas-upnp-org:service:LANHostConfigManagement:1" + URN_Layer3Forwarding_1 = "urn:schemas-upnp-org:service:Layer3Forwarding:1" + URN_WANCableLinkConfig_1 = "urn:schemas-upnp-org:service:WANCableLinkConfig:1" + URN_WANCommonInterfaceConfig_1 = "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" + URN_WANDSLLinkConfig_1 = "urn:schemas-upnp-org:service:WANDSLLinkConfig:1" + URN_WANEthernetLinkConfig_1 = "urn:schemas-upnp-org:service:WANEthernetLinkConfig:1" + URN_WANIPConnection_1 = "urn:schemas-upnp-org:service:WANIPConnection:1" + URN_WANIPConnection_2 = "urn:schemas-upnp-org:service:WANIPConnection:2" + URN_WANIPv6FirewallControl_1 = "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" + URN_WANPOTSLinkConfig_1 = "urn:schemas-upnp-org:service:WANPOTSLinkConfig:1" + URN_WANPPPConnection_1 = "urn:schemas-upnp-org:service:WANPPPConnection:1" +) + +// LANHostConfigManagement1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:LANHostConfigManagement:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type LANHostConfigManagement1 struct { + goupnp.ServiceClient +} + +// NewLANHostConfigManagement1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewLANHostConfigManagement1Clients() (clients []*LANHostConfigManagement1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_LANHostConfigManagement_1); err != nil { + return + } + clients = make([]*LANHostConfigManagement1, len(genericClients)) + for i := range genericClients { + clients[i] = &LANHostConfigManagement1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewDHCPServerConfigurable: +// +// +func (client *LANHostConfigManagement1) SetDHCPServerConfigurable(NewDHCPServerConfigurable bool) (err error) { + // Request structure. + request := &struct { + NewDHCPServerConfigurable string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDHCPServerConfigurable, err = soap.MarshalBoolean(NewDHCPServerConfigurable); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDHCPServerConfigurable", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDHCPServerConfigurable: +func (client *LANHostConfigManagement1) GetDHCPServerConfigurable() (NewDHCPServerConfigurable bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDHCPServerConfigurable string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDHCPServerConfigurable", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDHCPServerConfigurable, err = soap.UnmarshalBoolean(response.NewDHCPServerConfigurable); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewDHCPRelay: +// +// +func (client *LANHostConfigManagement1) SetDHCPRelay(NewDHCPRelay bool) (err error) { + // Request structure. + request := &struct { + NewDHCPRelay string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDHCPRelay, err = soap.MarshalBoolean(NewDHCPRelay); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDHCPRelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDHCPRelay: +func (client *LANHostConfigManagement1) GetDHCPRelay() (NewDHCPRelay bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDHCPRelay string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDHCPRelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDHCPRelay, err = soap.UnmarshalBoolean(response.NewDHCPRelay); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewSubnetMask: +// +// +func (client *LANHostConfigManagement1) SetSubnetMask(NewSubnetMask string) (err error) { + // Request structure. + request := &struct { + NewSubnetMask string + }{} + // BEGIN Marshal arguments into request. + + if request.NewSubnetMask, err = soap.MarshalString(NewSubnetMask); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetSubnetMask", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewSubnetMask: +func (client *LANHostConfigManagement1) GetSubnetMask() (NewSubnetMask string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewSubnetMask string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetSubnetMask", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewSubnetMask, err = soap.UnmarshalString(response.NewSubnetMask); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewIPRouters: +// +// +func (client *LANHostConfigManagement1) SetIPRouter(NewIPRouters string) (err error) { + // Request structure. + request := &struct { + NewIPRouters string + }{} + // BEGIN Marshal arguments into request. + + if request.NewIPRouters, err = soap.MarshalString(NewIPRouters); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetIPRouter", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewIPRouters: +// +// +func (client *LANHostConfigManagement1) DeleteIPRouter(NewIPRouters string) (err error) { + // Request structure. + request := &struct { + NewIPRouters string + }{} + // BEGIN Marshal arguments into request. + + if request.NewIPRouters, err = soap.MarshalString(NewIPRouters); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "DeleteIPRouter", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewIPRouters: +func (client *LANHostConfigManagement1) GetIPRoutersList() (NewIPRouters string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewIPRouters string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetIPRoutersList", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewIPRouters, err = soap.UnmarshalString(response.NewIPRouters); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewDomainName: +// +// +func (client *LANHostConfigManagement1) SetDomainName(NewDomainName string) (err error) { + // Request structure. + request := &struct { + NewDomainName string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDomainName, err = soap.MarshalString(NewDomainName); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDomainName", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDomainName: +func (client *LANHostConfigManagement1) GetDomainName() (NewDomainName string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDomainName string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDomainName", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDomainName, err = soap.UnmarshalString(response.NewDomainName); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewMinAddress: +// +// * NewMaxAddress: +// +// +func (client *LANHostConfigManagement1) SetAddressRange(NewMinAddress string, NewMaxAddress string) (err error) { + // Request structure. + request := &struct { + NewMinAddress string + + NewMaxAddress string + }{} + // BEGIN Marshal arguments into request. + + if request.NewMinAddress, err = soap.MarshalString(NewMinAddress); err != nil { + return + } + if request.NewMaxAddress, err = soap.MarshalString(NewMaxAddress); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetAddressRange", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewMinAddress: +// +// * NewMaxAddress: +func (client *LANHostConfigManagement1) GetAddressRange() (NewMinAddress string, NewMaxAddress string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewMinAddress string + + NewMaxAddress string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetAddressRange", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewMinAddress, err = soap.UnmarshalString(response.NewMinAddress); err != nil { + return + } + if NewMaxAddress, err = soap.UnmarshalString(response.NewMaxAddress); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewReservedAddresses: +// +// +func (client *LANHostConfigManagement1) SetReservedAddress(NewReservedAddresses string) (err error) { + // Request structure. + request := &struct { + NewReservedAddresses string + }{} + // BEGIN Marshal arguments into request. + + if request.NewReservedAddresses, err = soap.MarshalString(NewReservedAddresses); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetReservedAddress", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewReservedAddresses: +// +// +func (client *LANHostConfigManagement1) DeleteReservedAddress(NewReservedAddresses string) (err error) { + // Request structure. + request := &struct { + NewReservedAddresses string + }{} + // BEGIN Marshal arguments into request. + + if request.NewReservedAddresses, err = soap.MarshalString(NewReservedAddresses); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "DeleteReservedAddress", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewReservedAddresses: +func (client *LANHostConfigManagement1) GetReservedAddresses() (NewReservedAddresses string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewReservedAddresses string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetReservedAddresses", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewReservedAddresses, err = soap.UnmarshalString(response.NewReservedAddresses); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewDNSServers: +// +// +func (client *LANHostConfigManagement1) SetDNSServer(NewDNSServers string) (err error) { + // Request structure. + request := &struct { + NewDNSServers string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDNSServers, err = soap.MarshalString(NewDNSServers); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDNSServer", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewDNSServers: +// +// +func (client *LANHostConfigManagement1) DeleteDNSServer(NewDNSServers string) (err error) { + // Request structure. + request := &struct { + NewDNSServers string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDNSServers, err = soap.MarshalString(NewDNSServers); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "DeleteDNSServer", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDNSServers: +func (client *LANHostConfigManagement1) GetDNSServers() (NewDNSServers string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDNSServers string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDNSServers", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDNSServers, err = soap.UnmarshalString(response.NewDNSServers); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Layer3Forwarding1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:Layer3Forwarding:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type Layer3Forwarding1 struct { + goupnp.ServiceClient +} + +// NewLayer3Forwarding1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewLayer3Forwarding1Clients() (clients []*Layer3Forwarding1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_Layer3Forwarding_1); err != nil { + return + } + clients = make([]*Layer3Forwarding1, len(genericClients)) + for i := range genericClients { + clients[i] = &Layer3Forwarding1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewDefaultConnectionService: +// +// +func (client *Layer3Forwarding1) SetDefaultConnectionService(NewDefaultConnectionService string) (err error) { + // Request structure. + request := &struct { + NewDefaultConnectionService string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDefaultConnectionService, err = soap.MarshalString(NewDefaultConnectionService); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_Layer3Forwarding_1, "SetDefaultConnectionService", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDefaultConnectionService: +func (client *Layer3Forwarding1) GetDefaultConnectionService() (NewDefaultConnectionService string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDefaultConnectionService string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_Layer3Forwarding_1, "GetDefaultConnectionService", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDefaultConnectionService, err = soap.UnmarshalString(response.NewDefaultConnectionService); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANCableLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANCableLinkConfig:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANCableLinkConfig1 struct { + goupnp.ServiceClient +} + +// NewWANCableLinkConfig1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANCableLinkConfig1Clients() (clients []*WANCableLinkConfig1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANCableLinkConfig_1); err != nil { + return + } + clients = make([]*WANCableLinkConfig1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANCableLinkConfig1{genericClients[i]} + } + return +} + +// +// +// Return values: +// +// * NewCableLinkConfigState: allowed values: notReady, dsSyncComplete, usParamAcquired, rangingComplete, ipComplete, todEstablished, paramTransferComplete, registrationComplete, operational, accessDenied +// +// * NewLinkType: allowed values: Ethernet +func (client *WANCableLinkConfig1) GetCableLinkConfigInfo() (NewCableLinkConfigState string, NewLinkType string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewCableLinkConfigState string + + NewLinkType string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetCableLinkConfigInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewCableLinkConfigState, err = soap.UnmarshalString(response.NewCableLinkConfigState); err != nil { + return + } + if NewLinkType, err = soap.UnmarshalString(response.NewLinkType); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDownstreamFrequency: +func (client *WANCableLinkConfig1) GetDownstreamFrequency() (NewDownstreamFrequency uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDownstreamFrequency string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetDownstreamFrequency", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDownstreamFrequency, err = soap.UnmarshalUi4(response.NewDownstreamFrequency); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDownstreamModulation: allowed values: 64QAM, 256QAM +func (client *WANCableLinkConfig1) GetDownstreamModulation() (NewDownstreamModulation string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDownstreamModulation string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetDownstreamModulation", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDownstreamModulation, err = soap.UnmarshalString(response.NewDownstreamModulation); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewUpstreamFrequency: +func (client *WANCableLinkConfig1) GetUpstreamFrequency() (NewUpstreamFrequency uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewUpstreamFrequency string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamFrequency", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewUpstreamFrequency, err = soap.UnmarshalUi4(response.NewUpstreamFrequency); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewUpstreamModulation: allowed values: QPSK, 16QAM +func (client *WANCableLinkConfig1) GetUpstreamModulation() (NewUpstreamModulation string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewUpstreamModulation string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamModulation", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewUpstreamModulation, err = soap.UnmarshalString(response.NewUpstreamModulation); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewUpstreamChannelID: +func (client *WANCableLinkConfig1) GetUpstreamChannelID() (NewUpstreamChannelID uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewUpstreamChannelID string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamChannelID", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewUpstreamChannelID, err = soap.UnmarshalUi4(response.NewUpstreamChannelID); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewUpstreamPowerLevel: +func (client *WANCableLinkConfig1) GetUpstreamPowerLevel() (NewUpstreamPowerLevel uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewUpstreamPowerLevel string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamPowerLevel", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewUpstreamPowerLevel, err = soap.UnmarshalUi4(response.NewUpstreamPowerLevel); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewBPIEncryptionEnabled: +func (client *WANCableLinkConfig1) GetBPIEncryptionEnabled() (NewBPIEncryptionEnabled bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewBPIEncryptionEnabled string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetBPIEncryptionEnabled", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewBPIEncryptionEnabled, err = soap.UnmarshalBoolean(response.NewBPIEncryptionEnabled); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewConfigFile: +func (client *WANCableLinkConfig1) GetConfigFile() (NewConfigFile string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewConfigFile string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetConfigFile", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewConfigFile, err = soap.UnmarshalString(response.NewConfigFile); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewTFTPServer: +func (client *WANCableLinkConfig1) GetTFTPServer() (NewTFTPServer string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewTFTPServer string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetTFTPServer", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewTFTPServer, err = soap.UnmarshalString(response.NewTFTPServer); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANCommonInterfaceConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANCommonInterfaceConfig1 struct { + goupnp.ServiceClient +} + +// NewWANCommonInterfaceConfig1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANCommonInterfaceConfig1Clients() (clients []*WANCommonInterfaceConfig1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANCommonInterfaceConfig_1); err != nil { + return + } + clients = make([]*WANCommonInterfaceConfig1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANCommonInterfaceConfig1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewEnabledForInternet: +// +// +func (client *WANCommonInterfaceConfig1) SetEnabledForInternet(NewEnabledForInternet bool) (err error) { + // Request structure. + request := &struct { + NewEnabledForInternet string + }{} + // BEGIN Marshal arguments into request. + + if request.NewEnabledForInternet, err = soap.MarshalBoolean(NewEnabledForInternet); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "SetEnabledForInternet", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewEnabledForInternet: +func (client *WANCommonInterfaceConfig1) GetEnabledForInternet() (NewEnabledForInternet bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewEnabledForInternet string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetEnabledForInternet", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewEnabledForInternet, err = soap.UnmarshalBoolean(response.NewEnabledForInternet); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewWANAccessType: allowed values: DSL, POTS, Cable, Ethernet +// +// * NewLayer1UpstreamMaxBitRate: +// +// * NewLayer1DownstreamMaxBitRate: +// +// * NewPhysicalLinkStatus: allowed values: Up, Down +func (client *WANCommonInterfaceConfig1) GetCommonLinkProperties() (NewWANAccessType string, NewLayer1UpstreamMaxBitRate uint32, NewLayer1DownstreamMaxBitRate uint32, NewPhysicalLinkStatus string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewWANAccessType string + + NewLayer1UpstreamMaxBitRate string + + NewLayer1DownstreamMaxBitRate string + + NewPhysicalLinkStatus string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetCommonLinkProperties", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewWANAccessType, err = soap.UnmarshalString(response.NewWANAccessType); err != nil { + return + } + if NewLayer1UpstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewLayer1UpstreamMaxBitRate); err != nil { + return + } + if NewLayer1DownstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewLayer1DownstreamMaxBitRate); err != nil { + return + } + if NewPhysicalLinkStatus, err = soap.UnmarshalString(response.NewPhysicalLinkStatus); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewWANAccessProvider: +func (client *WANCommonInterfaceConfig1) GetWANAccessProvider() (NewWANAccessProvider string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewWANAccessProvider string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetWANAccessProvider", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewWANAccessProvider, err = soap.UnmarshalString(response.NewWANAccessProvider); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewMaximumActiveConnections: allowed value range: minimum=1, step=1 +func (client *WANCommonInterfaceConfig1) GetMaximumActiveConnections() (NewMaximumActiveConnections uint16, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewMaximumActiveConnections string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetMaximumActiveConnections", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewMaximumActiveConnections, err = soap.UnmarshalUi2(response.NewMaximumActiveConnections); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewTotalBytesSent: +func (client *WANCommonInterfaceConfig1) GetTotalBytesSent() (NewTotalBytesSent uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewTotalBytesSent string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalBytesSent", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewTotalBytesSent, err = soap.UnmarshalUi4(response.NewTotalBytesSent); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewTotalBytesReceived: +func (client *WANCommonInterfaceConfig1) GetTotalBytesReceived() (NewTotalBytesReceived uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewTotalBytesReceived string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalBytesReceived", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewTotalBytesReceived, err = soap.UnmarshalUi4(response.NewTotalBytesReceived); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewTotalPacketsSent: +func (client *WANCommonInterfaceConfig1) GetTotalPacketsSent() (NewTotalPacketsSent uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewTotalPacketsSent string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalPacketsSent", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewTotalPacketsSent, err = soap.UnmarshalUi4(response.NewTotalPacketsSent); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewTotalPacketsReceived: +func (client *WANCommonInterfaceConfig1) GetTotalPacketsReceived() (NewTotalPacketsReceived uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewTotalPacketsReceived string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalPacketsReceived", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewTotalPacketsReceived, err = soap.UnmarshalUi4(response.NewTotalPacketsReceived); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewActiveConnectionIndex: +// +// Return values: +// +// * NewActiveConnDeviceContainer: +// +// * NewActiveConnectionServiceID: +func (client *WANCommonInterfaceConfig1) GetActiveConnection(NewActiveConnectionIndex uint16) (NewActiveConnDeviceContainer string, NewActiveConnectionServiceID string, err error) { + // Request structure. + request := &struct { + NewActiveConnectionIndex string + }{} + // BEGIN Marshal arguments into request. + + if request.NewActiveConnectionIndex, err = soap.MarshalUi2(NewActiveConnectionIndex); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewActiveConnDeviceContainer string + + NewActiveConnectionServiceID string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetActiveConnection", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewActiveConnDeviceContainer, err = soap.UnmarshalString(response.NewActiveConnDeviceContainer); err != nil { + return + } + if NewActiveConnectionServiceID, err = soap.UnmarshalString(response.NewActiveConnectionServiceID); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANDSLLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANDSLLinkConfig:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANDSLLinkConfig1 struct { + goupnp.ServiceClient +} + +// NewWANDSLLinkConfig1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANDSLLinkConfig1Clients() (clients []*WANDSLLinkConfig1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANDSLLinkConfig_1); err != nil { + return + } + clients = make([]*WANDSLLinkConfig1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANDSLLinkConfig1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewLinkType: +// +// +func (client *WANDSLLinkConfig1) SetDSLLinkType(NewLinkType string) (err error) { + // Request structure. + request := &struct { + NewLinkType string + }{} + // BEGIN Marshal arguments into request. + + if request.NewLinkType, err = soap.MarshalString(NewLinkType); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetDSLLinkType", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewLinkType: +// +// * NewLinkStatus: allowed values: Up, Down +func (client *WANDSLLinkConfig1) GetDSLLinkInfo() (NewLinkType string, NewLinkStatus string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewLinkType string + + NewLinkStatus string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetDSLLinkInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewLinkType, err = soap.UnmarshalString(response.NewLinkType); err != nil { + return + } + if NewLinkStatus, err = soap.UnmarshalString(response.NewLinkStatus); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewAutoConfig: +func (client *WANDSLLinkConfig1) GetAutoConfig() (NewAutoConfig bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewAutoConfig string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetAutoConfig", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewAutoConfig, err = soap.UnmarshalBoolean(response.NewAutoConfig); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewModulationType: +func (client *WANDSLLinkConfig1) GetModulationType() (NewModulationType string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewModulationType string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetModulationType", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewModulationType, err = soap.UnmarshalString(response.NewModulationType); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewDestinationAddress: +// +// +func (client *WANDSLLinkConfig1) SetDestinationAddress(NewDestinationAddress string) (err error) { + // Request structure. + request := &struct { + NewDestinationAddress string + }{} + // BEGIN Marshal arguments into request. + + if request.NewDestinationAddress, err = soap.MarshalString(NewDestinationAddress); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetDestinationAddress", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDestinationAddress: +func (client *WANDSLLinkConfig1) GetDestinationAddress() (NewDestinationAddress string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDestinationAddress string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetDestinationAddress", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDestinationAddress, err = soap.UnmarshalString(response.NewDestinationAddress); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewATMEncapsulation: +// +// +func (client *WANDSLLinkConfig1) SetATMEncapsulation(NewATMEncapsulation string) (err error) { + // Request structure. + request := &struct { + NewATMEncapsulation string + }{} + // BEGIN Marshal arguments into request. + + if request.NewATMEncapsulation, err = soap.MarshalString(NewATMEncapsulation); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetATMEncapsulation", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewATMEncapsulation: +func (client *WANDSLLinkConfig1) GetATMEncapsulation() (NewATMEncapsulation string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewATMEncapsulation string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetATMEncapsulation", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewATMEncapsulation, err = soap.UnmarshalString(response.NewATMEncapsulation); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewFCSPreserved: +// +// +func (client *WANDSLLinkConfig1) SetFCSPreserved(NewFCSPreserved bool) (err error) { + // Request structure. + request := &struct { + NewFCSPreserved string + }{} + // BEGIN Marshal arguments into request. + + if request.NewFCSPreserved, err = soap.MarshalBoolean(NewFCSPreserved); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetFCSPreserved", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewFCSPreserved: +func (client *WANDSLLinkConfig1) GetFCSPreserved() (NewFCSPreserved bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewFCSPreserved string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetFCSPreserved", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewFCSPreserved, err = soap.UnmarshalBoolean(response.NewFCSPreserved); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANEthernetLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANEthernetLinkConfig:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANEthernetLinkConfig1 struct { + goupnp.ServiceClient +} + +// NewWANEthernetLinkConfig1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANEthernetLinkConfig1Clients() (clients []*WANEthernetLinkConfig1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANEthernetLinkConfig_1); err != nil { + return + } + clients = make([]*WANEthernetLinkConfig1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANEthernetLinkConfig1{genericClients[i]} + } + return +} + +// +// +// Return values: +// +// * NewEthernetLinkStatus: allowed values: Up, Down +func (client *WANEthernetLinkConfig1) GetEthernetLinkStatus() (NewEthernetLinkStatus string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewEthernetLinkStatus string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANEthernetLinkConfig_1, "GetEthernetLinkStatus", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewEthernetLinkStatus, err = soap.UnmarshalString(response.NewEthernetLinkStatus); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANIPConnection1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANIPConnection:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANIPConnection1 struct { + goupnp.ServiceClient +} + +// NewWANIPConnection1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANIPConnection1Clients() (clients []*WANIPConnection1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANIPConnection_1); err != nil { + return + } + clients = make([]*WANIPConnection1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANIPConnection1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewConnectionType: +// +// +func (client *WANIPConnection1) SetConnectionType(NewConnectionType string) (err error) { + // Request structure. + request := &struct { + NewConnectionType string + }{} + // BEGIN Marshal arguments into request. + + if request.NewConnectionType, err = soap.MarshalString(NewConnectionType); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetConnectionType", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewConnectionType: +// +// * NewPossibleConnectionTypes: allowed values: Unconfigured, IP_Routed, IP_Bridged +func (client *WANIPConnection1) GetConnectionTypeInfo() (NewConnectionType string, NewPossibleConnectionTypes string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewConnectionType string + + NewPossibleConnectionTypes string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetConnectionTypeInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewConnectionType, err = soap.UnmarshalString(response.NewConnectionType); err != nil { + return + } + if NewPossibleConnectionTypes, err = soap.UnmarshalString(response.NewPossibleConnectionTypes); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANIPConnection1) RequestConnection() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "RequestConnection", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANIPConnection1) RequestTermination() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "RequestTermination", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANIPConnection1) ForceTermination() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "ForceTermination", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewAutoDisconnectTime: +// +// +func (client *WANIPConnection1) SetAutoDisconnectTime(NewAutoDisconnectTime uint32) (err error) { + // Request structure. + request := &struct { + NewAutoDisconnectTime string + }{} + // BEGIN Marshal arguments into request. + + if request.NewAutoDisconnectTime, err = soap.MarshalUi4(NewAutoDisconnectTime); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetAutoDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewIdleDisconnectTime: +// +// +func (client *WANIPConnection1) SetIdleDisconnectTime(NewIdleDisconnectTime uint32) (err error) { + // Request structure. + request := &struct { + NewIdleDisconnectTime string + }{} + // BEGIN Marshal arguments into request. + + if request.NewIdleDisconnectTime, err = soap.MarshalUi4(NewIdleDisconnectTime); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetIdleDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewWarnDisconnectDelay: +// +// +func (client *WANIPConnection1) SetWarnDisconnectDelay(NewWarnDisconnectDelay uint32) (err error) { + // Request structure. + request := &struct { + NewWarnDisconnectDelay string + }{} + // BEGIN Marshal arguments into request. + + if request.NewWarnDisconnectDelay, err = soap.MarshalUi4(NewWarnDisconnectDelay); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetWarnDisconnectDelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewConnectionStatus: allowed values: Unconfigured, Connected, Disconnected +// +// * NewLastConnectionError: allowed values: ERROR_NONE +// +// * NewUptime: +func (client *WANIPConnection1) GetStatusInfo() (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewConnectionStatus string + + NewLastConnectionError string + + NewUptime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetStatusInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewConnectionStatus, err = soap.UnmarshalString(response.NewConnectionStatus); err != nil { + return + } + if NewLastConnectionError, err = soap.UnmarshalString(response.NewLastConnectionError); err != nil { + return + } + if NewUptime, err = soap.UnmarshalUi4(response.NewUptime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewAutoDisconnectTime: +func (client *WANIPConnection1) GetAutoDisconnectTime() (NewAutoDisconnectTime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewAutoDisconnectTime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetAutoDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewAutoDisconnectTime, err = soap.UnmarshalUi4(response.NewAutoDisconnectTime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewIdleDisconnectTime: +func (client *WANIPConnection1) GetIdleDisconnectTime() (NewIdleDisconnectTime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewIdleDisconnectTime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetIdleDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewIdleDisconnectTime, err = soap.UnmarshalUi4(response.NewIdleDisconnectTime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewWarnDisconnectDelay: +func (client *WANIPConnection1) GetWarnDisconnectDelay() (NewWarnDisconnectDelay uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewWarnDisconnectDelay string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetWarnDisconnectDelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewWarnDisconnectDelay, err = soap.UnmarshalUi4(response.NewWarnDisconnectDelay); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewRSIPAvailable: +// +// * NewNATEnabled: +func (client *WANIPConnection1) GetNATRSIPStatus() (NewRSIPAvailable bool, NewNATEnabled bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewRSIPAvailable string + + NewNATEnabled string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetNATRSIPStatus", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewRSIPAvailable, err = soap.UnmarshalBoolean(response.NewRSIPAvailable); err != nil { + return + } + if NewNATEnabled, err = soap.UnmarshalBoolean(response.NewNATEnabled); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewPortMappingIndex: +// +// Return values: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// * NewInternalPort: +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: +func (client *WANIPConnection1) GetGenericPortMappingEntry(NewPortMappingIndex uint16) (NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { + // Request structure. + request := &struct { + NewPortMappingIndex string + }{} + // BEGIN Marshal arguments into request. + + if request.NewPortMappingIndex, err = soap.MarshalUi2(NewPortMappingIndex); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetGenericPortMappingEntry", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewRemoteHost, err = soap.UnmarshalString(response.NewRemoteHost); err != nil { + return + } + if NewExternalPort, err = soap.UnmarshalUi2(response.NewExternalPort); err != nil { + return + } + if NewProtocol, err = soap.UnmarshalString(response.NewProtocol); err != nil { + return + } + if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { + return + } + if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { + return + } + if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { + return + } + if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { + return + } + if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// Return values: +// +// * NewInternalPort: +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: +func (client *WANIPConnection1) GetSpecificPortMappingEntry(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetSpecificPortMappingEntry", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { + return + } + if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { + return + } + if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { + return + } + if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { + return + } + if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// * NewInternalPort: +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: +// +// +func (client *WANIPConnection1) AddPortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32) (err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + if request.NewInternalPort, err = soap.MarshalUi2(NewInternalPort); err != nil { + return + } + if request.NewInternalClient, err = soap.MarshalString(NewInternalClient); err != nil { + return + } + if request.NewEnabled, err = soap.MarshalBoolean(NewEnabled); err != nil { + return + } + if request.NewPortMappingDescription, err = soap.MarshalString(NewPortMappingDescription); err != nil { + return + } + if request.NewLeaseDuration, err = soap.MarshalUi4(NewLeaseDuration); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "AddPortMapping", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// +func (client *WANIPConnection1) DeletePortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "DeletePortMapping", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewExternalIPAddress: +func (client *WANIPConnection1) GetExternalIPAddress() (NewExternalIPAddress string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewExternalIPAddress string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetExternalIPAddress", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewExternalIPAddress, err = soap.UnmarshalString(response.NewExternalIPAddress); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANIPConnection2 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANIPConnection:2". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANIPConnection2 struct { + goupnp.ServiceClient +} + +// NewWANIPConnection2Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANIPConnection2Clients() (clients []*WANIPConnection2, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANIPConnection_2); err != nil { + return + } + clients = make([]*WANIPConnection2, len(genericClients)) + for i := range genericClients { + clients[i] = &WANIPConnection2{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewConnectionType: allowed values: Unconfigured, IP_Routed, IP_Bridged +// +// +func (client *WANIPConnection2) SetConnectionType(NewConnectionType string) (err error) { + // Request structure. + request := &struct { + NewConnectionType string + }{} + // BEGIN Marshal arguments into request. + + if request.NewConnectionType, err = soap.MarshalString(NewConnectionType); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "SetConnectionType", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewConnectionType: allowed values: Unconfigured, IP_Routed, IP_Bridged +// +// * NewPossibleConnectionTypes: +func (client *WANIPConnection2) GetConnectionTypeInfo() (NewConnectionType string, NewPossibleConnectionTypes string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewConnectionType string + + NewPossibleConnectionTypes string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetConnectionTypeInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewConnectionType, err = soap.UnmarshalString(response.NewConnectionType); err != nil { + return + } + if NewPossibleConnectionTypes, err = soap.UnmarshalString(response.NewPossibleConnectionTypes); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANIPConnection2) RequestConnection() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "RequestConnection", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANIPConnection2) RequestTermination() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "RequestTermination", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANIPConnection2) ForceTermination() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "ForceTermination", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewAutoDisconnectTime: +// +// +func (client *WANIPConnection2) SetAutoDisconnectTime(NewAutoDisconnectTime uint32) (err error) { + // Request structure. + request := &struct { + NewAutoDisconnectTime string + }{} + // BEGIN Marshal arguments into request. + + if request.NewAutoDisconnectTime, err = soap.MarshalUi4(NewAutoDisconnectTime); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "SetAutoDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewIdleDisconnectTime: +// +// +func (client *WANIPConnection2) SetIdleDisconnectTime(NewIdleDisconnectTime uint32) (err error) { + // Request structure. + request := &struct { + NewIdleDisconnectTime string + }{} + // BEGIN Marshal arguments into request. + + if request.NewIdleDisconnectTime, err = soap.MarshalUi4(NewIdleDisconnectTime); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "SetIdleDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewWarnDisconnectDelay: +// +// +func (client *WANIPConnection2) SetWarnDisconnectDelay(NewWarnDisconnectDelay uint32) (err error) { + // Request structure. + request := &struct { + NewWarnDisconnectDelay string + }{} + // BEGIN Marshal arguments into request. + + if request.NewWarnDisconnectDelay, err = soap.MarshalUi4(NewWarnDisconnectDelay); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "SetWarnDisconnectDelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewConnectionStatus: allowed values: Unconfigured, Connected, Disconnected +// +// * NewLastConnectionError: allowed values: ERROR_NONE +// +// * NewUptime: +func (client *WANIPConnection2) GetStatusInfo() (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewConnectionStatus string + + NewLastConnectionError string + + NewUptime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetStatusInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewConnectionStatus, err = soap.UnmarshalString(response.NewConnectionStatus); err != nil { + return + } + if NewLastConnectionError, err = soap.UnmarshalString(response.NewLastConnectionError); err != nil { + return + } + if NewUptime, err = soap.UnmarshalUi4(response.NewUptime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewAutoDisconnectTime: +func (client *WANIPConnection2) GetAutoDisconnectTime() (NewAutoDisconnectTime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewAutoDisconnectTime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetAutoDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewAutoDisconnectTime, err = soap.UnmarshalUi4(response.NewAutoDisconnectTime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewIdleDisconnectTime: +func (client *WANIPConnection2) GetIdleDisconnectTime() (NewIdleDisconnectTime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewIdleDisconnectTime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetIdleDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewIdleDisconnectTime, err = soap.UnmarshalUi4(response.NewIdleDisconnectTime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewWarnDisconnectDelay: +func (client *WANIPConnection2) GetWarnDisconnectDelay() (NewWarnDisconnectDelay uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewWarnDisconnectDelay string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetWarnDisconnectDelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewWarnDisconnectDelay, err = soap.UnmarshalUi4(response.NewWarnDisconnectDelay); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewRSIPAvailable: +// +// * NewNATEnabled: +func (client *WANIPConnection2) GetNATRSIPStatus() (NewRSIPAvailable bool, NewNATEnabled bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewRSIPAvailable string + + NewNATEnabled string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetNATRSIPStatus", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewRSIPAvailable, err = soap.UnmarshalBoolean(response.NewRSIPAvailable); err != nil { + return + } + if NewNATEnabled, err = soap.UnmarshalBoolean(response.NewNATEnabled); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewPortMappingIndex: +// +// Return values: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// * NewInternalPort: allowed value range: minimum=1, maximum=65535 +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: allowed value range: minimum=0, maximum=604800 +func (client *WANIPConnection2) GetGenericPortMappingEntry(NewPortMappingIndex uint16) (NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { + // Request structure. + request := &struct { + NewPortMappingIndex string + }{} + // BEGIN Marshal arguments into request. + + if request.NewPortMappingIndex, err = soap.MarshalUi2(NewPortMappingIndex); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetGenericPortMappingEntry", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewRemoteHost, err = soap.UnmarshalString(response.NewRemoteHost); err != nil { + return + } + if NewExternalPort, err = soap.UnmarshalUi2(response.NewExternalPort); err != nil { + return + } + if NewProtocol, err = soap.UnmarshalString(response.NewProtocol); err != nil { + return + } + if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { + return + } + if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { + return + } + if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { + return + } + if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { + return + } + if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// Return values: +// +// * NewInternalPort: allowed value range: minimum=1, maximum=65535 +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: allowed value range: minimum=0, maximum=604800 +func (client *WANIPConnection2) GetSpecificPortMappingEntry(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetSpecificPortMappingEntry", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { + return + } + if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { + return + } + if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { + return + } + if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { + return + } + if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// * NewInternalPort: allowed value range: minimum=1, maximum=65535 +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: allowed value range: minimum=0, maximum=604800 +// +// +func (client *WANIPConnection2) AddPortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32) (err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + if request.NewInternalPort, err = soap.MarshalUi2(NewInternalPort); err != nil { + return + } + if request.NewInternalClient, err = soap.MarshalString(NewInternalClient); err != nil { + return + } + if request.NewEnabled, err = soap.MarshalBoolean(NewEnabled); err != nil { + return + } + if request.NewPortMappingDescription, err = soap.MarshalString(NewPortMappingDescription); err != nil { + return + } + if request.NewLeaseDuration, err = soap.MarshalUi4(NewLeaseDuration); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "AddPortMapping", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// +func (client *WANIPConnection2) DeletePortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "DeletePortMapping", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewStartPort: +// +// * NewEndPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// * NewManage: +// +// +func (client *WANIPConnection2) DeletePortMappingRange(NewStartPort uint16, NewEndPort uint16, NewProtocol string, NewManage bool) (err error) { + // Request structure. + request := &struct { + NewStartPort string + + NewEndPort string + + NewProtocol string + + NewManage string + }{} + // BEGIN Marshal arguments into request. + + if request.NewStartPort, err = soap.MarshalUi2(NewStartPort); err != nil { + return + } + if request.NewEndPort, err = soap.MarshalUi2(NewEndPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + if request.NewManage, err = soap.MarshalBoolean(NewManage); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "DeletePortMappingRange", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewExternalIPAddress: +func (client *WANIPConnection2) GetExternalIPAddress() (NewExternalIPAddress string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewExternalIPAddress string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetExternalIPAddress", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewExternalIPAddress, err = soap.UnmarshalString(response.NewExternalIPAddress); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewStartPort: +// +// * NewEndPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// * NewManage: +// +// * NewNumberOfPorts: +// +// Return values: +// +// * NewPortListing: +func (client *WANIPConnection2) GetListOfPortMappings(NewStartPort uint16, NewEndPort uint16, NewProtocol string, NewManage bool, NewNumberOfPorts uint16) (NewPortListing string, err error) { + // Request structure. + request := &struct { + NewStartPort string + + NewEndPort string + + NewProtocol string + + NewManage string + + NewNumberOfPorts string + }{} + // BEGIN Marshal arguments into request. + + if request.NewStartPort, err = soap.MarshalUi2(NewStartPort); err != nil { + return + } + if request.NewEndPort, err = soap.MarshalUi2(NewEndPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + if request.NewManage, err = soap.MarshalBoolean(NewManage); err != nil { + return + } + if request.NewNumberOfPorts, err = soap.MarshalUi2(NewNumberOfPorts); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewPortListing string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetListOfPortMappings", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewPortListing, err = soap.UnmarshalString(response.NewPortListing); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// * NewInternalPort: allowed value range: minimum=1, maximum=65535 +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: allowed value range: minimum=0, maximum=604800 +// +// Return values: +// +// * NewReservedPort: +func (client *WANIPConnection2) AddAnyPortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32) (NewReservedPort uint16, err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + if request.NewInternalPort, err = soap.MarshalUi2(NewInternalPort); err != nil { + return + } + if request.NewInternalClient, err = soap.MarshalString(NewInternalClient); err != nil { + return + } + if request.NewEnabled, err = soap.MarshalBoolean(NewEnabled); err != nil { + return + } + if request.NewPortMappingDescription, err = soap.MarshalString(NewPortMappingDescription); err != nil { + return + } + if request.NewLeaseDuration, err = soap.MarshalUi4(NewLeaseDuration); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewReservedPort string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "AddAnyPortMapping", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewReservedPort, err = soap.UnmarshalUi2(response.NewReservedPort); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANIPv6FirewallControl1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANIPv6FirewallControl1 struct { + goupnp.ServiceClient +} + +// NewWANIPv6FirewallControl1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANIPv6FirewallControl1Clients() (clients []*WANIPv6FirewallControl1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANIPv6FirewallControl_1); err != nil { + return + } + clients = make([]*WANIPv6FirewallControl1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANIPv6FirewallControl1{genericClients[i]} + } + return +} + +// +// +// Return values: +// +// * FirewallEnabled: +// +// * InboundPinholeAllowed: +func (client *WANIPv6FirewallControl1) GetFirewallStatus() (FirewallEnabled bool, InboundPinholeAllowed bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + FirewallEnabled string + + InboundPinholeAllowed string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "GetFirewallStatus", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if FirewallEnabled, err = soap.UnmarshalBoolean(response.FirewallEnabled); err != nil { + return + } + if InboundPinholeAllowed, err = soap.UnmarshalBoolean(response.InboundPinholeAllowed); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * RemoteHost: +// +// * RemotePort: +// +// * InternalClient: +// +// * InternalPort: +// +// * Protocol: +// +// Return values: +// +// * OutboundPinholeTimeout: +func (client *WANIPv6FirewallControl1) GetOutboundPinholeTimeout(RemoteHost string, RemotePort uint16, InternalClient string, InternalPort uint16, Protocol uint16) (OutboundPinholeTimeout uint32, err error) { + // Request structure. + request := &struct { + RemoteHost string + + RemotePort string + + InternalClient string + + InternalPort string + + Protocol string + }{} + // BEGIN Marshal arguments into request. + + if request.RemoteHost, err = soap.MarshalString(RemoteHost); err != nil { + return + } + if request.RemotePort, err = soap.MarshalUi2(RemotePort); err != nil { + return + } + if request.InternalClient, err = soap.MarshalString(InternalClient); err != nil { + return + } + if request.InternalPort, err = soap.MarshalUi2(InternalPort); err != nil { + return + } + if request.Protocol, err = soap.MarshalUi2(Protocol); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + OutboundPinholeTimeout string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "GetOutboundPinholeTimeout", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if OutboundPinholeTimeout, err = soap.UnmarshalUi4(response.OutboundPinholeTimeout); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * RemoteHost: +// +// * RemotePort: +// +// * InternalClient: +// +// * InternalPort: +// +// * Protocol: +// +// * LeaseTime: allowed value range: minimum=1, maximum=86400 +// +// Return values: +// +// * UniqueID: +func (client *WANIPv6FirewallControl1) AddPinhole(RemoteHost string, RemotePort uint16, InternalClient string, InternalPort uint16, Protocol uint16, LeaseTime uint32) (UniqueID uint16, err error) { + // Request structure. + request := &struct { + RemoteHost string + + RemotePort string + + InternalClient string + + InternalPort string + + Protocol string + + LeaseTime string + }{} + // BEGIN Marshal arguments into request. + + if request.RemoteHost, err = soap.MarshalString(RemoteHost); err != nil { + return + } + if request.RemotePort, err = soap.MarshalUi2(RemotePort); err != nil { + return + } + if request.InternalClient, err = soap.MarshalString(InternalClient); err != nil { + return + } + if request.InternalPort, err = soap.MarshalUi2(InternalPort); err != nil { + return + } + if request.Protocol, err = soap.MarshalUi2(Protocol); err != nil { + return + } + if request.LeaseTime, err = soap.MarshalUi4(LeaseTime); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + UniqueID string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "AddPinhole", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if UniqueID, err = soap.UnmarshalUi2(response.UniqueID); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * UniqueID: +// +// * NewLeaseTime: allowed value range: minimum=1, maximum=86400 +// +// +func (client *WANIPv6FirewallControl1) UpdatePinhole(UniqueID uint16, NewLeaseTime uint32) (err error) { + // Request structure. + request := &struct { + UniqueID string + + NewLeaseTime string + }{} + // BEGIN Marshal arguments into request. + + if request.UniqueID, err = soap.MarshalUi2(UniqueID); err != nil { + return + } + if request.NewLeaseTime, err = soap.MarshalUi4(NewLeaseTime); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "UpdatePinhole", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * UniqueID: +// +// +func (client *WANIPv6FirewallControl1) DeletePinhole(UniqueID uint16) (err error) { + // Request structure. + request := &struct { + UniqueID string + }{} + // BEGIN Marshal arguments into request. + + if request.UniqueID, err = soap.MarshalUi2(UniqueID); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "DeletePinhole", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * UniqueID: +// +// Return values: +// +// * PinholePackets: +func (client *WANIPv6FirewallControl1) GetPinholePackets(UniqueID uint16) (PinholePackets uint32, err error) { + // Request structure. + request := &struct { + UniqueID string + }{} + // BEGIN Marshal arguments into request. + + if request.UniqueID, err = soap.MarshalUi2(UniqueID); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + PinholePackets string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "GetPinholePackets", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if PinholePackets, err = soap.UnmarshalUi4(response.PinholePackets); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * UniqueID: +// +// Return values: +// +// * IsWorking: +func (client *WANIPv6FirewallControl1) CheckPinholeWorking(UniqueID uint16) (IsWorking bool, err error) { + // Request structure. + request := &struct { + UniqueID string + }{} + // BEGIN Marshal arguments into request. + + if request.UniqueID, err = soap.MarshalUi2(UniqueID); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + IsWorking string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "CheckPinholeWorking", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if IsWorking, err = soap.UnmarshalBoolean(response.IsWorking); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANPOTSLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANPOTSLinkConfig:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANPOTSLinkConfig1 struct { + goupnp.ServiceClient +} + +// NewWANPOTSLinkConfig1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANPOTSLinkConfig1Clients() (clients []*WANPOTSLinkConfig1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANPOTSLinkConfig_1); err != nil { + return + } + clients = make([]*WANPOTSLinkConfig1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANPOTSLinkConfig1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewISPPhoneNumber: +// +// * NewISPInfo: +// +// * NewLinkType: allowed values: PPP_Dialup +// +// +func (client *WANPOTSLinkConfig1) SetISPInfo(NewISPPhoneNumber string, NewISPInfo string, NewLinkType string) (err error) { + // Request structure. + request := &struct { + NewISPPhoneNumber string + + NewISPInfo string + + NewLinkType string + }{} + // BEGIN Marshal arguments into request. + + if request.NewISPPhoneNumber, err = soap.MarshalString(NewISPPhoneNumber); err != nil { + return + } + if request.NewISPInfo, err = soap.MarshalString(NewISPInfo); err != nil { + return + } + if request.NewLinkType, err = soap.MarshalString(NewLinkType); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "SetISPInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewNumberOfRetries: +// +// * NewDelayBetweenRetries: +// +// +func (client *WANPOTSLinkConfig1) SetCallRetryInfo(NewNumberOfRetries uint32, NewDelayBetweenRetries uint32) (err error) { + // Request structure. + request := &struct { + NewNumberOfRetries string + + NewDelayBetweenRetries string + }{} + // BEGIN Marshal arguments into request. + + if request.NewNumberOfRetries, err = soap.MarshalUi4(NewNumberOfRetries); err != nil { + return + } + if request.NewDelayBetweenRetries, err = soap.MarshalUi4(NewDelayBetweenRetries); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "SetCallRetryInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewISPPhoneNumber: +// +// * NewISPInfo: +// +// * NewLinkType: allowed values: PPP_Dialup +func (client *WANPOTSLinkConfig1) GetISPInfo() (NewISPPhoneNumber string, NewISPInfo string, NewLinkType string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewISPPhoneNumber string + + NewISPInfo string + + NewLinkType string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetISPInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewISPPhoneNumber, err = soap.UnmarshalString(response.NewISPPhoneNumber); err != nil { + return + } + if NewISPInfo, err = soap.UnmarshalString(response.NewISPInfo); err != nil { + return + } + if NewLinkType, err = soap.UnmarshalString(response.NewLinkType); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewNumberOfRetries: +// +// * NewDelayBetweenRetries: +func (client *WANPOTSLinkConfig1) GetCallRetryInfo() (NewNumberOfRetries uint32, NewDelayBetweenRetries uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewNumberOfRetries string + + NewDelayBetweenRetries string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetCallRetryInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewNumberOfRetries, err = soap.UnmarshalUi4(response.NewNumberOfRetries); err != nil { + return + } + if NewDelayBetweenRetries, err = soap.UnmarshalUi4(response.NewDelayBetweenRetries); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewFclass: +func (client *WANPOTSLinkConfig1) GetFclass() (NewFclass string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewFclass string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetFclass", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewFclass, err = soap.UnmarshalString(response.NewFclass); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDataModulationSupported: +func (client *WANPOTSLinkConfig1) GetDataModulationSupported() (NewDataModulationSupported string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDataModulationSupported string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetDataModulationSupported", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDataModulationSupported, err = soap.UnmarshalString(response.NewDataModulationSupported); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDataProtocol: +func (client *WANPOTSLinkConfig1) GetDataProtocol() (NewDataProtocol string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDataProtocol string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetDataProtocol", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDataProtocol, err = soap.UnmarshalString(response.NewDataProtocol); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewDataCompression: +func (client *WANPOTSLinkConfig1) GetDataCompression() (NewDataCompression string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewDataCompression string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetDataCompression", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewDataCompression, err = soap.UnmarshalString(response.NewDataCompression); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewPlusVTRCommandSupported: +func (client *WANPOTSLinkConfig1) GetPlusVTRCommandSupported() (NewPlusVTRCommandSupported bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewPlusVTRCommandSupported string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetPlusVTRCommandSupported", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewPlusVTRCommandSupported, err = soap.UnmarshalBoolean(response.NewPlusVTRCommandSupported); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// WANPPPConnection1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANPPPConnection:1". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type WANPPPConnection1 struct { + goupnp.ServiceClient +} + +// NewWANPPPConnection1Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func NewWANPPPConnection1Clients() (clients []*WANPPPConnection1, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients(URN_WANPPPConnection_1); err != nil { + return + } + clients = make([]*WANPPPConnection1, len(genericClients)) + for i := range genericClients { + clients[i] = &WANPPPConnection1{genericClients[i]} + } + return +} + +// Arguments: +// +// * NewConnectionType: +// +// +func (client *WANPPPConnection1) SetConnectionType(NewConnectionType string) (err error) { + // Request structure. + request := &struct { + NewConnectionType string + }{} + // BEGIN Marshal arguments into request. + + if request.NewConnectionType, err = soap.MarshalString(NewConnectionType); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetConnectionType", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewConnectionType: +// +// * NewPossibleConnectionTypes: allowed values: Unconfigured, IP_Routed, DHCP_Spoofed, PPPoE_Bridged, PPTP_Relay, L2TP_Relay, PPPoE_Relay +func (client *WANPPPConnection1) GetConnectionTypeInfo() (NewConnectionType string, NewPossibleConnectionTypes string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewConnectionType string + + NewPossibleConnectionTypes string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetConnectionTypeInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewConnectionType, err = soap.UnmarshalString(response.NewConnectionType); err != nil { + return + } + if NewPossibleConnectionTypes, err = soap.UnmarshalString(response.NewPossibleConnectionTypes); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewUserName: +// +// * NewPassword: +// +// +func (client *WANPPPConnection1) ConfigureConnection(NewUserName string, NewPassword string) (err error) { + // Request structure. + request := &struct { + NewUserName string + + NewPassword string + }{} + // BEGIN Marshal arguments into request. + + if request.NewUserName, err = soap.MarshalString(NewUserName); err != nil { + return + } + if request.NewPassword, err = soap.MarshalString(NewPassword); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "ConfigureConnection", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANPPPConnection1) RequestConnection() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "RequestConnection", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANPPPConnection1) RequestTermination() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "RequestTermination", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// +func (client *WANPPPConnection1) ForceTermination() (err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "ForceTermination", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewAutoDisconnectTime: +// +// +func (client *WANPPPConnection1) SetAutoDisconnectTime(NewAutoDisconnectTime uint32) (err error) { + // Request structure. + request := &struct { + NewAutoDisconnectTime string + }{} + // BEGIN Marshal arguments into request. + + if request.NewAutoDisconnectTime, err = soap.MarshalUi4(NewAutoDisconnectTime); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetAutoDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewIdleDisconnectTime: +// +// +func (client *WANPPPConnection1) SetIdleDisconnectTime(NewIdleDisconnectTime uint32) (err error) { + // Request structure. + request := &struct { + NewIdleDisconnectTime string + }{} + // BEGIN Marshal arguments into request. + + if request.NewIdleDisconnectTime, err = soap.MarshalUi4(NewIdleDisconnectTime); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetIdleDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewWarnDisconnectDelay: +// +// +func (client *WANPPPConnection1) SetWarnDisconnectDelay(NewWarnDisconnectDelay uint32) (err error) { + // Request structure. + request := &struct { + NewWarnDisconnectDelay string + }{} + // BEGIN Marshal arguments into request. + + if request.NewWarnDisconnectDelay, err = soap.MarshalUi4(NewWarnDisconnectDelay); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetWarnDisconnectDelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewConnectionStatus: allowed values: Unconfigured, Connected, Disconnected +// +// * NewLastConnectionError: allowed values: ERROR_NONE +// +// * NewUptime: +func (client *WANPPPConnection1) GetStatusInfo() (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewConnectionStatus string + + NewLastConnectionError string + + NewUptime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetStatusInfo", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewConnectionStatus, err = soap.UnmarshalString(response.NewConnectionStatus); err != nil { + return + } + if NewLastConnectionError, err = soap.UnmarshalString(response.NewLastConnectionError); err != nil { + return + } + if NewUptime, err = soap.UnmarshalUi4(response.NewUptime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewUpstreamMaxBitRate: +// +// * NewDownstreamMaxBitRate: +func (client *WANPPPConnection1) GetLinkLayerMaxBitRates() (NewUpstreamMaxBitRate uint32, NewDownstreamMaxBitRate uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewUpstreamMaxBitRate string + + NewDownstreamMaxBitRate string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetLinkLayerMaxBitRates", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewUpstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewUpstreamMaxBitRate); err != nil { + return + } + if NewDownstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewDownstreamMaxBitRate); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewPPPEncryptionProtocol: +func (client *WANPPPConnection1) GetPPPEncryptionProtocol() (NewPPPEncryptionProtocol string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewPPPEncryptionProtocol string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPPPEncryptionProtocol", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewPPPEncryptionProtocol, err = soap.UnmarshalString(response.NewPPPEncryptionProtocol); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewPPPCompressionProtocol: +func (client *WANPPPConnection1) GetPPPCompressionProtocol() (NewPPPCompressionProtocol string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewPPPCompressionProtocol string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPPPCompressionProtocol", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewPPPCompressionProtocol, err = soap.UnmarshalString(response.NewPPPCompressionProtocol); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewPPPAuthenticationProtocol: +func (client *WANPPPConnection1) GetPPPAuthenticationProtocol() (NewPPPAuthenticationProtocol string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewPPPAuthenticationProtocol string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPPPAuthenticationProtocol", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewPPPAuthenticationProtocol, err = soap.UnmarshalString(response.NewPPPAuthenticationProtocol); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewUserName: +func (client *WANPPPConnection1) GetUserName() (NewUserName string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewUserName string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetUserName", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewUserName, err = soap.UnmarshalString(response.NewUserName); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewPassword: +func (client *WANPPPConnection1) GetPassword() (NewPassword string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewPassword string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPassword", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewPassword, err = soap.UnmarshalString(response.NewPassword); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewAutoDisconnectTime: +func (client *WANPPPConnection1) GetAutoDisconnectTime() (NewAutoDisconnectTime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewAutoDisconnectTime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetAutoDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewAutoDisconnectTime, err = soap.UnmarshalUi4(response.NewAutoDisconnectTime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewIdleDisconnectTime: +func (client *WANPPPConnection1) GetIdleDisconnectTime() (NewIdleDisconnectTime uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewIdleDisconnectTime string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetIdleDisconnectTime", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewIdleDisconnectTime, err = soap.UnmarshalUi4(response.NewIdleDisconnectTime); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewWarnDisconnectDelay: +func (client *WANPPPConnection1) GetWarnDisconnectDelay() (NewWarnDisconnectDelay uint32, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewWarnDisconnectDelay string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetWarnDisconnectDelay", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewWarnDisconnectDelay, err = soap.UnmarshalUi4(response.NewWarnDisconnectDelay); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewRSIPAvailable: +// +// * NewNATEnabled: +func (client *WANPPPConnection1) GetNATRSIPStatus() (NewRSIPAvailable bool, NewNATEnabled bool, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewRSIPAvailable string + + NewNATEnabled string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetNATRSIPStatus", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewRSIPAvailable, err = soap.UnmarshalBoolean(response.NewRSIPAvailable); err != nil { + return + } + if NewNATEnabled, err = soap.UnmarshalBoolean(response.NewNATEnabled); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewPortMappingIndex: +// +// Return values: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// * NewInternalPort: +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: +func (client *WANPPPConnection1) GetGenericPortMappingEntry(NewPortMappingIndex uint16) (NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { + // Request structure. + request := &struct { + NewPortMappingIndex string + }{} + // BEGIN Marshal arguments into request. + + if request.NewPortMappingIndex, err = soap.MarshalUi2(NewPortMappingIndex); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetGenericPortMappingEntry", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewRemoteHost, err = soap.UnmarshalString(response.NewRemoteHost); err != nil { + return + } + if NewExternalPort, err = soap.UnmarshalUi2(response.NewExternalPort); err != nil { + return + } + if NewProtocol, err = soap.UnmarshalString(response.NewProtocol); err != nil { + return + } + if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { + return + } + if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { + return + } + if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { + return + } + if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { + return + } + if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// Return values: +// +// * NewInternalPort: +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: +func (client *WANPPPConnection1) GetSpecificPortMappingEntry(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetSpecificPortMappingEntry", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { + return + } + if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { + return + } + if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { + return + } + if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { + return + } + if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { + return + } + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// * NewInternalPort: +// +// * NewInternalClient: +// +// * NewEnabled: +// +// * NewPortMappingDescription: +// +// * NewLeaseDuration: +// +// +func (client *WANPPPConnection1) AddPortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32) (err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + + NewInternalPort string + + NewInternalClient string + + NewEnabled string + + NewPortMappingDescription string + + NewLeaseDuration string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + if request.NewInternalPort, err = soap.MarshalUi2(NewInternalPort); err != nil { + return + } + if request.NewInternalClient, err = soap.MarshalString(NewInternalClient); err != nil { + return + } + if request.NewEnabled, err = soap.MarshalBoolean(NewEnabled); err != nil { + return + } + if request.NewPortMappingDescription, err = soap.MarshalString(NewPortMappingDescription); err != nil { + return + } + if request.NewLeaseDuration, err = soap.MarshalUi4(NewLeaseDuration); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "AddPortMapping", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// Arguments: +// +// * NewRemoteHost: +// +// * NewExternalPort: +// +// * NewProtocol: allowed values: TCP, UDP +// +// +func (client *WANPPPConnection1) DeletePortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { + // Request structure. + request := &struct { + NewRemoteHost string + + NewExternalPort string + + NewProtocol string + }{} + // BEGIN Marshal arguments into request. + + if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { + return + } + if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { + return + } + if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { + return + } + // END Marshal arguments into request. + + // Response structure. + response := interface{}(nil) + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "DeletePortMapping", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + // END Unmarshal arguments from response. + return +} + +// +// +// Return values: +// +// * NewExternalIPAddress: +func (client *WANPPPConnection1) GetExternalIPAddress() (NewExternalIPAddress string, err error) { + // Request structure. + request := interface{}(nil) + // BEGIN Marshal arguments into request. + + // END Marshal arguments into request. + + // Response structure. + response := &struct { + NewExternalIPAddress string + }{} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetExternalIPAddress", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. + + if NewExternalIPAddress, err = soap.UnmarshalString(response.NewExternalIPAddress); err != nil { + return + } + // END Unmarshal arguments from response. + return +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/device.go b/Godeps/_workspace/src/github.com/huin/goupnp/device.go new file mode 100644 index 0000000000..e5b658b21a --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/device.go @@ -0,0 +1,184 @@ +// This file contains XML structures for communicating with UPnP devices. + +package goupnp + +import ( + "encoding/xml" + "errors" + "fmt" + "net/url" + + "github.com/huin/goupnp/scpd" + "github.com/huin/goupnp/soap" +) + +const ( + DeviceXMLNamespace = "urn:schemas-upnp-org:device-1-0" +) + +// RootDevice is the device description as described by section 2.3 "Device +// description" in +// http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf +type RootDevice struct { + XMLName xml.Name `xml:"root"` + SpecVersion SpecVersion `xml:"specVersion"` + URLBase url.URL `xml:"-"` + URLBaseStr string `xml:"URLBase"` + Device Device `xml:"device"` +} + +// SetURLBase sets the URLBase for the RootDevice and its underlying components. +func (root *RootDevice) SetURLBase(urlBase *url.URL) { + root.URLBase = *urlBase + root.URLBaseStr = urlBase.String() + root.Device.SetURLBase(urlBase) +} + +// SpecVersion is part of a RootDevice, describes the version of the +// specification that the data adheres to. +type SpecVersion struct { + Major int32 `xml:"major"` + Minor int32 `xml:"minor"` +} + +// Device is a UPnP device. It can have child devices. +type Device struct { + DeviceType string `xml:"deviceType"` + FriendlyName string `xml:"friendlyName"` + Manufacturer string `xml:"manufacturer"` + ManufacturerURL URLField `xml:"manufacturerURL"` + ModelDescription string `xml:"modelDescription"` + ModelName string `xml:"modelName"` + ModelNumber string `xml:"modelNumber"` + ModelURL URLField `xml:"modelURL"` + SerialNumber string `xml:"serialNumber"` + UDN string `xml:"UDN"` + UPC string `xml:"UPC,omitempty"` + Icons []Icon `xml:"iconList>icon,omitempty"` + Services []Service `xml:"serviceList>service,omitempty"` + Devices []Device `xml:"deviceList>device,omitempty"` + + // Extra observed elements: + PresentationURL URLField `xml:"presentationURL"` +} + +// VisitDevices calls visitor for the device, and all its descendent devices. +func (device *Device) VisitDevices(visitor func(*Device)) { + visitor(device) + for i := range device.Devices { + device.Devices[i].VisitDevices(visitor) + } +} + +// VisitServices calls visitor for all Services under the device and all its +// descendent devices. +func (device *Device) VisitServices(visitor func(*Service)) { + device.VisitDevices(func(d *Device) { + for i := range d.Services { + visitor(&d.Services[i]) + } + }) +} + +// FindService finds all (if any) Services under the device and its descendents +// that have the given ServiceType. +func (device *Device) FindService(serviceType string) []*Service { + var services []*Service + device.VisitServices(func(s *Service) { + if s.ServiceType == serviceType { + services = append(services, s) + } + }) + return services +} + +// SetURLBase sets the URLBase for the Device and its underlying components. +func (device *Device) SetURLBase(urlBase *url.URL) { + device.ManufacturerURL.SetURLBase(urlBase) + device.ModelURL.SetURLBase(urlBase) + device.PresentationURL.SetURLBase(urlBase) + for i := range device.Icons { + device.Icons[i].SetURLBase(urlBase) + } + for i := range device.Services { + device.Services[i].SetURLBase(urlBase) + } + for i := range device.Devices { + device.Devices[i].SetURLBase(urlBase) + } +} + +func (device *Device) String() string { + return fmt.Sprintf("Device ID %s : %s (%s)", device.UDN, device.DeviceType, device.FriendlyName) +} + +// Icon is a representative image that a device might include in its +// description. +type Icon struct { + Mimetype string `xml:"mimetype"` + Width int32 `xml:"width"` + Height int32 `xml:"height"` + Depth int32 `xml:"depth"` + URL URLField `xml:"url"` +} + +// SetURLBase sets the URLBase for the Icon. +func (icon *Icon) SetURLBase(url *url.URL) { + icon.URL.SetURLBase(url) +} + +// Service is a service provided by a UPnP Device. +type Service struct { + ServiceType string `xml:"serviceType"` + ServiceId string `xml:"serviceId"` + SCPDURL URLField `xml:"SCPDURL"` + ControlURL URLField `xml:"controlURL"` + EventSubURL URLField `xml:"eventSubURL"` +} + +// SetURLBase sets the URLBase for the Service. +func (srv *Service) SetURLBase(urlBase *url.URL) { + srv.SCPDURL.SetURLBase(urlBase) + srv.ControlURL.SetURLBase(urlBase) + srv.EventSubURL.SetURLBase(urlBase) +} + +func (srv *Service) String() string { + return fmt.Sprintf("Service ID %s : %s", srv.ServiceId, srv.ServiceType) +} + +// RequestSCDP requests the SCPD (soap actions and state variables description) +// for the service. +func (srv *Service) RequestSCDP() (*scpd.SCPD, error) { + if !srv.SCPDURL.Ok { + return nil, errors.New("bad/missing SCPD URL, or no URLBase has been set") + } + s := new(scpd.SCPD) + if err := requestXml(srv.SCPDURL.URL.String(), scpd.SCPDXMLNamespace, s); err != nil { + return nil, err + } + return s, nil +} + +func (srv *Service) NewSOAPClient() *soap.SOAPClient { + return soap.NewSOAPClient(srv.ControlURL.URL) +} + +// URLField is a URL that is part of a device description. +type URLField struct { + URL url.URL `xml:"-"` + Ok bool `xml:"-"` + Str string `xml:",chardata"` +} + +func (uf *URLField) SetURLBase(urlBase *url.URL) { + refUrl, err := url.Parse(uf.Str) + if err != nil { + uf.URL = url.URL{} + uf.Ok = false + return + } + + uf.URL = *urlBase.ResolveReference(refUrl) + uf.Ok = true +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/example/example.go b/Godeps/_workspace/src/github.com/huin/goupnp/example/example.go new file mode 100644 index 0000000000..df74202268 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/example/example.go @@ -0,0 +1,6 @@ +// Serves as examples of using the goupnp library. +// +// To run examples and see the output for your local network, run the following +// command (specifically including the -v flag): +// go test -v github.com/huin/goupnp/example +package example diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/example/example_test.go b/Godeps/_workspace/src/github.com/huin/goupnp/example/example_test.go new file mode 100644 index 0000000000..1f3667df78 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/example/example_test.go @@ -0,0 +1,62 @@ +package example_test + +import ( + "fmt" + "os" + + "github.com/huin/goupnp" + "github.com/huin/goupnp/dcps/internetgateway1" +) + +// Use discovered WANPPPConnection1 services to find external IP addresses. +func Example_WANPPPConnection1_GetExternalIPAddress() { + clients, errors, err := internetgateway1.NewWANPPPConnection1Clients() + extIPClients := make([]GetExternalIPAddresser, len(clients)) + for i, client := range clients { + extIPClients[i] = client + } + DisplayExternalIPResults(extIPClients, errors, err) + // Output: +} + +// Use discovered WANIPConnection services to find external IP addresses. +func Example_WANIPConnection_GetExternalIPAddress() { + clients, errors, err := internetgateway1.NewWANIPConnection1Clients() + extIPClients := make([]GetExternalIPAddresser, len(clients)) + for i, client := range clients { + extIPClients[i] = client + } + DisplayExternalIPResults(extIPClients, errors, err) + // Output: +} + +type GetExternalIPAddresser interface { + GetExternalIPAddress() (NewExternalIPAddress string, err error) + GetServiceClient() *goupnp.ServiceClient +} + +func DisplayExternalIPResults(clients []GetExternalIPAddresser, errors []error, err error) { + if err != nil { + fmt.Fprintln(os.Stderr, "Error discovering service with UPnP: ", err) + return + } + + if len(errors) > 0 { + fmt.Fprintf(os.Stderr, "Error discovering %d services:\n", len(errors)) + for _, err := range errors { + fmt.Println(" ", err) + } + } + + fmt.Fprintf(os.Stderr, "Successfully discovered %d services:\n", len(clients)) + for _, client := range clients { + device := &client.GetServiceClient().RootDevice.Device + + fmt.Fprintln(os.Stderr, " Device:", device.FriendlyName) + if addr, err := client.GetExternalIPAddress(); err != nil { + fmt.Fprintf(os.Stderr, " Failed to get external IP address: %v\n", err) + } else { + fmt.Fprintf(os.Stderr, " External IP address: %v\n", addr) + } + } +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/gotasks/specgen_task.go b/Godeps/_workspace/src/github.com/huin/goupnp/gotasks/specgen_task.go new file mode 100644 index 0000000000..0ac1d4ff32 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/gotasks/specgen_task.go @@ -0,0 +1,539 @@ +// +build gotask + +package gotasks + +import ( + "archive/zip" + "bytes" + "encoding/xml" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "path" + "path/filepath" + "regexp" + "strings" + "text/template" + + "github.com/huin/goupnp" + "github.com/huin/goupnp/scpd" + "github.com/huin/goutil/codegen" + "github.com/jingweno/gotask/tasking" +) + +var ( + deviceURNPrefix = "urn:schemas-upnp-org:device:" + serviceURNPrefix = "urn:schemas-upnp-org:service:" +) + +// NAME +// specgen - generates Go code from the UPnP specification files. +// +// DESCRIPTION +// The specification is available for download from: +// +// OPTIONS +// -s, --spec_filename= +// Path to the specification file, available from http://upnp.org/resources/upnpresources.zip +// -o, --out_dir= +// Path to the output directory. This is is where the DCP source files will be placed. Should normally correspond to the directory for github.com/huin/goupnp/dcps +// --nogofmt +// Disable passing the output through gofmt. Do this if debugging code output problems and needing to see the generated code prior to being passed through gofmt. +func TaskSpecgen(t *tasking.T) { + specFilename := t.Flags.String("spec-filename") + if specFilename == "" { + specFilename = t.Flags.String("s") + } + if specFilename == "" { + t.Fatal("--spec_filename is required") + } + outDir := t.Flags.String("out-dir") + if outDir == "" { + outDir = t.Flags.String("o") + } + if outDir == "" { + log.Fatal("--out_dir is required") + } + useGofmt := !t.Flags.Bool("nogofmt") + + specArchive, err := openZipfile(specFilename) + if err != nil { + t.Fatalf("Error opening spec file: %v", err) + } + defer specArchive.Close() + + dcpCol := newDcpsCollection() + for _, f := range globFiles("standardizeddcps/*/*.zip", specArchive.Reader) { + dirName := strings.TrimPrefix(f.Name, "standardizeddcps/") + slashIndex := strings.Index(dirName, "/") + if slashIndex == -1 { + // Should not happen. + t.Logf("Could not find / in %q", dirName) + return + } + dirName = dirName[:slashIndex] + + dcp := dcpCol.dcpForDir(dirName) + if dcp == nil { + t.Logf("No alias defined for directory %q: skipping %s\n", dirName, f.Name) + continue + } else { + t.Logf("Alias found for directory %q: processing %s\n", dirName, f.Name) + } + + dcp.processZipFile(f) + } + + for _, dcp := range dcpCol.dcpByAlias { + if err := dcp.writePackage(outDir, useGofmt); err != nil { + log.Printf("Error writing package %q: %v", dcp.Metadata.Name, err) + } + } +} + +// DCP contains extra metadata to use when generating DCP source files. +type DCPMetadata struct { + Name string // What to name the Go DCP package. + OfficialName string // Official name for the DCP. + DocURL string // Optional - URL for futher documentation about the DCP. +} + +var dcpMetadataByDir = map[string]DCPMetadata{ + "Internet Gateway_1": { + Name: "internetgateway1", + OfficialName: "Internet Gateway Device v1", + DocURL: "http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v1-Device.pdf", + }, + "Internet Gateway_2": { + Name: "internetgateway2", + OfficialName: "Internet Gateway Device v2", + DocURL: "http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v2-Device.pdf", + }, +} + +type dcpCollection struct { + dcpByAlias map[string]*DCP +} + +func newDcpsCollection() *dcpCollection { + c := &dcpCollection{ + dcpByAlias: make(map[string]*DCP), + } + for _, metadata := range dcpMetadataByDir { + c.dcpByAlias[metadata.Name] = newDCP(metadata) + } + return c +} + +func (c *dcpCollection) dcpForDir(dirName string) *DCP { + metadata, ok := dcpMetadataByDir[dirName] + if !ok { + return nil + } + return c.dcpByAlias[metadata.Name] +} + +// DCP collects together information about a UPnP Device Control Protocol. +type DCP struct { + Metadata DCPMetadata + DeviceTypes map[string]*URNParts + ServiceTypes map[string]*URNParts + Services []SCPDWithURN +} + +func newDCP(metadata DCPMetadata) *DCP { + return &DCP{ + Metadata: metadata, + DeviceTypes: make(map[string]*URNParts), + ServiceTypes: make(map[string]*URNParts), + } +} + +func (dcp *DCP) processZipFile(file *zip.File) { + archive, err := openChildZip(file) + if err != nil { + log.Println("Error reading child zip file:", err) + return + } + for _, deviceFile := range globFiles("*/device/*.xml", archive) { + dcp.processDeviceFile(deviceFile) + } + for _, scpdFile := range globFiles("*/service/*.xml", archive) { + dcp.processSCPDFile(scpdFile) + } +} + +func (dcp *DCP) processDeviceFile(file *zip.File) { + var device goupnp.Device + if err := unmarshalXmlFile(file, &device); err != nil { + log.Printf("Error decoding device XML from file %q: %v", file.Name, err) + return + } + device.VisitDevices(func(d *goupnp.Device) { + t := strings.TrimSpace(d.DeviceType) + if t != "" { + u, err := extractURNParts(t, deviceURNPrefix) + if err != nil { + log.Println(err) + return + } + dcp.DeviceTypes[t] = u + } + }) + device.VisitServices(func(s *goupnp.Service) { + u, err := extractURNParts(s.ServiceType, serviceURNPrefix) + if err != nil { + log.Println(err) + return + } + dcp.ServiceTypes[s.ServiceType] = u + }) +} + +func (dcp *DCP) writePackage(outDir string, useGofmt bool) error { + packageDirname := filepath.Join(outDir, dcp.Metadata.Name) + err := os.MkdirAll(packageDirname, os.ModePerm) + if err != nil && !os.IsExist(err) { + return err + } + packageFilename := filepath.Join(packageDirname, dcp.Metadata.Name+".go") + packageFile, err := os.Create(packageFilename) + if err != nil { + return err + } + var output io.WriteCloser = packageFile + if useGofmt { + if output, err = codegen.NewGofmtWriteCloser(output); err != nil { + packageFile.Close() + return err + } + } + if err = packageTmpl.Execute(output, dcp); err != nil { + output.Close() + return err + } + return output.Close() +} + +func (dcp *DCP) processSCPDFile(file *zip.File) { + scpd := new(scpd.SCPD) + if err := unmarshalXmlFile(file, scpd); err != nil { + log.Printf("Error decoding SCPD XML from file %q: %v", file.Name, err) + return + } + scpd.Clean() + urnParts, err := urnPartsFromSCPDFilename(file.Name) + if err != nil { + log.Printf("Could not recognize SCPD filename %q: %v", file.Name, err) + return + } + dcp.Services = append(dcp.Services, SCPDWithURN{ + URNParts: urnParts, + SCPD: scpd, + }) +} + +type SCPDWithURN struct { + *URNParts + SCPD *scpd.SCPD +} + +func (s *SCPDWithURN) WrapArgument(arg scpd.Argument) (*argumentWrapper, error) { + relVar := s.SCPD.GetStateVariable(arg.RelatedStateVariable) + if relVar == nil { + return nil, fmt.Errorf("no such state variable: %q, for argument %q", arg.RelatedStateVariable, arg.Name) + } + cnv, ok := typeConvs[relVar.DataType.Name] + if !ok { + return nil, fmt.Errorf("unknown data type: %q, for state variable %q, for argument %q", relVar.DataType.Type, arg.RelatedStateVariable, arg.Name) + } + return &argumentWrapper{ + Argument: arg, + relVar: relVar, + conv: cnv, + }, nil +} + +type argumentWrapper struct { + scpd.Argument + relVar *scpd.StateVariable + conv conv +} + +func (arg *argumentWrapper) AsParameter() string { + return fmt.Sprintf("%s %s", arg.Name, arg.conv.ExtType) +} + +func (arg *argumentWrapper) Document() string { + relVar := arg.relVar + if rng := relVar.AllowedValueRange; rng != nil { + var parts []string + if rng.Minimum != "" { + parts = append(parts, fmt.Sprintf("minimum=%s", rng.Minimum)) + } + if rng.Maximum != "" { + parts = append(parts, fmt.Sprintf("maximum=%s", rng.Maximum)) + } + if rng.Step != "" { + parts = append(parts, fmt.Sprintf("step=%s", rng.Step)) + } + return "allowed value range: " + strings.Join(parts, ", ") + } + if len(relVar.AllowedValues) != 0 { + return "allowed values: " + strings.Join(relVar.AllowedValues, ", ") + } + return "" +} + +func (arg *argumentWrapper) Marshal() string { + return fmt.Sprintf("soap.Marshal%s(%s)", arg.conv.FuncSuffix, arg.Name) +} + +func (arg *argumentWrapper) Unmarshal(objVar string) string { + return fmt.Sprintf("soap.Unmarshal%s(%s.%s)", arg.conv.FuncSuffix, objVar, arg.Name) +} + +type conv struct { + FuncSuffix string + ExtType string +} + +// typeConvs maps from a SOAP type (e.g "fixed.14.4") to the function name +// suffix inside the soap module (e.g "Fixed14_4") and the Go type. +var typeConvs = map[string]conv{ + "ui1": conv{"Ui1", "uint8"}, + "ui2": conv{"Ui2", "uint16"}, + "ui4": conv{"Ui4", "uint32"}, + "i1": conv{"I1", "int8"}, + "i2": conv{"I2", "int16"}, + "i4": conv{"I4", "int32"}, + "int": conv{"Int", "int64"}, + "r4": conv{"R4", "float32"}, + "r8": conv{"R8", "float64"}, + "number": conv{"R8", "float64"}, // Alias for r8. + "fixed.14.4": conv{"Fixed14_4", "float64"}, + "float": conv{"R8", "float64"}, + "char": conv{"Char", "rune"}, + "string": conv{"String", "string"}, + "date": conv{"Date", "time.Time"}, + "dateTime": conv{"DateTime", "time.Time"}, + "dateTime.tz": conv{"DateTimeTz", "time.Time"}, + "time": conv{"TimeOfDay", "soap.TimeOfDay"}, + "time.tz": conv{"TimeOfDayTz", "soap.TimeOfDay"}, + "boolean": conv{"Boolean", "bool"}, + "bin.base64": conv{"BinBase64", "[]byte"}, + "bin.hex": conv{"BinHex", "[]byte"}, +} + +type closeableZipReader struct { + io.Closer + *zip.Reader +} + +func openZipfile(filename string) (*closeableZipReader, error) { + file, err := os.Open(filename) + if err != nil { + return nil, err + } + fi, err := file.Stat() + if err != nil { + return nil, err + } + archive, err := zip.NewReader(file, fi.Size()) + if err != nil { + return nil, err + } + return &closeableZipReader{ + Closer: file, + Reader: archive, + }, nil +} + +// openChildZip opens a zip file within another zip file. +func openChildZip(file *zip.File) (*zip.Reader, error) { + zipFile, err := file.Open() + if err != nil { + return nil, err + } + defer zipFile.Close() + + zipBytes, err := ioutil.ReadAll(zipFile) + if err != nil { + return nil, err + } + + return zip.NewReader(bytes.NewReader(zipBytes), int64(len(zipBytes))) +} + +func globFiles(pattern string, archive *zip.Reader) []*zip.File { + var files []*zip.File + for _, f := range archive.File { + if matched, err := path.Match(pattern, f.Name); err != nil { + // This shouldn't happen - all patterns are hard-coded, errors in them + // are a programming error. + panic(err) + } else if matched { + files = append(files, f) + } + } + return files +} + +func unmarshalXmlFile(file *zip.File, data interface{}) error { + r, err := file.Open() + if err != nil { + return err + } + decoder := xml.NewDecoder(r) + r.Close() + return decoder.Decode(data) +} + +type URNParts struct { + URN string + Name string + Version string +} + +func (u *URNParts) Const() string { + return fmt.Sprintf("URN_%s_%s", u.Name, u.Version) +} + +// extractURNParts extracts the name and version from a URN string. +func extractURNParts(urn, expectedPrefix string) (*URNParts, error) { + if !strings.HasPrefix(urn, expectedPrefix) { + return nil, fmt.Errorf("%q does not have expected prefix %q", urn, expectedPrefix) + } + parts := strings.SplitN(strings.TrimPrefix(urn, expectedPrefix), ":", 2) + if len(parts) != 2 { + return nil, fmt.Errorf("%q does not have a name and version", urn) + } + name, version := parts[0], parts[1] + return &URNParts{urn, name, version}, nil +} + +var scpdFilenameRe = regexp.MustCompile( + `.*/([a-zA-Z0-9]+)([0-9]+)\.xml`) + +func urnPartsFromSCPDFilename(filename string) (*URNParts, error) { + parts := scpdFilenameRe.FindStringSubmatch(filename) + if len(parts) != 3 { + return nil, fmt.Errorf("SCPD filename %q does not have expected number of parts", filename) + } + name, version := parts[1], parts[2] + return &URNParts{ + URN: serviceURNPrefix + name + ":" + version, + Name: name, + Version: version, + }, nil +} + +var packageTmpl = template.Must(template.New("package").Parse(`{{$name := .Metadata.Name}} +// Client for UPnP Device Control Protocol {{.Metadata.OfficialName}}. +// {{if .Metadata.DocURL}} +// This DCP is documented in detail at: {{.Metadata.DocURL}}{{end}} +// +// Typically, use one of the New* functions to discover services on the local +// network. +package {{$name}} + +// Generated file - do not edit by hand. See README.md + + +import ( + "time" + + "github.com/huin/goupnp" + "github.com/huin/goupnp/soap" +) + +// Hack to avoid Go complaining if time isn't used. +var _ time.Time + +// Device URNs: +const ({{range .DeviceTypes}} + {{.Const}} = "{{.URN}}"{{end}} +) + +// Service URNs: +const ({{range .ServiceTypes}} + {{.Const}} = "{{.URN}}"{{end}} +) + +{{range .Services}} +{{$srv := .}} +{{$srvIdent := printf "%s%s" .Name .Version}} + +// {{$srvIdent}} is a client for UPnP SOAP service with URN "{{.URN}}". See +// goupnp.ServiceClient, which contains RootDevice and Service attributes which +// are provided for informational value. +type {{$srvIdent}} struct { + goupnp.ServiceClient +} + +// New{{$srvIdent}}Clients discovers instances of the service on the network, +// and returns clients to any that are found. errors will contain an error for +// any devices that replied but which could not be queried, and err will be set +// if the discovery process failed outright. +// +// This is a typical entry calling point into this package. +func New{{$srvIdent}}Clients() (clients []*{{$srvIdent}}, errors []error, err error) { + var genericClients []goupnp.ServiceClient + if genericClients, errors, err = goupnp.NewServiceClients({{$srv.Const}}); err != nil { + return + } + clients = make([]*{{$srvIdent}}, len(genericClients)) + for i := range genericClients { + clients[i] = &{{$srvIdent}}{genericClients[i]} + } + return +} + +{{range .SCPD.Actions}}{{/* loops over *SCPDWithURN values */}} + +{{$inargs := .InputArguments}}{{$outargs := .OutputArguments}} +// {{if $inargs}}Arguments:{{range $inargs}}{{$argWrap := $srv.WrapArgument .}} +// +// * {{.Name}}: {{$argWrap.Document}}{{end}}{{end}} +// +// {{if $outargs}}Return values:{{range $outargs}}{{$argWrap := $srv.WrapArgument .}} +// +// * {{.Name}}: {{$argWrap.Document}}{{end}}{{end}} +func (client *{{$srvIdent}}) {{.Name}}({{range $inargs}}{{/* +*/}}{{$argWrap := $srv.WrapArgument .}}{{$argWrap.AsParameter}}, {{end}}{{/* +*/}}) ({{range $outargs}}{{/* +*/}}{{$argWrap := $srv.WrapArgument .}}{{$argWrap.AsParameter}}, {{end}} err error) { + // Request structure. + request := {{if $inargs}}&{{template "argstruct" $inargs}}{{"{}"}}{{else}}{{"interface{}(nil)"}}{{end}} + // BEGIN Marshal arguments into request. +{{range $inargs}}{{$argWrap := $srv.WrapArgument .}} + if request.{{.Name}}, err = {{$argWrap.Marshal}}; err != nil { + return + }{{end}} + // END Marshal arguments into request. + + // Response structure. + response := {{if $outargs}}&{{template "argstruct" $outargs}}{{"{}"}}{{else}}{{"interface{}(nil)"}}{{end}} + + // Perform the SOAP call. + if err = client.SOAPClient.PerformAction({{$srv.URNParts.Const}}, "{{.Name}}", request, response); err != nil { + return + } + + // BEGIN Unmarshal arguments from response. +{{range $outargs}}{{$argWrap := $srv.WrapArgument .}} + if {{.Name}}, err = {{$argWrap.Unmarshal "response"}}; err != nil { + return + }{{end}} + // END Unmarshal arguments from response. + return +} +{{end}}{{/* range .SCPD.Actions */}} +{{end}}{{/* range .Services */}} + +{{define "argstruct"}}struct {{"{"}}{{range .}} +{{.Name}} string +{{end}}{{"}"}}{{end}} +`)) diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/goupnp.go b/Godeps/_workspace/src/github.com/huin/goupnp/goupnp.go new file mode 100644 index 0000000000..7799a32ce7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/goupnp.go @@ -0,0 +1,115 @@ +// goupnp is an implementation of a client for various UPnP services. +// +// For most uses, it is recommended to use the code-generated packages under +// github.com/huin/goupnp/dcps. Example use is shown at +// http://godoc.org/github.com/huin/goupnp/example +// +// A commonly used client is internetgateway1.WANPPPConnection1: +// http://godoc.org/github.com/huin/goupnp/dcps/internetgateway1#WANPPPConnection1 +// +// Currently only a couple of schemas have code generated for them from the +// UPnP example XML specifications. Not all methods will work on these clients, +// because the generated stubs contain the full set of specified methods from +// the XML specifications, and the discovered services will likely support a +// subset of those methods. +package goupnp + +import ( + "encoding/xml" + "fmt" + "net/http" + "net/url" + "time" + "golang.org/x/net/html/charset" + + "github.com/huin/goupnp/httpu" + "github.com/huin/goupnp/ssdp" +) + +// ContextError is an error that wraps an error with some context information. +type ContextError struct { + Context string + Err error +} + +func (err ContextError) Error() string { + return fmt.Sprintf("%s: %v", err.Context, err.Err) +} + +// MaybeRootDevice contains either a RootDevice or an error. +type MaybeRootDevice struct { + Root *RootDevice + Err error +} + +// DiscoverDevices attempts to find targets of the given type. This is +// typically the entry-point for this package. searchTarget is typically a URN +// in the form "urn:schemas-upnp-org:device:..." or +// "urn:schemas-upnp-org:service:...". A single error is returned for errors +// while attempting to send the query. An error or RootDevice is returned for +// each discovered RootDevice. +func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) { + httpu, err := httpu.NewHTTPUClient() + if err != nil { + return nil, err + } + defer httpu.Close() + responses, err := ssdp.SSDPRawSearch(httpu, string(searchTarget), 2, 3) + if err != nil { + return nil, err + } + + results := make([]MaybeRootDevice, len(responses)) + for i, response := range responses { + maybe := &results[i] + loc, err := response.Location() + if err != nil { + maybe.Err = ContextError{"unexpected bad location from search", err} + continue + } + locStr := loc.String() + root := new(RootDevice) + if err := requestXml(locStr, DeviceXMLNamespace, root); err != nil { + maybe.Err = ContextError{fmt.Sprintf("error requesting root device details from %q", locStr), err} + continue + } + var urlBaseStr string + if root.URLBaseStr != "" { + urlBaseStr = root.URLBaseStr + } else { + urlBaseStr = locStr + } + urlBase, err := url.Parse(urlBaseStr) + if err != nil { + maybe.Err = ContextError{fmt.Sprintf("error parsing location URL %q", locStr), err} + continue + } + root.SetURLBase(urlBase) + maybe.Root = root + } + + return results, nil +} + +func requestXml(url string, defaultSpace string, doc interface{}) error { + timeout := time.Duration(3 * time.Second) + client := http.Client{ + Timeout: timeout, + } + resp, err := client.Get(url) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + return fmt.Errorf("goupnp: got response status %s from %q", + resp.Status, url) + } + + decoder := xml.NewDecoder(resp.Body) + decoder.DefaultSpace = defaultSpace + decoder.CharsetReader = charset.NewReaderLabel + + return decoder.Decode(doc) +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/httpu/httpu.go b/Godeps/_workspace/src/github.com/huin/goupnp/httpu/httpu.go new file mode 100644 index 0000000000..862c3def42 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/httpu/httpu.go @@ -0,0 +1,117 @@ +package httpu + +import ( + "bufio" + "bytes" + "fmt" + "log" + "net" + "net/http" + "sync" + "time" +) + +// HTTPUClient is a client for dealing with HTTPU (HTTP over UDP). Its typical +// function is for HTTPMU, and particularly SSDP. +type HTTPUClient struct { + connLock sync.Mutex // Protects use of conn. + conn net.PacketConn +} + +// NewHTTPUClient creates a new HTTPUClient, opening up a new UDP socket for the +// purpose. +func NewHTTPUClient() (*HTTPUClient, error) { + conn, err := net.ListenPacket("udp", ":0") + if err != nil { + return nil, err + } + return &HTTPUClient{conn: conn}, nil +} + +// Close shuts down the client. The client will no longer be useful following +// this. +func (httpu *HTTPUClient) Close() error { + httpu.connLock.Lock() + defer httpu.connLock.Unlock() + return httpu.conn.Close() +} + +// Do performs a request. The timeout is how long to wait for before returning +// the responses that were received. An error is only returned for failing to +// send the request. Failures in receipt simply do not add to the resulting +// responses. +// +// Note that at present only one concurrent connection will happen per +// HTTPUClient. +func (httpu *HTTPUClient) Do(req *http.Request, timeout time.Duration, numSends int) ([]*http.Response, error) { + httpu.connLock.Lock() + defer httpu.connLock.Unlock() + + // Create the request. This is a subset of what http.Request.Write does + // deliberately to avoid creating extra fields which may confuse some + // devices. + var requestBuf bytes.Buffer + method := req.Method + if method == "" { + method = "GET" + } + if _, err := fmt.Fprintf(&requestBuf, "%s %s HTTP/1.1\r\n", method, req.URL.RequestURI()); err != nil { + return nil, err + } + if err := req.Header.Write(&requestBuf); err != nil { + return nil, err + } + if _, err := requestBuf.Write([]byte{'\r', '\n'}); err != nil { + return nil, err + } + + destAddr, err := net.ResolveUDPAddr("udp", req.Host) + if err != nil { + return nil, err + } + if err = httpu.conn.SetDeadline(time.Now().Add(timeout)); err != nil { + return nil, err + } + + // Send request. + for i := 0; i < numSends; i++ { + if n, err := httpu.conn.WriteTo(requestBuf.Bytes(), destAddr); err != nil { + return nil, err + } else if n < len(requestBuf.Bytes()) { + return nil, fmt.Errorf("httpu: wrote %d bytes rather than full %d in request", + n, len(requestBuf.Bytes())) + } + time.Sleep(5 * time.Millisecond) + } + + // Await responses until timeout. + var responses []*http.Response + responseBytes := make([]byte, 2048) + for { + // 2048 bytes should be sufficient for most networks. + n, _, err := httpu.conn.ReadFrom(responseBytes) + if err != nil { + if err, ok := err.(net.Error); ok { + if err.Timeout() { + break + } + if err.Temporary() { + // Sleep in case this is a persistent error to avoid pegging CPU until deadline. + time.Sleep(10 * time.Millisecond) + continue + } + } + return nil, err + } + + // Parse response. + response, err := http.ReadResponse(bufio.NewReader(bytes.NewBuffer(responseBytes[:n])), req) + if err != nil { + log.Print("httpu: error while parsing response: %v", err) + continue + } + + responses = append(responses, response) + } + return responses, err +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/httpu/serve.go b/Godeps/_workspace/src/github.com/huin/goupnp/httpu/serve.go new file mode 100644 index 0000000000..9f67af85b7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/httpu/serve.go @@ -0,0 +1,108 @@ +package httpu + +import ( + "bufio" + "bytes" + "log" + "net" + "net/http" + "regexp" +) + +const ( + DefaultMaxMessageBytes = 2048 +) + +var ( + trailingWhitespaceRx = regexp.MustCompile(" +\r\n") + crlf = []byte("\r\n") +) + +// Handler is the interface by which received HTTPU messages are passed to +// handling code. +type Handler interface { + // ServeMessage is called for each HTTPU message received. peerAddr contains + // the address that the message was received from. + ServeMessage(r *http.Request) +} + +// HandlerFunc is a function-to-Handler adapter. +type HandlerFunc func(r *http.Request) + +func (f HandlerFunc) ServeMessage(r *http.Request) { + f(r) +} + +// A Server defines parameters for running an HTTPU server. +type Server struct { + Addr string // UDP address to listen on + Multicast bool // Should listen for multicast? + Interface *net.Interface // Network interface to listen on for multicast, nil for default multicast interface + Handler Handler // handler to invoke + MaxMessageBytes int // maximum number of bytes to read from a packet, DefaultMaxMessageBytes if 0 +} + +// ListenAndServe listens on the UDP network address srv.Addr. If srv.Multicast +// is true, then a multicast UDP listener will be used on srv.Interface (or +// default interface if nil). +func (srv *Server) ListenAndServe() error { + var err error + + var addr *net.UDPAddr + if addr, err = net.ResolveUDPAddr("udp", srv.Addr); err != nil { + log.Fatal(err) + } + + var conn net.PacketConn + if srv.Multicast { + if conn, err = net.ListenMulticastUDP("udp", srv.Interface, addr); err != nil { + return err + } + } else { + if conn, err = net.ListenUDP("udp", addr); err != nil { + return err + } + } + + return srv.Serve(conn) +} + +// Serve messages received on the given packet listener to the srv.Handler. +func (srv *Server) Serve(l net.PacketConn) error { + maxMessageBytes := DefaultMaxMessageBytes + if srv.MaxMessageBytes != 0 { + maxMessageBytes = srv.MaxMessageBytes + } + for { + buf := make([]byte, maxMessageBytes) + n, peerAddr, err := l.ReadFrom(buf) + if err != nil { + return err + } + buf = buf[:n] + + go func(buf []byte, peerAddr net.Addr) { + // At least one router's UPnP implementation has added a trailing space + // after "HTTP/1.1" - trim it. + buf = trailingWhitespaceRx.ReplaceAllLiteral(buf, crlf) + + req, err := http.ReadRequest(bufio.NewReader(bytes.NewBuffer(buf))) + if err != nil { + log.Printf("httpu: Failed to parse request: %v", err) + return + } + req.RemoteAddr = peerAddr.String() + srv.Handler.ServeMessage(req) + // No need to call req.Body.Close - underlying reader is bytes.Buffer. + }(buf, peerAddr) + } +} + +// Serve messages received on the given packet listener to the given handler. +func Serve(l net.PacketConn, handler Handler) error { + srv := Server{ + Handler: handler, + MaxMessageBytes: DefaultMaxMessageBytes, + } + return srv.Serve(l) +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/scpd/scpd.go b/Godeps/_workspace/src/github.com/huin/goupnp/scpd/scpd.go new file mode 100644 index 0000000000..c9d2e69e81 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/scpd/scpd.go @@ -0,0 +1,167 @@ +package scpd + +import ( + "encoding/xml" + "strings" +) + +const ( + SCPDXMLNamespace = "urn:schemas-upnp-org:service-1-0" +) + +func cleanWhitespace(s *string) { + *s = strings.TrimSpace(*s) +} + +// SCPD is the service description as described by section 2.5 "Service +// description" in +// http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf +type SCPD struct { + XMLName xml.Name `xml:"scpd"` + ConfigId string `xml:"configId,attr"` + SpecVersion SpecVersion `xml:"specVersion"` + Actions []Action `xml:"actionList>action"` + StateVariables []StateVariable `xml:"serviceStateTable>stateVariable"` +} + +// Clean attempts to remove stray whitespace etc. in the structure. It seems +// unfortunately common for stray whitespace to be present in SCPD documents, +// this method attempts to make it easy to clean them out. +func (scpd *SCPD) Clean() { + cleanWhitespace(&scpd.ConfigId) + for i := range scpd.Actions { + scpd.Actions[i].clean() + } + for i := range scpd.StateVariables { + scpd.StateVariables[i].clean() + } +} + +func (scpd *SCPD) GetStateVariable(variable string) *StateVariable { + for i := range scpd.StateVariables { + v := &scpd.StateVariables[i] + if v.Name == variable { + return v + } + } + return nil +} + +func (scpd *SCPD) GetAction(action string) *Action { + for i := range scpd.Actions { + a := &scpd.Actions[i] + if a.Name == action { + return a + } + } + return nil +} + +// SpecVersion is part of a SCPD document, describes the version of the +// specification that the data adheres to. +type SpecVersion struct { + Major int32 `xml:"major"` + Minor int32 `xml:"minor"` +} + +type Action struct { + Name string `xml:"name"` + Arguments []Argument `xml:"argumentList>argument"` +} + +func (action *Action) clean() { + cleanWhitespace(&action.Name) + for i := range action.Arguments { + action.Arguments[i].clean() + } +} + +func (action *Action) InputArguments() []*Argument { + var result []*Argument + for i := range action.Arguments { + arg := &action.Arguments[i] + if arg.IsInput() { + result = append(result, arg) + } + } + return result +} + +func (action *Action) OutputArguments() []*Argument { + var result []*Argument + for i := range action.Arguments { + arg := &action.Arguments[i] + if arg.IsOutput() { + result = append(result, arg) + } + } + return result +} + +type Argument struct { + Name string `xml:"name"` + Direction string `xml:"direction"` // in|out + RelatedStateVariable string `xml:"relatedStateVariable"` // ? + Retval string `xml:"retval"` // ? +} + +func (arg *Argument) clean() { + cleanWhitespace(&arg.Name) + cleanWhitespace(&arg.Direction) + cleanWhitespace(&arg.RelatedStateVariable) + cleanWhitespace(&arg.Retval) +} + +func (arg *Argument) IsInput() bool { + return arg.Direction == "in" +} + +func (arg *Argument) IsOutput() bool { + return arg.Direction == "out" +} + +type StateVariable struct { + Name string `xml:"name"` + SendEvents string `xml:"sendEvents,attr"` // yes|no + Multicast string `xml:"multicast,attr"` // yes|no + DataType DataType `xml:"dataType"` + DefaultValue string `xml:"defaultValue"` + AllowedValueRange *AllowedValueRange `xml:"allowedValueRange"` + AllowedValues []string `xml:"allowedValueList>allowedValue"` +} + +func (v *StateVariable) clean() { + cleanWhitespace(&v.Name) + cleanWhitespace(&v.SendEvents) + cleanWhitespace(&v.Multicast) + v.DataType.clean() + cleanWhitespace(&v.DefaultValue) + if v.AllowedValueRange != nil { + v.AllowedValueRange.clean() + } + for i := range v.AllowedValues { + cleanWhitespace(&v.AllowedValues[i]) + } +} + +type AllowedValueRange struct { + Minimum string `xml:"minimum"` + Maximum string `xml:"maximum"` + Step string `xml:"step"` +} + +func (r *AllowedValueRange) clean() { + cleanWhitespace(&r.Minimum) + cleanWhitespace(&r.Maximum) + cleanWhitespace(&r.Step) +} + +type DataType struct { + Name string `xml:",chardata"` + Type string `xml:"type,attr"` +} + +func (dt *DataType) clean() { + cleanWhitespace(&dt.Name) + cleanWhitespace(&dt.Type) +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/service_client.go b/Godeps/_workspace/src/github.com/huin/goupnp/service_client.go new file mode 100644 index 0000000000..c0d16ce2a1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/service_client.go @@ -0,0 +1,56 @@ +package goupnp + +import ( + "fmt" + "github.com/huin/goupnp/soap" +) + +// ServiceClient is a SOAP client, root device and the service for the SOAP +// client rolled into one value. The root device and service are intended to be +// informational. +type ServiceClient struct { + SOAPClient *soap.SOAPClient + RootDevice *RootDevice + Service *Service +} + +func NewServiceClients(searchTarget string) (clients []ServiceClient, errors []error, err error) { + var maybeRootDevices []MaybeRootDevice + if maybeRootDevices, err = DiscoverDevices(searchTarget); err != nil { + return + } + + clients = make([]ServiceClient, 0, len(maybeRootDevices)) + + for _, maybeRootDevice := range maybeRootDevices { + if maybeRootDevice.Err != nil { + errors = append(errors, maybeRootDevice.Err) + continue + } + + device := &maybeRootDevice.Root.Device + srvs := device.FindService(searchTarget) + if len(srvs) == 0 { + errors = append(errors, fmt.Errorf("goupnp: service %q not found within device %q (UDN=%q)", + searchTarget, device.FriendlyName, device.UDN)) + continue + } + + for _, srv := range srvs { + clients = append(clients, ServiceClient{ + SOAPClient: srv.NewSOAPClient(), + RootDevice: maybeRootDevice.Root, + Service: srv, + }) + } + } + + return +} + +// GetServiceClient returns the ServiceClient itself. This is provided so that the +// service client attributes can be accessed via an interface method on a +// wrapping type. +func (client *ServiceClient) GetServiceClient() *ServiceClient { + return client +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap.go b/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap.go new file mode 100644 index 0000000000..815610734c --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap.go @@ -0,0 +1,157 @@ +// Definition for the SOAP structure required for UPnP's SOAP usage. + +package soap + +import ( + "bytes" + "encoding/xml" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "reflect" +) + +const ( + soapEncodingStyle = "http://schemas.xmlsoap.org/soap/encoding/" + soapPrefix = xml.Header + `` + soapSuffix = `` +) + +type SOAPClient struct { + EndpointURL url.URL + HTTPClient http.Client +} + +func NewSOAPClient(endpointURL url.URL) *SOAPClient { + return &SOAPClient{ + EndpointURL: endpointURL, + } +} + +// PerformSOAPAction makes a SOAP request, with the given action. +// inAction and outAction must both be pointers to structs with string fields +// only. +func (client *SOAPClient) PerformAction(actionNamespace, actionName string, inAction interface{}, outAction interface{}) error { + requestBytes, err := encodeRequestAction(actionNamespace, actionName, inAction) + if err != nil { + return err + } + + response, err := client.HTTPClient.Do(&http.Request{ + Method: "POST", + URL: &client.EndpointURL, + Header: http.Header{ + "SOAPACTION": []string{`"` + actionNamespace + "#" + actionName + `"`}, + "CONTENT-TYPE": []string{"text/xml; charset=\"utf-8\""}, + }, + Body: ioutil.NopCloser(bytes.NewBuffer(requestBytes)), + // Set ContentLength to avoid chunked encoding - some servers might not support it. + ContentLength: int64(len(requestBytes)), + }) + if err != nil { + return fmt.Errorf("goupnp: error performing SOAP HTTP request: %v", err) + } + defer response.Body.Close() + if response.StatusCode != 200 { + return fmt.Errorf("goupnp: SOAP request got HTTP %s", response.Status) + } + + responseEnv := newSOAPEnvelope() + decoder := xml.NewDecoder(response.Body) + if err := decoder.Decode(responseEnv); err != nil { + return fmt.Errorf("goupnp: error decoding response body: %v", err) + } + + if responseEnv.Body.Fault != nil { + return responseEnv.Body.Fault + } + + if outAction != nil { + if err := xml.Unmarshal(responseEnv.Body.RawAction, outAction); err != nil { + return fmt.Errorf("goupnp: error unmarshalling out action: %v, %v", err, responseEnv.Body.RawAction) + } + } + + return nil +} + +// newSOAPAction creates a soapEnvelope with the given action and arguments. +func newSOAPEnvelope() *soapEnvelope { + return &soapEnvelope{ + EncodingStyle: soapEncodingStyle, + } +} + +// encodeRequestAction is a hacky way to create an encoded SOAP envelope +// containing the given action. Experiments with one router have shown that it +// 500s for requests where the outer default xmlns is set to the SOAP +// namespace, and then reassigning the default namespace within that to the +// service namespace. Hand-coding the outer XML to work-around this. +func encodeRequestAction(actionNamespace, actionName string, inAction interface{}) ([]byte, error) { + requestBuf := new(bytes.Buffer) + requestBuf.WriteString(soapPrefix) + requestBuf.WriteString(``) + if inAction != nil { + if err := encodeRequestArgs(requestBuf, inAction); err != nil { + return nil, err + } + } + requestBuf.WriteString(``) + requestBuf.WriteString(soapSuffix) + return requestBuf.Bytes(), nil +} + +func encodeRequestArgs(w *bytes.Buffer, inAction interface{}) error { + in := reflect.Indirect(reflect.ValueOf(inAction)) + if in.Kind() != reflect.Struct { + return fmt.Errorf("goupnp: SOAP inAction is not a struct but of type %v", in.Type()) + } + enc := xml.NewEncoder(w) + nFields := in.NumField() + inType := in.Type() + for i := 0; i < nFields; i++ { + field := inType.Field(i) + argName := field.Name + if nameOverride := field.Tag.Get("soap"); nameOverride != "" { + argName = nameOverride + } + value := in.Field(i) + if value.Kind() != reflect.String { + return fmt.Errorf("goupnp: SOAP arg %q is not of type string, but of type %v", argName, value.Type()) + } + if err := enc.EncodeElement(value.Interface(), xml.StartElement{xml.Name{"", argName}, nil}); err != nil { + return fmt.Errorf("goupnp: error encoding SOAP arg %q: %v", argName, err) + } + } + enc.Flush() + return nil +} + +type soapEnvelope struct { + XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"` + EncodingStyle string `xml:"http://schemas.xmlsoap.org/soap/envelope/ encodingStyle,attr"` + Body soapBody `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"` +} + +type soapBody struct { + Fault *SOAPFaultError `xml:"Fault"` + RawAction []byte `xml:",innerxml"` +} + +// SOAPFaultError implements error, and contains SOAP fault information. +type SOAPFaultError struct { + FaultCode string `xml:"faultcode"` + FaultString string `xml:"faultstring"` + Detail string `xml:"detail"` +} + +func (err *SOAPFaultError) Error() string { + return fmt.Sprintf("SOAP fault: %s", err.FaultString) +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap_test.go b/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap_test.go new file mode 100644 index 0000000000..75dbbdbf1c --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap_test.go @@ -0,0 +1,85 @@ +package soap + +import ( + "bytes" + "io/ioutil" + "net/http" + "net/url" + "reflect" + "testing" +) + +type capturingRoundTripper struct { + err error + resp *http.Response + capturedReq *http.Request +} + +func (rt *capturingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + rt.capturedReq = req + return rt.resp, rt.err +} + +func TestActionInputs(t *testing.T) { + url, err := url.Parse("http://example.com/soap") + if err != nil { + t.Fatal(err) + } + rt := &capturingRoundTripper{ + err: nil, + resp: &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewBufferString(` + + + + valueA + valueB + + + + `)), + }, + } + client := SOAPClient{ + EndpointURL: *url, + HTTPClient: http.Client{ + Transport: rt, + }, + } + + type In struct { + Foo string + Bar string `soap:"bar"` + } + type Out struct { + A string + B string + } + in := In{"foo", "bar"} + gotOut := Out{} + err = client.PerformAction("mynamespace", "myaction", &in, &gotOut) + if err != nil { + t.Fatal(err) + } + + wantBody := (soapPrefix + + `` + + `foo` + + `bar` + + `` + + soapSuffix) + body, err := ioutil.ReadAll(rt.capturedReq.Body) + if err != nil { + t.Fatal(err) + } + gotBody := string(body) + if wantBody != gotBody { + t.Errorf("Bad request body\nwant: %q\n got: %q", wantBody, gotBody) + } + + wantOut := Out{"valueA", "valueB"} + if !reflect.DeepEqual(wantOut, gotOut) { + t.Errorf("Bad output\nwant: %+v\n got: %+v", wantOut, gotOut) + } +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/soap/types.go b/Godeps/_workspace/src/github.com/huin/goupnp/soap/types.go new file mode 100644 index 0000000000..cd16510e3a --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/soap/types.go @@ -0,0 +1,508 @@ +package soap + +import ( + "encoding/base64" + "encoding/hex" + "errors" + "fmt" + "regexp" + "strconv" + "strings" + "time" + "unicode/utf8" +) + +var ( + // localLoc acts like time.Local for this package, but is faked out by the + // unit tests to ensure that things stay constant (especially when running + // this test in a place where local time is UTC which might mask bugs). + localLoc = time.Local +) + +func MarshalUi1(v uint8) (string, error) { + return strconv.FormatUint(uint64(v), 10), nil +} + +func UnmarshalUi1(s string) (uint8, error) { + v, err := strconv.ParseUint(s, 10, 8) + return uint8(v), err +} + +func MarshalUi2(v uint16) (string, error) { + return strconv.FormatUint(uint64(v), 10), nil +} + +func UnmarshalUi2(s string) (uint16, error) { + v, err := strconv.ParseUint(s, 10, 16) + return uint16(v), err +} + +func MarshalUi4(v uint32) (string, error) { + return strconv.FormatUint(uint64(v), 10), nil +} + +func UnmarshalUi4(s string) (uint32, error) { + v, err := strconv.ParseUint(s, 10, 32) + return uint32(v), err +} + +func MarshalI1(v int8) (string, error) { + return strconv.FormatInt(int64(v), 10), nil +} + +func UnmarshalI1(s string) (int8, error) { + v, err := strconv.ParseInt(s, 10, 8) + return int8(v), err +} + +func MarshalI2(v int16) (string, error) { + return strconv.FormatInt(int64(v), 10), nil +} + +func UnmarshalI2(s string) (int16, error) { + v, err := strconv.ParseInt(s, 10, 16) + return int16(v), err +} + +func MarshalI4(v int32) (string, error) { + return strconv.FormatInt(int64(v), 10), nil +} + +func UnmarshalI4(s string) (int32, error) { + v, err := strconv.ParseInt(s, 10, 32) + return int32(v), err +} + +func MarshalInt(v int64) (string, error) { + return strconv.FormatInt(v, 10), nil +} + +func UnmarshalInt(s string) (int64, error) { + return strconv.ParseInt(s, 10, 64) +} + +func MarshalR4(v float32) (string, error) { + return strconv.FormatFloat(float64(v), 'G', -1, 32), nil +} + +func UnmarshalR4(s string) (float32, error) { + v, err := strconv.ParseFloat(s, 32) + return float32(v), err +} + +func MarshalR8(v float64) (string, error) { + return strconv.FormatFloat(v, 'G', -1, 64), nil +} + +func UnmarshalR8(s string) (float64, error) { + v, err := strconv.ParseFloat(s, 64) + return float64(v), err +} + +// MarshalFixed14_4 marshals float64 to SOAP "fixed.14.4" type. +func MarshalFixed14_4(v float64) (string, error) { + if v >= 1e14 || v <= -1e14 { + return "", fmt.Errorf("soap fixed14.4: value %v out of bounds", v) + } + return strconv.FormatFloat(v, 'f', 4, 64), nil +} + +// UnmarshalFixed14_4 unmarshals float64 from SOAP "fixed.14.4" type. +func UnmarshalFixed14_4(s string) (float64, error) { + v, err := strconv.ParseFloat(s, 64) + if err != nil { + return 0, err + } + if v >= 1e14 || v <= -1e14 { + return 0, fmt.Errorf("soap fixed14.4: value %q out of bounds", s) + } + return v, nil +} + +// MarshalChar marshals rune to SOAP "char" type. +func MarshalChar(v rune) (string, error) { + if v == 0 { + return "", errors.New("soap char: rune 0 is not allowed") + } + return string(v), nil +} + +// UnmarshalChar unmarshals rune from SOAP "char" type. +func UnmarshalChar(s string) (rune, error) { + if len(s) == 0 { + return 0, errors.New("soap char: got empty string") + } + r, n := utf8.DecodeRune([]byte(s)) + if n != len(s) { + return 0, fmt.Errorf("soap char: value %q is not a single rune", s) + } + return r, nil +} + +func MarshalString(v string) (string, error) { + return v, nil +} + +func UnmarshalString(v string) (string, error) { + return v, nil +} + +func parseInt(s string, err *error) int { + v, parseErr := strconv.ParseInt(s, 10, 64) + if parseErr != nil { + *err = parseErr + } + return int(v) +} + +var dateRegexps = []*regexp.Regexp{ + // yyyy[-mm[-dd]] + regexp.MustCompile(`^(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?$`), + // yyyy[mm[dd]] + regexp.MustCompile(`^(\d{4})(?:(\d{2})(?:(\d{2}))?)?$`), +} + +func parseDateParts(s string) (year, month, day int, err error) { + var parts []string + for _, re := range dateRegexps { + parts = re.FindStringSubmatch(s) + if parts != nil { + break + } + } + if parts == nil { + err = fmt.Errorf("soap date: value %q is not in a recognized ISO8601 date format", s) + return + } + + year = parseInt(parts[1], &err) + month = 1 + day = 1 + if len(parts[2]) != 0 { + month = parseInt(parts[2], &err) + if len(parts[3]) != 0 { + day = parseInt(parts[3], &err) + } + } + + if err != nil { + err = fmt.Errorf("soap date: %q: %v", s, err) + } + + return +} + +var timeRegexps = []*regexp.Regexp{ + // hh[:mm[:ss]] + regexp.MustCompile(`^(\d{2})(?::(\d{2})(?::(\d{2}))?)?$`), + // hh[mm[ss]] + regexp.MustCompile(`^(\d{2})(?:(\d{2})(?:(\d{2}))?)?$`), +} + +func parseTimeParts(s string) (hour, minute, second int, err error) { + var parts []string + for _, re := range timeRegexps { + parts = re.FindStringSubmatch(s) + if parts != nil { + break + } + } + if parts == nil { + err = fmt.Errorf("soap time: value %q is not in ISO8601 time format", s) + return + } + + hour = parseInt(parts[1], &err) + if len(parts[2]) != 0 { + minute = parseInt(parts[2], &err) + if len(parts[3]) != 0 { + second = parseInt(parts[3], &err) + } + } + + if err != nil { + err = fmt.Errorf("soap time: %q: %v", s, err) + } + + return +} + +// (+|-)hh[[:]mm] +var timezoneRegexp = regexp.MustCompile(`^([+-])(\d{2})(?::?(\d{2}))?$`) + +func parseTimezone(s string) (offset int, err error) { + if s == "Z" { + return 0, nil + } + parts := timezoneRegexp.FindStringSubmatch(s) + if parts == nil { + err = fmt.Errorf("soap timezone: value %q is not in ISO8601 timezone format", s) + return + } + + offset = parseInt(parts[2], &err) * 3600 + if len(parts[3]) != 0 { + offset += parseInt(parts[3], &err) * 60 + } + if parts[1] == "-" { + offset = -offset + } + + if err != nil { + err = fmt.Errorf("soap timezone: %q: %v", s, err) + } + + return +} + +var completeDateTimeZoneRegexp = regexp.MustCompile(`^([^T]+)(?:T([^-+Z]+)(.+)?)?$`) + +// splitCompleteDateTimeZone splits date, time and timezone apart from an +// ISO8601 string. It does not ensure that the contents of each part are +// correct, it merely splits on certain delimiters. +// e.g "2010-09-08T12:15:10+0700" => "2010-09-08", "12:15:10", "+0700". +// Timezone can only be present if time is also present. +func splitCompleteDateTimeZone(s string) (dateStr, timeStr, zoneStr string, err error) { + parts := completeDateTimeZoneRegexp.FindStringSubmatch(s) + if parts == nil { + err = fmt.Errorf("soap date/time/zone: value %q is not in ISO8601 datetime format", s) + return + } + dateStr = parts[1] + timeStr = parts[2] + zoneStr = parts[3] + return +} + +// MarshalDate marshals time.Time to SOAP "date" type. Note that this converts +// to local time, and discards the time-of-day components. +func MarshalDate(v time.Time) (string, error) { + return v.In(localLoc).Format("2006-01-02"), nil +} + +var dateFmts = []string{"2006-01-02", "20060102"} + +// UnmarshalDate unmarshals time.Time from SOAP "date" type. This outputs the +// date as midnight in the local time zone. +func UnmarshalDate(s string) (time.Time, error) { + year, month, day, err := parseDateParts(s) + if err != nil { + return time.Time{}, err + } + return time.Date(year, time.Month(month), day, 0, 0, 0, 0, localLoc), nil +} + +// TimeOfDay is used in cases where SOAP "time" or "time.tz" is used. +type TimeOfDay struct { + // Duration of time since midnight. + FromMidnight time.Duration + + // Set to true if Offset is specified. If false, then the timezone is + // unspecified (and by ISO8601 - implies some "local" time). + HasOffset bool + + // Offset is non-zero only if time.tz is used. It is otherwise ignored. If + // non-zero, then it is regarded as a UTC offset in seconds. Note that the + // sub-minutes is ignored by the marshal function. + Offset int +} + +// MarshalTimeOfDay marshals TimeOfDay to the "time" type. +func MarshalTimeOfDay(v TimeOfDay) (string, error) { + d := int64(v.FromMidnight / time.Second) + hour := d / 3600 + d = d % 3600 + minute := d / 60 + second := d % 60 + + return fmt.Sprintf("%02d:%02d:%02d", hour, minute, second), nil +} + +// UnmarshalTimeOfDay unmarshals TimeOfDay from the "time" type. +func UnmarshalTimeOfDay(s string) (TimeOfDay, error) { + t, err := UnmarshalTimeOfDayTz(s) + if err != nil { + return TimeOfDay{}, err + } else if t.HasOffset { + return TimeOfDay{}, fmt.Errorf("soap time: value %q contains unexpected timezone") + } + return t, nil +} + +// MarshalTimeOfDayTz marshals TimeOfDay to the "time.tz" type. +func MarshalTimeOfDayTz(v TimeOfDay) (string, error) { + d := int64(v.FromMidnight / time.Second) + hour := d / 3600 + d = d % 3600 + minute := d / 60 + second := d % 60 + + tz := "" + if v.HasOffset { + if v.Offset == 0 { + tz = "Z" + } else { + offsetMins := v.Offset / 60 + sign := '+' + if offsetMins < 1 { + offsetMins = -offsetMins + sign = '-' + } + tz = fmt.Sprintf("%c%02d:%02d", sign, offsetMins/60, offsetMins%60) + } + } + + return fmt.Sprintf("%02d:%02d:%02d%s", hour, minute, second, tz), nil +} + +// UnmarshalTimeOfDayTz unmarshals TimeOfDay from the "time.tz" type. +func UnmarshalTimeOfDayTz(s string) (tod TimeOfDay, err error) { + zoneIndex := strings.IndexAny(s, "Z+-") + var timePart string + var hasOffset bool + var offset int + if zoneIndex == -1 { + hasOffset = false + timePart = s + } else { + hasOffset = true + timePart = s[:zoneIndex] + if offset, err = parseTimezone(s[zoneIndex:]); err != nil { + return + } + } + + hour, minute, second, err := parseTimeParts(timePart) + if err != nil { + return + } + + fromMidnight := time.Duration(hour*3600+minute*60+second) * time.Second + + // ISO8601 special case - values up to 24:00:00 are allowed, so using + // strictly greater-than for the maximum value. + if fromMidnight > 24*time.Hour || minute >= 60 || second >= 60 { + return TimeOfDay{}, fmt.Errorf("soap time.tz: value %q has value(s) out of range", s) + } + + return TimeOfDay{ + FromMidnight: time.Duration(hour*3600+minute*60+second) * time.Second, + HasOffset: hasOffset, + Offset: offset, + }, nil +} + +// MarshalDateTime marshals time.Time to SOAP "dateTime" type. Note that this +// converts to local time. +func MarshalDateTime(v time.Time) (string, error) { + return v.In(localLoc).Format("2006-01-02T15:04:05"), nil +} + +// UnmarshalDateTime unmarshals time.Time from the SOAP "dateTime" type. This +// returns a value in the local timezone. +func UnmarshalDateTime(s string) (result time.Time, err error) { + dateStr, timeStr, zoneStr, err := splitCompleteDateTimeZone(s) + if err != nil { + return + } + + if len(zoneStr) != 0 { + err = fmt.Errorf("soap datetime: unexpected timezone in %q", s) + return + } + + year, month, day, err := parseDateParts(dateStr) + if err != nil { + return + } + + var hour, minute, second int + if len(timeStr) != 0 { + hour, minute, second, err = parseTimeParts(timeStr) + if err != nil { + return + } + } + + result = time.Date(year, time.Month(month), day, hour, minute, second, 0, localLoc) + return +} + +// MarshalDateTimeTz marshals time.Time to SOAP "dateTime.tz" type. +func MarshalDateTimeTz(v time.Time) (string, error) { + return v.Format("2006-01-02T15:04:05-07:00"), nil +} + +// UnmarshalDateTimeTz unmarshals time.Time from the SOAP "dateTime.tz" type. +// This returns a value in the local timezone when the timezone is unspecified. +func UnmarshalDateTimeTz(s string) (result time.Time, err error) { + dateStr, timeStr, zoneStr, err := splitCompleteDateTimeZone(s) + if err != nil { + return + } + + year, month, day, err := parseDateParts(dateStr) + if err != nil { + return + } + + var hour, minute, second int + var location *time.Location = localLoc + if len(timeStr) != 0 { + hour, minute, second, err = parseTimeParts(timeStr) + if err != nil { + return + } + if len(zoneStr) != 0 { + var offset int + offset, err = parseTimezone(zoneStr) + if offset == 0 { + location = time.UTC + } else { + location = time.FixedZone("", offset) + } + } + } + + result = time.Date(year, time.Month(month), day, hour, minute, second, 0, location) + return +} + +// MarshalBoolean marshals bool to SOAP "boolean" type. +func MarshalBoolean(v bool) (string, error) { + if v { + return "1", nil + } + return "0", nil +} + +// UnmarshalBoolean unmarshals bool from the SOAP "boolean" type. +func UnmarshalBoolean(s string) (bool, error) { + switch s { + case "0", "false", "no": + return false, nil + case "1", "true", "yes": + return true, nil + } + return false, fmt.Errorf("soap boolean: %q is not a valid boolean value", s) +} + +// MarshalBinBase64 marshals []byte to SOAP "bin.base64" type. +func MarshalBinBase64(v []byte) (string, error) { + return base64.StdEncoding.EncodeToString(v), nil +} + +// UnmarshalBinBase64 unmarshals []byte from the SOAP "bin.base64" type. +func UnmarshalBinBase64(s string) ([]byte, error) { + return base64.StdEncoding.DecodeString(s) +} + +// MarshalBinHex marshals []byte to SOAP "bin.hex" type. +func MarshalBinHex(v []byte) (string, error) { + return hex.EncodeToString(v), nil +} + +// UnmarshalBinHex unmarshals []byte from the SOAP "bin.hex" type. +func UnmarshalBinHex(s string) ([]byte, error) { + return hex.DecodeString(s) +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/soap/types_test.go b/Godeps/_workspace/src/github.com/huin/goupnp/soap/types_test.go new file mode 100644 index 0000000000..da68161909 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/soap/types_test.go @@ -0,0 +1,481 @@ +package soap + +import ( + "bytes" + "math" + "testing" + "time" +) + +type convTest interface { + Marshal() (string, error) + Unmarshal(string) (interface{}, error) + Equal(result interface{}) bool +} + +// duper is an interface that convTest values may optionally also implement to +// generate another convTest for a value in an otherwise identical testCase. +type duper interface { + Dupe(tag string) []convTest +} + +type testCase struct { + value convTest + str string + wantMarshalErr bool + wantUnmarshalErr bool + noMarshal bool + noUnMarshal bool + tag string +} + +type Ui1Test uint8 + +func (v Ui1Test) Marshal() (string, error) { + return MarshalUi1(uint8(v)) +} +func (v Ui1Test) Unmarshal(s string) (interface{}, error) { + return UnmarshalUi1(s) +} +func (v Ui1Test) Equal(result interface{}) bool { + return uint8(v) == result.(uint8) +} +func (v Ui1Test) Dupe(tag string) []convTest { + if tag == "dupe" { + return []convTest{ + Ui2Test(v), + Ui4Test(v), + } + } + return nil +} + +type Ui2Test uint16 + +func (v Ui2Test) Marshal() (string, error) { + return MarshalUi2(uint16(v)) +} +func (v Ui2Test) Unmarshal(s string) (interface{}, error) { + return UnmarshalUi2(s) +} +func (v Ui2Test) Equal(result interface{}) bool { + return uint16(v) == result.(uint16) +} + +type Ui4Test uint32 + +func (v Ui4Test) Marshal() (string, error) { + return MarshalUi4(uint32(v)) +} +func (v Ui4Test) Unmarshal(s string) (interface{}, error) { + return UnmarshalUi4(s) +} +func (v Ui4Test) Equal(result interface{}) bool { + return uint32(v) == result.(uint32) +} + +type I1Test int8 + +func (v I1Test) Marshal() (string, error) { + return MarshalI1(int8(v)) +} +func (v I1Test) Unmarshal(s string) (interface{}, error) { + return UnmarshalI1(s) +} +func (v I1Test) Equal(result interface{}) bool { + return int8(v) == result.(int8) +} +func (v I1Test) Dupe(tag string) []convTest { + if tag == "dupe" { + return []convTest{ + I2Test(v), + I4Test(v), + } + } + return nil +} + +type I2Test int16 + +func (v I2Test) Marshal() (string, error) { + return MarshalI2(int16(v)) +} +func (v I2Test) Unmarshal(s string) (interface{}, error) { + return UnmarshalI2(s) +} +func (v I2Test) Equal(result interface{}) bool { + return int16(v) == result.(int16) +} + +type I4Test int32 + +func (v I4Test) Marshal() (string, error) { + return MarshalI4(int32(v)) +} +func (v I4Test) Unmarshal(s string) (interface{}, error) { + return UnmarshalI4(s) +} +func (v I4Test) Equal(result interface{}) bool { + return int32(v) == result.(int32) +} + +type IntTest int64 + +func (v IntTest) Marshal() (string, error) { + return MarshalInt(int64(v)) +} +func (v IntTest) Unmarshal(s string) (interface{}, error) { + return UnmarshalInt(s) +} +func (v IntTest) Equal(result interface{}) bool { + return int64(v) == result.(int64) +} + +type Fixed14_4Test float64 + +func (v Fixed14_4Test) Marshal() (string, error) { + return MarshalFixed14_4(float64(v)) +} +func (v Fixed14_4Test) Unmarshal(s string) (interface{}, error) { + return UnmarshalFixed14_4(s) +} +func (v Fixed14_4Test) Equal(result interface{}) bool { + return math.Abs(float64(v)-result.(float64)) < 0.001 +} + +type CharTest rune + +func (v CharTest) Marshal() (string, error) { + return MarshalChar(rune(v)) +} +func (v CharTest) Unmarshal(s string) (interface{}, error) { + return UnmarshalChar(s) +} +func (v CharTest) Equal(result interface{}) bool { + return rune(v) == result.(rune) +} + +type DateTest struct{ time.Time } + +func (v DateTest) Marshal() (string, error) { + return MarshalDate(time.Time(v.Time)) +} +func (v DateTest) Unmarshal(s string) (interface{}, error) { + return UnmarshalDate(s) +} +func (v DateTest) Equal(result interface{}) bool { + return v.Time.Equal(result.(time.Time)) +} +func (v DateTest) Dupe(tag string) []convTest { + if tag != "no:dateTime" { + return []convTest{DateTimeTest{v.Time}} + } + return nil +} + +type TimeOfDayTest struct { + TimeOfDay +} + +func (v TimeOfDayTest) Marshal() (string, error) { + return MarshalTimeOfDay(v.TimeOfDay) +} +func (v TimeOfDayTest) Unmarshal(s string) (interface{}, error) { + return UnmarshalTimeOfDay(s) +} +func (v TimeOfDayTest) Equal(result interface{}) bool { + return v.TimeOfDay == result.(TimeOfDay) +} +func (v TimeOfDayTest) Dupe(tag string) []convTest { + if tag != "no:time.tz" { + return []convTest{TimeOfDayTzTest{v.TimeOfDay}} + } + return nil +} + +type TimeOfDayTzTest struct { + TimeOfDay +} + +func (v TimeOfDayTzTest) Marshal() (string, error) { + return MarshalTimeOfDayTz(v.TimeOfDay) +} +func (v TimeOfDayTzTest) Unmarshal(s string) (interface{}, error) { + return UnmarshalTimeOfDayTz(s) +} +func (v TimeOfDayTzTest) Equal(result interface{}) bool { + return v.TimeOfDay == result.(TimeOfDay) +} + +type DateTimeTest struct{ time.Time } + +func (v DateTimeTest) Marshal() (string, error) { + return MarshalDateTime(time.Time(v.Time)) +} +func (v DateTimeTest) Unmarshal(s string) (interface{}, error) { + return UnmarshalDateTime(s) +} +func (v DateTimeTest) Equal(result interface{}) bool { + return v.Time.Equal(result.(time.Time)) +} +func (v DateTimeTest) Dupe(tag string) []convTest { + if tag != "no:dateTime.tz" { + return []convTest{DateTimeTzTest{v.Time}} + } + return nil +} + +type DateTimeTzTest struct{ time.Time } + +func (v DateTimeTzTest) Marshal() (string, error) { + return MarshalDateTimeTz(time.Time(v.Time)) +} +func (v DateTimeTzTest) Unmarshal(s string) (interface{}, error) { + return UnmarshalDateTimeTz(s) +} +func (v DateTimeTzTest) Equal(result interface{}) bool { + return v.Time.Equal(result.(time.Time)) +} + +type BooleanTest bool + +func (v BooleanTest) Marshal() (string, error) { + return MarshalBoolean(bool(v)) +} +func (v BooleanTest) Unmarshal(s string) (interface{}, error) { + return UnmarshalBoolean(s) +} +func (v BooleanTest) Equal(result interface{}) bool { + return bool(v) == result.(bool) +} + +type BinBase64Test []byte + +func (v BinBase64Test) Marshal() (string, error) { + return MarshalBinBase64([]byte(v)) +} +func (v BinBase64Test) Unmarshal(s string) (interface{}, error) { + return UnmarshalBinBase64(s) +} +func (v BinBase64Test) Equal(result interface{}) bool { + return bytes.Equal([]byte(v), result.([]byte)) +} + +type BinHexTest []byte + +func (v BinHexTest) Marshal() (string, error) { + return MarshalBinHex([]byte(v)) +} +func (v BinHexTest) Unmarshal(s string) (interface{}, error) { + return UnmarshalBinHex(s) +} +func (v BinHexTest) Equal(result interface{}) bool { + return bytes.Equal([]byte(v), result.([]byte)) +} + +func Test(t *testing.T) { + const time010203 time.Duration = (1*3600 + 2*60 + 3) * time.Second + const time0102 time.Duration = (1*3600 + 2*60) * time.Second + const time01 time.Duration = (1 * 3600) * time.Second + const time235959 time.Duration = (23*3600 + 59*60 + 59) * time.Second + + // Fake out the local time for the implementation. + localLoc = time.FixedZone("Fake/Local", 6*3600) + defer func() { + localLoc = time.Local + }() + + tests := []testCase{ + // ui1 + {str: "", value: Ui1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, + {str: " ", value: Ui1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, + {str: "abc", value: Ui1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, + {str: "-1", value: Ui1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, + {str: "0", value: Ui1Test(0), tag: "dupe"}, + {str: "1", value: Ui1Test(1), tag: "dupe"}, + {str: "255", value: Ui1Test(255), tag: "dupe"}, + {str: "256", value: Ui1Test(0), wantUnmarshalErr: true, noMarshal: true}, + + // ui2 + {str: "65535", value: Ui2Test(65535)}, + {str: "65536", value: Ui2Test(0), wantUnmarshalErr: true, noMarshal: true}, + + // ui4 + {str: "4294967295", value: Ui4Test(4294967295)}, + {str: "4294967296", value: Ui4Test(0), wantUnmarshalErr: true, noMarshal: true}, + + // i1 + {str: "", value: I1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, + {str: " ", value: I1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, + {str: "abc", value: I1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, + {str: "0", value: I1Test(0), tag: "dupe"}, + {str: "-1", value: I1Test(-1), tag: "dupe"}, + {str: "127", value: I1Test(127), tag: "dupe"}, + {str: "-128", value: I1Test(-128), tag: "dupe"}, + {str: "128", value: I1Test(0), wantUnmarshalErr: true, noMarshal: true}, + {str: "-129", value: I1Test(0), wantUnmarshalErr: true, noMarshal: true}, + + // i2 + {str: "32767", value: I2Test(32767)}, + {str: "-32768", value: I2Test(-32768)}, + {str: "32768", value: I2Test(0), wantUnmarshalErr: true, noMarshal: true}, + {str: "-32769", value: I2Test(0), wantUnmarshalErr: true, noMarshal: true}, + + // i4 + {str: "2147483647", value: I4Test(2147483647)}, + {str: "-2147483648", value: I4Test(-2147483648)}, + {str: "2147483648", value: I4Test(0), wantUnmarshalErr: true, noMarshal: true}, + {str: "-2147483649", value: I4Test(0), wantUnmarshalErr: true, noMarshal: true}, + + // int + {str: "9223372036854775807", value: IntTest(9223372036854775807)}, + {str: "-9223372036854775808", value: IntTest(-9223372036854775808)}, + {str: "9223372036854775808", value: IntTest(0), wantUnmarshalErr: true, noMarshal: true}, + {str: "-9223372036854775809", value: IntTest(0), wantUnmarshalErr: true, noMarshal: true}, + + // fixed.14.4 + {str: "0.0000", value: Fixed14_4Test(0)}, + {str: "1.0000", value: Fixed14_4Test(1)}, + {str: "1.2346", value: Fixed14_4Test(1.23456)}, + {str: "-1.0000", value: Fixed14_4Test(-1)}, + {str: "-1.2346", value: Fixed14_4Test(-1.23456)}, + {str: "10000000000000.0000", value: Fixed14_4Test(1e13)}, + {str: "100000000000000.0000", value: Fixed14_4Test(1e14), wantMarshalErr: true, wantUnmarshalErr: true}, + {str: "-10000000000000.0000", value: Fixed14_4Test(-1e13)}, + {str: "-100000000000000.0000", value: Fixed14_4Test(-1e14), wantMarshalErr: true, wantUnmarshalErr: true}, + + // char + {str: "a", value: CharTest('a')}, + {str: "z", value: CharTest('z')}, + {str: "\u1234", value: CharTest(0x1234)}, + {str: "aa", value: CharTest(0), wantMarshalErr: true, wantUnmarshalErr: true}, + {str: "", value: CharTest(0), wantMarshalErr: true, wantUnmarshalErr: true}, + + // date + {str: "2013-10-08", value: DateTest{time.Date(2013, 10, 8, 0, 0, 0, 0, localLoc)}, tag: "no:dateTime"}, + {str: "20131008", value: DateTest{time.Date(2013, 10, 8, 0, 0, 0, 0, localLoc)}, noMarshal: true, tag: "no:dateTime"}, + {str: "2013-10-08T10:30:50", value: DateTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime"}, + {str: "2013-10-08T10:30:50Z", value: DateTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime"}, + {str: "", value: DateTest{}, wantMarshalErr: true, wantUnmarshalErr: true, noMarshal: true}, + {str: "-1", value: DateTest{}, wantUnmarshalErr: true, noMarshal: true}, + + // time + {str: "00:00:00", value: TimeOfDayTest{TimeOfDay{FromMidnight: 0}}}, + {str: "000000", value: TimeOfDayTest{TimeOfDay{FromMidnight: 0}}, noMarshal: true}, + {str: "24:00:00", value: TimeOfDayTest{TimeOfDay{FromMidnight: 24 * time.Hour}}, noMarshal: true}, // ISO8601 special case + {str: "24:01:00", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true}, + {str: "24:00:01", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true}, + {str: "25:00:00", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true}, + {str: "00:60:00", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true}, + {str: "00:00:60", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true}, + {str: "01:02:03", value: TimeOfDayTest{TimeOfDay{FromMidnight: time010203}}}, + {str: "010203", value: TimeOfDayTest{TimeOfDay{FromMidnight: time010203}}, noMarshal: true}, + {str: "23:59:59", value: TimeOfDayTest{TimeOfDay{FromMidnight: time235959}}}, + {str: "235959", value: TimeOfDayTest{TimeOfDay{FromMidnight: time235959}}, noMarshal: true}, + {str: "01:02", value: TimeOfDayTest{TimeOfDay{FromMidnight: time0102}}, noMarshal: true}, + {str: "0102", value: TimeOfDayTest{TimeOfDay{FromMidnight: time0102}}, noMarshal: true}, + {str: "01", value: TimeOfDayTest{TimeOfDay{FromMidnight: time01}}, noMarshal: true}, + {str: "foo 01:02:03", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, + {str: "foo\n01:02:03", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, + {str: "01:02:03 foo", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, + {str: "01:02:03\nfoo", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, + {str: "01:02:03Z", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, + {str: "01:02:03+01", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, + {str: "01:02:03+01:23", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, + {str: "01:02:03+0123", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, + {str: "01:02:03-01", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, + {str: "01:02:03-01:23", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, + {str: "01:02:03-0123", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, + + // time.tz + {str: "24:00:01", value: TimeOfDayTzTest{}, wantUnmarshalErr: true, noMarshal: true}, + {str: "01Z", value: TimeOfDayTzTest{TimeOfDay{time01, true, 0}}, noMarshal: true}, + {str: "01:02:03Z", value: TimeOfDayTzTest{TimeOfDay{time010203, true, 0}}}, + {str: "01+01", value: TimeOfDayTzTest{TimeOfDay{time01, true, 3600}}, noMarshal: true}, + {str: "01:02:03+01", value: TimeOfDayTzTest{TimeOfDay{time010203, true, 3600}}, noMarshal: true}, + {str: "01:02:03+01:23", value: TimeOfDayTzTest{TimeOfDay{time010203, true, 3600 + 23*60}}}, + {str: "01:02:03+0123", value: TimeOfDayTzTest{TimeOfDay{time010203, true, 3600 + 23*60}}, noMarshal: true}, + {str: "01:02:03-01", value: TimeOfDayTzTest{TimeOfDay{time010203, true, -3600}}, noMarshal: true}, + {str: "01:02:03-01:23", value: TimeOfDayTzTest{TimeOfDay{time010203, true, -(3600 + 23*60)}}}, + {str: "01:02:03-0123", value: TimeOfDayTzTest{TimeOfDay{time010203, true, -(3600 + 23*60)}}, noMarshal: true}, + + // dateTime + {str: "2013-10-08T00:00:00", value: DateTimeTest{time.Date(2013, 10, 8, 0, 0, 0, 0, localLoc)}, tag: "no:dateTime.tz"}, + {str: "20131008", value: DateTimeTest{time.Date(2013, 10, 8, 0, 0, 0, 0, localLoc)}, noMarshal: true}, + {str: "2013-10-08T10:30:50", value: DateTimeTest{time.Date(2013, 10, 8, 10, 30, 50, 0, localLoc)}, tag: "no:dateTime.tz"}, + {str: "2013-10-08T10:30:50T", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true}, + {str: "2013-10-08T10:30:50+01", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime.tz"}, + {str: "2013-10-08T10:30:50+01:23", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime.tz"}, + {str: "2013-10-08T10:30:50+0123", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime.tz"}, + {str: "2013-10-08T10:30:50-01", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime.tz"}, + {str: "2013-10-08T10:30:50-01:23", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime.tz"}, + {str: "2013-10-08T10:30:50-0123", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime.tz"}, + + // dateTime.tz + {str: "2013-10-08T10:30:50", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, localLoc)}, noMarshal: true}, + {str: "2013-10-08T10:30:50+01", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, time.FixedZone("+01:00", 3600))}, noMarshal: true}, + {str: "2013-10-08T10:30:50+01:23", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, time.FixedZone("+01:23", 3600+23*60))}}, + {str: "2013-10-08T10:30:50+0123", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, time.FixedZone("+01:23", 3600+23*60))}, noMarshal: true}, + {str: "2013-10-08T10:30:50-01", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, time.FixedZone("-01:00", -3600))}, noMarshal: true}, + {str: "2013-10-08T10:30:50-01:23", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, time.FixedZone("-01:23", -(3600+23*60)))}}, + {str: "2013-10-08T10:30:50-0123", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, time.FixedZone("-01:23", -(3600+23*60)))}, noMarshal: true}, + + // boolean + {str: "0", value: BooleanTest(false)}, + {str: "1", value: BooleanTest(true)}, + {str: "false", value: BooleanTest(false), noMarshal: true}, + {str: "true", value: BooleanTest(true), noMarshal: true}, + {str: "no", value: BooleanTest(false), noMarshal: true}, + {str: "yes", value: BooleanTest(true), noMarshal: true}, + {str: "", value: BooleanTest(false), noMarshal: true, wantUnmarshalErr: true}, + {str: "other", value: BooleanTest(false), noMarshal: true, wantUnmarshalErr: true}, + {str: "2", value: BooleanTest(false), noMarshal: true, wantUnmarshalErr: true}, + {str: "-1", value: BooleanTest(false), noMarshal: true, wantUnmarshalErr: true}, + + // bin.base64 + {str: "", value: BinBase64Test{}}, + {str: "YQ==", value: BinBase64Test("a")}, + {str: "TG9uZ2VyIFN0cmluZy4=", value: BinBase64Test("Longer String.")}, + {str: "TG9uZ2VyIEFsaWduZWQu", value: BinBase64Test("Longer Aligned.")}, + + // bin.hex + {str: "", value: BinHexTest{}}, + {str: "61", value: BinHexTest("a")}, + {str: "4c6f6e67657220537472696e672e", value: BinHexTest("Longer String.")}, + {str: "4C6F6E67657220537472696E672E", value: BinHexTest("Longer String."), noMarshal: true}, + } + + // Generate extra test cases from convTests that implement duper. + var extras []testCase + for i := range tests { + if duper, ok := tests[i].value.(duper); ok { + dupes := duper.Dupe(tests[i].tag) + for _, duped := range dupes { + dupedCase := testCase(tests[i]) + dupedCase.value = duped + extras = append(extras, dupedCase) + } + } + } + tests = append(tests, extras...) + + for _, test := range tests { + if test.noMarshal { + } else if resultStr, err := test.value.Marshal(); err != nil && !test.wantMarshalErr { + t.Errorf("For %T marshal %v, want %q, got error: %v", test.value, test.value, test.str, err) + } else if err == nil && test.wantMarshalErr { + t.Errorf("For %T marshal %v, want error, got %q", test.value, test.value, resultStr) + } else if err == nil && resultStr != test.str { + t.Errorf("For %T marshal %v, want %q, got %q", test.value, test.value, test.str, resultStr) + } + + if test.noUnMarshal { + } else if resultValue, err := test.value.Unmarshal(test.str); err != nil && !test.wantUnmarshalErr { + t.Errorf("For %T unmarshal %q, want %v, got error: %v", test.value, test.str, test.value, err) + } else if err == nil && test.wantUnmarshalErr { + t.Errorf("For %T unmarshal %q, want error, got %v", test.value, test.str, resultValue) + } else if err == nil && !test.value.Equal(resultValue) { + t.Errorf("For %T unmarshal %q, want %v, got %v", test.value, test.str, test.value, resultValue) + } + } +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/ssdp/registry.go b/Godeps/_workspace/src/github.com/huin/goupnp/ssdp/registry.go new file mode 100644 index 0000000000..38d10203fb --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/ssdp/registry.go @@ -0,0 +1,202 @@ +package ssdp + +import ( + "fmt" + "log" + "net/http" + "net/url" + "regexp" + "strconv" + "sync" + "time" + + "github.com/huin/goupnp/httpu" +) + +const ( + maxExpiryTimeSeconds = 24 * 60 * 60 +) + +var ( + maxAgeRx = regexp.MustCompile("max-age=([0-9]+)") +) + +type Entry struct { + // The address that the entry data was actually received from. + RemoteAddr string + // Unique Service Name. Identifies a unique instance of a device or service. + USN string + // Notfication Type. The type of device or service being announced. + NT string + // Server's self-identifying string. + Server string + Host string + // Location of the UPnP root device description. + Location *url.URL + + // Despite BOOTID,CONFIGID being required fields, apparently they are not + // always set by devices. Set to -1 if not present. + + BootID int32 + ConfigID int32 + + SearchPort uint16 + + // When the last update was received for this entry identified by this USN. + LastUpdate time.Time + // When the last update's cached values are advised to expire. + CacheExpiry time.Time +} + +func newEntryFromRequest(r *http.Request) (*Entry, error) { + now := time.Now() + expiryDuration, err := parseCacheControlMaxAge(r.Header.Get("CACHE-CONTROL")) + if err != nil { + return nil, fmt.Errorf("ssdp: error parsing CACHE-CONTROL max age: %v", err) + } + + loc, err := url.Parse(r.Header.Get("LOCATION")) + if err != nil { + return nil, fmt.Errorf("ssdp: error parsing entry Location URL: %v", err) + } + + bootID, err := parseUpnpIntHeader(r.Header, "BOOTID.UPNP.ORG", -1) + if err != nil { + return nil, err + } + configID, err := parseUpnpIntHeader(r.Header, "CONFIGID.UPNP.ORG", -1) + if err != nil { + return nil, err + } + searchPort, err := parseUpnpIntHeader(r.Header, "SEARCHPORT.UPNP.ORG", ssdpSearchPort) + if err != nil { + return nil, err + } + + if searchPort < 1 || searchPort > 65535 { + return nil, fmt.Errorf("ssdp: search port %d is out of range", searchPort) + } + + return &Entry{ + RemoteAddr: r.RemoteAddr, + USN: r.Header.Get("USN"), + NT: r.Header.Get("NT"), + Server: r.Header.Get("SERVER"), + Host: r.Header.Get("HOST"), + Location: loc, + BootID: bootID, + ConfigID: configID, + SearchPort: uint16(searchPort), + LastUpdate: now, + CacheExpiry: now.Add(expiryDuration), + }, nil +} + +func parseCacheControlMaxAge(cc string) (time.Duration, error) { + matches := maxAgeRx.FindStringSubmatch(cc) + if len(matches) != 2 { + return 0, fmt.Errorf("did not find exactly one max-age in cache control header: %q", cc) + } + expirySeconds, err := strconv.ParseInt(matches[1], 10, 16) + if err != nil { + return 0, err + } + if expirySeconds < 1 || expirySeconds > maxExpiryTimeSeconds { + return 0, fmt.Errorf("rejecting bad expiry time of %d seconds", expirySeconds) + } + return time.Duration(expirySeconds) * time.Second, nil +} + +// parseUpnpIntHeader is intended to parse the +// {BOOT,CONFIGID,SEARCHPORT}.UPNP.ORG header fields. It returns the def if +// the head is empty or missing. +func parseUpnpIntHeader(headers http.Header, headerName string, def int32) (int32, error) { + s := headers.Get(headerName) + if s == "" { + return def, nil + } + v, err := strconv.ParseInt(s, 10, 32) + if err != nil { + return 0, fmt.Errorf("ssdp: could not parse header %s: %v", headerName, err) + } + return int32(v), nil +} + +var _ httpu.Handler = new(Registry) + +// Registry maintains knowledge of discovered devices and services. +type Registry struct { + lock sync.Mutex + byUSN map[string]*Entry +} + +func NewRegistry() *Registry { + return &Registry{ + byUSN: make(map[string]*Entry), + } +} + +// ServeMessage implements httpu.Handler, and uses SSDP NOTIFY requests to +// maintain the registry of devices and services. +func (reg *Registry) ServeMessage(r *http.Request) { + if r.Method != methodNotify { + return + } + + nts := r.Header.Get("nts") + + var err error + switch nts { + case ntsAlive: + err = reg.handleNTSAlive(r) + case ntsUpdate: + err = reg.handleNTSUpdate(r) + case ntsByebye: + err = reg.handleNTSByebye(r) + default: + err = fmt.Errorf("unknown NTS value: %q", nts) + } + log.Printf("In %s request from %s: %v", nts, r.RemoteAddr, err) +} + +func (reg *Registry) handleNTSAlive(r *http.Request) error { + entry, err := newEntryFromRequest(r) + if err != nil { + return err + } + + reg.lock.Lock() + defer reg.lock.Unlock() + + reg.byUSN[entry.USN] = entry + + return nil +} + +func (reg *Registry) handleNTSUpdate(r *http.Request) error { + entry, err := newEntryFromRequest(r) + if err != nil { + return err + } + nextBootID, err := parseUpnpIntHeader(r.Header, "NEXTBOOTID.UPNP.ORG", -1) + if err != nil { + return err + } + entry.BootID = nextBootID + + reg.lock.Lock() + defer reg.lock.Unlock() + + reg.byUSN[entry.USN] = entry + + return nil +} + +func (reg *Registry) handleNTSByebye(r *http.Request) error { + reg.lock.Lock() + defer reg.lock.Unlock() + + delete(reg.byUSN, r.Header.Get("USN")) + + return nil +} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/ssdp/ssdp.go b/Godeps/_workspace/src/github.com/huin/goupnp/ssdp/ssdp.go new file mode 100644 index 0000000000..8178f5d948 --- /dev/null +++ b/Godeps/_workspace/src/github.com/huin/goupnp/ssdp/ssdp.go @@ -0,0 +1,83 @@ +package ssdp + +import ( + "errors" + "log" + "net/http" + "net/url" + "strconv" + "time" + + "github.com/huin/goupnp/httpu" +) + +const ( + ssdpDiscover = `"ssdp:discover"` + ntsAlive = `ssdp:alive` + ntsByebye = `ssdp:byebye` + ntsUpdate = `ssdp:update` + ssdpUDP4Addr = "239.255.255.250:1900" + ssdpSearchPort = 1900 + methodSearch = "M-SEARCH" + methodNotify = "NOTIFY" +) + +// SSDPRawSearch performs a fairly raw SSDP search request, and returns the +// unique response(s) that it receives. Each response has the requested +// searchTarget, a USN, and a valid location. maxWaitSeconds states how long to +// wait for responses in seconds, and must be a minimum of 1 (the +// implementation waits an additional 100ms for responses to arrive), 2 is a +// reasonable value for this. numSends is the number of requests to send - 3 is +// a reasonable value for this. +func SSDPRawSearch(httpu *httpu.HTTPUClient, searchTarget string, maxWaitSeconds int, numSends int) ([]*http.Response, error) { + if maxWaitSeconds < 1 { + return nil, errors.New("ssdp: maxWaitSeconds must be >= 1") + } + + seenUsns := make(map[string]bool) + var responses []*http.Response + req := http.Request{ + Method: methodSearch, + // TODO: Support both IPv4 and IPv6. + Host: ssdpUDP4Addr, + URL: &url.URL{Opaque: "*"}, + Header: http.Header{ + // Putting headers in here avoids them being title-cased. + // (The UPnP discovery protocol uses case-sensitive headers) + "HOST": []string{ssdpUDP4Addr}, + "MX": []string{strconv.FormatInt(int64(maxWaitSeconds), 10)}, + "MAN": []string{ssdpDiscover}, + "ST": []string{searchTarget}, + }, + } + allResponses, err := httpu.Do(&req, time.Duration(maxWaitSeconds)*time.Second+100*time.Millisecond, numSends) + if err != nil { + return nil, err + } + for _, response := range allResponses { + if response.StatusCode != 200 { + log.Printf("ssdp: got response status code %q in search response", response.Status) + continue + } + if st := response.Header.Get("ST"); st != searchTarget { + log.Printf("ssdp: got unexpected search target result %q", st) + continue + } + location, err := response.Location() + if err != nil { + log.Printf("ssdp: no usable location in search response (discarding): %v", err) + continue + } + usn := response.Header.Get("USN") + if usn == "" { + log.Printf("ssdp: empty/missing USN in search response (using location instead): %v", err) + usn = location.String() + } + if _, alreadySeen := seenUsns[usn]; !alreadySeen { + seenUsns[usn] = true + responses = append(responses, response) + } + } + + return responses, nil +} diff --git a/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/LICENSE b/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/LICENSE new file mode 100644 index 0000000000..249514b0fb --- /dev/null +++ b/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/LICENSE @@ -0,0 +1,13 @@ + Copyright 2013 John Howard Palevich + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/README.md b/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/README.md new file mode 100644 index 0000000000..15f72fd815 --- /dev/null +++ b/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/README.md @@ -0,0 +1,48 @@ +go-nat-pmp +========== + +A Go language client for the NAT-PMP internet protocol for port mapping and discovering the external +IP address of a firewall. + +NAT-PMP is supported by Apple brand routers and open source routers like Tomato and DD-WRT. + +See http://tools.ietf.org/html/draft-cheshire-nat-pmp-03 + +Get the package +--------------- + + go get -u github.com/jackpal/go-nat-pmp + +Usage +----- + + import natpmp "github.com/jackpal/go-nat-pmp" + + client := natpmp.NewClient(gatewayIP) + response, err := client.GetExternalAddress() + if err != nil { + return + } + print("External IP address:", response.ExternalIPAddress) + +Notes +----- + +There doesn't seem to be an easy way to programmatically determine the address of the default gateway. +(Linux and OSX have a "routes" kernel API that can be examined to get this information, but there is +no Go package for getting this information.) + +Clients +------- + +This library is used in the Taipei Torrent BitTorrent client http://github.com/jackpal/Taipei-Torrent + +Complete documentation +---------------------- + + http://godoc.org/github.com/jackpal/go-nat-pmp + +License +------- + +This project is licensed under the Apache License 2.0. diff --git a/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go b/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go new file mode 100644 index 0000000000..8ce4e8342e --- /dev/null +++ b/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go @@ -0,0 +1,184 @@ +package natpmp + +import ( + "fmt" + "log" + "net" + "time" +) + +// Implement the NAT-PMP protocol, typically supported by Apple routers and open source +// routers such as DD-WRT and Tomato. +// +// See http://tools.ietf.org/html/draft-cheshire-nat-pmp-03 +// +// Usage: +// +// client := natpmp.NewClient(gatewayIP) +// response, err := client.GetExternalAddress() + +const nAT_PMP_PORT = 5351 + +const nAT_TRIES = 9 + +const nAT_INITIAL_MS = 250 + +// The recommended mapping lifetime for AddPortMapping +const RECOMMENDED_MAPPING_LIFETIME_SECONDS = 3600 + +// Client is a NAT-PMP protocol client. +type Client struct { + gateway net.IP +} + +// Create a NAT-PMP client for the NAT-PMP server at the gateway. +func NewClient(gateway net.IP) (nat *Client) { + return &Client{gateway} +} + +// Results of the NAT-PMP GetExternalAddress operation +type GetExternalAddressResult struct { + SecondsSinceStartOfEpoc uint32 + ExternalIPAddress [4]byte +} + +// Get the external address of the router. +func (n *Client) GetExternalAddress() (result *GetExternalAddressResult, err error) { + msg := make([]byte, 2) + msg[0] = 0 // Version 0 + msg[1] = 0 // OP Code 0 + response, err := n.rpc(msg, 12) + if err != nil { + return + } + result = &GetExternalAddressResult{} + result.SecondsSinceStartOfEpoc = readNetworkOrderUint32(response[4:8]) + copy(result.ExternalIPAddress[:], response[8:12]) + return +} + +// Results of the NAT-PMP AddPortMapping operation +type AddPortMappingResult struct { + SecondsSinceStartOfEpoc uint32 + InternalPort uint16 + MappedExternalPort uint16 + PortMappingLifetimeInSeconds uint32 +} + +// Add (or delete) a port mapping. To delete a mapping, set the requestedExternalPort and lifetime to 0 +func (n *Client) AddPortMapping(protocol string, internalPort, requestedExternalPort int, lifetime int) (result *AddPortMappingResult, err error) { + var opcode byte + if protocol == "udp" { + opcode = 1 + } else if protocol == "tcp" { + opcode = 2 + } else { + err = fmt.Errorf("unknown protocol %v", protocol) + return + } + msg := make([]byte, 12) + msg[0] = 0 // Version 0 + msg[1] = opcode + writeNetworkOrderUint16(msg[4:6], uint16(internalPort)) + writeNetworkOrderUint16(msg[6:8], uint16(requestedExternalPort)) + writeNetworkOrderUint32(msg[8:12], uint32(lifetime)) + response, err := n.rpc(msg, 16) + if err != nil { + return + } + result = &AddPortMappingResult{} + result.SecondsSinceStartOfEpoc = readNetworkOrderUint32(response[4:8]) + result.InternalPort = readNetworkOrderUint16(response[8:10]) + result.MappedExternalPort = readNetworkOrderUint16(response[10:12]) + result.PortMappingLifetimeInSeconds = readNetworkOrderUint32(response[12:16]) + return +} + +func (n *Client) rpc(msg []byte, resultSize int) (result []byte, err error) { + var server net.UDPAddr + server.IP = n.gateway + server.Port = nAT_PMP_PORT + conn, err := net.DialUDP("udp", nil, &server) + if err != nil { + return + } + defer conn.Close() + + result = make([]byte, resultSize) + + needNewDeadline := true + + var tries uint + for tries = 0; tries < nAT_TRIES; { + if needNewDeadline { + err = conn.SetDeadline(time.Now().Add((nAT_INITIAL_MS << tries) * time.Millisecond)) + if err != nil { + return + } + needNewDeadline = false + } + _, err = conn.Write(msg) + if err != nil { + return + } + var bytesRead int + var remoteAddr *net.UDPAddr + bytesRead, remoteAddr, err = conn.ReadFromUDP(result) + if err != nil { + if err.(net.Error).Timeout() { + tries++ + needNewDeadline = true + continue + } + return + } + if !remoteAddr.IP.Equal(n.gateway) { + log.Printf("Ignoring packet because IPs differ:", remoteAddr, n.gateway) + // Ignore this packet. + // Continue without increasing retransmission timeout or deadline. + continue + } + if bytesRead != resultSize { + err = fmt.Errorf("unexpected result size %d, expected %d", bytesRead, resultSize) + return + } + if result[0] != 0 { + err = fmt.Errorf("unknown protocol version %d", result[0]) + return + } + expectedOp := msg[1] | 0x80 + if result[1] != expectedOp { + err = fmt.Errorf("Unexpected opcode %d. Expected %d", result[1], expectedOp) + return + } + resultCode := readNetworkOrderUint16(result[2:4]) + if resultCode != 0 { + err = fmt.Errorf("Non-zero result code %d", resultCode) + return + } + // If we got here the RPC is good. + return + } + err = fmt.Errorf("Timed out trying to contact gateway") + return +} + +func writeNetworkOrderUint16(buf []byte, d uint16) { + buf[0] = byte(d >> 8) + buf[1] = byte(d) +} + +func writeNetworkOrderUint32(buf []byte, d uint32) { + buf[0] = byte(d >> 24) + buf[1] = byte(d >> 16) + buf[2] = byte(d >> 8) + buf[3] = byte(d) +} + +func readNetworkOrderUint16(buf []byte) uint16 { + return (uint16(buf[0]) << 8) | uint16(buf[1]) +} + +func readNetworkOrderUint32(buf []byte) uint32 { + return (uint32(buf[0]) << 24) | (uint32(buf[1]) << 16) | (uint32(buf[2]) << 8) | uint32(buf[3]) +} diff --git a/Godeps/_workspace/src/github.com/kardianos/osext/LICENSE b/Godeps/_workspace/src/github.com/kardianos/osext/LICENSE new file mode 100644 index 0000000000..7448756763 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kardianos/osext/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/Godeps/_workspace/src/github.com/kardianos/osext/README.md b/Godeps/_workspace/src/github.com/kardianos/osext/README.md new file mode 100644 index 0000000000..820e1ecb54 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kardianos/osext/README.md @@ -0,0 +1,14 @@ +### Extensions to the "os" package. + +## Find the current Executable and ExecutableFolder. + +There is sometimes utility in finding the current executable file +that is running. This can be used for upgrading the current executable +or finding resources located relative to the executable file. + +Multi-platform and supports: + * Linux + * OS X + * Windows + * Plan 9 + * BSDs. diff --git a/Godeps/_workspace/src/github.com/kardianos/osext/osext.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext.go new file mode 100644 index 0000000000..4ed4b9aa33 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kardianos/osext/osext.go @@ -0,0 +1,27 @@ +// 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. + +// Extensions to the standard "os" package. +package osext + +import "path/filepath" + +// Executable returns an absolute path that can be used to +// re-invoke the current program. +// It may not be valid after the current program exits. +func Executable() (string, error) { + p, err := executable() + return filepath.Clean(p), err +} + +// Returns same path as Executable, returns just the folder +// path. Excludes the executable name. +func ExecutableFolder() (string, error) { + p, err := Executable() + if err != nil { + return "", err + } + folder, _ := filepath.Split(p) + return folder, nil +} diff --git a/Godeps/_workspace/src/github.com/kardianos/osext/osext_plan9.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_plan9.go new file mode 100644 index 0000000000..655750c542 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kardianos/osext/osext_plan9.go @@ -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. + +package osext + +import ( + "os" + "strconv" + "syscall" +) + +func executable() (string, error) { + f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text") + if err != nil { + return "", err + } + defer f.Close() + return syscall.Fd2path(int(f.Fd())) +} diff --git a/Godeps/_workspace/src/github.com/kardianos/osext/osext_procfs.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_procfs.go new file mode 100644 index 0000000000..a50021ad53 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kardianos/osext/osext_procfs.go @@ -0,0 +1,28 @@ +// 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 linux netbsd openbsd solaris dragonfly + +package osext + +import ( + "errors" + "fmt" + "os" + "runtime" +) + +func executable() (string, error) { + switch runtime.GOOS { + case "linux": + return os.Readlink("/proc/self/exe") + case "netbsd": + return os.Readlink("/proc/curproc/exe") + case "openbsd", "dragonfly": + return os.Readlink("/proc/curproc/file") + case "solaris": + return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid())) + } + return "", errors.New("ExecPath not implemented for " + runtime.GOOS) +} diff --git a/Godeps/_workspace/src/github.com/kardianos/osext/osext_sysctl.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_sysctl.go new file mode 100644 index 0000000000..b66cac878c --- /dev/null +++ b/Godeps/_workspace/src/github.com/kardianos/osext/osext_sysctl.go @@ -0,0 +1,79 @@ +// 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 darwin freebsd + +package osext + +import ( + "os" + "path/filepath" + "runtime" + "syscall" + "unsafe" +) + +var initCwd, initCwdErr = os.Getwd() + +func executable() (string, error) { + var mib [4]int32 + switch runtime.GOOS { + case "freebsd": + mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1} + case "darwin": + mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1} + } + + n := uintptr(0) + // Get length. + _, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0) + if errNum != 0 { + return "", errNum + } + if n == 0 { // This shouldn't happen. + return "", nil + } + buf := make([]byte, n) + _, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0) + if errNum != 0 { + return "", errNum + } + if n == 0 { // This shouldn't happen. + return "", nil + } + for i, v := range buf { + if v == 0 { + buf = buf[:i] + break + } + } + var err error + execPath := string(buf) + // execPath will not be empty due to above checks. + // Try to get the absolute path if the execPath is not rooted. + if execPath[0] != '/' { + execPath, err = getAbs(execPath) + if err != nil { + return execPath, err + } + } + // For darwin KERN_PROCARGS may return the path to a symlink rather than the + // actual executable. + if runtime.GOOS == "darwin" { + if execPath, err = filepath.EvalSymlinks(execPath); err != nil { + return execPath, err + } + } + return execPath, nil +} + +func getAbs(execPath string) (string, error) { + if initCwdErr != nil { + return execPath, initCwdErr + } + // The execPath may begin with a "../" or a "./" so clean it first. + // Join the two paths, trailing and starting slashes undetermined, so use + // the generic Join function. + return filepath.Join(initCwd, filepath.Clean(execPath)), nil +} diff --git a/Godeps/_workspace/src/github.com/kardianos/osext/osext_test.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_test.go new file mode 100644 index 0000000000..dc661dbc21 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kardianos/osext/osext_test.go @@ -0,0 +1,79 @@ +// 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 darwin linux freebsd netbsd windows + +package osext + +import ( + "fmt" + "os" + oexec "os/exec" + "path/filepath" + "runtime" + "testing" +) + +const execPath_EnvVar = "OSTEST_OUTPUT_EXECPATH" + +func TestExecPath(t *testing.T) { + ep, err := Executable() + if err != nil { + t.Fatalf("ExecPath failed: %v", err) + } + // we want fn to be of the form "dir/prog" + dir := filepath.Dir(filepath.Dir(ep)) + fn, err := filepath.Rel(dir, ep) + if err != nil { + t.Fatalf("filepath.Rel: %v", err) + } + cmd := &oexec.Cmd{} + // make child start with a relative program path + cmd.Dir = dir + cmd.Path = fn + // forge argv[0] for child, so that we can verify we could correctly + // get real path of the executable without influenced by argv[0]. + cmd.Args = []string{"-", "-test.run=XXXX"} + cmd.Env = []string{fmt.Sprintf("%s=1", execPath_EnvVar)} + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("exec(self) failed: %v", err) + } + outs := string(out) + if !filepath.IsAbs(outs) { + t.Fatalf("Child returned %q, want an absolute path", out) + } + if !sameFile(outs, ep) { + t.Fatalf("Child returned %q, not the same file as %q", out, ep) + } +} + +func sameFile(fn1, fn2 string) bool { + fi1, err := os.Stat(fn1) + if err != nil { + return false + } + fi2, err := os.Stat(fn2) + if err != nil { + return false + } + return os.SameFile(fi1, fi2) +} + +func init() { + if e := os.Getenv(execPath_EnvVar); e != "" { + // first chdir to another path + dir := "/" + if runtime.GOOS == "windows" { + dir = filepath.VolumeName(".") + } + os.Chdir(dir) + if ep, err := Executable(); err != nil { + fmt.Fprint(os.Stderr, "ERROR: ", err) + } else { + fmt.Fprint(os.Stderr, ep) + } + os.Exit(0) + } +} diff --git a/Godeps/_workspace/src/github.com/kardianos/osext/osext_windows.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_windows.go new file mode 100644 index 0000000000..72d282cf8c --- /dev/null +++ b/Godeps/_workspace/src/github.com/kardianos/osext/osext_windows.go @@ -0,0 +1,34 @@ +// 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 osext + +import ( + "syscall" + "unicode/utf16" + "unsafe" +) + +var ( + kernel = syscall.MustLoadDLL("kernel32.dll") + getModuleFileNameProc = kernel.MustFindProc("GetModuleFileNameW") +) + +// GetModuleFileName() with hModule = NULL +func executable() (exePath string, err error) { + return getModuleFileName() +} + +func getModuleFileName() (string, error) { + var n uint32 + b := make([]uint16, syscall.MAX_PATH) + size := uint32(len(b)) + + r0, _, e1 := getModuleFileNameProc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(size)) + n = uint32(r0) + if n == 0 { + return "", e1 + } + return string(utf16.Decode(b[0:n])), nil +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-colorable/README.md b/Godeps/_workspace/src/github.com/mattn/go-colorable/README.md new file mode 100644 index 0000000000..c69da4a761 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-colorable/README.md @@ -0,0 +1,42 @@ +# go-colorable + +Colorable writer for windows. + +For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.) +This package is possible to handle escape sequence for ansi color on windows. + +## Too Bad! + +![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png) + + +## So Good! + +![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png) + +## Usage + +```go +logrus.SetOutput(colorable.NewColorableStdout()) + +logrus.Info("succeeded") +logrus.Warn("not correct") +logrus.Error("something error") +logrus.Fatal("panic") +``` + +You can compile above code on non-windows OSs. + +## Installation + +``` +$ go get github.com/mattn/go-colorable +``` + +# License + +MIT + +# Author + +Yasuhiro Matsumoto (a.k.a mattn) diff --git a/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go b/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go new file mode 100644 index 0000000000..219f02f62a --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go @@ -0,0 +1,16 @@ +// +build !windows + +package colorable + +import ( + "io" + "os" +) + +func NewColorableStdout() io.Writer { + return os.Stdout +} + +func NewColorableStderr() io.Writer { + return os.Stderr +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go b/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go new file mode 100644 index 0000000000..6a27878088 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go @@ -0,0 +1,594 @@ +package colorable + +import ( + "bytes" + "fmt" + "io" + "os" + "strconv" + "strings" + "syscall" + "unsafe" + + "github.com/mattn/go-isatty" +) + +const ( + foregroundBlue = 0x1 + foregroundGreen = 0x2 + foregroundRed = 0x4 + foregroundIntensity = 0x8 + foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity) + backgroundBlue = 0x10 + backgroundGreen = 0x20 + backgroundRed = 0x40 + backgroundIntensity = 0x80 + backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity) +) + +type wchar uint16 +type short int16 +type dword uint32 +type word uint16 + +type coord struct { + x short + y short +} + +type smallRect struct { + left short + top short + right short + bottom short +} + +type consoleScreenBufferInfo struct { + size coord + cursorPosition coord + attributes word + window smallRect + maximumWindowSize coord +} + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") + procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") +) + +type Writer struct { + out io.Writer + handle syscall.Handle + lastbuf bytes.Buffer + oldattr word +} + +func NewColorableStdout() io.Writer { + var csbi consoleScreenBufferInfo + out := os.Stdout + if !isatty.IsTerminal(out.Fd()) { + return out + } + handle := syscall.Handle(out.Fd()) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + return &Writer{out: out, handle: handle, oldattr: csbi.attributes} +} + +func NewColorableStderr() io.Writer { + var csbi consoleScreenBufferInfo + out := os.Stderr + if !isatty.IsTerminal(out.Fd()) { + return out + } + handle := syscall.Handle(out.Fd()) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + return &Writer{out: out, handle: handle, oldattr: csbi.attributes} +} + +var color256 = map[int]int{ + 0: 0x000000, + 1: 0x800000, + 2: 0x008000, + 3: 0x808000, + 4: 0x000080, + 5: 0x800080, + 6: 0x008080, + 7: 0xc0c0c0, + 8: 0x808080, + 9: 0xff0000, + 10: 0x00ff00, + 11: 0xffff00, + 12: 0x0000ff, + 13: 0xff00ff, + 14: 0x00ffff, + 15: 0xffffff, + 16: 0x000000, + 17: 0x00005f, + 18: 0x000087, + 19: 0x0000af, + 20: 0x0000d7, + 21: 0x0000ff, + 22: 0x005f00, + 23: 0x005f5f, + 24: 0x005f87, + 25: 0x005faf, + 26: 0x005fd7, + 27: 0x005fff, + 28: 0x008700, + 29: 0x00875f, + 30: 0x008787, + 31: 0x0087af, + 32: 0x0087d7, + 33: 0x0087ff, + 34: 0x00af00, + 35: 0x00af5f, + 36: 0x00af87, + 37: 0x00afaf, + 38: 0x00afd7, + 39: 0x00afff, + 40: 0x00d700, + 41: 0x00d75f, + 42: 0x00d787, + 43: 0x00d7af, + 44: 0x00d7d7, + 45: 0x00d7ff, + 46: 0x00ff00, + 47: 0x00ff5f, + 48: 0x00ff87, + 49: 0x00ffaf, + 50: 0x00ffd7, + 51: 0x00ffff, + 52: 0x5f0000, + 53: 0x5f005f, + 54: 0x5f0087, + 55: 0x5f00af, + 56: 0x5f00d7, + 57: 0x5f00ff, + 58: 0x5f5f00, + 59: 0x5f5f5f, + 60: 0x5f5f87, + 61: 0x5f5faf, + 62: 0x5f5fd7, + 63: 0x5f5fff, + 64: 0x5f8700, + 65: 0x5f875f, + 66: 0x5f8787, + 67: 0x5f87af, + 68: 0x5f87d7, + 69: 0x5f87ff, + 70: 0x5faf00, + 71: 0x5faf5f, + 72: 0x5faf87, + 73: 0x5fafaf, + 74: 0x5fafd7, + 75: 0x5fafff, + 76: 0x5fd700, + 77: 0x5fd75f, + 78: 0x5fd787, + 79: 0x5fd7af, + 80: 0x5fd7d7, + 81: 0x5fd7ff, + 82: 0x5fff00, + 83: 0x5fff5f, + 84: 0x5fff87, + 85: 0x5fffaf, + 86: 0x5fffd7, + 87: 0x5fffff, + 88: 0x870000, + 89: 0x87005f, + 90: 0x870087, + 91: 0x8700af, + 92: 0x8700d7, + 93: 0x8700ff, + 94: 0x875f00, + 95: 0x875f5f, + 96: 0x875f87, + 97: 0x875faf, + 98: 0x875fd7, + 99: 0x875fff, + 100: 0x878700, + 101: 0x87875f, + 102: 0x878787, + 103: 0x8787af, + 104: 0x8787d7, + 105: 0x8787ff, + 106: 0x87af00, + 107: 0x87af5f, + 108: 0x87af87, + 109: 0x87afaf, + 110: 0x87afd7, + 111: 0x87afff, + 112: 0x87d700, + 113: 0x87d75f, + 114: 0x87d787, + 115: 0x87d7af, + 116: 0x87d7d7, + 117: 0x87d7ff, + 118: 0x87ff00, + 119: 0x87ff5f, + 120: 0x87ff87, + 121: 0x87ffaf, + 122: 0x87ffd7, + 123: 0x87ffff, + 124: 0xaf0000, + 125: 0xaf005f, + 126: 0xaf0087, + 127: 0xaf00af, + 128: 0xaf00d7, + 129: 0xaf00ff, + 130: 0xaf5f00, + 131: 0xaf5f5f, + 132: 0xaf5f87, + 133: 0xaf5faf, + 134: 0xaf5fd7, + 135: 0xaf5fff, + 136: 0xaf8700, + 137: 0xaf875f, + 138: 0xaf8787, + 139: 0xaf87af, + 140: 0xaf87d7, + 141: 0xaf87ff, + 142: 0xafaf00, + 143: 0xafaf5f, + 144: 0xafaf87, + 145: 0xafafaf, + 146: 0xafafd7, + 147: 0xafafff, + 148: 0xafd700, + 149: 0xafd75f, + 150: 0xafd787, + 151: 0xafd7af, + 152: 0xafd7d7, + 153: 0xafd7ff, + 154: 0xafff00, + 155: 0xafff5f, + 156: 0xafff87, + 157: 0xafffaf, + 158: 0xafffd7, + 159: 0xafffff, + 160: 0xd70000, + 161: 0xd7005f, + 162: 0xd70087, + 163: 0xd700af, + 164: 0xd700d7, + 165: 0xd700ff, + 166: 0xd75f00, + 167: 0xd75f5f, + 168: 0xd75f87, + 169: 0xd75faf, + 170: 0xd75fd7, + 171: 0xd75fff, + 172: 0xd78700, + 173: 0xd7875f, + 174: 0xd78787, + 175: 0xd787af, + 176: 0xd787d7, + 177: 0xd787ff, + 178: 0xd7af00, + 179: 0xd7af5f, + 180: 0xd7af87, + 181: 0xd7afaf, + 182: 0xd7afd7, + 183: 0xd7afff, + 184: 0xd7d700, + 185: 0xd7d75f, + 186: 0xd7d787, + 187: 0xd7d7af, + 188: 0xd7d7d7, + 189: 0xd7d7ff, + 190: 0xd7ff00, + 191: 0xd7ff5f, + 192: 0xd7ff87, + 193: 0xd7ffaf, + 194: 0xd7ffd7, + 195: 0xd7ffff, + 196: 0xff0000, + 197: 0xff005f, + 198: 0xff0087, + 199: 0xff00af, + 200: 0xff00d7, + 201: 0xff00ff, + 202: 0xff5f00, + 203: 0xff5f5f, + 204: 0xff5f87, + 205: 0xff5faf, + 206: 0xff5fd7, + 207: 0xff5fff, + 208: 0xff8700, + 209: 0xff875f, + 210: 0xff8787, + 211: 0xff87af, + 212: 0xff87d7, + 213: 0xff87ff, + 214: 0xffaf00, + 215: 0xffaf5f, + 216: 0xffaf87, + 217: 0xffafaf, + 218: 0xffafd7, + 219: 0xffafff, + 220: 0xffd700, + 221: 0xffd75f, + 222: 0xffd787, + 223: 0xffd7af, + 224: 0xffd7d7, + 225: 0xffd7ff, + 226: 0xffff00, + 227: 0xffff5f, + 228: 0xffff87, + 229: 0xffffaf, + 230: 0xffffd7, + 231: 0xffffff, + 232: 0x080808, + 233: 0x121212, + 234: 0x1c1c1c, + 235: 0x262626, + 236: 0x303030, + 237: 0x3a3a3a, + 238: 0x444444, + 239: 0x4e4e4e, + 240: 0x585858, + 241: 0x626262, + 242: 0x6c6c6c, + 243: 0x767676, + 244: 0x808080, + 245: 0x8a8a8a, + 246: 0x949494, + 247: 0x9e9e9e, + 248: 0xa8a8a8, + 249: 0xb2b2b2, + 250: 0xbcbcbc, + 251: 0xc6c6c6, + 252: 0xd0d0d0, + 253: 0xdadada, + 254: 0xe4e4e4, + 255: 0xeeeeee, +} + +func (w *Writer) Write(data []byte) (n int, err error) { + var csbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + + er := bytes.NewBuffer(data) +loop: + for { + r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + if r1 == 0 { + break loop + } + + c1, _, err := er.ReadRune() + if err != nil { + break loop + } + if c1 != 0x1b { + fmt.Fprint(w.out, string(c1)) + continue + } + c2, _, err := er.ReadRune() + if err != nil { + w.lastbuf.WriteRune(c1) + break loop + } + if c2 != 0x5b { + w.lastbuf.WriteRune(c1) + w.lastbuf.WriteRune(c2) + continue + } + + var buf bytes.Buffer + var m rune + for { + c, _, err := er.ReadRune() + if err != nil { + w.lastbuf.WriteRune(c1) + w.lastbuf.WriteRune(c2) + w.lastbuf.Write(buf.Bytes()) + break loop + } + if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { + m = c + break + } + buf.Write([]byte(string(c))) + } + + switch m { + case 'm': + attr := csbi.attributes + cs := buf.String() + if cs == "" { + procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr)) + continue + } + token := strings.Split(cs, ";") + for i, ns := range token { + if n, err = strconv.Atoi(ns); err == nil { + switch { + case n == 0 || n == 100: + attr = w.oldattr + case 1 <= n && n <= 5: + attr |= foregroundIntensity + case n == 7: + attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) + case 22 == n || n == 25 || n == 25: + attr |= foregroundIntensity + case n == 27: + attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) + case 30 <= n && n <= 37: + attr = (attr & backgroundMask) + if (n-30)&1 != 0 { + attr |= foregroundRed + } + if (n-30)&2 != 0 { + attr |= foregroundGreen + } + if (n-30)&4 != 0 { + attr |= foregroundBlue + } + case n == 38: // set foreground color. + if i < len(token)-2 && token[i+1] == "5" { + if n256, err := strconv.Atoi(token[i+2]); err == nil { + if n256foreAttr == nil { + n256setup() + } + attr &= backgroundMask + attr |= n256foreAttr[n256] + i += 2 + } + } else { + attr = attr & (w.oldattr & backgroundMask) + } + case n == 39: // reset foreground color. + attr &= backgroundMask + attr |= w.oldattr & foregroundMask + case 40 <= n && n <= 47: + attr = (attr & foregroundMask) + if (n-40)&1 != 0 { + attr |= backgroundRed + } + if (n-40)&2 != 0 { + attr |= backgroundGreen + } + if (n-40)&4 != 0 { + attr |= backgroundBlue + } + case n == 48: // set background color. + if i < len(token)-2 && token[i+1] == "5" { + if n256, err := strconv.Atoi(token[i+2]); err == nil { + if n256backAttr == nil { + n256setup() + } + attr &= foregroundMask + attr |= n256backAttr[n256] + i += 2 + } + } else { + attr = attr & (w.oldattr & foregroundMask) + } + case n == 49: // reset foreground color. + attr &= foregroundMask + attr |= w.oldattr & backgroundMask + } + procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) + } + } + } + } + return len(data) - w.lastbuf.Len(), nil +} + +type consoleColor struct { + red bool + green bool + blue bool + intensity bool +} + +func minmax3(a, b, c int) (min, max int) { + if a < b { + if b < c { + return a, c + } else if a < c { + return a, b + } else { + return c, b + } + } else { + if a < c { + return b, c + } else if b < c { + return b, a + } else { + return c, a + } + } +} + +func toConsoleColor(rgb int) (c consoleColor) { + r, g, b := (rgb&0xFF0000)>>16, (rgb&0x00FF00)>>8, rgb&0x0000FF + min, max := minmax3(r, g, b) + a := (min + max) / 2 + if r < 128 && g < 128 && b < 128 { + if r >= a { + c.red = true + } + if g >= a { + c.green = true + } + if b >= a { + c.blue = true + } + // non-intensed white is lighter than intensed black, so swap those. + if c.red && c.green && c.blue { + c.red, c.green, c.blue = false, false, false + c.intensity = true + } + } else { + if min < 128 { + min = 128 + a = (min + max) / 2 + } + if r >= a { + c.red = true + } + if g >= a { + c.green = true + } + if b >= a { + c.blue = true + } + c.intensity = true + // intensed black is darker than non-intensed white, so swap those. + if !c.red && !c.green && !c.blue { + c.red, c.green, c.blue = true, true, true + c.intensity = false + } + } + return c +} + +func (c consoleColor) foregroundAttr() (attr word) { + if c.red { + attr |= foregroundRed + } + if c.green { + attr |= foregroundGreen + } + if c.blue { + attr |= foregroundBlue + } + if c.intensity { + attr |= foregroundIntensity + } + return +} + +func (c consoleColor) backgroundAttr() (attr word) { + if c.red { + attr |= backgroundRed + } + if c.green { + attr |= backgroundGreen + } + if c.blue { + attr |= backgroundBlue + } + if c.intensity { + attr |= backgroundIntensity + } + return +} + +var n256foreAttr []word +var n256backAttr []word + +func n256setup() { + n256foreAttr = make([]word, 256) + n256backAttr = make([]word, 256) + for i, rgb := range color256 { + c := toConsoleColor(rgb) + n256foreAttr[i] = c.foregroundAttr() + n256backAttr[i] = c.backgroundAttr() + } +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-isatty/README.md b/Godeps/_workspace/src/github.com/mattn/go-isatty/README.md new file mode 100644 index 0000000000..74845de4a2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-isatty/README.md @@ -0,0 +1,37 @@ +# go-isatty + +isatty for golang + +## Usage + +```go +package main + +import ( + "fmt" + "github.com/mattn/go-isatty" + "os" +) + +func main() { + if isatty.IsTerminal(os.Stdout.Fd()) { + fmt.Println("Is Terminal") + } else { + fmt.Println("Is Not Terminal") + } +} +``` + +## Installation + +``` +$ go get github.com/mattn/go-isatty +``` + +# License + +MIT + +# Author + +Yasuhiro Matsumoto (a.k.a mattn) diff --git a/Godeps/_workspace/src/github.com/mattn/go-isatty/doc.go b/Godeps/_workspace/src/github.com/mattn/go-isatty/doc.go new file mode 100644 index 0000000000..17d4f90ebc --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-isatty/doc.go @@ -0,0 +1,2 @@ +// Package isatty implements interface to isatty +package isatty diff --git a/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_bsd.go b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_bsd.go new file mode 100644 index 0000000000..0352747512 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_bsd.go @@ -0,0 +1,17 @@ +// +build darwin freebsd + +package isatty + +import ( + "syscall" + "unsafe" +) + +const ioctlReadTermios = syscall.TIOCGETA + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var termios syscall.Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_linux.go b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_linux.go new file mode 100644 index 0000000000..8b361d7fbe --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_linux.go @@ -0,0 +1,17 @@ +// +build linux + +package isatty + +import ( + "syscall" + "unsafe" +) + +const ioctlReadTermios = syscall.TCGETS + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var termios syscall.Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_windows.go b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_windows.go new file mode 100644 index 0000000000..562ee39ca0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_windows.go @@ -0,0 +1,18 @@ +// +build windows + +package isatty + +import ( + "syscall" + "unsafe" +) + +var kernel32 = syscall.NewLazyDLL("kernel32.dll") +var procGetConsoleMode = kernel32.NewProc("GetConsoleMode") + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var st uint32 + r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) + return r != 0 && e == 0 +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/.travis.yml b/Godeps/_workspace/src/github.com/mattn/go-runewidth/.travis.yml new file mode 100644 index 0000000000..ad584f4da5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/.travis.yml @@ -0,0 +1,9 @@ +language: go +go: + - tip +before_install: + - go get github.com/axw/gocov/gocov + - go get github.com/mattn/goveralls + - go get golang.org/x/tools/cmd/cover +script: + - $HOME/gopath/bin/goveralls -repotoken lAKAWPzcGsD3A8yBX3BGGtRUdJ6CaGERL diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/README.mkd b/Godeps/_workspace/src/github.com/mattn/go-runewidth/README.mkd new file mode 100644 index 0000000000..4f0d583beb --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/README.mkd @@ -0,0 +1,25 @@ +go-runewidth +============ + +[![Build Status](https://travis-ci.org/mattn/go-runewidth.png?branch=master)](https://travis-ci.org/mattn/go-runewidth) +[![Coverage Status](https://coveralls.io/repos/mattn/go-runewidth/badge.png?branch=HEAD)](https://coveralls.io/r/mattn/go-runewidth?branch=HEAD) + +Provides functions to get fixed width of the character or string. + +Usage +----- + +```go +runewidth.StringWidth("ã¤ã®ã â˜†HIRO") == 12 +``` + + +Author +------ + +Yasuhiro Matsumoto + +License +------- + +under the MIT License: http://mattn.mit-license.org/2013 diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth.go b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth.go new file mode 100644 index 0000000000..0b417db15a --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth.go @@ -0,0 +1,404 @@ +package runewidth + +var EastAsianWidth = IsEastAsian() +var DefaultCondition = &Condition{EastAsianWidth} + +type interval struct { + first rune + last rune +} + +var combining = []interval{ + {0x0300, 0x036F}, {0x0483, 0x0486}, {0x0488, 0x0489}, + {0x0591, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, + {0x05C4, 0x05C5}, {0x05C7, 0x05C7}, {0x0600, 0x0603}, + {0x0610, 0x0615}, {0x064B, 0x065E}, {0x0670, 0x0670}, + {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, + {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A}, + {0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x0901, 0x0902}, + {0x093C, 0x093C}, {0x0941, 0x0948}, {0x094D, 0x094D}, + {0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0981}, + {0x09BC, 0x09BC}, {0x09C1, 0x09C4}, {0x09CD, 0x09CD}, + {0x09E2, 0x09E3}, {0x0A01, 0x0A02}, {0x0A3C, 0x0A3C}, + {0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, + {0x0A70, 0x0A71}, {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC}, + {0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD}, + {0x0AE2, 0x0AE3}, {0x0B01, 0x0B01}, {0x0B3C, 0x0B3C}, + {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, {0x0B4D, 0x0B4D}, + {0x0B56, 0x0B56}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0}, + {0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, {0x0C46, 0x0C48}, + {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0CBC, 0x0CBC}, + {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD}, + {0x0CE2, 0x0CE3}, {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D}, + {0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, + {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, + {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, + {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, + {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F71, 0x0F7E}, + {0x0F80, 0x0F84}, {0x0F86, 0x0F87}, {0x0F90, 0x0F97}, + {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030}, + {0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039}, + {0x1058, 0x1059}, {0x1160, 0x11FF}, {0x135F, 0x135F}, + {0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753}, + {0x1772, 0x1773}, {0x17B4, 0x17B5}, {0x17B7, 0x17BD}, + {0x17C6, 0x17C6}, {0x17C9, 0x17D3}, {0x17DD, 0x17DD}, + {0x180B, 0x180D}, {0x18A9, 0x18A9}, {0x1920, 0x1922}, + {0x1927, 0x1928}, {0x1932, 0x1932}, {0x1939, 0x193B}, + {0x1A17, 0x1A18}, {0x1B00, 0x1B03}, {0x1B34, 0x1B34}, + {0x1B36, 0x1B3A}, {0x1B3C, 0x1B3C}, {0x1B42, 0x1B42}, + {0x1B6B, 0x1B73}, {0x1DC0, 0x1DCA}, {0x1DFE, 0x1DFF}, + {0x200B, 0x200F}, {0x202A, 0x202E}, {0x2060, 0x2063}, + {0x206A, 0x206F}, {0x20D0, 0x20EF}, {0x302A, 0x302F}, + {0x3099, 0x309A}, {0xA806, 0xA806}, {0xA80B, 0xA80B}, + {0xA825, 0xA826}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F}, + {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, + {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, + {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x1D167, 0x1D169}, + {0x1D173, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD}, + {0x1D242, 0x1D244}, {0xE0001, 0xE0001}, {0xE0020, 0xE007F}, + {0xE0100, 0xE01EF}, +} + +type ctype int + +const ( + narrow ctype = iota + ambiguous + wide + halfwidth + fullwidth + neutral +) + +type intervalType struct { + first rune + last rune + ctype ctype +} + +var ctypes = []intervalType{ + {0x0020, 0x007E, narrow}, + {0x00A1, 0x00A1, ambiguous}, + {0x00A2, 0x00A3, narrow}, + {0x00A4, 0x00A4, ambiguous}, + {0x00A5, 0x00A6, narrow}, + {0x00A7, 0x00A8, ambiguous}, + {0x00AA, 0x00AA, ambiguous}, + {0x00AC, 0x00AC, narrow}, + {0x00AD, 0x00AE, ambiguous}, + {0x00AF, 0x00AF, narrow}, + {0x00B0, 0x00B4, ambiguous}, + {0x00B6, 0x00BA, ambiguous}, + {0x00BC, 0x00BF, ambiguous}, + {0x00C6, 0x00C6, ambiguous}, + {0x00D0, 0x00D0, ambiguous}, + {0x00D7, 0x00D8, ambiguous}, + {0x00DE, 0x00E1, ambiguous}, + {0x00E6, 0x00E6, ambiguous}, + {0x00E8, 0x00EA, ambiguous}, + {0x00EC, 0x00ED, ambiguous}, + {0x00F0, 0x00F0, ambiguous}, + {0x00F2, 0x00F3, ambiguous}, + {0x00F7, 0x00FA, ambiguous}, + {0x00FC, 0x00FC, ambiguous}, + {0x00FE, 0x00FE, ambiguous}, + {0x0101, 0x0101, ambiguous}, + {0x0111, 0x0111, ambiguous}, + {0x0113, 0x0113, ambiguous}, + {0x011B, 0x011B, ambiguous}, + {0x0126, 0x0127, ambiguous}, + {0x012B, 0x012B, ambiguous}, + {0x0131, 0x0133, ambiguous}, + {0x0138, 0x0138, ambiguous}, + {0x013F, 0x0142, ambiguous}, + {0x0144, 0x0144, ambiguous}, + {0x0148, 0x014B, ambiguous}, + {0x014D, 0x014D, ambiguous}, + {0x0152, 0x0153, ambiguous}, + {0x0166, 0x0167, ambiguous}, + {0x016B, 0x016B, ambiguous}, + {0x01CE, 0x01CE, ambiguous}, + {0x01D0, 0x01D0, ambiguous}, + {0x01D2, 0x01D2, ambiguous}, + {0x01D4, 0x01D4, ambiguous}, + {0x01D6, 0x01D6, ambiguous}, + {0x01D8, 0x01D8, ambiguous}, + {0x01DA, 0x01DA, ambiguous}, + {0x01DC, 0x01DC, ambiguous}, + {0x0251, 0x0251, ambiguous}, + {0x0261, 0x0261, ambiguous}, + {0x02C4, 0x02C4, ambiguous}, + {0x02C7, 0x02C7, ambiguous}, + {0x02C9, 0x02CB, ambiguous}, + {0x02CD, 0x02CD, ambiguous}, + {0x02D0, 0x02D0, ambiguous}, + {0x02D8, 0x02DB, ambiguous}, + {0x02DD, 0x02DD, ambiguous}, + {0x02DF, 0x02DF, ambiguous}, + {0x0300, 0x036F, ambiguous}, + {0x0391, 0x03A2, ambiguous}, + {0x03A3, 0x03A9, ambiguous}, + {0x03B1, 0x03C1, ambiguous}, + {0x03C3, 0x03C9, ambiguous}, + {0x0401, 0x0401, ambiguous}, + {0x0410, 0x044F, ambiguous}, + {0x0451, 0x0451, ambiguous}, + {0x1100, 0x115F, wide}, + {0x2010, 0x2010, ambiguous}, + {0x2013, 0x2016, ambiguous}, + {0x2018, 0x2019, ambiguous}, + {0x201C, 0x201D, ambiguous}, + {0x2020, 0x2022, ambiguous}, + {0x2024, 0x2027, ambiguous}, + {0x2030, 0x2030, ambiguous}, + {0x2032, 0x2033, ambiguous}, + {0x2035, 0x2035, ambiguous}, + {0x203B, 0x203B, ambiguous}, + {0x203E, 0x203E, ambiguous}, + {0x2074, 0x2074, ambiguous}, + {0x207F, 0x207F, ambiguous}, + {0x2081, 0x2084, ambiguous}, + {0x20A9, 0x20A9, halfwidth}, + {0x20AC, 0x20AC, ambiguous}, + {0x2103, 0x2103, ambiguous}, + {0x2105, 0x2105, ambiguous}, + {0x2109, 0x2109, ambiguous}, + {0x2113, 0x2113, ambiguous}, + {0x2116, 0x2116, ambiguous}, + {0x2121, 0x2122, ambiguous}, + {0x2126, 0x2126, ambiguous}, + {0x212B, 0x212B, ambiguous}, + {0x2153, 0x2154, ambiguous}, + {0x215B, 0x215E, ambiguous}, + {0x2160, 0x216B, ambiguous}, + {0x2170, 0x2179, ambiguous}, + {0x2189, 0x218A, ambiguous}, + {0x2190, 0x2199, ambiguous}, + {0x21B8, 0x21B9, ambiguous}, + {0x21D2, 0x21D2, ambiguous}, + {0x21D4, 0x21D4, ambiguous}, + {0x21E7, 0x21E7, ambiguous}, + {0x2200, 0x2200, ambiguous}, + {0x2202, 0x2203, ambiguous}, + {0x2207, 0x2208, ambiguous}, + {0x220B, 0x220B, ambiguous}, + {0x220F, 0x220F, ambiguous}, + {0x2211, 0x2211, ambiguous}, + {0x2215, 0x2215, ambiguous}, + {0x221A, 0x221A, ambiguous}, + {0x221D, 0x2220, ambiguous}, + {0x2223, 0x2223, ambiguous}, + {0x2225, 0x2225, ambiguous}, + {0x2227, 0x222C, ambiguous}, + {0x222E, 0x222E, ambiguous}, + {0x2234, 0x2237, ambiguous}, + {0x223C, 0x223D, ambiguous}, + {0x2248, 0x2248, ambiguous}, + {0x224C, 0x224C, ambiguous}, + {0x2252, 0x2252, ambiguous}, + {0x2260, 0x2261, ambiguous}, + {0x2264, 0x2267, ambiguous}, + {0x226A, 0x226B, ambiguous}, + {0x226E, 0x226F, ambiguous}, + {0x2282, 0x2283, ambiguous}, + {0x2286, 0x2287, ambiguous}, + {0x2295, 0x2295, ambiguous}, + {0x2299, 0x2299, ambiguous}, + {0x22A5, 0x22A5, ambiguous}, + {0x22BF, 0x22BF, ambiguous}, + {0x2312, 0x2312, ambiguous}, + {0x2329, 0x232A, wide}, + {0x2460, 0x24E9, ambiguous}, + {0x24EB, 0x254B, ambiguous}, + {0x2550, 0x2573, ambiguous}, + {0x2580, 0x258F, ambiguous}, + {0x2592, 0x2595, ambiguous}, + {0x25A0, 0x25A1, ambiguous}, + {0x25A3, 0x25A9, ambiguous}, + {0x25B2, 0x25B3, ambiguous}, + {0x25B6, 0x25B7, ambiguous}, + {0x25BC, 0x25BD, ambiguous}, + {0x25C0, 0x25C1, ambiguous}, + {0x25C6, 0x25C8, ambiguous}, + {0x25CB, 0x25CB, ambiguous}, + {0x25CE, 0x25D1, ambiguous}, + {0x25E2, 0x25E5, ambiguous}, + {0x25EF, 0x25EF, ambiguous}, + {0x2605, 0x2606, ambiguous}, + {0x2609, 0x2609, ambiguous}, + {0x260E, 0x260F, ambiguous}, + {0x2614, 0x2615, ambiguous}, + {0x261C, 0x261C, ambiguous}, + {0x261E, 0x261E, ambiguous}, + {0x2640, 0x2640, ambiguous}, + {0x2642, 0x2642, ambiguous}, + {0x2660, 0x2661, ambiguous}, + {0x2663, 0x2665, ambiguous}, + {0x2667, 0x266A, ambiguous}, + {0x266C, 0x266D, ambiguous}, + {0x266F, 0x266F, ambiguous}, + {0x269E, 0x269F, ambiguous}, + {0x26BE, 0x26BF, ambiguous}, + {0x26C4, 0x26CD, ambiguous}, + {0x26CF, 0x26E1, ambiguous}, + {0x26E3, 0x26E3, ambiguous}, + {0x26E8, 0x26FF, ambiguous}, + {0x273D, 0x273D, ambiguous}, + {0x2757, 0x2757, ambiguous}, + {0x2776, 0x277F, ambiguous}, + {0x27E6, 0x27ED, narrow}, + {0x2985, 0x2986, narrow}, + {0x2B55, 0x2B59, ambiguous}, + {0x2E80, 0x2E9A, wide}, + {0x2E9B, 0x2EF4, wide}, + {0x2F00, 0x2FD6, wide}, + {0x2FF0, 0x2FFC, wide}, + {0x3000, 0x3000, fullwidth}, + {0x3001, 0x303E, wide}, + {0x3041, 0x3097, wide}, + {0x3099, 0x3100, wide}, + {0x3105, 0x312E, wide}, + {0x3131, 0x318F, wide}, + {0x3190, 0x31BB, wide}, + {0x31C0, 0x31E4, wide}, + {0x31F0, 0x321F, wide}, + {0x3220, 0x3247, wide}, + {0x3248, 0x324F, ambiguous}, + {0x3250, 0x32FF, wide}, + {0x3300, 0x4DBF, wide}, + {0x4E00, 0xA48D, wide}, + {0xA490, 0xA4C7, wide}, + {0xA960, 0xA97D, wide}, + {0xAC00, 0xD7A4, wide}, + {0xE000, 0xF8FF, ambiguous}, + {0xF900, 0xFAFF, wide}, + {0xFE00, 0xFE0F, ambiguous}, + {0xFE10, 0xFE1A, wide}, + {0xFE30, 0xFE53, wide}, + {0xFE54, 0xFE67, wide}, + {0xFE68, 0xFE6C, wide}, + {0xFF01, 0xFF60, fullwidth}, + {0xFF61, 0xFFBF, halfwidth}, + {0xFFC2, 0xFFC8, halfwidth}, + {0xFFCA, 0xFFD0, halfwidth}, + {0xFFD2, 0xFFD8, halfwidth}, + {0xFFDA, 0xFFDD, halfwidth}, + {0xFFE0, 0xFFE7, fullwidth}, + {0xFFE8, 0xFFEF, halfwidth}, + {0xFFFD, 0xFFFE, ambiguous}, + {0x1B000, 0x1B002, wide}, + {0x1F100, 0x1F10A, ambiguous}, + {0x1F110, 0x1F12D, ambiguous}, + {0x1F130, 0x1F169, ambiguous}, + {0x1F170, 0x1F19B, ambiguous}, + {0x1F200, 0x1F203, wide}, + {0x1F210, 0x1F23B, wide}, + {0x1F240, 0x1F249, wide}, + {0x1F250, 0x1F252, wide}, + {0x20000, 0x2FFFE, wide}, + {0x30000, 0x3FFFE, wide}, + {0xE0100, 0xE01F0, ambiguous}, + {0xF0000, 0xFFFFD, ambiguous}, + {0x100000, 0x10FFFE, ambiguous}, +} + +type Condition struct { + EastAsianWidth bool +} + +func NewCondition() *Condition { + return &Condition{EastAsianWidth} +} + +// RuneWidth returns the number of cells in r. +// See http://www.unicode.org/reports/tr11/ +func (c *Condition) RuneWidth(r rune) int { + if r == 0 { + return 0 + } + if r < 32 || (r >= 0x7f && r < 0xa0) { + return 1 + } + for _, iv := range combining { + if iv.first <= r && r <= iv.last { + return 0 + } + } + + if c.EastAsianWidth && IsAmbiguousWidth(r) { + return 2 + } + + if r >= 0x1100 && + (r <= 0x115f || r == 0x2329 || r == 0x232a || + (r >= 0x2e80 && r <= 0xa4cf && r != 0x303f) || + (r >= 0xac00 && r <= 0xd7a3) || + (r >= 0xf900 && r <= 0xfaff) || + (r >= 0xfe30 && r <= 0xfe6f) || + (r >= 0xff00 && r <= 0xff60) || + (r >= 0xffe0 && r <= 0xffe6) || + (r >= 0x20000 && r <= 0x2fffd) || + (r >= 0x30000 && r <= 0x3fffd)) { + return 2 + } + return 1 +} + +func (c *Condition) StringWidth(s string) (width int) { + for _, r := range []rune(s) { + width += c.RuneWidth(r) + } + return width +} + +func (c *Condition) Truncate(s string, w int, tail string) string { + r := []rune(s) + tw := StringWidth(tail) + w -= tw + width := 0 + i := 0 + for ; i < len(r); i++ { + cw := RuneWidth(r[i]) + if width+cw > w { + break + } + width += cw + } + if i == len(r) { + return string(r[0:i]) + } + return string(r[0:i]) + tail +} + +// RuneWidth returns the number of cells in r. +// See http://www.unicode.org/reports/tr11/ +func RuneWidth(r rune) int { + return DefaultCondition.RuneWidth(r) +} + +func ct(r rune) ctype { + for _, iv := range ctypes { + if iv.first <= r && r <= iv.last { + return iv.ctype + } + } + return neutral +} + +// IsAmbiguousWidth returns whether is ambiguous width or not. +func IsAmbiguousWidth(r rune) bool { + return ct(r) == ambiguous +} + +// IsAmbiguousWidth returns whether is ambiguous width or not. +func IsNeutralWidth(r rune) bool { + return ct(r) == neutral +} + +func StringWidth(s string) (width int) { + return DefaultCondition.StringWidth(s) +} + +func Truncate(s string, w int, tail string) string { + return DefaultCondition.Truncate(s, w, tail) +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_js.go b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_js.go new file mode 100644 index 0000000000..0ce32c5e7b --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_js.go @@ -0,0 +1,8 @@ +// +build js + +package runewidth + +func IsEastAsian() bool { + // TODO: Implement this for the web. Detect east asian in a compatible way, and return true. + return false +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_posix.go b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_posix.go new file mode 100644 index 0000000000..a4495909d8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_posix.go @@ -0,0 +1,69 @@ +// +build !windows,!js + +package runewidth + +import ( + "os" + "regexp" + "strings" +) + +var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`) + +func IsEastAsian() bool { + locale := os.Getenv("LC_CTYPE") + if locale == "" { + locale = os.Getenv("LANG") + } + + // ignore C locale + if locale == "POSIX" || locale == "C" { + return false + } + if len(locale) > 1 && locale[0] == 'C' && (locale[1] == '.' || locale[1] == '-') { + return false + } + + charset := strings.ToLower(locale) + r := reLoc.FindStringSubmatch(locale) + if len(r) == 2 { + charset = strings.ToLower(r[1]) + } + + if strings.HasSuffix(charset, "@cjk_narrow") { + return false + } + + for pos, b := range []byte(charset) { + if b == '@' { + charset = charset[:pos] + break + } + } + + mbc_max := 1 + switch charset { + case "utf-8", "utf8": + mbc_max = 6 + case "jis": + mbc_max = 8 + case "eucjp": + mbc_max = 3 + case "euckr", "euccn": + mbc_max = 2 + case "sjis", "cp932", "cp51932", "cp936", "cp949", "cp950": + mbc_max = 2 + case "big5": + mbc_max = 2 + case "gbk", "gb2312": + mbc_max = 2 + } + + if mbc_max > 1 && (charset[0] != 'u' || + strings.HasPrefix(locale, "ja") || + strings.HasPrefix(locale, "ko") || + strings.HasPrefix(locale, "zh")) { + return true + } + return false +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_test.go b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_test.go new file mode 100644 index 0000000000..5cef3d6a49 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_test.go @@ -0,0 +1,134 @@ +package runewidth + +import ( + "testing" +) + +var runewidthtests = []struct { + in rune + out int +}{ + {'世', 2}, + {'界', 2}, + {'ï½¾', 1}, + {'ï½¶', 1}, + {'ï½²', 1}, + {'☆', 2}, // double width in ambiguous + {'\x00', 0}, + {'\x01', 1}, + {'\u0300', 0}, +} + +func TestRuneWidth(t *testing.T) { + c := NewCondition() + c.EastAsianWidth = true + for _, tt := range runewidthtests { + if out := c.RuneWidth(tt.in); out != tt.out { + t.Errorf("Width(%q) = %v, want %v", tt.in, out, tt.out) + } + } +} + +var isambiguouswidthtests = []struct { + in rune + out bool +}{ + {'世', false}, + {'â– ', true}, + {'界', false}, + {'â—‹', true}, + {'㈱', false}, + {'â‘ ', true}, + {'â‘¡', true}, + {'â‘¢', true}, + {'â‘£', true}, + {'⑤', true}, + {'â‘¥', true}, + {'⑦', true}, + {'â‘§', true}, + {'⑨', true}, + {'â‘©', true}, + {'⑪', true}, + {'â‘«', true}, + {'⑬', true}, + {'â‘­', true}, + {'â‘®', true}, + {'⑯', true}, + {'â‘°', true}, + {'⑱', true}, + {'⑲', true}, + {'⑳', true}, + {'☆', true}, +} + +func TestIsAmbiguousWidth(t *testing.T) { + for _, tt := range isambiguouswidthtests { + if out := IsAmbiguousWidth(tt.in); out != tt.out { + t.Errorf("IsAmbiguousWidth(%q) = %v, want %v", tt.in, out, tt.out) + } + } +} + +var stringwidthtests = []struct { + in string + out int +}{ + {"■㈱ã®ä¸–界①", 12}, + {"スター☆", 8}, +} + +func TestStringWidth(t *testing.T) { + c := NewCondition() + c.EastAsianWidth = true + for _, tt := range stringwidthtests { + if out := c.StringWidth(tt.in); out != tt.out { + t.Errorf("StringWidth(%q) = %v, want %v", tt.in, out, tt.out) + } + } +} + +func TestStringWidthInvalid(t *testing.T) { + s := "ã“ã‚“ã«ã¡ã‚\x00世界" + if out := StringWidth(s); out != 14 { + t.Errorf("StringWidth(%q) = %v, want %v", s, out, 14) + } +} + +func TestTruncate(t *testing.T) { + s := "ã‚ã„ã†ãˆãŠã‚ã„ã†ãˆãŠãˆãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠ" + expected := "ã‚ã„ã†ãˆãŠã‚ã„ã†ãˆãŠãˆãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠãŠ..." + + if out := Truncate(s, 80, "..."); out != expected { + t.Errorf("Truncate(%q) = %v, want %v", s, out, expected) + } +} + +func TestTruncateNoNeeded(t *testing.T) { + s := "ã‚ã„ã†ãˆãŠã‚ã„" + expected := "ã‚ã„ã†ãˆãŠã‚ã„" + + if out := Truncate(s, 80, "..."); out != expected { + t.Errorf("Truncate(%q) = %v, want %v", s, out, expected) + } +} + +var isneutralwidthtests = []struct { + in rune + out bool +}{ + {'→', false}, + {'┊', false}, + {'┈', false}, + {'~', false}, + {'â””', false}, + {'⣀', true}, + {'⣀', true}, +} + +func TestIsNeutralWidth(t *testing.T) { + for _, tt := range isneutralwidthtests { + if out := IsNeutralWidth(tt.in); out != tt.out { + t.Errorf("IsNeutralWidth(%q) = %v, want %v", tt.in, out, tt.out) + } + } +} diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_windows.go b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_windows.go new file mode 100644 index 0000000000..bdd84454be --- /dev/null +++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_windows.go @@ -0,0 +1,24 @@ +package runewidth + +import ( + "syscall" +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32") + procGetConsoleOutputCP = kernel32.NewProc("GetConsoleOutputCP") +) + +func IsEastAsian() bool { + r1, _, _ := procGetConsoleOutputCP.Call() + if r1 == 0 { + return false + } + + switch int(r1) { + case 932, 51932, 936, 949, 950: + return true + } + + return false +} diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/AUTHORS b/Godeps/_workspace/src/github.com/nsf/termbox-go/AUTHORS new file mode 100644 index 0000000000..fe26fb0fb0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/AUTHORS @@ -0,0 +1,4 @@ +# Please keep this file sorted. + +Georg Reinke +nsf diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/LICENSE b/Godeps/_workspace/src/github.com/nsf/termbox-go/LICENSE new file mode 100644 index 0000000000..d9bc068ce7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2012 termbox-go authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md b/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md new file mode 100644 index 0000000000..334d751024 --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md @@ -0,0 +1,21 @@ +## Termbox +Termbox is a library that provides a minimalistic API which allows the programmer to write text-based user interfaces. The library is crossplatform and has both terminal-based implementations on *nix operating systems and a winapi console based implementation for windows operating systems. The basic idea is an abstraction of the greatest common subset of features available on all major terminals and other terminal-like APIs in a minimalistic fashion. Small API means it is easy to implement, test, maintain and learn it, that's what makes the termbox a distinct library in its area. + +### Installation +Install and update this go package with `go get -u github.com/nsf/termbox-go` + +### Examples +For examples of what can be done take a look at demos in the _demos directory. You can try them with go run: `go run _demos/keyboard.go` + +There are also some interesting projects using termbox-go: + - [godit](https://github.com/nsf/godit) is an emacsish lightweight text editor written using termbox. + - [gomatrix](https://github.com/GeertJohan/gomatrix) connects to The Matrix and displays its data streams in your terminal. + - [gotetris](https://github.com/jjinux/gotetris) is an implementation of Tetris. + - [sokoban-go](https://github.com/rn2dy/sokoban-go) is an implementation of sokoban game. + - [hecate](https://github.com/evanmiller/hecate) is a hex editor designed by Satan. + - [httopd](https://github.com/verdverm/httopd) is top for httpd logs. + - [mop](https://github.com/michaeldv/mop) is stock market tracker for hackers. + - [termui](https://github.com/gizak/termui) is a terminal dashboard. + +### API reference +[godoc.org/github.com/nsf/termbox-go](http://godoc.org/github.com/nsf/termbox-go) diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go new file mode 100644 index 0000000000..b08bca61a5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go @@ -0,0 +1,451 @@ +// +build !windows + +package termbox + +import "github.com/mattn/go-runewidth" +import "fmt" +import "os" +import "os/signal" +import "syscall" +import "runtime" + +// public API + +// Initializes termbox library. This function should be called before any other functions. +// After successful initialization, the library must be finalized using 'Close' function. +// +// Example usage: +// err := termbox.Init() +// if err != nil { +// panic(err) +// } +// defer termbox.Close() +func Init() error { + var err error + + out, err = os.OpenFile("/dev/tty", syscall.O_WRONLY, 0) + if err != nil { + return err + } + in, err = syscall.Open("/dev/tty", syscall.O_RDONLY, 0) + if err != nil { + return err + } + + err = setup_term() + if err != nil { + return fmt.Errorf("termbox: error while reading terminfo data: %v", err) + } + + signal.Notify(sigwinch, syscall.SIGWINCH) + signal.Notify(sigio, syscall.SIGIO) + + _, err = fcntl(in, syscall.F_SETFL, syscall.O_ASYNC|syscall.O_NONBLOCK) + if err != nil { + return err + } + _, err = fcntl(in, syscall.F_SETOWN, syscall.Getpid()) + if runtime.GOOS != "darwin" && err != nil { + return err + } + err = tcgetattr(out.Fd(), &orig_tios) + if err != nil { + return err + } + + tios := orig_tios + tios.Iflag &^= syscall_IGNBRK | syscall_BRKINT | syscall_PARMRK | + syscall_ISTRIP | syscall_INLCR | syscall_IGNCR | + syscall_ICRNL | syscall_IXON + tios.Oflag &^= syscall_OPOST + tios.Lflag &^= syscall_ECHO | syscall_ECHONL | syscall_ICANON | + syscall_ISIG | syscall_IEXTEN + tios.Cflag &^= syscall_CSIZE | syscall_PARENB + tios.Cflag |= syscall_CS8 + tios.Cc[syscall_VMIN] = 1 + tios.Cc[syscall_VTIME] = 0 + + err = tcsetattr(out.Fd(), &tios) + if err != nil { + return err + } + + out.WriteString(funcs[t_enter_ca]) + out.WriteString(funcs[t_enter_keypad]) + out.WriteString(funcs[t_hide_cursor]) + out.WriteString(funcs[t_clear_screen]) + + termw, termh = get_term_size(out.Fd()) + back_buffer.init(termw, termh) + front_buffer.init(termw, termh) + back_buffer.clear() + front_buffer.clear() + + go func() { + buf := make([]byte, 128) + for { + select { + case <-sigio: + for { + n, err := syscall.Read(in, buf) + if err == syscall.EAGAIN || err == syscall.EWOULDBLOCK { + break + } + select { + case input_comm <- input_event{buf[:n], err}: + ie := <-input_comm + buf = ie.data[:128] + case <-quit: + return + } + } + case <-quit: + return + } + } + }() + + IsInit = true + return nil +} + +// Interrupt an in-progress call to PollEvent by causing it to return +// EventInterrupt. Note that this function will block until the PollEvent +// function has successfully been interrupted. +func Interrupt() { + interrupt_comm <- struct{}{} +} + +// Finalizes termbox library, should be called after successful initialization +// when termbox's functionality isn't required anymore. +func Close() { + quit <- 1 + out.WriteString(funcs[t_show_cursor]) + out.WriteString(funcs[t_sgr0]) + out.WriteString(funcs[t_clear_screen]) + out.WriteString(funcs[t_exit_ca]) + out.WriteString(funcs[t_exit_keypad]) + out.WriteString(funcs[t_exit_mouse]) + tcsetattr(out.Fd(), &orig_tios) + + out.Close() + syscall.Close(in) + + // reset the state, so that on next Init() it will work again + termw = 0 + termh = 0 + input_mode = InputEsc + out = nil + in = 0 + lastfg = attr_invalid + lastbg = attr_invalid + lastx = coord_invalid + lasty = coord_invalid + cursor_x = cursor_hidden + cursor_y = cursor_hidden + foreground = ColorDefault + background = ColorDefault + IsInit = false +} + +// Synchronizes the internal back buffer with the terminal. +func Flush() error { + // invalidate cursor position + lastx = coord_invalid + lasty = coord_invalid + + update_size_maybe() + + for y := 0; y < front_buffer.height; y++ { + line_offset := y * front_buffer.width + for x := 0; x < front_buffer.width; { + cell_offset := line_offset + x + back := &back_buffer.cells[cell_offset] + front := &front_buffer.cells[cell_offset] + if back.Ch < ' ' { + back.Ch = ' ' + } + w := runewidth.RuneWidth(back.Ch) + if w == 0 || w == 2 && runewidth.IsAmbiguousWidth(back.Ch) { + w = 1 + } + if *back == *front { + x += w + continue + } + *front = *back + send_attr(back.Fg, back.Bg) + + if w == 2 && x == front_buffer.width-1 { + // there's not enough space for 2-cells rune, + // let's just put a space in there + send_char(x, y, ' ') + } else { + send_char(x, y, back.Ch) + if w == 2 { + next := cell_offset + 1 + front_buffer.cells[next] = Cell{ + Ch: 0, + Fg: back.Fg, + Bg: back.Bg, + } + } + } + x += w + } + } + if !is_cursor_hidden(cursor_x, cursor_y) { + write_cursor(cursor_x, cursor_y) + } + return flush() +} + +// Sets the position of the cursor. See also HideCursor(). +func SetCursor(x, y int) { + if is_cursor_hidden(cursor_x, cursor_y) && !is_cursor_hidden(x, y) { + outbuf.WriteString(funcs[t_show_cursor]) + } + + if !is_cursor_hidden(cursor_x, cursor_y) && is_cursor_hidden(x, y) { + outbuf.WriteString(funcs[t_hide_cursor]) + } + + cursor_x, cursor_y = x, y + if !is_cursor_hidden(cursor_x, cursor_y) { + write_cursor(cursor_x, cursor_y) + } +} + +// The shortcut for SetCursor(-1, -1). +func HideCursor() { + SetCursor(cursor_hidden, cursor_hidden) +} + +// Changes cell's parameters in the internal back buffer at the specified +// position. +func SetCell(x, y int, ch rune, fg, bg Attribute) { + if x < 0 || x >= back_buffer.width { + return + } + if y < 0 || y >= back_buffer.height { + return + } + + back_buffer.cells[y*back_buffer.width+x] = Cell{ch, fg, bg} +} + +// Returns a slice into the termbox's back buffer. You can get its dimensions +// using 'Size' function. The slice remains valid as long as no 'Clear' or +// 'Flush' function calls were made after call to this function. +func CellBuffer() []Cell { + return back_buffer.cells +} + +// After getting a raw event from PollRawEvent function call, you can parse it +// again into an ordinary one using termbox logic. That is parse an event as +// termbox would do it. Returned event in addition to usual Event struct fields +// sets N field to the amount of bytes used within 'data' slice. If the length +// of 'data' slice is zero or event cannot be parsed for some other reason, the +// function will return a special event type: EventNone. +// +// IMPORTANT: EventNone may contain a non-zero N, which means you should skip +// these bytes, because termbox cannot recognize them. +// +// NOTE: This API is experimental and may change in future. +func ParseEvent(data []byte) Event { + event := Event{Type: EventKey} + ok := extract_event(data, &event) + if !ok { + return Event{Type: EventNone, N: event.N} + } + return event +} + +// Wait for an event and return it. This is a blocking function call. Instead +// of EventKey and EventMouse it returns EventRaw events. Raw event is written +// into `data` slice and Event's N field is set to the amount of bytes written. +// The minimum required length of the 'data' slice is 1. This requirement may +// vary on different platforms. +// +// NOTE: This API is experimental and may change in future. +func PollRawEvent(data []byte) Event { + if len(data) == 0 { + panic("len(data) >= 1 is a requirement") + } + + var event Event + if extract_raw_event(data, &event) { + return event + } + + for { + select { + case ev := <-input_comm: + if ev.err != nil { + return Event{Type: EventError, Err: ev.err} + } + + inbuf = append(inbuf, ev.data...) + input_comm <- ev + if extract_raw_event(data, &event) { + return event + } + case <-interrupt_comm: + event.Type = EventInterrupt + return event + + case <-sigwinch: + event.Type = EventResize + event.Width, event.Height = get_term_size(out.Fd()) + return event + } + } +} + +// Wait for an event and return it. This is a blocking function call. +func PollEvent() Event { + var event Event + + // try to extract event from input buffer, return on success + event.Type = EventKey + ok := extract_event(inbuf, &event) + if event.N != 0 { + copy(inbuf, inbuf[event.N:]) + inbuf = inbuf[:len(inbuf)-event.N] + } + if ok { + return event + } + + for { + select { + case ev := <-input_comm: + if ev.err != nil { + return Event{Type: EventError, Err: ev.err} + } + + inbuf = append(inbuf, ev.data...) + input_comm <- ev + ok := extract_event(inbuf, &event) + if event.N != 0 { + copy(inbuf, inbuf[event.N:]) + inbuf = inbuf[:len(inbuf)-event.N] + } + if ok { + return event + } + case <-interrupt_comm: + event.Type = EventInterrupt + return event + + case <-sigwinch: + event.Type = EventResize + event.Width, event.Height = get_term_size(out.Fd()) + return event + } + } + panic("unreachable") +} + +// Returns the size of the internal back buffer (which is mostly the same as +// terminal's window size in characters). But it doesn't always match the size +// of the terminal window, after the terminal size has changed, the internal +// back buffer will get in sync only after Clear or Flush function calls. +func Size() (int, int) { + return termw, termh +} + +// Clears the internal back buffer. +func Clear(fg, bg Attribute) error { + foreground, background = fg, bg + err := update_size_maybe() + back_buffer.clear() + return err +} + +// Sets termbox input mode. Termbox has two input modes: +// +// 1. Esc input mode. When ESC sequence is in the buffer and it doesn't match +// any known sequence. ESC means KeyEsc. This is the default input mode. +// +// 2. Alt input mode. When ESC sequence is in the buffer and it doesn't match +// any known sequence. ESC enables ModAlt modifier for the next keyboard event. +// +// Both input modes can be OR'ed with Mouse mode. Setting Mouse mode bit up will +// enable mouse button click events. +// +// If 'mode' is InputCurrent, returns the current input mode. See also Input* +// constants. +func SetInputMode(mode InputMode) InputMode { + if mode == InputCurrent { + return input_mode + } + if mode&InputMouse != 0 { + out.WriteString(funcs[t_enter_mouse]) + } else { + out.WriteString(funcs[t_exit_mouse]) + } + + input_mode = mode + return input_mode +} + +// Sets the termbox output mode. Termbox has four output options: +// 1. OutputNormal => [1..8] +// This mode provides 8 different colors: +// black, red, green, yellow, blue, magenta, cyan, white +// Shortcut: ColorBlack, ColorRed, ... +// Attributes: AttrBold, AttrUnderline, AttrReverse +// +// Example usage: +// SetCell(x, y, '@', ColorBlack | AttrBold, ColorRed); +// +// 2. Output256 => [1..256] +// In this mode you can leverage the 256 terminal mode: +// 0x00 - 0x07: the 8 colors as in OutputNormal +// 0x08 - 0x0f: Color* | AttrBold +// 0x10 - 0xe7: 216 different colors +// 0xe8 - 0xff: 24 different shades of grey +// +// Example usage: +// SetCell(x, y, '@', 184, 240); +// SetCell(x, y, '@', 0xb8, 0xf0); +// +// 3. Output216 => [1..216] +// This mode supports the 3rd range of the 256 mode only. +// But you dont need to provide an offset. +// +// 4. OutputGrayscale => [1..24] +// This mode supports the 4th range of the 256 mode only. +// But you dont need to provide an offset. +// +// In all modes, 0 represents the default color. +// +// `go run _demos/output.go` to see its impact on your terminal. +// +// If 'mode' is OutputCurrent, it returns the current output mode. +// +// Note that this may return a different OutputMode than the one requested, +// as the requested mode may not be available on the target platform. +func SetOutputMode(mode OutputMode) OutputMode { + if mode == OutputCurrent { + return output_mode + } + + output_mode = mode + return output_mode +} + +// Sync comes handy when something causes desync between termbox's understanding +// of a terminal buffer and the reality. Such as a third party process. Sync +// forces a complete resync between the termbox and a terminal, it may not be +// visually pretty though. +func Sync() error { + front_buffer.clear() + err := send_clear() + if err != nil { + return err + } + + return Flush() +} diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/api_common.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_common.go new file mode 100644 index 0000000000..c0069fb289 --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_common.go @@ -0,0 +1,183 @@ +// termbox is a library for creating cross-platform text-based interfaces +package termbox + +// public API, common OS agnostic part + +type ( + InputMode int + OutputMode int + EventType uint8 + Modifier uint8 + Key uint16 + Attribute uint16 +) + +// This type represents a termbox event. The 'Mod', 'Key' and 'Ch' fields are +// valid if 'Type' is EventKey. The 'Width' and 'Height' fields are valid if +// 'Type' is EventResize. The 'Err' field is valid if 'Type' is EventError. +type Event struct { + Type EventType // one of Event* constants + Mod Modifier // one of Mod* constants or 0 + Key Key // one of Key* constants, invalid if 'Ch' is not 0 + Ch rune // a unicode character + Width int // width of the screen + Height int // height of the screen + Err error // error in case if input failed + MouseX int // x coord of mouse + MouseY int // y coord of mouse + N int // number of bytes written when getting a raw event +} + +// A cell, single conceptual entity on the screen. The screen is basically a 2d +// array of cells. 'Ch' is a unicode character, 'Fg' and 'Bg' are foreground +// and background attributes respectively. +type Cell struct { + Ch rune + Fg Attribute + Bg Attribute +} + +// To know if termbox has been initialized or not +var ( + IsInit bool = false +) + +// Key constants, see Event.Key field. +const ( + KeyF1 Key = 0xFFFF - iota + KeyF2 + KeyF3 + KeyF4 + KeyF5 + KeyF6 + KeyF7 + KeyF8 + KeyF9 + KeyF10 + KeyF11 + KeyF12 + KeyInsert + KeyDelete + KeyHome + KeyEnd + KeyPgup + KeyPgdn + KeyArrowUp + KeyArrowDown + KeyArrowLeft + KeyArrowRight + key_min // see terminfo + MouseLeft + MouseMiddle + MouseRight +) + +const ( + KeyCtrlTilde Key = 0x00 + KeyCtrl2 Key = 0x00 + KeyCtrlSpace Key = 0x00 + KeyCtrlA Key = 0x01 + KeyCtrlB Key = 0x02 + KeyCtrlC Key = 0x03 + KeyCtrlD Key = 0x04 + KeyCtrlE Key = 0x05 + KeyCtrlF Key = 0x06 + KeyCtrlG Key = 0x07 + KeyBackspace Key = 0x08 + KeyCtrlH Key = 0x08 + KeyTab Key = 0x09 + KeyCtrlI Key = 0x09 + KeyCtrlJ Key = 0x0A + KeyCtrlK Key = 0x0B + KeyCtrlL Key = 0x0C + KeyEnter Key = 0x0D + KeyCtrlM Key = 0x0D + KeyCtrlN Key = 0x0E + KeyCtrlO Key = 0x0F + KeyCtrlP Key = 0x10 + KeyCtrlQ Key = 0x11 + KeyCtrlR Key = 0x12 + KeyCtrlS Key = 0x13 + KeyCtrlT Key = 0x14 + KeyCtrlU Key = 0x15 + KeyCtrlV Key = 0x16 + KeyCtrlW Key = 0x17 + KeyCtrlX Key = 0x18 + KeyCtrlY Key = 0x19 + KeyCtrlZ Key = 0x1A + KeyEsc Key = 0x1B + KeyCtrlLsqBracket Key = 0x1B + KeyCtrl3 Key = 0x1B + KeyCtrl4 Key = 0x1C + KeyCtrlBackslash Key = 0x1C + KeyCtrl5 Key = 0x1D + KeyCtrlRsqBracket Key = 0x1D + KeyCtrl6 Key = 0x1E + KeyCtrl7 Key = 0x1F + KeyCtrlSlash Key = 0x1F + KeyCtrlUnderscore Key = 0x1F + KeySpace Key = 0x20 + KeyBackspace2 Key = 0x7F + KeyCtrl8 Key = 0x7F +) + +// Alt modifier constant, see Event.Mod field and SetInputMode function. +const ( + ModAlt Modifier = 0x01 +) + +// Cell colors, you can combine a color with multiple attributes using bitwise +// OR ('|'). +const ( + ColorDefault Attribute = iota + ColorBlack + ColorRed + ColorGreen + ColorYellow + ColorBlue + ColorMagenta + ColorCyan + ColorWhite +) + +// Cell attributes, it is possible to use multiple attributes by combining them +// using bitwise OR ('|'). Although, colors cannot be combined. But you can +// combine attributes and a single color. +// +// It's worth mentioning that some platforms don't support certain attibutes. +// For example windows console doesn't support AttrUnderline. And on some +// terminals applying AttrBold to background may result in blinking text. Use +// them with caution and test your code on various terminals. +const ( + AttrBold Attribute = 1 << (iota + 9) + AttrUnderline + AttrReverse +) + +// Input mode. See SetInputMode function. +const ( + InputEsc InputMode = 1 << iota + InputAlt + InputMouse + InputCurrent InputMode = 0 +) + +// Output mode. See SetOutputMode function. +const ( + OutputCurrent OutputMode = iota + OutputNormal + Output256 + Output216 + OutputGrayscale +) + +// Event type. See Event.Type field. +const ( + EventKey EventType = iota + EventResize + EventMouse + EventError + EventInterrupt + EventRaw + EventNone +) diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go new file mode 100644 index 0000000000..78d954b36c --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go @@ -0,0 +1,235 @@ +package termbox + +import ( + "syscall" +) + +// public API + +// Initializes termbox library. This function should be called before any other functions. +// After successful initialization, the library must be finalized using 'Close' function. +// +// Example usage: +// err := termbox.Init() +// if err != nil { +// panic(err) +// } +// defer termbox.Close() +func Init() error { + var err error + + interrupt, err = create_event() + if err != nil { + return err + } + + in, err = syscall.Open("CONIN$", syscall.O_RDWR, 0) + if err != nil { + return err + } + out, err = syscall.Open("CONOUT$", syscall.O_RDWR, 0) + if err != nil { + return err + } + + err = get_console_mode(in, &orig_mode) + if err != nil { + return err + } + + err = set_console_mode(in, enable_window_input) + if err != nil { + return err + } + + orig_size = get_term_size(out) + win_size := get_win_size(out) + + err = set_console_screen_buffer_size(out, win_size) + if err != nil { + return err + } + + err = get_console_cursor_info(out, &orig_cursor_info) + if err != nil { + return err + } + + show_cursor(false) + term_size = get_term_size(out) + back_buffer.init(int(term_size.x), int(term_size.y)) + front_buffer.init(int(term_size.x), int(term_size.y)) + back_buffer.clear() + front_buffer.clear() + clear() + + diffbuf = make([]diff_msg, 0, 32) + + go input_event_producer() + IsInit = true + return nil +} + +// Finalizes termbox library, should be called after successful initialization +// when termbox's functionality isn't required anymore. +func Close() { + // we ignore errors here, because we can't really do anything about them + Clear(0, 0) + Flush() + + // stop event producer + cancel_comm <- true + set_event(interrupt) + <-cancel_done_comm + + set_console_cursor_info(out, &orig_cursor_info) + set_console_cursor_position(out, coord{}) + set_console_screen_buffer_size(out, orig_size) + set_console_mode(in, orig_mode) + syscall.Close(in) + syscall.Close(out) + syscall.Close(interrupt) + IsInit = false +} + +// Interrupt an in-progress call to PollEvent by causing it to return +// EventInterrupt. Note that this function will block until the PollEvent +// function has successfully been interrupted. +func Interrupt() { + interrupt_comm <- struct{}{} +} + +// Synchronizes the internal back buffer with the terminal. +func Flush() error { + update_size_maybe() + prepare_diff_messages() + for _, diff := range diffbuf { + r := small_rect{ + left: 0, + top: diff.pos, + right: term_size.x - 1, + bottom: diff.pos + diff.lines - 1, + } + write_console_output(out, diff.chars, r) + } + if !is_cursor_hidden(cursor_x, cursor_y) { + move_cursor(cursor_x, cursor_y) + } + return nil +} + +// Sets the position of the cursor. See also HideCursor(). +func SetCursor(x, y int) { + if is_cursor_hidden(cursor_x, cursor_y) && !is_cursor_hidden(x, y) { + show_cursor(true) + } + + if !is_cursor_hidden(cursor_x, cursor_y) && is_cursor_hidden(x, y) { + show_cursor(false) + } + + cursor_x, cursor_y = x, y + if !is_cursor_hidden(cursor_x, cursor_y) { + move_cursor(cursor_x, cursor_y) + } +} + +// The shortcut for SetCursor(-1, -1). +func HideCursor() { + SetCursor(cursor_hidden, cursor_hidden) +} + +// Changes cell's parameters in the internal back buffer at the specified +// position. +func SetCell(x, y int, ch rune, fg, bg Attribute) { + if x < 0 || x >= back_buffer.width { + return + } + if y < 0 || y >= back_buffer.height { + return + } + + back_buffer.cells[y*back_buffer.width+x] = Cell{ch, fg, bg} +} + +// Returns a slice into the termbox's back buffer. You can get its dimensions +// using 'Size' function. The slice remains valid as long as no 'Clear' or +// 'Flush' function calls were made after call to this function. +func CellBuffer() []Cell { + return back_buffer.cells +} + +// Wait for an event and return it. This is a blocking function call. +func PollEvent() Event { + select { + case ev := <-input_comm: + return ev + case <-interrupt_comm: + return Event{Type: EventInterrupt} + } +} + +// Returns the size of the internal back buffer (which is mostly the same as +// console's window size in characters). But it doesn't always match the size +// of the console window, after the console size has changed, the internal back +// buffer will get in sync only after Clear or Flush function calls. +func Size() (int, int) { + return int(term_size.x), int(term_size.y) +} + +// Clears the internal back buffer. +func Clear(fg, bg Attribute) error { + foreground, background = fg, bg + update_size_maybe() + back_buffer.clear() + return nil +} + +// Sets termbox input mode. Termbox has two input modes: +// +// 1. Esc input mode. When ESC sequence is in the buffer and it doesn't match +// any known sequence. ESC means KeyEsc. This is the default input mode. +// +// 2. Alt input mode. When ESC sequence is in the buffer and it doesn't match +// any known sequence. ESC enables ModAlt modifier for the next keyboard event. +// +// Both input modes can be OR'ed with Mouse mode. Setting Mouse mode bit up will +// enable mouse button click events. +// +// If 'mode' is InputCurrent, returns the current input mode. See also Input* +// constants. +func SetInputMode(mode InputMode) InputMode { + if mode == InputCurrent { + return input_mode + } + if mode&InputMouse != 0 { + err := set_console_mode(in, enable_window_input|enable_mouse_input|enable_extended_flags) + if err != nil { + panic(err) + } + } else { + err := set_console_mode(in, enable_window_input) + if err != nil { + panic(err) + } + } + + input_mode = mode + return input_mode +} + +// Sets the termbox output mode. +// +// Windows console does not support extra colour modes, +// so this will always set and return OutputNormal. +func SetOutputMode(mode OutputMode) OutputMode { + return OutputNormal +} + +// Sync comes handy when something causes desync between termbox's understanding +// of a terminal buffer and the reality. Such as a third party process. Sync +// forces a complete resync between the termbox and a terminal, it may not be +// visually pretty though. At the moment on Windows it does nothing. +func Sync() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/collect_terminfo.py b/Godeps/_workspace/src/github.com/nsf/termbox-go/collect_terminfo.py new file mode 100644 index 0000000000..5e50975e63 --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/collect_terminfo.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python + +import sys, os, subprocess + +def escaped(s): + return repr(s)[1:-1] + +def tput(term, name): + try: + return subprocess.check_output(['tput', '-T%s' % term, name]).decode() + except subprocess.CalledProcessError as e: + return e.output.decode() + + +def w(s): + if s == None: + return + sys.stdout.write(s) + +terminals = { + 'xterm' : 'xterm', + 'rxvt-256color' : 'rxvt_256color', + 'rxvt-unicode' : 'rxvt_unicode', + 'linux' : 'linux', + 'Eterm' : 'eterm', + 'screen' : 'screen' +} + +keys = [ + "F1", "kf1", + "F2", "kf2", + "F3", "kf3", + "F4", "kf4", + "F5", "kf5", + "F6", "kf6", + "F7", "kf7", + "F8", "kf8", + "F9", "kf9", + "F10", "kf10", + "F11", "kf11", + "F12", "kf12", + "INSERT", "kich1", + "DELETE", "kdch1", + "HOME", "khome", + "END", "kend", + "PGUP", "kpp", + "PGDN", "knp", + "KEY_UP", "kcuu1", + "KEY_DOWN", "kcud1", + "KEY_LEFT", "kcub1", + "KEY_RIGHT", "kcuf1" +] + +funcs = [ + "T_ENTER_CA", "smcup", + "T_EXIT_CA", "rmcup", + "T_SHOW_CURSOR", "cnorm", + "T_HIDE_CURSOR", "civis", + "T_CLEAR_SCREEN", "clear", + "T_SGR0", "sgr0", + "T_UNDERLINE", "smul", + "T_BOLD", "bold", + "T_BLINK", "blink", + "T_REVERSE", "rev", + "T_ENTER_KEYPAD", "smkx", + "T_EXIT_KEYPAD", "rmkx" +] + +def iter_pairs(iterable): + iterable = iter(iterable) + while True: + yield (next(iterable), next(iterable)) + +def do_term(term, nick): + w("// %s\n" % term) + w("var %s_keys = []string{\n\t" % nick) + for k, v in iter_pairs(keys): + w('"') + w(escaped(tput(term, v))) + w('",') + w("\n}\n") + w("var %s_funcs = []string{\n\t" % nick) + for k,v in iter_pairs(funcs): + w('"') + if v == "sgr": + w("\\033[3%d;4%dm") + elif v == "cup": + w("\\033[%d;%dH") + else: + w(escaped(tput(term, v))) + w('", ') + w("\n}\n\n") + +def do_terms(d): + w("var terms = []struct {\n") + w("\tname string\n") + w("\tkeys []string\n") + w("\tfuncs []string\n") + w("}{\n") + for k, v in d.items(): + w('\t{"%s", %s_keys, %s_funcs},\n' % (k, v, v)) + w("}\n\n") + +w("// +build !windows\n\npackage termbox\n\n") + +for k,v in terminals.items(): + do_term(k, v) + +do_terms(terminals) + diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls.go new file mode 100644 index 0000000000..4f52bb9af9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls.go @@ -0,0 +1,39 @@ +// +build ignore + +package termbox + +/* +#include +#include +*/ +import "C" + +type syscall_Termios C.struct_termios + +const ( + syscall_IGNBRK = C.IGNBRK + syscall_BRKINT = C.BRKINT + syscall_PARMRK = C.PARMRK + syscall_ISTRIP = C.ISTRIP + syscall_INLCR = C.INLCR + syscall_IGNCR = C.IGNCR + syscall_ICRNL = C.ICRNL + syscall_IXON = C.IXON + syscall_OPOST = C.OPOST + syscall_ECHO = C.ECHO + syscall_ECHONL = C.ECHONL + syscall_ICANON = C.ICANON + syscall_ISIG = C.ISIG + syscall_IEXTEN = C.IEXTEN + syscall_CSIZE = C.CSIZE + syscall_PARENB = C.PARENB + syscall_CS8 = C.CS8 + syscall_VMIN = C.VMIN + syscall_VTIME = C.VTIME + + // on darwin change these to (on *bsd too?): + // C.TIOCGETA + // C.TIOCSETA + syscall_TCGETS = C.TCGETS + syscall_TCSETS = C.TCSETS +) diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_386.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_386.go new file mode 100644 index 0000000000..e03624ebc7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_386.go @@ -0,0 +1,39 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs syscalls.go + +package termbox + +type syscall_Termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [20]uint8 + Ispeed uint32 + Ospeed uint32 +} + +const ( + syscall_IGNBRK = 0x1 + syscall_BRKINT = 0x2 + syscall_PARMRK = 0x8 + syscall_ISTRIP = 0x20 + syscall_INLCR = 0x40 + syscall_IGNCR = 0x80 + syscall_ICRNL = 0x100 + syscall_IXON = 0x200 + syscall_OPOST = 0x1 + syscall_ECHO = 0x8 + syscall_ECHONL = 0x10 + syscall_ICANON = 0x100 + syscall_ISIG = 0x80 + syscall_IEXTEN = 0x400 + syscall_CSIZE = 0x300 + syscall_PARENB = 0x1000 + syscall_CS8 = 0x300 + syscall_VMIN = 0x10 + syscall_VTIME = 0x11 + + syscall_TCGETS = 0x402c7413 + syscall_TCSETS = 0x802c7414 +) diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_amd64.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_amd64.go new file mode 100644 index 0000000000..11f25be79a --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_amd64.go @@ -0,0 +1,40 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs syscalls.go + +package termbox + +type syscall_Termios struct { + Iflag uint64 + Oflag uint64 + Cflag uint64 + Lflag uint64 + Cc [20]uint8 + Pad_cgo_0 [4]byte + Ispeed uint64 + Ospeed uint64 +} + +const ( + syscall_IGNBRK = 0x1 + syscall_BRKINT = 0x2 + syscall_PARMRK = 0x8 + syscall_ISTRIP = 0x20 + syscall_INLCR = 0x40 + syscall_IGNCR = 0x80 + syscall_ICRNL = 0x100 + syscall_IXON = 0x200 + syscall_OPOST = 0x1 + syscall_ECHO = 0x8 + syscall_ECHONL = 0x10 + syscall_ICANON = 0x100 + syscall_ISIG = 0x80 + syscall_IEXTEN = 0x400 + syscall_CSIZE = 0x300 + syscall_PARENB = 0x1000 + syscall_CS8 = 0x300 + syscall_VMIN = 0x10 + syscall_VTIME = 0x11 + + syscall_TCGETS = 0x40487413 + syscall_TCSETS = 0x80487414 +) diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_freebsd.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_freebsd.go new file mode 100644 index 0000000000..e03624ebc7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_freebsd.go @@ -0,0 +1,39 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs syscalls.go + +package termbox + +type syscall_Termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [20]uint8 + Ispeed uint32 + Ospeed uint32 +} + +const ( + syscall_IGNBRK = 0x1 + syscall_BRKINT = 0x2 + syscall_PARMRK = 0x8 + syscall_ISTRIP = 0x20 + syscall_INLCR = 0x40 + syscall_IGNCR = 0x80 + syscall_ICRNL = 0x100 + syscall_IXON = 0x200 + syscall_OPOST = 0x1 + syscall_ECHO = 0x8 + syscall_ECHONL = 0x10 + syscall_ICANON = 0x100 + syscall_ISIG = 0x80 + syscall_IEXTEN = 0x400 + syscall_CSIZE = 0x300 + syscall_PARENB = 0x1000 + syscall_CS8 = 0x300 + syscall_VMIN = 0x10 + syscall_VTIME = 0x11 + + syscall_TCGETS = 0x402c7413 + syscall_TCSETS = 0x802c7414 +) diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_linux.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_linux.go new file mode 100644 index 0000000000..b88960de61 --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_linux.go @@ -0,0 +1,33 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs syscalls.go + +package termbox + +import "syscall" + +type syscall_Termios syscall.Termios + +const ( + syscall_IGNBRK = syscall.IGNBRK + syscall_BRKINT = syscall.BRKINT + syscall_PARMRK = syscall.PARMRK + syscall_ISTRIP = syscall.ISTRIP + syscall_INLCR = syscall.INLCR + syscall_IGNCR = syscall.IGNCR + syscall_ICRNL = syscall.ICRNL + syscall_IXON = syscall.IXON + syscall_OPOST = syscall.OPOST + syscall_ECHO = syscall.ECHO + syscall_ECHONL = syscall.ECHONL + syscall_ICANON = syscall.ICANON + syscall_ISIG = syscall.ISIG + syscall_IEXTEN = syscall.IEXTEN + syscall_CSIZE = syscall.CSIZE + syscall_PARENB = syscall.PARENB + syscall_CS8 = syscall.CS8 + syscall_VMIN = syscall.VMIN + syscall_VTIME = syscall.VTIME + + syscall_TCGETS = syscall.TCGETS + syscall_TCSETS = syscall.TCSETS +) diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_netbsd.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_netbsd.go new file mode 100644 index 0000000000..49a3355b9a --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_netbsd.go @@ -0,0 +1,39 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs syscalls.go + +package termbox + +type syscall_Termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [20]uint8 + Ispeed int32 + Ospeed int32 +} + +const ( + syscall_IGNBRK = 0x1 + syscall_BRKINT = 0x2 + syscall_PARMRK = 0x8 + syscall_ISTRIP = 0x20 + syscall_INLCR = 0x40 + syscall_IGNCR = 0x80 + syscall_ICRNL = 0x100 + syscall_IXON = 0x200 + syscall_OPOST = 0x1 + syscall_ECHO = 0x8 + syscall_ECHONL = 0x10 + syscall_ICANON = 0x100 + syscall_ISIG = 0x80 + syscall_IEXTEN = 0x400 + syscall_CSIZE = 0x300 + syscall_PARENB = 0x1000 + syscall_CS8 = 0x300 + syscall_VMIN = 0x10 + syscall_VTIME = 0x11 + + syscall_TCGETS = 0x402c7413 + syscall_TCSETS = 0x802c7414 +) diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_openbsd.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_openbsd.go new file mode 100644 index 0000000000..49a3355b9a --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_openbsd.go @@ -0,0 +1,39 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs syscalls.go + +package termbox + +type syscall_Termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [20]uint8 + Ispeed int32 + Ospeed int32 +} + +const ( + syscall_IGNBRK = 0x1 + syscall_BRKINT = 0x2 + syscall_PARMRK = 0x8 + syscall_ISTRIP = 0x20 + syscall_INLCR = 0x40 + syscall_IGNCR = 0x80 + syscall_ICRNL = 0x100 + syscall_IXON = 0x200 + syscall_OPOST = 0x1 + syscall_ECHO = 0x8 + syscall_ECHONL = 0x10 + syscall_ICANON = 0x100 + syscall_ISIG = 0x80 + syscall_IEXTEN = 0x400 + syscall_CSIZE = 0x300 + syscall_PARENB = 0x1000 + syscall_CS8 = 0x300 + syscall_VMIN = 0x10 + syscall_VTIME = 0x11 + + syscall_TCGETS = 0x402c7413 + syscall_TCSETS = 0x802c7414 +) diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_windows.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_windows.go new file mode 100644 index 0000000000..472d002a56 --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_windows.go @@ -0,0 +1,61 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs -- -DUNICODE syscalls.go + +package termbox + +const ( + foreground_blue = 0x1 + foreground_green = 0x2 + foreground_red = 0x4 + foreground_intensity = 0x8 + background_blue = 0x10 + background_green = 0x20 + background_red = 0x40 + background_intensity = 0x80 + std_input_handle = -0xa + std_output_handle = -0xb + key_event = 0x1 + mouse_event = 0x2 + window_buffer_size_event = 0x4 + enable_window_input = 0x8 + enable_mouse_input = 0x10 + enable_extended_flags = 0x80 + + vk_f1 = 0x70 + vk_f2 = 0x71 + vk_f3 = 0x72 + vk_f4 = 0x73 + vk_f5 = 0x74 + vk_f6 = 0x75 + vk_f7 = 0x76 + vk_f8 = 0x77 + vk_f9 = 0x78 + vk_f10 = 0x79 + vk_f11 = 0x7a + vk_f12 = 0x7b + vk_insert = 0x2d + vk_delete = 0x2e + vk_home = 0x24 + vk_end = 0x23 + vk_pgup = 0x21 + vk_pgdn = 0x22 + vk_arrow_up = 0x26 + vk_arrow_down = 0x28 + vk_arrow_left = 0x25 + vk_arrow_right = 0x27 + vk_backspace = 0x8 + vk_tab = 0x9 + vk_enter = 0xd + vk_esc = 0x1b + vk_space = 0x20 + + left_alt_pressed = 0x2 + left_ctrl_pressed = 0x8 + right_alt_pressed = 0x1 + right_ctrl_pressed = 0x4 + shift_pressed = 0x10 + + generic_read = 0x80000000 + generic_write = 0x40000000 + console_textmode_buffer = 0x1 +) diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go new file mode 100644 index 0000000000..0aee8aca90 --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go @@ -0,0 +1,407 @@ +// +build !windows + +package termbox + +import "unicode/utf8" +import "bytes" +import "syscall" +import "unsafe" +import "strings" +import "strconv" +import "os" +import "io" + +// private API + +const ( + t_enter_ca = iota + t_exit_ca + t_show_cursor + t_hide_cursor + t_clear_screen + t_sgr0 + t_underline + t_bold + t_blink + t_reverse + t_enter_keypad + t_exit_keypad + t_enter_mouse + t_exit_mouse + t_max_funcs +) + +const ( + coord_invalid = -2 + attr_invalid = Attribute(0xFFFF) +) + +type input_event struct { + data []byte + err error +} + +var ( + // term specific sequences + keys []string + funcs []string + + // termbox inner state + orig_tios syscall_Termios + back_buffer cellbuf + front_buffer cellbuf + termw int + termh int + input_mode = InputEsc + output_mode = OutputNormal + out *os.File + in int + lastfg = attr_invalid + lastbg = attr_invalid + lastx = coord_invalid + lasty = coord_invalid + cursor_x = cursor_hidden + cursor_y = cursor_hidden + foreground = ColorDefault + background = ColorDefault + inbuf = make([]byte, 0, 64) + outbuf bytes.Buffer + sigwinch = make(chan os.Signal, 1) + sigio = make(chan os.Signal, 1) + quit = make(chan int) + input_comm = make(chan input_event) + interrupt_comm = make(chan struct{}) + intbuf = make([]byte, 0, 16) +) + +func write_cursor(x, y int) { + outbuf.WriteString("\033[") + outbuf.Write(strconv.AppendUint(intbuf, uint64(y+1), 10)) + outbuf.WriteString(";") + outbuf.Write(strconv.AppendUint(intbuf, uint64(x+1), 10)) + outbuf.WriteString("H") +} + +func write_sgr_fg(a Attribute) { + switch output_mode { + case Output256, Output216, OutputGrayscale: + outbuf.WriteString("\033[38;5;") + outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10)) + outbuf.WriteString("m") + default: + outbuf.WriteString("\033[3") + outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10)) + outbuf.WriteString("m") + } +} + +func write_sgr_bg(a Attribute) { + switch output_mode { + case Output256, Output216, OutputGrayscale: + outbuf.WriteString("\033[48;5;") + outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10)) + outbuf.WriteString("m") + default: + outbuf.WriteString("\033[4") + outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10)) + outbuf.WriteString("m") + } +} + +func write_sgr(fg, bg Attribute) { + switch output_mode { + case Output256, Output216, OutputGrayscale: + outbuf.WriteString("\033[38;5;") + outbuf.Write(strconv.AppendUint(intbuf, uint64(fg-1), 10)) + outbuf.WriteString("m") + outbuf.WriteString("\033[48;5;") + outbuf.Write(strconv.AppendUint(intbuf, uint64(bg-1), 10)) + outbuf.WriteString("m") + default: + outbuf.WriteString("\033[3") + outbuf.Write(strconv.AppendUint(intbuf, uint64(fg-1), 10)) + outbuf.WriteString(";4") + outbuf.Write(strconv.AppendUint(intbuf, uint64(bg-1), 10)) + outbuf.WriteString("m") + } +} + +type winsize struct { + rows uint16 + cols uint16 + xpixels uint16 + ypixels uint16 +} + +func get_term_size(fd uintptr) (int, int) { + var sz winsize + _, _, _ = syscall.Syscall(syscall.SYS_IOCTL, + fd, uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&sz))) + return int(sz.cols), int(sz.rows) +} + +func send_attr(fg, bg Attribute) { + if fg == lastfg && bg == lastbg { + return + } + + outbuf.WriteString(funcs[t_sgr0]) + + var fgcol, bgcol Attribute + + switch output_mode { + case Output256: + fgcol = fg & 0x1FF + bgcol = bg & 0x1FF + case Output216: + fgcol = fg & 0xFF + bgcol = bg & 0xFF + if fgcol > 216 { + fgcol = ColorDefault + } + if bgcol > 216 { + bgcol = ColorDefault + } + if fgcol != ColorDefault { + fgcol += 0x10 + } + if bgcol != ColorDefault { + bgcol += 0x10 + } + case OutputGrayscale: + fgcol = fg & 0x1F + bgcol = bg & 0x1F + if fgcol > 24 { + fgcol = ColorDefault + } + if bgcol > 24 { + bgcol = ColorDefault + } + if fgcol != ColorDefault { + fgcol += 0xe8 + } + if bgcol != ColorDefault { + bgcol += 0xe8 + } + default: + fgcol = fg & 0x0F + bgcol = bg & 0x0F + } + + if fgcol != ColorDefault { + if bgcol != ColorDefault { + write_sgr(fgcol, bgcol) + } else { + write_sgr_fg(fgcol) + } + } else if bgcol != ColorDefault { + write_sgr_bg(bgcol) + } + + if fg&AttrBold != 0 { + outbuf.WriteString(funcs[t_bold]) + } + if bg&AttrBold != 0 { + outbuf.WriteString(funcs[t_blink]) + } + if fg&AttrUnderline != 0 { + outbuf.WriteString(funcs[t_underline]) + } + if fg&AttrReverse|bg&AttrReverse != 0 { + outbuf.WriteString(funcs[t_reverse]) + } + + lastfg, lastbg = fg, bg +} + +func send_char(x, y int, ch rune) { + var buf [8]byte + n := utf8.EncodeRune(buf[:], ch) + if x-1 != lastx || y != lasty { + write_cursor(x, y) + } + lastx, lasty = x, y + outbuf.Write(buf[:n]) +} + +func flush() error { + _, err := io.Copy(out, &outbuf) + outbuf.Reset() + if err != nil { + return err + } + return nil +} + +func send_clear() error { + send_attr(foreground, background) + outbuf.WriteString(funcs[t_clear_screen]) + if !is_cursor_hidden(cursor_x, cursor_y) { + write_cursor(cursor_x, cursor_y) + } + + // we need to invalidate cursor position too and these two vars are + // used only for simple cursor positioning optimization, cursor + // actually may be in the correct place, but we simply discard + // optimization once and it gives us simple solution for the case when + // cursor moved + lastx = coord_invalid + lasty = coord_invalid + + return flush() +} + +func update_size_maybe() error { + w, h := get_term_size(out.Fd()) + if w != termw || h != termh { + termw, termh = w, h + back_buffer.resize(termw, termh) + front_buffer.resize(termw, termh) + front_buffer.clear() + return send_clear() + } + return nil +} + +func tcsetattr(fd uintptr, termios *syscall_Termios) error { + r, _, e := syscall.Syscall(syscall.SYS_IOCTL, + fd, uintptr(syscall_TCSETS), uintptr(unsafe.Pointer(termios))) + if r != 0 { + return os.NewSyscallError("SYS_IOCTL", e) + } + return nil +} + +func tcgetattr(fd uintptr, termios *syscall_Termios) error { + r, _, e := syscall.Syscall(syscall.SYS_IOCTL, + fd, uintptr(syscall_TCGETS), uintptr(unsafe.Pointer(termios))) + if r != 0 { + return os.NewSyscallError("SYS_IOCTL", e) + } + return nil +} + +func parse_escape_sequence(event *Event, buf []byte) (int, bool) { + bufstr := string(buf) + // mouse + if len(bufstr) >= 6 && strings.HasPrefix(bufstr, "\033[M") { + switch buf[3] & 3 { + case 0: + event.Key = MouseLeft + case 1: + event.Key = MouseMiddle + case 2: + event.Key = MouseRight + case 3: + return 6, false + } + event.Type = EventMouse // KeyEvent by default + // wheel up outputs MouseLeft + if buf[3] == 0x60 || buf[3] == 0x70 { + event.Key = MouseMiddle + } + // the coord is 1,1 for upper left + event.MouseX = int(buf[4]) - 1 - 32 + event.MouseY = int(buf[5]) - 1 - 32 + return 6, true + } + + for i, key := range keys { + if strings.HasPrefix(bufstr, key) { + event.Ch = 0 + event.Key = Key(0xFFFF - i) + return len(key), true + } + } + return 0, true +} + +func extract_raw_event(data []byte, event *Event) bool { + if len(inbuf) == 0 { + return false + } + + n := len(data) + if n == 0 { + return false + } + + n = copy(data, inbuf) + copy(inbuf, inbuf[n:]) + inbuf = inbuf[:len(inbuf)-n] + + event.N = n + event.Type = EventRaw + return true +} + +func extract_event(inbuf []byte, event *Event) bool { + if len(inbuf) == 0 { + event.N = 0 + return false + } + + if inbuf[0] == '\033' { + // possible escape sequence + n, ok := parse_escape_sequence(event, inbuf) + if n != 0 { + event.N = n + return ok + } + + // it's not escape sequence, then it's Alt or Esc, check input_mode + switch { + case input_mode&InputEsc != 0: + // if we're in escape mode, fill Esc event, pop buffer, return success + event.Ch = 0 + event.Key = KeyEsc + event.Mod = 0 + event.N = 1 + return true + case input_mode&InputAlt != 0: + // if we're in alt mode, set Alt modifier to event and redo parsing + event.Mod = ModAlt + ok := extract_event(inbuf[1:], event) + if ok { + event.N++ + } else { + event.N = 0 + } + return ok + default: + panic("unreachable") + } + } + + // if we're here, this is not an escape sequence and not an alt sequence + // so, it's a FUNCTIONAL KEY or a UNICODE character + + // first of all check if it's a functional key + if Key(inbuf[0]) <= KeySpace || Key(inbuf[0]) == KeyBackspace2 { + // fill event, pop buffer, return success + event.Ch = 0 + event.Key = Key(inbuf[0]) + event.N = 1 + return true + } + + // the only possible option is utf8 rune + if r, n := utf8.DecodeRune(inbuf); r != utf8.RuneError { + event.Ch = r + event.Key = 0 + event.N = n + return true + } + + return false +} + +func fcntl(fd int, cmd int, arg int) (val int, err error) { + r, _, e := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), uintptr(cmd), + uintptr(arg)) + val = int(r) + if e != 0 { + err = e + } + return +} diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_common.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_common.go new file mode 100644 index 0000000000..c3355cc25e --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_common.go @@ -0,0 +1,59 @@ +package termbox + +// private API, common OS agnostic part + +type cellbuf struct { + width int + height int + cells []Cell +} + +func (this *cellbuf) init(width, height int) { + this.width = width + this.height = height + this.cells = make([]Cell, width*height) +} + +func (this *cellbuf) resize(width, height int) { + if this.width == width && this.height == height { + return + } + + oldw := this.width + oldh := this.height + oldcells := this.cells + + this.init(width, height) + this.clear() + + minw, minh := oldw, oldh + + if width < minw { + minw = width + } + if height < minh { + minh = height + } + + for i := 0; i < minh; i++ { + srco, dsto := i*oldw, i*width + src := oldcells[srco : srco+minw] + dst := this.cells[dsto : dsto+minw] + copy(dst, src) + } +} + +func (this *cellbuf) clear() { + for i := range this.cells { + c := &this.cells[i] + c.Ch = ' ' + c.Fg = foreground + c.Bg = background + } +} + +const cursor_hidden = -1 + +func is_cursor_hidden(x, y int) bool { + return x == cursor_hidden || y == cursor_hidden +} diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go new file mode 100644 index 0000000000..17d1bdc84b --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go @@ -0,0 +1,813 @@ +package termbox + +import "syscall" +import "unsafe" +import "unicode/utf16" +import "github.com/mattn/go-runewidth" + +type ( + wchar uint16 + short int16 + dword uint32 + word uint16 + char_info struct { + char wchar + attr word + } + coord struct { + x short + y short + } + small_rect struct { + left short + top short + right short + bottom short + } + console_screen_buffer_info struct { + size coord + cursor_position coord + attributes word + window small_rect + maximum_window_size coord + } + console_cursor_info struct { + size dword + visible int32 + } + input_record struct { + event_type word + _ [2]byte + event [16]byte + } + key_event_record struct { + key_down int32 + repeat_count word + virtual_key_code word + virtual_scan_code word + unicode_char wchar + control_key_state dword + } + window_buffer_size_record struct { + size coord + } + mouse_event_record struct { + mouse_pos coord + button_state dword + control_key_state dword + event_flags dword + } +) + +const ( + mouse_lmb = 0x1 + mouse_rmb = 0x2 + mouse_mmb = 0x4 | 0x8 | 0x10 +) + +func (this coord) uintptr() uintptr { + return uintptr(*(*int32)(unsafe.Pointer(&this))) +} + +var kernel32 = syscall.NewLazyDLL("kernel32.dll") +var is_cjk = runewidth.IsEastAsian() + +var ( + proc_set_console_active_screen_buffer = kernel32.NewProc("SetConsoleActiveScreenBuffer") + proc_set_console_screen_buffer_size = kernel32.NewProc("SetConsoleScreenBufferSize") + proc_create_console_screen_buffer = kernel32.NewProc("CreateConsoleScreenBuffer") + proc_get_console_screen_buffer_info = kernel32.NewProc("GetConsoleScreenBufferInfo") + proc_write_console_output = kernel32.NewProc("WriteConsoleOutputW") + proc_write_console_output_character = kernel32.NewProc("WriteConsoleOutputCharacterW") + proc_write_console_output_attribute = kernel32.NewProc("WriteConsoleOutputAttribute") + proc_set_console_cursor_info = kernel32.NewProc("SetConsoleCursorInfo") + proc_set_console_cursor_position = kernel32.NewProc("SetConsoleCursorPosition") + proc_get_console_cursor_info = kernel32.NewProc("GetConsoleCursorInfo") + proc_read_console_input = kernel32.NewProc("ReadConsoleInputW") + proc_get_console_mode = kernel32.NewProc("GetConsoleMode") + proc_set_console_mode = kernel32.NewProc("SetConsoleMode") + proc_fill_console_output_character = kernel32.NewProc("FillConsoleOutputCharacterW") + proc_fill_console_output_attribute = kernel32.NewProc("FillConsoleOutputAttribute") + proc_create_event = kernel32.NewProc("CreateEventW") + proc_wait_for_multiple_objects = kernel32.NewProc("WaitForMultipleObjects") + proc_set_event = kernel32.NewProc("SetEvent") +) + +func set_console_active_screen_buffer(h syscall.Handle) (err error) { + r0, _, e1 := syscall.Syscall(proc_set_console_active_screen_buffer.Addr(), + 1, uintptr(h), 0, 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func set_console_screen_buffer_size(h syscall.Handle, size coord) (err error) { + r0, _, e1 := syscall.Syscall(proc_set_console_screen_buffer_size.Addr(), + 2, uintptr(h), size.uintptr(), 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func create_console_screen_buffer() (h syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall6(proc_create_console_screen_buffer.Addr(), + 5, uintptr(generic_read|generic_write), 0, 0, console_textmode_buffer, 0, 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return syscall.Handle(r0), nil +} + +func get_console_screen_buffer_info(h syscall.Handle, info *console_screen_buffer_info) (err error) { + r0, _, e1 := syscall.Syscall(proc_get_console_screen_buffer_info.Addr(), + 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func write_console_output(h syscall.Handle, chars []char_info, dst small_rect) (err error) { + tmp_coord = coord{dst.right - dst.left + 1, dst.bottom - dst.top + 1} + tmp_rect = dst + r0, _, e1 := syscall.Syscall6(proc_write_console_output.Addr(), + 5, uintptr(h), uintptr(unsafe.Pointer(&chars[0])), tmp_coord.uintptr(), + tmp_coord0.uintptr(), uintptr(unsafe.Pointer(&tmp_rect)), 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func write_console_output_character(h syscall.Handle, chars []wchar, pos coord) (err error) { + r0, _, e1 := syscall.Syscall6(proc_write_console_output_character.Addr(), + 5, uintptr(h), uintptr(unsafe.Pointer(&chars[0])), uintptr(len(chars)), + pos.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func write_console_output_attribute(h syscall.Handle, attrs []word, pos coord) (err error) { + r0, _, e1 := syscall.Syscall6(proc_write_console_output_attribute.Addr(), + 5, uintptr(h), uintptr(unsafe.Pointer(&attrs[0])), uintptr(len(attrs)), + pos.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func set_console_cursor_info(h syscall.Handle, info *console_cursor_info) (err error) { + r0, _, e1 := syscall.Syscall(proc_set_console_cursor_info.Addr(), + 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func get_console_cursor_info(h syscall.Handle, info *console_cursor_info) (err error) { + r0, _, e1 := syscall.Syscall(proc_get_console_cursor_info.Addr(), + 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func set_console_cursor_position(h syscall.Handle, pos coord) (err error) { + r0, _, e1 := syscall.Syscall(proc_set_console_cursor_position.Addr(), + 2, uintptr(h), pos.uintptr(), 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func read_console_input(h syscall.Handle, record *input_record) (err error) { + r0, _, e1 := syscall.Syscall6(proc_read_console_input.Addr(), + 4, uintptr(h), uintptr(unsafe.Pointer(record)), 1, uintptr(unsafe.Pointer(&tmp_arg)), 0, 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func get_console_mode(h syscall.Handle, mode *dword) (err error) { + r0, _, e1 := syscall.Syscall(proc_get_console_mode.Addr(), + 2, uintptr(h), uintptr(unsafe.Pointer(mode)), 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func set_console_mode(h syscall.Handle, mode dword) (err error) { + r0, _, e1 := syscall.Syscall(proc_set_console_mode.Addr(), + 2, uintptr(h), uintptr(mode), 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func fill_console_output_character(h syscall.Handle, char wchar, n int) (err error) { + r0, _, e1 := syscall.Syscall6(proc_fill_console_output_character.Addr(), + 5, uintptr(h), uintptr(char), uintptr(n), tmp_coord.uintptr(), + uintptr(unsafe.Pointer(&tmp_arg)), 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func fill_console_output_attribute(h syscall.Handle, attr word, n int) (err error) { + r0, _, e1 := syscall.Syscall6(proc_fill_console_output_attribute.Addr(), + 5, uintptr(h), uintptr(attr), uintptr(n), tmp_coord.uintptr(), + uintptr(unsafe.Pointer(&tmp_arg)), 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func create_event() (out syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall6(proc_create_event.Addr(), + 4, 0, 0, 0, 0, 0, 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return syscall.Handle(r0), nil +} + +func wait_for_multiple_objects(objects []syscall.Handle) (err error) { + r0, _, e1 := syscall.Syscall6(proc_wait_for_multiple_objects.Addr(), + 4, uintptr(len(objects)), uintptr(unsafe.Pointer(&objects[0])), + 0, 0xFFFFFFFF, 0, 0) + if uint32(r0) == 0xFFFFFFFF { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func set_event(ev syscall.Handle) (err error) { + r0, _, e1 := syscall.Syscall(proc_set_event.Addr(), + 1, uintptr(ev), 0, 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +type diff_msg struct { + pos short + lines short + chars []char_info +} + +type input_event struct { + event Event + err error +} + +var ( + orig_cursor_info console_cursor_info + orig_size coord + orig_mode dword + orig_screen syscall.Handle + back_buffer cellbuf + front_buffer cellbuf + term_size coord + input_mode = InputEsc + cursor_x = cursor_hidden + cursor_y = cursor_hidden + foreground = ColorDefault + background = ColorDefault + in syscall.Handle + out syscall.Handle + interrupt syscall.Handle + charbuf []char_info + diffbuf []diff_msg + beg_x = -1 + beg_y = -1 + beg_i = -1 + input_comm = make(chan Event) + interrupt_comm = make(chan struct{}) + cancel_comm = make(chan bool, 1) + cancel_done_comm = make(chan bool) + alt_mode_esc = false + + // these ones just to prevent heap allocs at all costs + tmp_info console_screen_buffer_info + tmp_arg dword + tmp_coord0 = coord{0, 0} + tmp_coord = coord{0, 0} + tmp_rect = small_rect{0, 0, 0, 0} +) + +func get_cursor_position(out syscall.Handle) coord { + err := get_console_screen_buffer_info(out, &tmp_info) + if err != nil { + panic(err) + } + return tmp_info.cursor_position +} + +func get_term_size(out syscall.Handle) coord { + err := get_console_screen_buffer_info(out, &tmp_info) + if err != nil { + panic(err) + } + return tmp_info.size +} + +func get_win_size(out syscall.Handle) coord { + err := get_console_screen_buffer_info(out, &tmp_info) + if err != nil { + panic(err) + } + return coord{ + x: tmp_info.window.right - tmp_info.window.left + 1, + y: tmp_info.window.bottom - tmp_info.window.top + 1, + } +} + +func update_size_maybe() { + size := get_term_size(out) + if size.x != term_size.x || size.y != term_size.y { + term_size = size + back_buffer.resize(int(size.x), int(size.y)) + front_buffer.resize(int(size.x), int(size.y)) + front_buffer.clear() + clear() + + area := int(size.x) * int(size.y) + if cap(charbuf) < area { + charbuf = make([]char_info, 0, area) + } + } +} + +var color_table_bg = []word{ + 0, // default (black) + 0, // black + background_red, + background_green, + background_red | background_green, // yellow + background_blue, + background_red | background_blue, // magenta + background_green | background_blue, // cyan + background_red | background_blue | background_green, // white +} + +var color_table_fg = []word{ + foreground_red | foreground_blue | foreground_green, // default (white) + 0, + foreground_red, + foreground_green, + foreground_red | foreground_green, // yellow + foreground_blue, + foreground_red | foreground_blue, // magenta + foreground_green | foreground_blue, // cyan + foreground_red | foreground_blue | foreground_green, // white +} + +const ( + replacement_char = '\uFFFD' + max_rune = '\U0010FFFF' + surr1 = 0xd800 + surr2 = 0xdc00 + surr3 = 0xe000 + surr_self = 0x10000 +) + +func append_diff_line(y int) int { + n := 0 + for x := 0; x < front_buffer.width; { + cell_offset := y*front_buffer.width + x + back := &back_buffer.cells[cell_offset] + front := &front_buffer.cells[cell_offset] + attr, char := cell_to_char_info(*back) + charbuf = append(charbuf, char_info{attr: attr, char: char[0]}) + *front = *back + n++ + w := runewidth.RuneWidth(back.Ch) + if w == 0 || w == 2 && runewidth.IsAmbiguousWidth(back.Ch) { + w = 1 + } + x += w + // If not CJK, fill trailing space with whitespace + if !is_cjk && w == 2 { + charbuf = append(charbuf, char_info{attr: attr, char: ' '}) + } + } + return n +} + +// compares 'back_buffer' with 'front_buffer' and prepares all changes in the form of +// 'diff_msg's in the 'diff_buf' +func prepare_diff_messages() { + // clear buffers + diffbuf = diffbuf[:0] + charbuf = charbuf[:0] + + var diff diff_msg + gbeg := 0 + for y := 0; y < front_buffer.height; y++ { + same := true + line_offset := y * front_buffer.width + for x := 0; x < front_buffer.width; x++ { + cell_offset := line_offset + x + back := &back_buffer.cells[cell_offset] + front := &front_buffer.cells[cell_offset] + if *back != *front { + same = false + break + } + } + if same && diff.lines > 0 { + diffbuf = append(diffbuf, diff) + diff = diff_msg{} + } + if !same { + beg := len(charbuf) + end := beg + append_diff_line(y) + if diff.lines == 0 { + diff.pos = short(y) + gbeg = beg + } + diff.lines++ + diff.chars = charbuf[gbeg:end] + } + } + if diff.lines > 0 { + diffbuf = append(diffbuf, diff) + diff = diff_msg{} + } +} + +func cell_to_char_info(c Cell) (attr word, wc [2]wchar) { + attr = color_table_fg[c.Fg&0x0F] | color_table_bg[c.Bg&0x0F] + if c.Fg&AttrReverse|c.Bg&AttrReverse != 0 { + attr = (attr&0xF0)>>4 | (attr&0x0F)<<4 + } + if c.Fg&AttrBold != 0 { + attr |= foreground_intensity + } + if c.Bg&AttrBold != 0 { + attr |= background_intensity + } + + r0, r1 := utf16.EncodeRune(c.Ch) + if r0 == 0xFFFD { + wc[0] = wchar(c.Ch) + wc[1] = ' ' + } else { + wc[0] = wchar(r0) + wc[1] = wchar(r1) + } + return +} + +func move_cursor(x, y int) { + err := set_console_cursor_position(out, coord{short(x), short(y)}) + if err != nil { + panic(err) + } +} + +func show_cursor(visible bool) { + var v int32 + if visible { + v = 1 + } + + var info console_cursor_info + info.size = 100 + info.visible = v + err := set_console_cursor_info(out, &info) + if err != nil { + panic(err) + } +} + +func clear() { + var err error + attr, char := cell_to_char_info(Cell{ + ' ', + foreground, + background, + }) + + area := int(term_size.x) * int(term_size.y) + err = fill_console_output_attribute(out, attr, area) + if err != nil { + panic(err) + } + err = fill_console_output_character(out, char[0], area) + if err != nil { + panic(err) + } + if !is_cursor_hidden(cursor_x, cursor_y) { + move_cursor(cursor_x, cursor_y) + } +} + +func key_event_record_to_event(r *key_event_record) (Event, bool) { + if r.key_down == 0 { + return Event{}, false + } + + e := Event{Type: EventKey} + if input_mode&InputAlt != 0 { + if alt_mode_esc { + e.Mod = ModAlt + alt_mode_esc = false + } + if r.control_key_state&(left_alt_pressed|right_alt_pressed) != 0 { + e.Mod = ModAlt + } + } + + ctrlpressed := r.control_key_state&(left_ctrl_pressed|right_ctrl_pressed) != 0 + + if r.virtual_key_code >= vk_f1 && r.virtual_key_code <= vk_f12 { + switch r.virtual_key_code { + case vk_f1: + e.Key = KeyF1 + case vk_f2: + e.Key = KeyF2 + case vk_f3: + e.Key = KeyF3 + case vk_f4: + e.Key = KeyF4 + case vk_f5: + e.Key = KeyF5 + case vk_f6: + e.Key = KeyF6 + case vk_f7: + e.Key = KeyF7 + case vk_f8: + e.Key = KeyF8 + case vk_f9: + e.Key = KeyF9 + case vk_f10: + e.Key = KeyF10 + case vk_f11: + e.Key = KeyF11 + case vk_f12: + e.Key = KeyF12 + default: + panic("unreachable") + } + + return e, true + } + + if r.virtual_key_code <= vk_delete { + switch r.virtual_key_code { + case vk_insert: + e.Key = KeyInsert + case vk_delete: + e.Key = KeyDelete + case vk_home: + e.Key = KeyHome + case vk_end: + e.Key = KeyEnd + case vk_pgup: + e.Key = KeyPgup + case vk_pgdn: + e.Key = KeyPgdn + case vk_arrow_up: + e.Key = KeyArrowUp + case vk_arrow_down: + e.Key = KeyArrowDown + case vk_arrow_left: + e.Key = KeyArrowLeft + case vk_arrow_right: + e.Key = KeyArrowRight + case vk_backspace: + if ctrlpressed { + e.Key = KeyBackspace2 + } else { + e.Key = KeyBackspace + } + case vk_tab: + e.Key = KeyTab + case vk_enter: + e.Key = KeyEnter + case vk_esc: + switch { + case input_mode&InputEsc != 0: + e.Key = KeyEsc + case input_mode&InputAlt != 0: + alt_mode_esc = true + return Event{}, false + } + case vk_space: + if ctrlpressed { + // manual return here, because KeyCtrlSpace is zero + e.Key = KeyCtrlSpace + return e, true + } else { + e.Key = KeySpace + } + } + + if e.Key != 0 { + return e, true + } + } + + if ctrlpressed { + if Key(r.unicode_char) >= KeyCtrlA && Key(r.unicode_char) <= KeyCtrlRsqBracket { + e.Key = Key(r.unicode_char) + if input_mode&InputAlt != 0 && e.Key == KeyEsc { + alt_mode_esc = true + return Event{}, false + } + return e, true + } + switch r.virtual_key_code { + case 192, 50: + // manual return here, because KeyCtrl2 is zero + e.Key = KeyCtrl2 + return e, true + case 51: + if input_mode&InputAlt != 0 { + alt_mode_esc = true + return Event{}, false + } + e.Key = KeyCtrl3 + case 52: + e.Key = KeyCtrl4 + case 53: + e.Key = KeyCtrl5 + case 54: + e.Key = KeyCtrl6 + case 189, 191, 55: + e.Key = KeyCtrl7 + case 8, 56: + e.Key = KeyCtrl8 + } + + if e.Key != 0 { + return e, true + } + } + + if r.unicode_char != 0 { + e.Ch = rune(r.unicode_char) + return e, true + } + + return Event{}, false +} + +func input_event_producer() { + var r input_record + var err error + var last_button Key + var last_state = dword(0) + handles := []syscall.Handle{in, interrupt} + for { + err = wait_for_multiple_objects(handles) + if err != nil { + input_comm <- Event{Type: EventError, Err: err} + } + + select { + case <-cancel_comm: + cancel_done_comm <- true + return + default: + } + + err = read_console_input(in, &r) + if err != nil { + input_comm <- Event{Type: EventError, Err: err} + } + + switch r.event_type { + case key_event: + kr := (*key_event_record)(unsafe.Pointer(&r.event)) + ev, ok := key_event_record_to_event(kr) + if ok { + for i := 0; i < int(kr.repeat_count); i++ { + input_comm <- ev + } + } + case window_buffer_size_event: + sr := *(*window_buffer_size_record)(unsafe.Pointer(&r.event)) + input_comm <- Event{ + Type: EventResize, + Width: int(sr.size.x), + Height: int(sr.size.y), + } + case mouse_event: + mr := *(*mouse_event_record)(unsafe.Pointer(&r.event)) + + // single or double click + switch mr.event_flags { + case 0: + cur_state := mr.button_state + switch { + case last_state&mouse_lmb == 0 && cur_state&mouse_lmb != 0: + last_button = MouseLeft + case last_state&mouse_rmb == 0 && cur_state&mouse_rmb != 0: + last_button = MouseRight + case last_state&mouse_mmb == 0 && cur_state&mouse_mmb != 0: + last_button = MouseMiddle + default: + last_state = cur_state + continue + } + last_state = cur_state + fallthrough + case 2: + input_comm <- Event{ + Type: EventMouse, + Key: last_button, + MouseX: int(mr.mouse_pos.x), + MouseY: int(mr.mouse_pos.y), + } + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo.go new file mode 100644 index 0000000000..3569e3c0e4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo.go @@ -0,0 +1,219 @@ +// +build !windows +// This file contains a simple and incomplete implementation of the terminfo +// database. Information was taken from the ncurses manpages term(5) and +// terminfo(5). Currently, only the string capabilities for special keys and for +// functions without parameters are actually used. Colors are still done with +// ANSI escape sequences. Other special features that are not (yet?) supported +// are reading from ~/.terminfo, the TERMINFO_DIRS variable, Berkeley database +// format and extended capabilities. + +package termbox + +import ( + "bytes" + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "io/ioutil" + "os" + "strings" +) + +const ( + ti_magic = 0432 + ti_header_length = 12 +) + +func load_terminfo() ([]byte, error) { + var data []byte + var err error + + term := os.Getenv("TERM") + if term == "" { + return nil, fmt.Errorf("termbox: TERM not set") + } + + // The following behaviour follows the one described in terminfo(5) as + // distributed by ncurses. + + terminfo := os.Getenv("TERMINFO") + if terminfo != "" { + // if TERMINFO is set, no other directory should be searched + return ti_try_path(terminfo) + } + + // next, consider ~/.terminfo + home := os.Getenv("HOME") + if home != "" { + data, err = ti_try_path(home + "/.terminfo") + if err == nil { + return data, nil + } + } + + // next, TERMINFO_DIRS + dirs := os.Getenv("TERMINFO_DIRS") + if dirs != "" { + for _, dir := range strings.Split(dirs, ":") { + if dir == "" { + // "" -> "/usr/share/terminfo" + dir = "/usr/share/terminfo" + } + data, err = ti_try_path(dir) + if err == nil { + return data, nil + } + } + } + + // fall back to /usr/share/terminfo + return ti_try_path("/usr/share/terminfo") +} + +func ti_try_path(path string) (data []byte, err error) { + // load_terminfo already made sure it is set + term := os.Getenv("TERM") + + // first try, the typical *nix path + terminfo := path + "/" + term[0:1] + "/" + term + data, err = ioutil.ReadFile(terminfo) + if err == nil { + return + } + + // fallback to darwin specific dirs structure + terminfo = path + "/" + hex.EncodeToString([]byte(term[:1])) + "/" + term + data, err = ioutil.ReadFile(terminfo) + return +} + +func setup_term_builtin() error { + name := os.Getenv("TERM") + if name == "" { + return errors.New("termbox: TERM environment variable not set") + } + + for _, t := range terms { + if t.name == name { + keys = t.keys + funcs = t.funcs + return nil + } + } + + compat_table := []struct { + partial string + keys []string + funcs []string + }{ + {"xterm", xterm_keys, xterm_funcs}, + {"rxvt", rxvt_unicode_keys, rxvt_unicode_funcs}, + {"linux", linux_keys, linux_funcs}, + {"Eterm", eterm_keys, eterm_funcs}, + {"screen", screen_keys, screen_funcs}, + // let's assume that 'cygwin' is xterm compatible + {"cygwin", xterm_keys, xterm_funcs}, + {"st", xterm_keys, xterm_funcs}, + } + + // try compatibility variants + for _, it := range compat_table { + if strings.Contains(name, it.partial) { + keys = it.keys + funcs = it.funcs + return nil + } + } + + return errors.New("termbox: unsupported terminal") +} + +func setup_term() (err error) { + var data []byte + var header [6]int16 + var str_offset, table_offset int16 + + data, err = load_terminfo() + if err != nil { + return setup_term_builtin() + } + + rd := bytes.NewReader(data) + // 0: magic number, 1: size of names section, 2: size of boolean section, 3: + // size of numbers section (in integers), 4: size of the strings section (in + // integers), 5: size of the string table + + err = binary.Read(rd, binary.LittleEndian, header[:]) + if err != nil { + return + } + + if (header[1]+header[2])%2 != 0 { + // old quirk to align everything on word boundaries + header[2] += 1 + } + str_offset = ti_header_length + header[1] + header[2] + 2*header[3] + table_offset = str_offset + 2*header[4] + + keys = make([]string, 0xFFFF-key_min) + for i, _ := range keys { + keys[i], err = ti_read_string(rd, str_offset+2*ti_keys[i], table_offset) + if err != nil { + return + } + } + funcs = make([]string, t_max_funcs) + // the last two entries are reserved for mouse. because the table offset is + // not there, the two entries have to fill in manually + for i, _ := range funcs[:len(funcs)-2] { + funcs[i], err = ti_read_string(rd, str_offset+2*ti_funcs[i], table_offset) + if err != nil { + return + } + } + funcs[t_max_funcs-2] = "\x1b[?1000h" + funcs[t_max_funcs-1] = "\x1b[?1000l" + return nil +} + +func ti_read_string(rd *bytes.Reader, str_off, table int16) (string, error) { + var off int16 + + _, err := rd.Seek(int64(str_off), 0) + if err != nil { + return "", err + } + err = binary.Read(rd, binary.LittleEndian, &off) + if err != nil { + return "", err + } + _, err = rd.Seek(int64(table+off), 0) + if err != nil { + return "", err + } + var bs []byte + for { + b, err := rd.ReadByte() + if err != nil { + return "", err + } + if b == byte(0x00) { + break + } + bs = append(bs, b) + } + return string(bs), nil +} + +// "Maps" the function constants from termbox.go to the number of the respective +// string capability in the terminfo file. Taken from (ncurses) term.h. +var ti_funcs = []int16{ + 28, 40, 16, 13, 5, 39, 36, 27, 26, 34, 89, 88, +} + +// Same as above for the special keys. +var ti_keys = []int16{ + 66, 68 /* apparently not a typo; 67 is F10 for whatever reason */, 69, 70, + 71, 72, 73, 74, 75, 67, 216, 217, 77, 59, 76, 164, 82, 81, 87, 61, 79, 83, +} diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo_builtin.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo_builtin.go new file mode 100644 index 0000000000..6f927c852f --- /dev/null +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo_builtin.go @@ -0,0 +1,64 @@ +// +build !windows + +package termbox + +// Eterm +var eterm_keys = []string{ + "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C", +} +var eterm_funcs = []string{ + "\x1b7\x1b[?47h", "\x1b[2J\x1b[?47l\x1b8", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "", "", "", "", +} + +// screen +var screen_keys = []string{ + "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC", +} +var screen_funcs = []string{ + "\x1b[?1049h", "\x1b[?1049l", "\x1b[34h\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b[?1h\x1b=", "\x1b[?1l\x1b>", "\x1b[?1000h", "\x1b[?1000l", +} + +// xterm +var xterm_keys = []string{ + "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1bOH", "\x1bOF", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC", +} +var xterm_funcs = []string{ + "\x1b[?1049h", "\x1b[?1049l", "\x1b[?12l\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b(B\x1b[m", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b[?1h\x1b=", "\x1b[?1l\x1b>", "\x1b[?1000h", "\x1b[?1000l", +} + +// rxvt-unicode +var rxvt_unicode_keys = []string{ + "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C", +} +var rxvt_unicode_funcs = []string{ + "\x1b[?1049h", "\x1b[r\x1b[?1049l", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x1b(B", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b=", "\x1b>", "\x1b[?1000h", "\x1b[?1000l", +} + +// linux +var linux_keys = []string{ + "\x1b[[A", "\x1b[[B", "\x1b[[C", "\x1b[[D", "\x1b[[E", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C", +} +var linux_funcs = []string{ + "", "", "\x1b[?25h\x1b[?0c", "\x1b[?25l\x1b[?1c", "\x1b[H\x1b[J", "\x1b[0;10m", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "", "", "", "", +} + +// rxvt-256color +var rxvt_256color_keys = []string{ + "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C", +} +var rxvt_256color_funcs = []string{ + "\x1b7\x1b[?47h", "\x1b[2J\x1b[?47l\x1b8", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b=", "\x1b>", "\x1b[?1000h", "\x1b[?1000l", +} + +var terms = []struct { + name string + keys []string + funcs []string +}{ + {"Eterm", eterm_keys, eterm_funcs}, + {"screen", screen_keys, screen_funcs}, + {"xterm", xterm_keys, xterm_funcs}, + {"rxvt-unicode", rxvt_unicode_keys, rxvt_unicode_funcs}, + {"linux", linux_keys, linux_funcs}, + {"rxvt-256color", rxvt_256color_keys, rxvt_256color_funcs}, +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/COPYING b/Godeps/_workspace/src/github.com/peterh/liner/COPYING new file mode 100644 index 0000000000..9e8c9f2066 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/COPYING @@ -0,0 +1,21 @@ +Copyright © 2012 Peter Harris + +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 (including the next +paragraph) 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/Godeps/_workspace/src/github.com/peterh/liner/README.md b/Godeps/_workspace/src/github.com/peterh/liner/README.md new file mode 100644 index 0000000000..99027c6e2d --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/README.md @@ -0,0 +1,95 @@ +Liner +===== + +Liner is a command line editor with history. It was inspired by linenoise; +everything Unix-like is a VT100 (or is trying very hard to be). If your +terminal is not pretending to be a VT100, change it. Liner also support +Windows. + +Liner is released under the X11 license (which is similar to the new BSD +license). + +Line Editing +------------ + +The following line editing commands are supported on platforms and terminals +that Liner supports: + +Keystroke | Action +--------- | ------ +Ctrl-A, Home | Move cursor to beginning of line +Ctrl-E, End | Move cursor to end of line +Ctrl-B, Left | Move cursor one character left +Ctrl-F, Right| Move cursor one character right +Ctrl-Left | Move cursor to previous word +Ctrl-Right | Move cursor to next word +Ctrl-D, Del | (if line is *not* empty) Delete character under cursor +Ctrl-D | (if line *is* empty) End of File - usually quits application +Ctrl-C | Reset input (create new empty prompt) +Ctrl-L | Clear screen (line is unmodified) +Ctrl-T | Transpose previous character with current character +Ctrl-H, BackSpace | Delete character before cursor +Ctrl-W | Delete word leading up to cursor +Ctrl-K | Delete from cursor to end of line +Ctrl-U | Delete from start of line to cursor +Ctrl-P, Up | Previous match from history +Ctrl-N, Down | Next match from history +Ctrl-R | Reverse Search history (Ctrl-S forward, Ctrl-G cancel) +Ctrl-Y | Paste from Yank buffer (Alt-Y to paste next yank instead) +Tab | Next completion +Shift-Tab | (after Tab) Previous completion + +Getting started +----------------- + +```go +package main + +import ( + "log" + "os" + "strings" + + "github.com/peterh/liner" +) + +var ( + history_fn = "/tmp/.liner_history" + names = []string{"john", "james", "mary", "nancy"} +) + +func main() { + line := liner.NewLiner() + defer line.Close() + + line.SetCompleter(func(line string) (c []string) { + for _, n := range names { + if strings.HasPrefix(n, strings.ToLower(line)) { + c = append(c, n) + } + } + return + }) + + if f, err := os.Open(history_fn); err == nil { + line.ReadHistory(f) + f.Close() + } + + if name, err := line.Prompt("What is your name? "); err != nil { + log.Print("Error reading line: ", err) + } else { + log.Print("Got: ", name) + line.AppendHistory(name) + } + + if f, err := os.Create(history_fn); err != nil { + log.Print("Error writing history file: ", err) + } else { + line.WriteHistory(f) + f.Close() + } +} +``` + +For documentation, see http://godoc.org/github.com/peterh/liner diff --git a/Godeps/_workspace/src/github.com/peterh/liner/bsdinput.go b/Godeps/_workspace/src/github.com/peterh/liner/bsdinput.go new file mode 100644 index 0000000000..4b552d44d9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/bsdinput.go @@ -0,0 +1,39 @@ +// +build openbsd freebsd netbsd + +package liner + +import "syscall" + +const ( + getTermios = syscall.TIOCGETA + setTermios = syscall.TIOCSETA +) + +const ( + // Input flags + inpck = 0x010 + istrip = 0x020 + icrnl = 0x100 + ixon = 0x200 + + // Output flags + opost = 0x1 + + // Control flags + cs8 = 0x300 + + // Local flags + isig = 0x080 + icanon = 0x100 + iexten = 0x400 +) + +type termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [20]byte + Ispeed int32 + Ospeed int32 +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/common.go b/Godeps/_workspace/src/github.com/peterh/liner/common.go new file mode 100644 index 0000000000..f8753a1951 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/common.go @@ -0,0 +1,219 @@ +/* +Package liner implements a simple command line editor, inspired by linenoise +(https://github.com/antirez/linenoise/). This package supports WIN32 in +addition to the xterm codes supported by everything else. +*/ +package liner + +import ( + "bufio" + "bytes" + "container/ring" + "errors" + "fmt" + "io" + "strings" + "sync" + "unicode/utf8" +) + +type commonState struct { + terminalSupported bool + outputRedirected bool + inputRedirected bool + history []string + historyMutex sync.RWMutex + completer WordCompleter + columns int + killRing *ring.Ring + ctrlCAborts bool + r *bufio.Reader + tabStyle TabStyle +} + +// TabStyle is used to select how tab completions are displayed. +type TabStyle int + +// Two tab styles are currently available: +// +// TabCircular cycles through each completion item and displays it directly on +// the prompt +// +// TabPrints prints the list of completion items to the screen after a second +// tab key is pressed. This behaves similar to GNU readline and BASH (which +// uses readline) +const ( + TabCircular TabStyle = iota + TabPrints +) + +// ErrPromptAborted is returned from Prompt or PasswordPrompt when the user presses Ctrl-C +// if SetCtrlCAborts(true) has been called on the State +var ErrPromptAborted = errors.New("prompt aborted") + +// ErrNotTerminalOutput is returned from Prompt or PasswordPrompt if the +// platform is normally supported, but stdout has been redirected +var ErrNotTerminalOutput = errors.New("standard output is not a terminal") + +// Max elements to save on the killring +const KillRingMax = 60 + +// HistoryLimit is the maximum number of entries saved in the scrollback history. +const HistoryLimit = 1000 + +// ReadHistory reads scrollback history from r. Returns the number of lines +// read, and any read error (except io.EOF). +func (s *State) ReadHistory(r io.Reader) (num int, err error) { + s.historyMutex.Lock() + defer s.historyMutex.Unlock() + + in := bufio.NewReader(r) + num = 0 + for { + line, part, err := in.ReadLine() + if err == io.EOF { + break + } + if err != nil { + return num, err + } + if part { + return num, fmt.Errorf("line %d is too long", num+1) + } + if !utf8.Valid(line) { + return num, fmt.Errorf("invalid string at line %d", num+1) + } + num++ + s.history = append(s.history, string(line)) + if len(s.history) > HistoryLimit { + s.history = s.history[1:] + } + } + return num, nil +} + +// WriteHistory writes scrollback history to w. Returns the number of lines +// successfully written, and any write error. +// +// Unlike the rest of liner's API, WriteHistory is safe to call +// from another goroutine while Prompt is in progress. +// This exception is to facilitate the saving of the history buffer +// during an unexpected exit (for example, due to Ctrl-C being invoked) +func (s *State) WriteHistory(w io.Writer) (num int, err error) { + s.historyMutex.RLock() + defer s.historyMutex.RUnlock() + + for _, item := range s.history { + _, err := fmt.Fprintln(w, item) + if err != nil { + return num, err + } + num++ + } + return num, nil +} + +// AppendHistory appends an entry to the scrollback history. AppendHistory +// should be called iff Prompt returns a valid command. +func (s *State) AppendHistory(item string) { + s.historyMutex.Lock() + defer s.historyMutex.Unlock() + + if len(s.history) > 0 { + if item == s.history[len(s.history)-1] { + return + } + } + s.history = append(s.history, item) + if len(s.history) > HistoryLimit { + s.history = s.history[1:] + } +} + +// Returns the history lines starting with prefix +func (s *State) getHistoryByPrefix(prefix string) (ph []string) { + for _, h := range s.history { + if strings.HasPrefix(h, prefix) { + ph = append(ph, h) + } + } + return +} + +// Returns the history lines matching the inteligent search +func (s *State) getHistoryByPattern(pattern string) (ph []string, pos []int) { + if pattern == "" { + return + } + for _, h := range s.history { + if i := strings.Index(h, pattern); i >= 0 { + ph = append(ph, h) + pos = append(pos, i) + } + } + return +} + +// Completer takes the currently edited line content at the left of the cursor +// and returns a list of completion candidates. +// If the line is "Hello, wo!!!" and the cursor is before the first '!', "Hello, wo" is passed +// to the completer which may return {"Hello, world", "Hello, Word"} to have "Hello, world!!!". +type Completer func(line string) []string + +// WordCompleter takes the currently edited line with the cursor position and +// returns the completion candidates for the partial word to be completed. +// If the line is "Hello, wo!!!" and the cursor is before the first '!', ("Hello, wo!!!", 9) is passed +// to the completer which may returns ("Hello, ", {"world", "Word"}, "!!!") to have "Hello, world!!!". +type WordCompleter func(line string, pos int) (head string, completions []string, tail string) + +// SetCompleter sets the completion function that Liner will call to +// fetch completion candidates when the user presses tab. +func (s *State) SetCompleter(f Completer) { + if f == nil { + s.completer = nil + return + } + s.completer = func(line string, pos int) (string, []string, string) { + return "", f(line[:pos]), line[pos:] + } +} + +// SetWordCompleter sets the completion function that Liner will call to +// fetch completion candidates when the user presses tab. +func (s *State) SetWordCompleter(f WordCompleter) { + s.completer = f +} + +// SetTabCompletionStyle sets the behvavior when the Tab key is pressed +// for auto-completion. TabCircular is the default behavior and cycles +// through the list of candidates at the prompt. TabPrints will print +// the available completion candidates to the screen similar to BASH +// and GNU Readline +func (s *State) SetTabCompletionStyle(tabStyle TabStyle) { + s.tabStyle = tabStyle +} + +// ModeApplier is the interface that wraps a representation of the terminal +// mode. ApplyMode sets the terminal to this mode. +type ModeApplier interface { + ApplyMode() error +} + +// SetCtrlCAborts sets whether Prompt on a supported terminal will return an +// ErrPromptAborted when Ctrl-C is pressed. The default is false (will not +// return when Ctrl-C is pressed). Unsupported terminals typically raise SIGINT +// (and Prompt does not return) regardless of the value passed to SetCtrlCAborts. +func (s *State) SetCtrlCAborts(aborts bool) { + s.ctrlCAborts = aborts +} + +func (s *State) promptUnsupported(p string) (string, error) { + if !s.inputRedirected { + fmt.Print(p) + } + linebuf, _, err := s.r.ReadLine() + if err != nil { + return "", err + } + return string(bytes.TrimSpace(linebuf)), nil +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/fallbackinput.go b/Godeps/_workspace/src/github.com/peterh/liner/fallbackinput.go new file mode 100644 index 0000000000..d9eb79d9e0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/fallbackinput.go @@ -0,0 +1,57 @@ +// +build !windows,!linux,!darwin,!openbsd,!freebsd,!netbsd + +package liner + +import ( + "bufio" + "errors" + "os" +) + +// State represents an open terminal +type State struct { + commonState +} + +// Prompt displays p, and then waits for user input. Prompt does not support +// line editing on this operating system. +func (s *State) Prompt(p string) (string, error) { + return s.promptUnsupported(p) +} + +// PasswordPrompt is not supported in this OS. +func (s *State) PasswordPrompt(p string) (string, error) { + return "", errors.New("liner: function not supported in this terminal") +} + +// NewLiner initializes a new *State +// +// Note that this operating system uses a fallback mode without line +// editing. Patches welcome. +func NewLiner() *State { + var s State + s.r = bufio.NewReader(os.Stdin) + return &s +} + +// Close returns the terminal to its previous mode +func (s *State) Close() error { + return nil +} + +// TerminalSupported returns false because line editing is not +// supported on this platform. +func TerminalSupported() bool { + return false +} + +type noopMode struct{} + +func (n noopMode) ApplyMode() error { + return nil +} + +// TerminalMode returns a noop InputModeSetter on this platform. +func TerminalMode() (ModeApplier, error) { + return noopMode{}, nil +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/input.go b/Godeps/_workspace/src/github.com/peterh/liner/input.go new file mode 100644 index 0000000000..cf71d2bce1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/input.go @@ -0,0 +1,359 @@ +// +build linux darwin openbsd freebsd netbsd + +package liner + +import ( + "bufio" + "errors" + "os" + "os/signal" + "strconv" + "strings" + "syscall" + "time" +) + +type nexter struct { + r rune + err error +} + +// State represents an open terminal +type State struct { + commonState + origMode termios + defaultMode termios + next <-chan nexter + winch chan os.Signal + pending []rune + useCHA bool +} + +// NewLiner initializes a new *State, and sets the terminal into raw mode. To +// restore the terminal to its previous state, call State.Close(). +// +// Note if you are still using Go 1.0: NewLiner handles SIGWINCH, so it will +// leak a channel every time you call it. Therefore, it is recommened that you +// upgrade to a newer release of Go, or ensure that NewLiner is only called +// once. +func NewLiner() *State { + var s State + s.r = bufio.NewReader(os.Stdin) + + s.terminalSupported = TerminalSupported() + if m, err := TerminalMode(); err == nil { + s.origMode = *m.(*termios) + } else { + s.terminalSupported = false + s.inputRedirected = true + } + if _, err := getMode(syscall.Stdout); err != 0 { + s.terminalSupported = false + s.outputRedirected = true + } + if s.terminalSupported { + mode := s.origMode + mode.Iflag &^= icrnl | inpck | istrip | ixon + mode.Cflag |= cs8 + mode.Lflag &^= syscall.ECHO | icanon | iexten + mode.ApplyMode() + + winch := make(chan os.Signal, 1) + signal.Notify(winch, syscall.SIGWINCH) + s.winch = winch + + s.checkOutput() + } + + if !s.outputRedirected { + s.getColumns() + s.outputRedirected = s.columns <= 0 + } + + return &s +} + +var errTimedOut = errors.New("timeout") + +func (s *State) startPrompt() { + if s.terminalSupported { + if m, err := TerminalMode(); err == nil { + s.defaultMode = *m.(*termios) + mode := s.defaultMode + mode.Lflag &^= isig + mode.ApplyMode() + } + } + s.restartPrompt() +} + +func (s *State) restartPrompt() { + next := make(chan nexter) + go func() { + for { + var n nexter + n.r, _, n.err = s.r.ReadRune() + next <- n + // Shut down nexter loop when an end condition has been reached + if n.err != nil || n.r == '\n' || n.r == '\r' || n.r == ctrlC || n.r == ctrlD { + close(next) + return + } + } + }() + s.next = next +} + +func (s *State) stopPrompt() { + if s.terminalSupported { + s.defaultMode.ApplyMode() + } +} + +func (s *State) nextPending(timeout <-chan time.Time) (rune, error) { + select { + case thing, ok := <-s.next: + if !ok { + return 0, errors.New("liner: internal error") + } + if thing.err != nil { + return 0, thing.err + } + s.pending = append(s.pending, thing.r) + return thing.r, nil + case <-timeout: + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, errTimedOut + } + // not reached + return 0, nil +} + +func (s *State) readNext() (interface{}, error) { + if len(s.pending) > 0 { + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + var r rune + select { + case thing, ok := <-s.next: + if !ok { + return 0, errors.New("liner: internal error") + } + if thing.err != nil { + return nil, thing.err + } + r = thing.r + case <-s.winch: + s.getColumns() + return winch, nil + } + if r != esc { + return r, nil + } + s.pending = append(s.pending, r) + + // Wait at most 50 ms for the rest of the escape sequence + // If nothing else arrives, it was an actual press of the esc key + timeout := time.After(50 * time.Millisecond) + flag, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return flag, nil + } + return unknown, err + } + + switch flag { + case '[': + code, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return code, nil + } + return unknown, err + } + switch code { + case 'A': + s.pending = s.pending[:0] // escape code complete + return up, nil + case 'B': + s.pending = s.pending[:0] // escape code complete + return down, nil + case 'C': + s.pending = s.pending[:0] // escape code complete + return right, nil + case 'D': + s.pending = s.pending[:0] // escape code complete + return left, nil + case 'F': + s.pending = s.pending[:0] // escape code complete + return end, nil + case 'H': + s.pending = s.pending[:0] // escape code complete + return home, nil + case 'Z': + s.pending = s.pending[:0] // escape code complete + return shiftTab, nil + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + num := []rune{code} + for { + code, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return code, nil + } + return nil, err + } + switch code { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + num = append(num, code) + case ';': + // Modifier code to follow + // This only supports Ctrl-left and Ctrl-right for now + x, _ := strconv.ParseInt(string(num), 10, 32) + if x != 1 { + // Can't be left or right + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + num = num[:0] + for { + code, err = s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + return nil, err + } + switch code { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + num = append(num, code) + case 'C', 'D': + // right, left + mod, _ := strconv.ParseInt(string(num), 10, 32) + if mod != 5 { + // Not bare Ctrl + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + s.pending = s.pending[:0] // escape code complete + if code == 'C' { + return wordRight, nil + } + return wordLeft, nil + default: + // Not left or right + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + } + case '~': + s.pending = s.pending[:0] // escape code complete + x, _ := strconv.ParseInt(string(num), 10, 32) + switch x { + case 2: + return insert, nil + case 3: + return del, nil + case 5: + return pageUp, nil + case 6: + return pageDown, nil + case 7: + return home, nil + case 8: + return end, nil + case 15: + return f5, nil + case 17: + return f6, nil + case 18: + return f7, nil + case 19: + return f8, nil + case 20: + return f9, nil + case 21: + return f10, nil + case 23: + return f11, nil + case 24: + return f12, nil + default: + return unknown, nil + } + default: + // unrecognized escape code + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + } + } + + case 'O': + code, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return code, nil + } + return nil, err + } + s.pending = s.pending[:0] // escape code complete + switch code { + case 'c': + return wordRight, nil + case 'd': + return wordLeft, nil + case 'H': + return home, nil + case 'F': + return end, nil + case 'P': + return f1, nil + case 'Q': + return f2, nil + case 'R': + return f3, nil + case 'S': + return f4, nil + default: + return unknown, nil + } + case 'y': + s.pending = s.pending[:0] // escape code complete + return altY, nil + default: + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + + // not reached + return r, nil +} + +// Close returns the terminal to its previous mode +func (s *State) Close() error { + stopSignal(s.winch) + if s.terminalSupported { + s.origMode.ApplyMode() + } + return nil +} + +// TerminalSupported returns true if the current terminal supports +// line editing features, and false if liner will use the 'dumb' +// fallback for input. +func TerminalSupported() bool { + bad := map[string]bool{"": true, "dumb": true, "cons25": true} + return !bad[strings.ToLower(os.Getenv("TERM"))] +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/input_darwin.go b/Godeps/_workspace/src/github.com/peterh/liner/input_darwin.go new file mode 100644 index 0000000000..23c9c5da0f --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/input_darwin.go @@ -0,0 +1,39 @@ +// +build darwin + +package liner + +import "syscall" + +const ( + getTermios = syscall.TIOCGETA + setTermios = syscall.TIOCSETA +) + +const ( + // Input flags + inpck = 0x010 + istrip = 0x020 + icrnl = 0x100 + ixon = 0x200 + + // Output flags + opost = 0x1 + + // Control flags + cs8 = 0x300 + + // Local flags + isig = 0x080 + icanon = 0x100 + iexten = 0x400 +) + +type termios struct { + Iflag uintptr + Oflag uintptr + Cflag uintptr + Lflag uintptr + Cc [20]byte + Ispeed uintptr + Ospeed uintptr +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/input_linux.go b/Godeps/_workspace/src/github.com/peterh/liner/input_linux.go new file mode 100644 index 0000000000..6ca87124ea --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/input_linux.go @@ -0,0 +1,26 @@ +// +build linux + +package liner + +import "syscall" + +const ( + getTermios = syscall.TCGETS + setTermios = syscall.TCSETS +) + +const ( + icrnl = syscall.ICRNL + inpck = syscall.INPCK + istrip = syscall.ISTRIP + ixon = syscall.IXON + opost = syscall.OPOST + cs8 = syscall.CS8 + isig = syscall.ISIG + icanon = syscall.ICANON + iexten = syscall.IEXTEN +) + +type termios struct { + syscall.Termios +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/input_test.go b/Godeps/_workspace/src/github.com/peterh/liner/input_test.go new file mode 100644 index 0000000000..e515a4894e --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/input_test.go @@ -0,0 +1,61 @@ +// +build !windows + +package liner + +import ( + "bufio" + "bytes" + "testing" +) + +func (s *State) expectRune(t *testing.T, r rune) { + item, err := s.readNext() + if err != nil { + t.Fatalf("Expected rune '%c', got error %s\n", r, err) + } + if v, ok := item.(rune); !ok { + t.Fatalf("Expected rune '%c', got non-rune %v\n", r, v) + } else { + if v != r { + t.Fatalf("Expected rune '%c', got rune '%c'\n", r, v) + } + } +} + +func (s *State) expectAction(t *testing.T, a action) { + item, err := s.readNext() + if err != nil { + t.Fatalf("Expected Action %d, got error %s\n", a, err) + } + if v, ok := item.(action); !ok { + t.Fatalf("Expected Action %d, got non-Action %v\n", a, v) + } else { + if v != a { + t.Fatalf("Expected Action %d, got Action %d\n", a, v) + } + } +} + +func TestTypes(t *testing.T) { + input := []byte{'A', 27, 'B', 27, 91, 68, 27, '[', '1', ';', '5', 'D', 'e'} + var s State + s.r = bufio.NewReader(bytes.NewBuffer(input)) + + next := make(chan nexter) + go func() { + for { + var n nexter + n.r, _, n.err = s.r.ReadRune() + next <- n + } + }() + s.next = next + + s.expectRune(t, 'A') + s.expectRune(t, 27) + s.expectRune(t, 'B') + s.expectAction(t, left) + s.expectAction(t, wordLeft) + + s.expectRune(t, 'e') +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/input_windows.go b/Godeps/_workspace/src/github.com/peterh/liner/input_windows.go new file mode 100644 index 0000000000..cc98719c1c --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/input_windows.go @@ -0,0 +1,313 @@ +package liner + +import ( + "bufio" + "os" + "syscall" + "unsafe" +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + + procGetStdHandle = kernel32.NewProc("GetStdHandle") + procReadConsoleInput = kernel32.NewProc("ReadConsoleInputW") + procGetConsoleMode = kernel32.NewProc("GetConsoleMode") + procSetConsoleMode = kernel32.NewProc("SetConsoleMode") + procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") + procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") +) + +// These names are from the Win32 api, so they use underscores (contrary to +// what golint suggests) +const ( + std_input_handle = uint32(-10 & 0xFFFFFFFF) + std_output_handle = uint32(-11 & 0xFFFFFFFF) + std_error_handle = uint32(-12 & 0xFFFFFFFF) + invalid_handle_value = ^uintptr(0) +) + +type inputMode uint32 + +// State represents an open terminal +type State struct { + commonState + handle syscall.Handle + hOut syscall.Handle + origMode inputMode + defaultMode inputMode + key interface{} + repeat uint16 +} + +const ( + enableEchoInput = 0x4 + enableInsertMode = 0x20 + enableLineInput = 0x2 + enableMouseInput = 0x10 + enableProcessedInput = 0x1 + enableQuickEditMode = 0x40 + enableWindowInput = 0x8 +) + +// NewLiner initializes a new *State, and sets the terminal into raw mode. To +// restore the terminal to its previous state, call State.Close(). +func NewLiner() *State { + var s State + hIn, _, _ := procGetStdHandle.Call(uintptr(std_input_handle)) + s.handle = syscall.Handle(hIn) + hOut, _, _ := procGetStdHandle.Call(uintptr(std_output_handle)) + s.hOut = syscall.Handle(hOut) + + s.terminalSupported = true + if m, err := TerminalMode(); err == nil { + s.origMode = m.(inputMode) + mode := s.origMode + mode &^= enableEchoInput + mode &^= enableInsertMode + mode &^= enableLineInput + mode &^= enableMouseInput + mode |= enableWindowInput + mode.ApplyMode() + } else { + s.inputRedirected = true + s.r = bufio.NewReader(os.Stdin) + } + + s.getColumns() + s.outputRedirected = s.columns <= 0 + + return &s +} + +// These names are from the Win32 api, so they use underscores (contrary to +// what golint suggests) +const ( + focus_event = 0x0010 + key_event = 0x0001 + menu_event = 0x0008 + mouse_event = 0x0002 + window_buffer_size_event = 0x0004 +) + +type input_record struct { + eventType uint16 + pad uint16 + blob [16]byte +} + +type key_event_record struct { + KeyDown int32 + RepeatCount uint16 + VirtualKeyCode uint16 + VirtualScanCode uint16 + Char int16 + ControlKeyState uint32 +} + +// These names are from the Win32 api, so they use underscores (contrary to +// what golint suggests) +const ( + vk_tab = 0x09 + vk_prior = 0x21 + vk_next = 0x22 + vk_end = 0x23 + vk_home = 0x24 + vk_left = 0x25 + vk_up = 0x26 + vk_right = 0x27 + vk_down = 0x28 + vk_insert = 0x2d + vk_delete = 0x2e + vk_f1 = 0x70 + vk_f2 = 0x71 + vk_f3 = 0x72 + vk_f4 = 0x73 + vk_f5 = 0x74 + vk_f6 = 0x75 + vk_f7 = 0x76 + vk_f8 = 0x77 + vk_f9 = 0x78 + vk_f10 = 0x79 + vk_f11 = 0x7a + vk_f12 = 0x7b + yKey = 0x59 +) + +const ( + shiftPressed = 0x0010 + leftAltPressed = 0x0002 + leftCtrlPressed = 0x0008 + rightAltPressed = 0x0001 + rightCtrlPressed = 0x0004 + + modKeys = shiftPressed | leftAltPressed | rightAltPressed | leftCtrlPressed | rightCtrlPressed +) + +func (s *State) readNext() (interface{}, error) { + if s.repeat > 0 { + s.repeat-- + return s.key, nil + } + + var input input_record + pbuf := uintptr(unsafe.Pointer(&input)) + var rv uint32 + prv := uintptr(unsafe.Pointer(&rv)) + + for { + ok, _, err := procReadConsoleInput.Call(uintptr(s.handle), pbuf, 1, prv) + + if ok == 0 { + return nil, err + } + + if input.eventType == window_buffer_size_event { + xy := (*coord)(unsafe.Pointer(&input.blob[0])) + s.columns = int(xy.x) + return winch, nil + } + if input.eventType != key_event { + continue + } + ke := (*key_event_record)(unsafe.Pointer(&input.blob[0])) + if ke.KeyDown == 0 { + continue + } + + if ke.VirtualKeyCode == vk_tab && ke.ControlKeyState&modKeys == shiftPressed { + s.key = shiftTab + } else if ke.VirtualKeyCode == yKey && (ke.ControlKeyState&modKeys == leftAltPressed || + ke.ControlKeyState&modKeys == rightAltPressed) { + s.key = altY + } else if ke.Char > 0 { + s.key = rune(ke.Char) + } else { + switch ke.VirtualKeyCode { + case vk_prior: + s.key = pageUp + case vk_next: + s.key = pageDown + case vk_end: + s.key = end + case vk_home: + s.key = home + case vk_left: + s.key = left + if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 { + if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) { + s.key = wordLeft + } + } + case vk_right: + s.key = right + if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 { + if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) { + s.key = wordRight + } + } + case vk_up: + s.key = up + case vk_down: + s.key = down + case vk_insert: + s.key = insert + case vk_delete: + s.key = del + case vk_f1: + s.key = f1 + case vk_f2: + s.key = f2 + case vk_f3: + s.key = f3 + case vk_f4: + s.key = f4 + case vk_f5: + s.key = f5 + case vk_f6: + s.key = f6 + case vk_f7: + s.key = f7 + case vk_f8: + s.key = f8 + case vk_f9: + s.key = f9 + case vk_f10: + s.key = f10 + case vk_f11: + s.key = f11 + case vk_f12: + s.key = f12 + default: + // Eat modifier keys + // TODO: return Action(Unknown) if the key isn't a + // modifier. + continue + } + } + + if ke.RepeatCount > 1 { + s.repeat = ke.RepeatCount - 1 + } + return s.key, nil + } + return unknown, nil +} + +// Close returns the terminal to its previous mode +func (s *State) Close() error { + s.origMode.ApplyMode() + return nil +} + +func (s *State) startPrompt() { + if m, err := TerminalMode(); err == nil { + s.defaultMode = m.(inputMode) + mode := s.defaultMode + mode &^= enableProcessedInput + mode.ApplyMode() + } +} + +func (s *State) restartPrompt() { +} + +func (s *State) stopPrompt() { + s.defaultMode.ApplyMode() +} + +// TerminalSupported returns true because line editing is always +// supported on Windows. +func TerminalSupported() bool { + return true +} + +func (mode inputMode) ApplyMode() error { + hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle)) + if hIn == invalid_handle_value || hIn == 0 { + return err + } + ok, _, err := procSetConsoleMode.Call(hIn, uintptr(mode)) + if ok != 0 { + err = nil + } + return err +} + +// TerminalMode returns the current terminal input mode as an InputModeSetter. +// +// This function is provided for convenience, and should +// not be necessary for most users of liner. +func TerminalMode() (ModeApplier, error) { + var mode inputMode + hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle)) + if hIn == invalid_handle_value || hIn == 0 { + return nil, err + } + ok, _, err := procGetConsoleMode.Call(hIn, uintptr(unsafe.Pointer(&mode))) + if ok != 0 { + err = nil + } + return mode, err +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/line.go b/Godeps/_workspace/src/github.com/peterh/liner/line.go new file mode 100644 index 0000000000..a70fb59e5b --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/line.go @@ -0,0 +1,864 @@ +// +build windows linux darwin openbsd freebsd netbsd + +package liner + +import ( + "container/ring" + "errors" + "fmt" + "io" + "strings" + "unicode" + "unicode/utf8" +) + +type action int + +const ( + left action = iota + right + up + down + home + end + insert + del + pageUp + pageDown + f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + altY + shiftTab + wordLeft + wordRight + winch + unknown +) + +const ( + ctrlA = 1 + ctrlB = 2 + ctrlC = 3 + ctrlD = 4 + ctrlE = 5 + ctrlF = 6 + ctrlG = 7 + ctrlH = 8 + tab = 9 + lf = 10 + ctrlK = 11 + ctrlL = 12 + cr = 13 + ctrlN = 14 + ctrlO = 15 + ctrlP = 16 + ctrlQ = 17 + ctrlR = 18 + ctrlS = 19 + ctrlT = 20 + ctrlU = 21 + ctrlV = 22 + ctrlW = 23 + ctrlX = 24 + ctrlY = 25 + ctrlZ = 26 + esc = 27 + bs = 127 +) + +const ( + beep = "\a" +) + +type tabDirection int + +const ( + tabForward tabDirection = iota + tabReverse +) + +func (s *State) refresh(prompt []rune, buf []rune, pos int) error { + s.cursorPos(0) + _, err := fmt.Print(string(prompt)) + if err != nil { + return err + } + + pLen := countGlyphs(prompt) + bLen := countGlyphs(buf) + pos = countGlyphs(buf[:pos]) + if pLen+bLen < s.columns { + _, err = fmt.Print(string(buf)) + s.eraseLine() + s.cursorPos(pLen + pos) + } else { + // Find space available + space := s.columns - pLen + space-- // space for cursor + start := pos - space/2 + end := start + space + if end > bLen { + end = bLen + start = end - space + } + if start < 0 { + start = 0 + end = space + } + pos -= start + + // Leave space for markers + if start > 0 { + start++ + } + if end < bLen { + end-- + } + startRune := len(getPrefixGlyphs(buf, start)) + line := getPrefixGlyphs(buf[startRune:], end-start) + + // Output + if start > 0 { + fmt.Print("{") + } + fmt.Print(string(line)) + if end < bLen { + fmt.Print("}") + } + + // Set cursor position + s.eraseLine() + s.cursorPos(pLen + pos) + } + return err +} + +func longestCommonPrefix(strs []string) string { + if len(strs) == 0 { + return "" + } + longest := strs[0] + + for _, str := range strs[1:] { + for !strings.HasPrefix(str, longest) { + longest = longest[:len(longest)-1] + } + } + // Remove trailing partial runes + longest = strings.TrimRight(longest, "\uFFFD") + return longest +} + +func (s *State) circularTabs(items []string) func(tabDirection) (string, error) { + item := -1 + return func(direction tabDirection) (string, error) { + if direction == tabForward { + if item < len(items)-1 { + item++ + } else { + item = 0 + } + } else if direction == tabReverse { + if item > 0 { + item-- + } else { + item = len(items) - 1 + } + } + return items[item], nil + } +} + +func (s *State) printedTabs(items []string) func(tabDirection) (string, error) { + numTabs := 1 + prefix := longestCommonPrefix(items) + return func(direction tabDirection) (string, error) { + if len(items) == 1 { + return items[0], nil + } + + if numTabs == 2 { + if len(items) > 100 { + fmt.Printf("\nDisplay all %d possibilities? (y or n) ", len(items)) + for { + next, err := s.readNext() + if err != nil { + return prefix, err + } + + if key, ok := next.(rune); ok { + if unicode.ToLower(key) == 'n' { + return prefix, nil + } else if unicode.ToLower(key) == 'y' { + break + } + } + } + } + fmt.Println("") + maxWidth := 0 + for _, item := range items { + if len(item) >= maxWidth { + maxWidth = len(item) + 1 + } + } + + numColumns := s.columns / maxWidth + numRows := len(items) / numColumns + if len(items)%numColumns > 0 { + numRows++ + } + + if len(items) <= numColumns { + maxWidth = 0 + } + for i := 0; i < numRows; i++ { + for j := 0; j < numColumns*numRows; j += numRows { + if i+j < len(items) { + if maxWidth > 0 { + fmt.Printf("%-*s", maxWidth, items[i+j]) + } else { + fmt.Printf("%v ", items[i+j]) + } + } + } + fmt.Println("") + } + } else { + numTabs++ + } + return prefix, nil + } +} + +func (s *State) tabComplete(p []rune, line []rune, pos int) ([]rune, int, interface{}, error) { + if s.completer == nil { + return line, pos, rune(esc), nil + } + head, list, tail := s.completer(string(line), pos) + if len(list) <= 0 { + return line, pos, rune(esc), nil + } + hl := utf8.RuneCountInString(head) + if len(list) == 1 { + s.refresh(p, []rune(head+list[0]+tail), hl+utf8.RuneCountInString(list[0])) + return []rune(head + list[0] + tail), hl + utf8.RuneCountInString(list[0]), rune(esc), nil + } + + direction := tabForward + tabPrinter := s.circularTabs(list) + if s.tabStyle == TabPrints { + tabPrinter = s.printedTabs(list) + } + + for { + pick, err := tabPrinter(direction) + if err != nil { + return line, pos, rune(esc), err + } + s.refresh(p, []rune(head+pick+tail), hl+utf8.RuneCountInString(pick)) + + next, err := s.readNext() + if err != nil { + return line, pos, rune(esc), err + } + if key, ok := next.(rune); ok { + if key == tab { + direction = tabForward + continue + } + if key == esc { + return line, pos, rune(esc), nil + } + } + if a, ok := next.(action); ok && a == shiftTab { + direction = tabReverse + continue + } + return []rune(head + pick + tail), hl + utf8.RuneCountInString(pick), next, nil + } + // Not reached + return line, pos, rune(esc), nil +} + +// reverse intelligent search, implements a bash-like history search. +func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, interface{}, error) { + p := "(reverse-i-search)`': " + s.refresh([]rune(p), origLine, origPos) + + line := []rune{} + pos := 0 + foundLine := string(origLine) + foundPos := origPos + + getLine := func() ([]rune, []rune, int) { + search := string(line) + prompt := "(reverse-i-search)`%s': " + return []rune(fmt.Sprintf(prompt, search)), []rune(foundLine), foundPos + } + + history, positions := s.getHistoryByPattern(string(line)) + historyPos := len(history) - 1 + + for { + next, err := s.readNext() + if err != nil { + return []rune(foundLine), foundPos, rune(esc), err + } + + switch v := next.(type) { + case rune: + switch v { + case ctrlR: // Search backwards + if historyPos > 0 && historyPos < len(history) { + historyPos-- + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + fmt.Print(beep) + } + case ctrlS: // Search forward + if historyPos < len(history)-1 && historyPos >= 0 { + historyPos++ + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + fmt.Print(beep) + } + case ctrlH, bs: // Backspace + if pos <= 0 { + fmt.Print(beep) + } else { + n := len(getSuffixGlyphs(line[:pos], 1)) + line = append(line[:pos-n], line[pos:]...) + pos -= n + + // For each char deleted, display the last matching line of history + history, positions := s.getHistoryByPattern(string(line)) + historyPos = len(history) - 1 + if len(history) > 0 { + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + foundLine = "" + foundPos = 0 + } + } + case ctrlG: // Cancel + return origLine, origPos, rune(esc), err + + case tab, cr, lf, ctrlA, ctrlB, ctrlD, ctrlE, ctrlF, ctrlK, + ctrlL, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ: + fallthrough + case 0, ctrlC, esc, 28, 29, 30, 31: + return []rune(foundLine), foundPos, next, err + default: + line = append(line[:pos], append([]rune{v}, line[pos:]...)...) + pos++ + + // For each keystroke typed, display the last matching line of history + history, positions = s.getHistoryByPattern(string(line)) + historyPos = len(history) - 1 + if len(history) > 0 { + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + foundLine = "" + foundPos = 0 + } + } + case action: + return []rune(foundLine), foundPos, next, err + } + s.refresh(getLine()) + } +} + +// addToKillRing adds some text to the kill ring. If mode is 0 it adds it to a +// new node in the end of the kill ring, and move the current pointer to the new +// node. If mode is 1 or 2 it appends or prepends the text to the current entry +// of the killRing. +func (s *State) addToKillRing(text []rune, mode int) { + // Don't use the same underlying array as text + killLine := make([]rune, len(text)) + copy(killLine, text) + + // Point killRing to a newNode, procedure depends on the killring state and + // append mode. + if mode == 0 { // Add new node to killRing + if s.killRing == nil { // if killring is empty, create a new one + s.killRing = ring.New(1) + } else if s.killRing.Len() >= KillRingMax { // if killring is "full" + s.killRing = s.killRing.Next() + } else { // Normal case + s.killRing.Link(ring.New(1)) + s.killRing = s.killRing.Next() + } + } else { + if s.killRing == nil { // if killring is empty, create a new one + s.killRing = ring.New(1) + s.killRing.Value = []rune{} + } + if mode == 1 { // Append to last entry + killLine = append(s.killRing.Value.([]rune), killLine...) + } else if mode == 2 { // Prepend to last entry + killLine = append(killLine, s.killRing.Value.([]rune)...) + } + } + + // Save text in the current killring node + s.killRing.Value = killLine +} + +func (s *State) yank(p []rune, text []rune, pos int) ([]rune, int, interface{}, error) { + if s.killRing == nil { + return text, pos, rune(esc), nil + } + + lineStart := text[:pos] + lineEnd := text[pos:] + var line []rune + + for { + value := s.killRing.Value.([]rune) + line = make([]rune, 0) + line = append(line, lineStart...) + line = append(line, value...) + line = append(line, lineEnd...) + + pos = len(lineStart) + len(value) + s.refresh(p, line, pos) + + next, err := s.readNext() + if err != nil { + return line, pos, next, err + } + + switch v := next.(type) { + case rune: + return line, pos, next, nil + case action: + switch v { + case altY: + s.killRing = s.killRing.Prev() + default: + return line, pos, next, nil + } + } + } + + return line, pos, esc, nil +} + +// Prompt displays p, and then waits for user input. Prompt allows line editing +// if the terminal supports it. +func (s *State) Prompt(prompt string) (string, error) { + if s.inputRedirected { + return s.promptUnsupported(prompt) + } + if s.outputRedirected { + return "", ErrNotTerminalOutput + } + if !s.terminalSupported { + return s.promptUnsupported(prompt) + } + + s.historyMutex.RLock() + defer s.historyMutex.RUnlock() + + s.startPrompt() + defer s.stopPrompt() + s.getColumns() + + fmt.Print(prompt) + p := []rune(prompt) + var line []rune + pos := 0 + historyEnd := "" + prefixHistory := s.getHistoryByPrefix(string(line)) + historyPos := len(prefixHistory) + historyAction := false // used to mark history related actions + killAction := 0 // used to mark kill related actions +mainLoop: + for { + next, err := s.readNext() + haveNext: + if err != nil { + return "", err + } + + historyAction = false + switch v := next.(type) { + case rune: + switch v { + case cr, lf: + fmt.Println() + break mainLoop + case ctrlA: // Start of line + pos = 0 + s.refresh(p, line, pos) + case ctrlE: // End of line + pos = len(line) + s.refresh(p, line, pos) + case ctrlB: // left + if pos > 0 { + pos -= len(getSuffixGlyphs(line[:pos], 1)) + s.refresh(p, line, pos) + } else { + fmt.Print(beep) + } + case ctrlF: // right + if pos < len(line) { + pos += len(getPrefixGlyphs(line[pos:], 1)) + s.refresh(p, line, pos) + } else { + fmt.Print(beep) + } + case ctrlD: // del + if pos == 0 && len(line) == 0 { + // exit + return "", io.EOF + } + + // ctrlD is a potential EOF, so the rune reader shuts down. + // Therefore, if it isn't actually an EOF, we must re-startPrompt. + s.restartPrompt() + + if pos >= len(line) { + fmt.Print(beep) + } else { + n := len(getPrefixGlyphs(line[pos:], 1)) + line = append(line[:pos], line[pos+n:]...) + s.refresh(p, line, pos) + } + case ctrlK: // delete remainder of line + if pos >= len(line) { + fmt.Print(beep) + } else { + if killAction > 0 { + s.addToKillRing(line[pos:], 1) // Add in apend mode + } else { + s.addToKillRing(line[pos:], 0) // Add in normal mode + } + + killAction = 2 // Mark that there was a kill action + line = line[:pos] + s.refresh(p, line, pos) + } + case ctrlP: // up + historyAction = true + if historyPos > 0 { + if historyPos == len(prefixHistory) { + historyEnd = string(line) + } + historyPos-- + line = []rune(prefixHistory[historyPos]) + pos = len(line) + s.refresh(p, line, pos) + } else { + fmt.Print(beep) + } + case ctrlN: // down + historyAction = true + if historyPos < len(prefixHistory) { + historyPos++ + if historyPos == len(prefixHistory) { + line = []rune(historyEnd) + } else { + line = []rune(prefixHistory[historyPos]) + } + pos = len(line) + s.refresh(p, line, pos) + } else { + fmt.Print(beep) + } + case ctrlT: // transpose prev glyph with glyph under cursor + if len(line) < 2 || pos < 1 { + fmt.Print(beep) + } else { + if pos == len(line) { + pos -= len(getSuffixGlyphs(line, 1)) + } + prev := getSuffixGlyphs(line[:pos], 1) + next := getPrefixGlyphs(line[pos:], 1) + scratch := make([]rune, len(prev)) + copy(scratch, prev) + copy(line[pos-len(prev):], next) + copy(line[pos-len(prev)+len(next):], scratch) + pos += len(next) + s.refresh(p, line, pos) + } + case ctrlL: // clear screen + s.eraseScreen() + s.refresh(p, line, pos) + case ctrlC: // reset + fmt.Println("^C") + if s.ctrlCAborts { + return "", ErrPromptAborted + } + line = line[:0] + pos = 0 + fmt.Print(prompt) + s.restartPrompt() + case ctrlH, bs: // Backspace + if pos <= 0 { + fmt.Print(beep) + } else { + n := len(getSuffixGlyphs(line[:pos], 1)) + line = append(line[:pos-n], line[pos:]...) + pos -= n + s.refresh(p, line, pos) + } + case ctrlU: // Erase line before cursor + if killAction > 0 { + s.addToKillRing(line[:pos], 2) // Add in prepend mode + } else { + s.addToKillRing(line[:pos], 0) // Add in normal mode + } + + killAction = 2 // Mark that there was some killing + line = line[pos:] + pos = 0 + s.refresh(p, line, pos) + case ctrlW: // Erase word + if pos == 0 { + fmt.Print(beep) + break + } + // Remove whitespace to the left + var buf []rune // Store the deleted chars in a buffer + for { + if pos == 0 || !unicode.IsSpace(line[pos-1]) { + break + } + buf = append(buf, line[pos-1]) + line = append(line[:pos-1], line[pos:]...) + pos-- + } + // Remove non-whitespace to the left + for { + if pos == 0 || unicode.IsSpace(line[pos-1]) { + break + } + buf = append(buf, line[pos-1]) + line = append(line[:pos-1], line[pos:]...) + pos-- + } + // Invert the buffer and save the result on the killRing + var newBuf []rune + for i := len(buf) - 1; i >= 0; i-- { + newBuf = append(newBuf, buf[i]) + } + if killAction > 0 { + s.addToKillRing(newBuf, 2) // Add in prepend mode + } else { + s.addToKillRing(newBuf, 0) // Add in normal mode + } + killAction = 2 // Mark that there was some killing + + s.refresh(p, line, pos) + case ctrlY: // Paste from Yank buffer + line, pos, next, err = s.yank(p, line, pos) + goto haveNext + case ctrlR: // Reverse Search + line, pos, next, err = s.reverseISearch(line, pos) + s.refresh(p, line, pos) + goto haveNext + case tab: // Tab completion + line, pos, next, err = s.tabComplete(p, line, pos) + goto haveNext + // Catch keys that do nothing, but you don't want them to beep + case esc: + // DO NOTHING + // Unused keys + case ctrlG, ctrlO, ctrlQ, ctrlS, ctrlV, ctrlX, ctrlZ: + fallthrough + // Catch unhandled control codes (anything <= 31) + case 0, 28, 29, 30, 31: + fmt.Print(beep) + default: + if pos == len(line) && len(p)+len(line) < s.columns-1 { + line = append(line, v) + fmt.Printf("%c", v) + pos++ + } else { + line = append(line[:pos], append([]rune{v}, line[pos:]...)...) + pos++ + s.refresh(p, line, pos) + } + } + case action: + switch v { + case del: + if pos >= len(line) { + fmt.Print(beep) + } else { + n := len(getPrefixGlyphs(line[pos:], 1)) + line = append(line[:pos], line[pos+n:]...) + } + case left: + if pos > 0 { + pos -= len(getSuffixGlyphs(line[:pos], 1)) + } else { + fmt.Print(beep) + } + case wordLeft: + if pos > 0 { + for { + pos-- + if pos == 0 || unicode.IsSpace(line[pos-1]) { + break + } + } + } else { + fmt.Print(beep) + } + case right: + if pos < len(line) { + pos += len(getPrefixGlyphs(line[pos:], 1)) + } else { + fmt.Print(beep) + } + case wordRight: + if pos < len(line) { + for { + pos++ + if pos == len(line) || unicode.IsSpace(line[pos]) { + break + } + } + } else { + fmt.Print(beep) + } + case up: + historyAction = true + if historyPos > 0 { + if historyPos == len(prefixHistory) { + historyEnd = string(line) + } + historyPos-- + line = []rune(prefixHistory[historyPos]) + pos = len(line) + } else { + fmt.Print(beep) + } + case down: + historyAction = true + if historyPos < len(prefixHistory) { + historyPos++ + if historyPos == len(prefixHistory) { + line = []rune(historyEnd) + } else { + line = []rune(prefixHistory[historyPos]) + } + pos = len(line) + } else { + fmt.Print(beep) + } + case home: // Start of line + pos = 0 + case end: // End of line + pos = len(line) + } + s.refresh(p, line, pos) + } + if !historyAction { + prefixHistory = s.getHistoryByPrefix(string(line)) + historyPos = len(prefixHistory) + } + if killAction > 0 { + killAction-- + } + } + return string(line), nil +} + +// PasswordPrompt displays p, and then waits for user input. The input typed by +// the user is not displayed in the terminal. +func (s *State) PasswordPrompt(prompt string) (string, error) { + if s.inputRedirected { + return s.promptUnsupported(prompt) + } + if s.outputRedirected { + return "", ErrNotTerminalOutput + } + if !s.terminalSupported { + return "", errors.New("liner: function not supported in this terminal") + } + + s.startPrompt() + defer s.stopPrompt() + s.getColumns() + + fmt.Print(prompt) + p := []rune(prompt) + var line []rune + pos := 0 + +mainLoop: + for { + next, err := s.readNext() + if err != nil { + return "", err + } + + switch v := next.(type) { + case rune: + switch v { + case cr, lf: + fmt.Println() + break mainLoop + case ctrlD: // del + if pos == 0 && len(line) == 0 { + // exit + return "", io.EOF + } + + // ctrlD is a potential EOF, so the rune reader shuts down. + // Therefore, if it isn't actually an EOF, we must re-startPrompt. + s.restartPrompt() + case ctrlL: // clear screen + s.eraseScreen() + s.refresh(p, []rune{}, 0) + case ctrlH, bs: // Backspace + if pos <= 0 { + fmt.Print(beep) + } else { + n := len(getSuffixGlyphs(line[:pos], 1)) + line = append(line[:pos-n], line[pos:]...) + pos -= n + } + case ctrlC: + fmt.Println("^C") + if s.ctrlCAborts { + return "", ErrPromptAborted + } + line = line[:0] + pos = 0 + fmt.Print(prompt) + s.restartPrompt() + // Unused keys + case esc, tab, ctrlA, ctrlB, ctrlE, ctrlF, ctrlG, ctrlK, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlR, ctrlS, + ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ: + fallthrough + // Catch unhandled control codes (anything <= 31) + case 0, 28, 29, 30, 31: + fmt.Print(beep) + default: + line = append(line[:pos], append([]rune{v}, line[pos:]...)...) + pos++ + } + } + } + return string(line), nil +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/line_test.go b/Godeps/_workspace/src/github.com/peterh/liner/line_test.go new file mode 100644 index 0000000000..727da6ce7c --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/line_test.go @@ -0,0 +1,90 @@ +package liner + +import ( + "bytes" + "strings" + "testing" +) + +func TestAppend(t *testing.T) { + var s State + s.AppendHistory("foo") + s.AppendHistory("bar") + + var out bytes.Buffer + num, err := s.WriteHistory(&out) + if err != nil { + t.Fatal("Unexpected error writing history", err) + } + if num != 2 { + t.Fatalf("Expected 2 history entries, got %d", num) + } + + s.AppendHistory("baz") + num, err = s.WriteHistory(&out) + if err != nil { + t.Fatal("Unexpected error writing history", err) + } + if num != 3 { + t.Fatalf("Expected 3 history entries, got %d", num) + } + + s.AppendHistory("baz") + num, err = s.WriteHistory(&out) + if err != nil { + t.Fatal("Unexpected error writing history", err) + } + if num != 3 { + t.Fatalf("Expected 3 history entries after duplicate append, got %d", num) + } + + s.AppendHistory("baz") + +} + +func TestHistory(t *testing.T) { + input := `foo +bar +baz +quux +dingle` + + var s State + num, err := s.ReadHistory(strings.NewReader(input)) + if err != nil { + t.Fatal("Unexpected error reading history", err) + } + if num != 5 { + t.Fatal("Wrong number of history entries read") + } + + var out bytes.Buffer + num, err = s.WriteHistory(&out) + if err != nil { + t.Fatal("Unexpected error writing history", err) + } + if num != 5 { + t.Fatal("Wrong number of history entries written") + } + if strings.TrimSpace(out.String()) != input { + t.Fatal("Round-trip failure") + } + + // Test reading with a trailing newline present + var s2 State + num, err = s2.ReadHistory(&out) + if err != nil { + t.Fatal("Unexpected error reading history the 2nd time", err) + } + if num != 5 { + t.Fatal("Wrong number of history entries read the 2nd time") + } + + num, err = s.ReadHistory(strings.NewReader(input + "\n\xff")) + if err == nil { + t.Fatal("Unexpected success reading corrupted history", err) + } + if num != 5 { + t.Fatal("Wrong number of history entries read the 3rd time") + } +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/output.go b/Godeps/_workspace/src/github.com/peterh/liner/output.go new file mode 100644 index 0000000000..e91f4ea818 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/output.go @@ -0,0 +1,63 @@ +// +build linux darwin openbsd freebsd netbsd + +package liner + +import ( + "fmt" + "os" + "strings" + "syscall" + "unsafe" +) + +func (s *State) cursorPos(x int) { + if s.useCHA { + // 'G' is "Cursor Character Absolute (CHA)" + fmt.Printf("\x1b[%dG", x+1) + } else { + // 'C' is "Cursor Forward (CUF)" + fmt.Print("\r") + if x > 0 { + fmt.Printf("\x1b[%dC", x) + } + } +} + +func (s *State) eraseLine() { + fmt.Print("\x1b[0K") +} + +func (s *State) eraseScreen() { + fmt.Print("\x1b[H\x1b[2J") +} + +type winSize struct { + row, col uint16 + xpixel, ypixel uint16 +} + +func (s *State) getColumns() { + var ws winSize + ok, _, _ := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdout), + syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws))) + if ok < 0 { + s.columns = 80 + } + s.columns = int(ws.col) +} + +func (s *State) checkOutput() { + // xterm is known to support CHA + if strings.Contains(strings.ToLower(os.Getenv("TERM")), "xterm") { + s.useCHA = true + return + } + + // The test for functional ANSI CHA is unreliable (eg the Windows + // telnet command does not support reading the cursor position with + // an ANSI DSR request, despite setting TERM=ansi) + + // Assume CHA isn't supported (which should be safe, although it + // does result in occasional visible cursor jitter) + s.useCHA = false +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/output_windows.go b/Godeps/_workspace/src/github.com/peterh/liner/output_windows.go new file mode 100644 index 0000000000..27ae55a144 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/output_windows.go @@ -0,0 +1,54 @@ +package liner + +import ( + "unsafe" +) + +type coord struct { + x, y int16 +} +type smallRect struct { + left, top, right, bottom int16 +} + +type consoleScreenBufferInfo struct { + dwSize coord + dwCursorPosition coord + wAttributes int16 + srWindow smallRect + dwMaximumWindowSize coord +} + +func (s *State) cursorPos(x int) { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + procSetConsoleCursorPosition.Call(uintptr(s.hOut), + uintptr(int(x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16)) +} + +func (s *State) eraseLine() { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + var numWritten uint32 + procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '), + uintptr(sbi.dwSize.x-sbi.dwCursorPosition.x), + uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16), + uintptr(unsafe.Pointer(&numWritten))) +} + +func (s *State) eraseScreen() { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + var numWritten uint32 + procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '), + uintptr(sbi.dwSize.x)*uintptr(sbi.dwSize.y), + 0, + uintptr(unsafe.Pointer(&numWritten))) + procSetConsoleCursorPosition.Call(uintptr(s.hOut), 0) +} + +func (s *State) getColumns() { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + s.columns = int(sbi.dwSize.x) +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go b/Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go new file mode 100644 index 0000000000..c826d6c3be --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go @@ -0,0 +1,37 @@ +// +build windows linux darwin openbsd freebsd netbsd + +package liner + +import "testing" + +type testItem struct { + list []string + prefix string +} + +func TestPrefix(t *testing.T) { + list := []testItem{ + {[]string{"food", "foot"}, "foo"}, + {[]string{"foo", "foot"}, "foo"}, + {[]string{"food", "foo"}, "foo"}, + {[]string{"food", "foe", "foot"}, "fo"}, + {[]string{"food", "foot", "barbeque"}, ""}, + {[]string{"cafeteria", "café"}, "caf"}, + {[]string{"cafe", "café"}, "caf"}, + {[]string{"cafè", "café"}, "caf"}, + {[]string{"cafés", "café"}, "café"}, + {[]string{"áéíóú", "áéíóú"}, "áéíóú"}, + {[]string{"éclairs", "éclairs"}, "éclairs"}, + {[]string{"éclairs are the best", "éclairs are great", "éclairs"}, "éclairs"}, + {[]string{"éclair", "éclairs"}, "éclair"}, + {[]string{"éclairs", "éclair"}, "éclair"}, + {[]string{"éclair", "élan"}, "é"}, + } + + for _, test := range list { + lcp := longestCommonPrefix(test.list) + if lcp != test.prefix { + t.Errorf("%s != %s for %+v", lcp, test.prefix, test.list) + } + } +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/race_test.go b/Godeps/_workspace/src/github.com/peterh/liner/race_test.go new file mode 100644 index 0000000000..e320849c7e --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/race_test.go @@ -0,0 +1,44 @@ +// +build race + +package liner + +import ( + "io/ioutil" + "os" + "sync" + "testing" +) + +func TestWriteHistory(t *testing.T) { + oldout := os.Stdout + defer func() { os.Stdout = oldout }() + oldin := os.Stdout + defer func() { os.Stdin = oldin }() + + newinr, newinw, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + os.Stdin = newinr + newoutr, newoutw, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + defer newoutr.Close() + os.Stdout = newoutw + + var wait sync.WaitGroup + wait.Add(1) + s := NewLiner() + go func() { + s.AppendHistory("foo") + s.AppendHistory("bar") + s.Prompt("") + wait.Done() + }() + + s.WriteHistory(ioutil.Discard) + + newinw.Close() + wait.Wait() +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/signal.go b/Godeps/_workspace/src/github.com/peterh/liner/signal.go new file mode 100644 index 0000000000..0cba79e7f8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/signal.go @@ -0,0 +1,12 @@ +// +build go1.1,!windows + +package liner + +import ( + "os" + "os/signal" +) + +func stopSignal(c chan<- os.Signal) { + signal.Stop(c) +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/signal_legacy.go b/Godeps/_workspace/src/github.com/peterh/liner/signal_legacy.go new file mode 100644 index 0000000000..fa3672daac --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/signal_legacy.go @@ -0,0 +1,11 @@ +// +build !go1.1,!windows + +package liner + +import ( + "os" +) + +func stopSignal(c chan<- os.Signal) { + // signal.Stop does not exist before Go 1.1 +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/unixmode.go b/Godeps/_workspace/src/github.com/peterh/liner/unixmode.go new file mode 100644 index 0000000000..9838923f5d --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/unixmode.go @@ -0,0 +1,37 @@ +// +build linux darwin freebsd openbsd netbsd + +package liner + +import ( + "syscall" + "unsafe" +) + +func (mode *termios) ApplyMode() error { + _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdin), setTermios, uintptr(unsafe.Pointer(mode))) + + if errno != 0 { + return errno + } + return nil +} + +// TerminalMode returns the current terminal input mode as an InputModeSetter. +// +// This function is provided for convenience, and should +// not be necessary for most users of liner. +func TerminalMode() (ModeApplier, error) { + mode, errno := getMode(syscall.Stdin) + + if errno != 0 { + return nil, errno + } + return mode, nil +} + +func getMode(handle int) (*termios, syscall.Errno) { + var mode termios + _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(handle), getTermios, uintptr(unsafe.Pointer(&mode))) + + return &mode, errno +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/width.go b/Godeps/_workspace/src/github.com/peterh/liner/width.go new file mode 100644 index 0000000000..02cfb5e1bf --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/width.go @@ -0,0 +1,47 @@ +package liner + +import "unicode" + +// These character classes are mostly zero width (when combined). +// A few might not be, depending on the user's font. Fixing this +// is non-trivial, given that some terminals don't support +// ANSI DSR/CPR +var zeroWidth = []*unicode.RangeTable{ + unicode.Mn, + unicode.Me, + unicode.Cc, + unicode.Cf, +} + +func countGlyphs(s []rune) int { + n := 0 + for _, r := range s { + if !unicode.IsOneOf(zeroWidth, r) { + n++ + } + } + return n +} + +func getPrefixGlyphs(s []rune, num int) []rune { + p := 0 + for n := 0; n < num && p < len(s); p++ { + if !unicode.IsOneOf(zeroWidth, s[p]) { + n++ + } + } + for p < len(s) && unicode.IsOneOf(zeroWidth, s[p]) { + p++ + } + return s[:p] +} + +func getSuffixGlyphs(s []rune, num int) []rune { + p := len(s) + for n := 0; n < num && p > 0; p-- { + if !unicode.IsOneOf(zeroWidth, s[p-1]) { + n++ + } + } + return s[p:] +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/width_test.go b/Godeps/_workspace/src/github.com/peterh/liner/width_test.go new file mode 100644 index 0000000000..134920a4b1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/width_test.go @@ -0,0 +1,87 @@ +package liner + +import ( + "strconv" + "testing" +) + +func accent(in []rune) []rune { + var out []rune + for _, r := range in { + out = append(out, r) + out = append(out, '\u0301') + } + return out +} + +var testString = []rune("query") + +func TestCountGlyphs(t *testing.T) { + count := countGlyphs(testString) + if count != len(testString) { + t.Errorf("ASCII count incorrect. %d != %d", count, len(testString)) + } + count = countGlyphs(accent(testString)) + if count != len(testString) { + t.Errorf("Accent count incorrect. %d != %d", count, len(testString)) + } +} + +func compare(a, b []rune, name string, t *testing.T) { + if len(a) != len(b) { + t.Errorf(`"%s" != "%s" in %s"`, string(a), string(b), name) + return + } + for i := range a { + if a[i] != b[i] { + t.Errorf(`"%s" != "%s" in %s"`, string(a), string(b), name) + return + } + } +} + +func TestPrefixGlyphs(t *testing.T) { + for i := 0; i <= len(testString); i++ { + iter := strconv.Itoa(i) + out := getPrefixGlyphs(testString, i) + compare(out, testString[:i], "ascii prefix "+iter, t) + out = getPrefixGlyphs(accent(testString), i) + compare(out, accent(testString[:i]), "accent prefix "+iter, t) + } + out := getPrefixGlyphs(testString, 999) + compare(out, testString, "ascii prefix overflow", t) + out = getPrefixGlyphs(accent(testString), 999) + compare(out, accent(testString), "accent prefix overflow", t) + + out = getPrefixGlyphs(testString, -3) + if len(out) != 0 { + t.Error("ascii prefix negative") + } + out = getPrefixGlyphs(accent(testString), -3) + if len(out) != 0 { + t.Error("accent prefix negative") + } +} + +func TestSuffixGlyphs(t *testing.T) { + for i := 0; i <= len(testString); i++ { + iter := strconv.Itoa(i) + out := getSuffixGlyphs(testString, i) + compare(out, testString[len(testString)-i:], "ascii suffix "+iter, t) + out = getSuffixGlyphs(accent(testString), i) + compare(out, accent(testString[len(testString)-i:]), "accent suffix "+iter, t) + } + out := getSuffixGlyphs(testString, 999) + compare(out, testString, "ascii suffix overflow", t) + out = getSuffixGlyphs(accent(testString), 999) + compare(out, accent(testString), "accent suffix overflow", t) + + out = getSuffixGlyphs(testString, -3) + if len(out) != 0 { + t.Error("ascii suffix negative") + } + out = getSuffixGlyphs(accent(testString), -3) + if len(out) != 0 { + t.Error("accent suffix negative") + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/.gitignore b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/.gitignore new file mode 100644 index 0000000000..83c8f82374 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/.gitignore @@ -0,0 +1,9 @@ +*.[68] +*.a +*.out +*.swp +_obj +_testmain.go +cmd/metrics-bench/metrics-bench +cmd/metrics-example/metrics-example +cmd/never-read/never-read diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/LICENSE b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/LICENSE new file mode 100644 index 0000000000..363fa9ee77 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/LICENSE @@ -0,0 +1,29 @@ +Copyright 2012 Richard Crowley. 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 RICHARD CROWLEY ``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 RICHARD CROWLEY 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. + +The views and conclusions contained in the software and documentation +are those of the authors and should not be interpreted as representing +official policies, either expressed or implied, of Richard Crowley. diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/README.md b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/README.md new file mode 100644 index 0000000000..e0091a4bd0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/README.md @@ -0,0 +1,104 @@ +go-metrics +========== + +Go port of Coda Hale's Metrics library: . + +Documentation: . + +Usage +----- + +Create and update metrics: + +```go +c := metrics.NewCounter() +metrics.Register("foo", c) +c.Inc(47) + +g := metrics.NewGauge() +metrics.Register("bar", g) +g.Update(47) + +s := metrics.NewExpDecaySample(1028, 0.015) // or metrics.NewUniformSample(1028) +h := metrics.NewHistogram(s) +metrics.Register("baz", h) +h.Update(47) + +m := metrics.NewMeter() +metrics.Register("quux", m) +m.Mark(47) + +t := metrics.NewTimer() +metrics.Register("bang", t) +t.Time(func() {}) +t.Update(47) +``` + +Periodically log every metric in human-readable form to standard error: + +```go +go metrics.Log(metrics.DefaultRegistry, 60e9, log.New(os.Stderr, "metrics: ", log.Lmicroseconds)) +``` + +Periodically log every metric in slightly-more-parseable form to syslog: + +```go +w, _ := syslog.Dial("unixgram", "/dev/log", syslog.LOG_INFO, "metrics") +go metrics.Syslog(metrics.DefaultRegistry, 60e9, w) +``` + +Periodically emit every metric to Graphite: + +```go +addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:2003") +go metrics.Graphite(metrics.DefaultRegistry, 10e9, "metrics", addr) +``` + +Periodically emit every metric into InfluxDB: + +```go +import "github.com/rcrowley/go-metrics/influxdb" + +go influxdb.Influxdb(metrics.DefaultRegistry, 10e9, &influxdb.Config{ + Host: "127.0.0.1:8086", + Database: "metrics", + Username: "test", + Password: "test", +}) +``` + +Periodically upload every metric to Librato: + +```go +import "github.com/rcrowley/go-metrics/librato" + +go librato.Librato(metrics.DefaultRegistry, + 10e9, // interval + "example@example.com", // account owner email address + "token", // Librato API token + "hostname", // source + []float64{0.95}, // precentiles to send + time.Millisecond, // time unit +) +``` + +Periodically emit every metric to StatHat: + +```go +import "github.com/rcrowley/go-metrics/stathat" + +go stathat.Stathat(metrics.DefaultRegistry, 10e9, "example@example.com") +``` + +Installation +------------ + +```sh +go get github.com/rcrowley/go-metrics +``` + +StatHat support additionally requires their Go client: + +```sh +go get github.com/stathat/go +``` diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/cmd/metrics-bench/metrics-bench.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/cmd/metrics-bench/metrics-bench.go new file mode 100644 index 0000000000..dddaf4b126 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/cmd/metrics-bench/metrics-bench.go @@ -0,0 +1,20 @@ +package main + +import ( + "fmt" + "github.com/rcrowley/go-metrics" + "time" +) + +func main() { + r := metrics.NewRegistry() + for i := 0; i < 10000; i++ { + r.Register(fmt.Sprintf("counter-%d", i), metrics.NewCounter()) + r.Register(fmt.Sprintf("gauge-%d", i), metrics.NewGauge()) + r.Register(fmt.Sprintf("gaugefloat64-%d", i), metrics.NewGaugeFloat64()) + r.Register(fmt.Sprintf("histogram-uniform-%d", i), metrics.NewHistogram(metrics.NewUniformSample(1028))) + r.Register(fmt.Sprintf("histogram-exp-%d", i), metrics.NewHistogram(metrics.NewExpDecaySample(1028, 0.015))) + r.Register(fmt.Sprintf("meter-%d", i), metrics.NewMeter()) + } + time.Sleep(600e9) +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/cmd/metrics-example/metrics-example.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/cmd/metrics-example/metrics-example.go new file mode 100644 index 0000000000..66f42c0468 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/cmd/metrics-example/metrics-example.go @@ -0,0 +1,154 @@ +package main + +import ( + "errors" + "github.com/rcrowley/go-metrics" + // "github.com/rcrowley/go-metrics/stathat" + "log" + "math/rand" + "os" + // "syslog" + "time" +) + +const fanout = 10 + +func main() { + + r := metrics.NewRegistry() + + c := metrics.NewCounter() + r.Register("foo", c) + for i := 0; i < fanout; i++ { + go func() { + for { + c.Dec(19) + time.Sleep(300e6) + } + }() + go func() { + for { + c.Inc(47) + time.Sleep(400e6) + } + }() + } + + g := metrics.NewGauge() + r.Register("bar", g) + for i := 0; i < fanout; i++ { + go func() { + for { + g.Update(19) + time.Sleep(300e6) + } + }() + go func() { + for { + g.Update(47) + time.Sleep(400e6) + } + }() + } + + gf := metrics.NewGaugeFloat64() + r.Register("barfloat64", gf) + for i := 0; i < fanout; i++ { + go func() { + for { + g.Update(19.0) + time.Sleep(300e6) + } + }() + go func() { + for { + g.Update(47.0) + time.Sleep(400e6) + } + }() + } + + hc := metrics.NewHealthcheck(func(h metrics.Healthcheck) { + if 0 < rand.Intn(2) { + h.Healthy() + } else { + h.Unhealthy(errors.New("baz")) + } + }) + r.Register("baz", hc) + + s := metrics.NewExpDecaySample(1028, 0.015) + //s := metrics.NewUniformSample(1028) + h := metrics.NewHistogram(s) + r.Register("bang", h) + for i := 0; i < fanout; i++ { + go func() { + for { + h.Update(19) + time.Sleep(300e6) + } + }() + go func() { + for { + h.Update(47) + time.Sleep(400e6) + } + }() + } + + m := metrics.NewMeter() + r.Register("quux", m) + for i := 0; i < fanout; i++ { + go func() { + for { + m.Mark(19) + time.Sleep(300e6) + } + }() + go func() { + for { + m.Mark(47) + time.Sleep(400e6) + } + }() + } + + t := metrics.NewTimer() + r.Register("hooah", t) + for i := 0; i < fanout; i++ { + go func() { + for { + t.Time(func() { time.Sleep(300e6) }) + } + }() + go func() { + for { + t.Time(func() { time.Sleep(400e6) }) + } + }() + } + + metrics.RegisterDebugGCStats(r) + go metrics.CaptureDebugGCStats(r, 5e9) + + metrics.RegisterRuntimeMemStats(r) + go metrics.CaptureRuntimeMemStats(r, 5e9) + + metrics.Log(r, 60e9, log.New(os.Stderr, "metrics: ", log.Lmicroseconds)) + + /* + w, err := syslog.Dial("unixgram", "/dev/log", syslog.LOG_INFO, "metrics") + if nil != err { log.Fatalln(err) } + metrics.Syslog(r, 60e9, w) + */ + + /* + addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:2003") + metrics.Graphite(r, 10e9, "metrics", addr) + */ + + /* + stathat.Stathat(r, 10e9, "example@example.com") + */ + +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/cmd/never-read/never-read.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/cmd/never-read/never-read.go new file mode 100644 index 0000000000..dc175b778e --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/cmd/never-read/never-read.go @@ -0,0 +1,22 @@ +package main + +import ( + "log" + "net" +) + +func main() { + addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:2003") + l, err := net.ListenTCP("tcp", addr) + if nil != err { + log.Fatalln(err) + } + log.Println("listening", l.Addr()) + for { + c, err := l.AcceptTCP() + if nil != err { + log.Fatalln(err) + } + log.Println("accepted", c.RemoteAddr()) + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/counter.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/counter.go new file mode 100644 index 0000000000..bb7b039cb5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/counter.go @@ -0,0 +1,112 @@ +package metrics + +import "sync/atomic" + +// Counters hold an int64 value that can be incremented and decremented. +type Counter interface { + Clear() + Count() int64 + Dec(int64) + Inc(int64) + Snapshot() Counter +} + +// GetOrRegisterCounter returns an existing Counter or constructs and registers +// a new StandardCounter. +func GetOrRegisterCounter(name string, r Registry) Counter { + if nil == r { + r = DefaultRegistry + } + return r.GetOrRegister(name, NewCounter).(Counter) +} + +// NewCounter constructs a new StandardCounter. +func NewCounter() Counter { + if UseNilMetrics { + return NilCounter{} + } + return &StandardCounter{0} +} + +// NewRegisteredCounter constructs and registers a new StandardCounter. +func NewRegisteredCounter(name string, r Registry) Counter { + c := NewCounter() + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + +// CounterSnapshot is a read-only copy of another Counter. +type CounterSnapshot int64 + +// Clear panics. +func (CounterSnapshot) Clear() { + panic("Clear called on a CounterSnapshot") +} + +// Count returns the count at the time the snapshot was taken. +func (c CounterSnapshot) Count() int64 { return int64(c) } + +// Dec panics. +func (CounterSnapshot) Dec(int64) { + panic("Dec called on a CounterSnapshot") +} + +// Inc panics. +func (CounterSnapshot) Inc(int64) { + panic("Inc called on a CounterSnapshot") +} + +// Snapshot returns the snapshot. +func (c CounterSnapshot) Snapshot() Counter { return c } + +// NilCounter is a no-op Counter. +type NilCounter struct{} + +// Clear is a no-op. +func (NilCounter) Clear() {} + +// Count is a no-op. +func (NilCounter) Count() int64 { return 0 } + +// Dec is a no-op. +func (NilCounter) Dec(i int64) {} + +// Inc is a no-op. +func (NilCounter) Inc(i int64) {} + +// Snapshot is a no-op. +func (NilCounter) Snapshot() Counter { return NilCounter{} } + +// StandardCounter is the standard implementation of a Counter and uses the +// sync/atomic package to manage a single int64 value. +type StandardCounter struct { + count int64 +} + +// Clear sets the counter to zero. +func (c *StandardCounter) Clear() { + atomic.StoreInt64(&c.count, 0) +} + +// Count returns the current count. +func (c *StandardCounter) Count() int64 { + return atomic.LoadInt64(&c.count) +} + +// Dec decrements the counter by the given amount. +func (c *StandardCounter) Dec(i int64) { + atomic.AddInt64(&c.count, -i) +} + +// Inc increments the counter by the given amount. +func (c *StandardCounter) Inc(i int64) { + atomic.AddInt64(&c.count, i) +} + +// Snapshot returns a read-only copy of the counter. +func (c *StandardCounter) Snapshot() Counter { + return CounterSnapshot(c.Count()) +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/counter_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/counter_test.go new file mode 100644 index 0000000000..dfb03b4e88 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/counter_test.go @@ -0,0 +1,77 @@ +package metrics + +import "testing" + +func BenchmarkCounter(b *testing.B) { + c := NewCounter() + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.Inc(1) + } +} + +func TestCounterClear(t *testing.T) { + c := NewCounter() + c.Inc(1) + c.Clear() + if count := c.Count(); 0 != count { + t.Errorf("c.Count(): 0 != %v\n", count) + } +} + +func TestCounterDec1(t *testing.T) { + c := NewCounter() + c.Dec(1) + if count := c.Count(); -1 != count { + t.Errorf("c.Count(): -1 != %v\n", count) + } +} + +func TestCounterDec2(t *testing.T) { + c := NewCounter() + c.Dec(2) + if count := c.Count(); -2 != count { + t.Errorf("c.Count(): -2 != %v\n", count) + } +} + +func TestCounterInc1(t *testing.T) { + c := NewCounter() + c.Inc(1) + if count := c.Count(); 1 != count { + t.Errorf("c.Count(): 1 != %v\n", count) + } +} + +func TestCounterInc2(t *testing.T) { + c := NewCounter() + c.Inc(2) + if count := c.Count(); 2 != count { + t.Errorf("c.Count(): 2 != %v\n", count) + } +} + +func TestCounterSnapshot(t *testing.T) { + c := NewCounter() + c.Inc(1) + snapshot := c.Snapshot() + c.Inc(1) + if count := snapshot.Count(); 1 != count { + t.Errorf("c.Count(): 1 != %v\n", count) + } +} + +func TestCounterZero(t *testing.T) { + c := NewCounter() + if count := c.Count(); 0 != count { + t.Errorf("c.Count(): 0 != %v\n", count) + } +} + +func TestGetOrRegisterCounter(t *testing.T) { + r := NewRegistry() + NewRegisteredCounter("foo", r).Inc(47) + if c := GetOrRegisterCounter("foo", r); 47 != c.Count() { + t.Fatal(c) + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/debug.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/debug.go new file mode 100644 index 0000000000..043ccefab6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/debug.go @@ -0,0 +1,76 @@ +package metrics + +import ( + "runtime/debug" + "time" +) + +var ( + debugMetrics struct { + GCStats struct { + LastGC Gauge + NumGC Gauge + Pause Histogram + //PauseQuantiles Histogram + PauseTotal Gauge + } + ReadGCStats Timer + } + gcStats debug.GCStats +) + +// Capture new values for the Go garbage collector statistics exported in +// debug.GCStats. This is designed to be called as a goroutine. +func CaptureDebugGCStats(r Registry, d time.Duration) { + for _ = range time.Tick(d) { + CaptureDebugGCStatsOnce(r) + } +} + +// Capture new values for the Go garbage collector statistics exported in +// debug.GCStats. This is designed to be called in a background goroutine. +// Giving a registry which has not been given to RegisterDebugGCStats will +// panic. +// +// Be careful (but much less so) with this because debug.ReadGCStats calls +// the C function runtime·lock(runtime·mheap) which, while not a stop-the-world +// operation, isn't something you want to be doing all the time. +func CaptureDebugGCStatsOnce(r Registry) { + lastGC := gcStats.LastGC + t := time.Now() + debug.ReadGCStats(&gcStats) + debugMetrics.ReadGCStats.UpdateSince(t) + + debugMetrics.GCStats.LastGC.Update(int64(gcStats.LastGC.UnixNano())) + debugMetrics.GCStats.NumGC.Update(int64(gcStats.NumGC)) + if lastGC != gcStats.LastGC && 0 < len(gcStats.Pause) { + debugMetrics.GCStats.Pause.Update(int64(gcStats.Pause[0])) + } + //debugMetrics.GCStats.PauseQuantiles.Update(gcStats.PauseQuantiles) + debugMetrics.GCStats.PauseTotal.Update(int64(gcStats.PauseTotal)) +} + +// Register metrics for the Go garbage collector statistics exported in +// debug.GCStats. The metrics are named by their fully-qualified Go symbols, +// i.e. debug.GCStats.PauseTotal. +func RegisterDebugGCStats(r Registry) { + debugMetrics.GCStats.LastGC = NewGauge() + debugMetrics.GCStats.NumGC = NewGauge() + debugMetrics.GCStats.Pause = NewHistogram(NewExpDecaySample(1028, 0.015)) + //debugMetrics.GCStats.PauseQuantiles = NewHistogram(NewExpDecaySample(1028, 0.015)) + debugMetrics.GCStats.PauseTotal = NewGauge() + debugMetrics.ReadGCStats = NewTimer() + + r.Register("debug.GCStats.LastGC", debugMetrics.GCStats.LastGC) + r.Register("debug.GCStats.NumGC", debugMetrics.GCStats.NumGC) + r.Register("debug.GCStats.Pause", debugMetrics.GCStats.Pause) + //r.Register("debug.GCStats.PauseQuantiles", debugMetrics.GCStats.PauseQuantiles) + r.Register("debug.GCStats.PauseTotal", debugMetrics.GCStats.PauseTotal) + r.Register("debug.ReadGCStats", debugMetrics.ReadGCStats) +} + +// Allocate an initial slice for gcStats.Pause to avoid allocations during +// normal operation. +func init() { + gcStats.Pause = make([]time.Duration, 11) +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/debug_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/debug_test.go new file mode 100644 index 0000000000..07eb867841 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/debug_test.go @@ -0,0 +1,48 @@ +package metrics + +import ( + "runtime" + "runtime/debug" + "testing" + "time" +) + +func BenchmarkDebugGCStats(b *testing.B) { + r := NewRegistry() + RegisterDebugGCStats(r) + b.ResetTimer() + for i := 0; i < b.N; i++ { + CaptureDebugGCStatsOnce(r) + } +} + +func TestDebugGCStatsBlocking(t *testing.T) { + if g := runtime.GOMAXPROCS(0); g < 2 { + t.Skipf("skipping TestDebugGCMemStatsBlocking with GOMAXPROCS=%d\n", g) + return + } + ch := make(chan int) + go testDebugGCStatsBlocking(ch) + var gcStats debug.GCStats + t0 := time.Now() + debug.ReadGCStats(&gcStats) + t1 := time.Now() + t.Log("i++ during debug.ReadGCStats:", <-ch) + go testDebugGCStatsBlocking(ch) + d := t1.Sub(t0) + t.Log(d) + time.Sleep(d) + t.Log("i++ during time.Sleep:", <-ch) +} + +func testDebugGCStatsBlocking(ch chan int) { + i := 0 + for { + select { + case ch <- i: + return + default: + i++ + } + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma.go new file mode 100644 index 0000000000..7c152a174a --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma.go @@ -0,0 +1,118 @@ +package metrics + +import ( + "math" + "sync" + "sync/atomic" +) + +// EWMAs continuously calculate an exponentially-weighted moving average +// based on an outside source of clock ticks. +type EWMA interface { + Rate() float64 + Snapshot() EWMA + Tick() + Update(int64) +} + +// NewEWMA constructs a new EWMA with the given alpha. +func NewEWMA(alpha float64) EWMA { + if UseNilMetrics { + return NilEWMA{} + } + return &StandardEWMA{alpha: alpha} +} + +// NewEWMA1 constructs a new EWMA for a one-minute moving average. +func NewEWMA1() EWMA { + return NewEWMA(1 - math.Exp(-5.0/60.0/1)) +} + +// NewEWMA5 constructs a new EWMA for a five-minute moving average. +func NewEWMA5() EWMA { + return NewEWMA(1 - math.Exp(-5.0/60.0/5)) +} + +// NewEWMA15 constructs a new EWMA for a fifteen-minute moving average. +func NewEWMA15() EWMA { + return NewEWMA(1 - math.Exp(-5.0/60.0/15)) +} + +// EWMASnapshot is a read-only copy of another EWMA. +type EWMASnapshot float64 + +// Rate returns the rate of events per second at the time the snapshot was +// taken. +func (a EWMASnapshot) Rate() float64 { return float64(a) } + +// Snapshot returns the snapshot. +func (a EWMASnapshot) Snapshot() EWMA { return a } + +// Tick panics. +func (EWMASnapshot) Tick() { + panic("Tick called on an EWMASnapshot") +} + +// Update panics. +func (EWMASnapshot) Update(int64) { + panic("Update called on an EWMASnapshot") +} + +// NilEWMA is a no-op EWMA. +type NilEWMA struct{} + +// Rate is a no-op. +func (NilEWMA) Rate() float64 { return 0.0 } + +// Snapshot is a no-op. +func (NilEWMA) Snapshot() EWMA { return NilEWMA{} } + +// Tick is a no-op. +func (NilEWMA) Tick() {} + +// Update is a no-op. +func (NilEWMA) Update(n int64) {} + +// StandardEWMA is the standard implementation of an EWMA and tracks the number +// of uncounted events and processes them on each tick. It uses the +// sync/atomic package to manage uncounted events. +type StandardEWMA struct { + uncounted int64 // /!\ this should be the first member to ensure 64-bit alignment + alpha float64 + rate float64 + init bool + mutex sync.Mutex +} + +// Rate returns the moving average rate of events per second. +func (a *StandardEWMA) Rate() float64 { + a.mutex.Lock() + defer a.mutex.Unlock() + return a.rate * float64(1e9) +} + +// Snapshot returns a read-only copy of the EWMA. +func (a *StandardEWMA) Snapshot() EWMA { + return EWMASnapshot(a.Rate()) +} + +// Tick ticks the clock to update the moving average. It assumes it is called +// every five seconds. +func (a *StandardEWMA) Tick() { + count := atomic.LoadInt64(&a.uncounted) + atomic.AddInt64(&a.uncounted, -count) + instantRate := float64(count) / float64(5e9) + a.mutex.Lock() + defer a.mutex.Unlock() + if a.init { + a.rate += a.alpha * (instantRate - a.rate) + } else { + a.init = true + a.rate = instantRate + } +} + +// Update adds n uncounted events. +func (a *StandardEWMA) Update(n int64) { + atomic.AddInt64(&a.uncounted, n) +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma_test.go new file mode 100644 index 0000000000..0430fbd247 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma_test.go @@ -0,0 +1,225 @@ +package metrics + +import "testing" + +func BenchmarkEWMA(b *testing.B) { + a := NewEWMA1() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Update(1) + a.Tick() + } +} + +func TestEWMA1(t *testing.T) { + a := NewEWMA1() + a.Update(3) + a.Tick() + if rate := a.Rate(); 0.6 != rate { + t.Errorf("initial a.Rate(): 0.6 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.22072766470286553 != rate { + t.Errorf("1 minute a.Rate(): 0.22072766470286553 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.08120116994196772 != rate { + t.Errorf("2 minute a.Rate(): 0.08120116994196772 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.029872241020718428 != rate { + t.Errorf("3 minute a.Rate(): 0.029872241020718428 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.01098938333324054 != rate { + t.Errorf("4 minute a.Rate(): 0.01098938333324054 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.004042768199451294 != rate { + t.Errorf("5 minute a.Rate(): 0.004042768199451294 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.0014872513059998212 != rate { + t.Errorf("6 minute a.Rate(): 0.0014872513059998212 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.0005471291793327122 != rate { + t.Errorf("7 minute a.Rate(): 0.0005471291793327122 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.00020127757674150815 != rate { + t.Errorf("8 minute a.Rate(): 0.00020127757674150815 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 7.404588245200814e-05 != rate { + t.Errorf("9 minute a.Rate(): 7.404588245200814e-05 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 2.7239957857491083e-05 != rate { + t.Errorf("10 minute a.Rate(): 2.7239957857491083e-05 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 1.0021020474147462e-05 != rate { + t.Errorf("11 minute a.Rate(): 1.0021020474147462e-05 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 3.6865274119969525e-06 != rate { + t.Errorf("12 minute a.Rate(): 3.6865274119969525e-06 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 1.3561976441886433e-06 != rate { + t.Errorf("13 minute a.Rate(): 1.3561976441886433e-06 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 4.989172314621449e-07 != rate { + t.Errorf("14 minute a.Rate(): 4.989172314621449e-07 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 1.8354139230109722e-07 != rate { + t.Errorf("15 minute a.Rate(): 1.8354139230109722e-07 != %v\n", rate) + } +} + +func TestEWMA5(t *testing.T) { + a := NewEWMA5() + a.Update(3) + a.Tick() + if rate := a.Rate(); 0.6 != rate { + t.Errorf("initial a.Rate(): 0.6 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.49123845184678905 != rate { + t.Errorf("1 minute a.Rate(): 0.49123845184678905 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.4021920276213837 != rate { + t.Errorf("2 minute a.Rate(): 0.4021920276213837 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.32928698165641596 != rate { + t.Errorf("3 minute a.Rate(): 0.32928698165641596 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.269597378470333 != rate { + t.Errorf("4 minute a.Rate(): 0.269597378470333 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.2207276647028654 != rate { + t.Errorf("5 minute a.Rate(): 0.2207276647028654 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.18071652714732128 != rate { + t.Errorf("6 minute a.Rate(): 0.18071652714732128 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.14795817836496392 != rate { + t.Errorf("7 minute a.Rate(): 0.14795817836496392 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.12113791079679326 != rate { + t.Errorf("8 minute a.Rate(): 0.12113791079679326 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.09917933293295193 != rate { + t.Errorf("9 minute a.Rate(): 0.09917933293295193 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.08120116994196763 != rate { + t.Errorf("10 minute a.Rate(): 0.08120116994196763 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.06648189501740036 != rate { + t.Errorf("11 minute a.Rate(): 0.06648189501740036 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.05443077197364752 != rate { + t.Errorf("12 minute a.Rate(): 0.05443077197364752 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.04456414692860035 != rate { + t.Errorf("13 minute a.Rate(): 0.04456414692860035 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.03648603757513079 != rate { + t.Errorf("14 minute a.Rate(): 0.03648603757513079 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.0298722410207183831020718428 != rate { + t.Errorf("15 minute a.Rate(): 0.0298722410207183831020718428 != %v\n", rate) + } +} + +func TestEWMA15(t *testing.T) { + a := NewEWMA15() + a.Update(3) + a.Tick() + if rate := a.Rate(); 0.6 != rate { + t.Errorf("initial a.Rate(): 0.6 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.5613041910189706 != rate { + t.Errorf("1 minute a.Rate(): 0.5613041910189706 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.5251039914257684 != rate { + t.Errorf("2 minute a.Rate(): 0.5251039914257684 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.4912384518467888184678905 != rate { + t.Errorf("3 minute a.Rate(): 0.4912384518467888184678905 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.459557003018789 != rate { + t.Errorf("4 minute a.Rate(): 0.459557003018789 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.4299187863442732 != rate { + t.Errorf("5 minute a.Rate(): 0.4299187863442732 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.4021920276213831 != rate { + t.Errorf("6 minute a.Rate(): 0.4021920276213831 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.37625345116383313 != rate { + t.Errorf("7 minute a.Rate(): 0.37625345116383313 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.3519877317060185 != rate { + t.Errorf("8 minute a.Rate(): 0.3519877317060185 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.3292869816564153165641596 != rate { + t.Errorf("9 minute a.Rate(): 0.3292869816564153165641596 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.3080502714195546 != rate { + t.Errorf("10 minute a.Rate(): 0.3080502714195546 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.2881831806538789 != rate { + t.Errorf("11 minute a.Rate(): 0.2881831806538789 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.26959737847033216 != rate { + t.Errorf("12 minute a.Rate(): 0.26959737847033216 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.2522102307052083 != rate { + t.Errorf("13 minute a.Rate(): 0.2522102307052083 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.23594443252115815 != rate { + t.Errorf("14 minute a.Rate(): 0.23594443252115815 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.2207276647028646247028654470286553 != rate { + t.Errorf("15 minute a.Rate(): 0.2207276647028646247028654470286553 != %v\n", rate) + } +} + +func elapseMinute(a EWMA) { + for i := 0; i < 12; i++ { + a.Tick() + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge.go new file mode 100644 index 0000000000..807638a31b --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge.go @@ -0,0 +1,84 @@ +package metrics + +import "sync/atomic" + +// Gauges hold an int64 value that can be set arbitrarily. +type Gauge interface { + Snapshot() Gauge + Update(int64) + Value() int64 +} + +// GetOrRegisterGauge returns an existing Gauge or constructs and registers a +// new StandardGauge. +func GetOrRegisterGauge(name string, r Registry) Gauge { + if nil == r { + r = DefaultRegistry + } + return r.GetOrRegister(name, NewGauge).(Gauge) +} + +// NewGauge constructs a new StandardGauge. +func NewGauge() Gauge { + if UseNilMetrics { + return NilGauge{} + } + return &StandardGauge{0} +} + +// NewRegisteredGauge constructs and registers a new StandardGauge. +func NewRegisteredGauge(name string, r Registry) Gauge { + c := NewGauge() + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + +// GaugeSnapshot is a read-only copy of another Gauge. +type GaugeSnapshot int64 + +// Snapshot returns the snapshot. +func (g GaugeSnapshot) Snapshot() Gauge { return g } + +// Update panics. +func (GaugeSnapshot) Update(int64) { + panic("Update called on a GaugeSnapshot") +} + +// Value returns the value at the time the snapshot was taken. +func (g GaugeSnapshot) Value() int64 { return int64(g) } + +// NilGauge is a no-op Gauge. +type NilGauge struct{} + +// Snapshot is a no-op. +func (NilGauge) Snapshot() Gauge { return NilGauge{} } + +// Update is a no-op. +func (NilGauge) Update(v int64) {} + +// Value is a no-op. +func (NilGauge) Value() int64 { return 0 } + +// StandardGauge is the standard implementation of a Gauge and uses the +// sync/atomic package to manage a single int64 value. +type StandardGauge struct { + value int64 +} + +// Snapshot returns a read-only copy of the gauge. +func (g *StandardGauge) Snapshot() Gauge { + return GaugeSnapshot(g.Value()) +} + +// Update updates the gauge's value. +func (g *StandardGauge) Update(v int64) { + atomic.StoreInt64(&g.value, v) +} + +// Value returns the gauge's current value. +func (g *StandardGauge) Value() int64 { + return atomic.LoadInt64(&g.value) +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_float64.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_float64.go new file mode 100644 index 0000000000..47c3566c25 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_float64.go @@ -0,0 +1,91 @@ +package metrics + +import "sync" + +// GaugeFloat64s hold a float64 value that can be set arbitrarily. +type GaugeFloat64 interface { + Snapshot() GaugeFloat64 + Update(float64) + Value() float64 +} + +// GetOrRegisterGaugeFloat64 returns an existing GaugeFloat64 or constructs and registers a +// new StandardGaugeFloat64. +func GetOrRegisterGaugeFloat64(name string, r Registry) GaugeFloat64 { + if nil == r { + r = DefaultRegistry + } + return r.GetOrRegister(name, NewGaugeFloat64()).(GaugeFloat64) +} + +// NewGaugeFloat64 constructs a new StandardGaugeFloat64. +func NewGaugeFloat64() GaugeFloat64 { + if UseNilMetrics { + return NilGaugeFloat64{} + } + return &StandardGaugeFloat64{ + value: 0.0, + } +} + +// NewRegisteredGaugeFloat64 constructs and registers a new StandardGaugeFloat64. +func NewRegisteredGaugeFloat64(name string, r Registry) GaugeFloat64 { + c := NewGaugeFloat64() + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + +// GaugeFloat64Snapshot is a read-only copy of another GaugeFloat64. +type GaugeFloat64Snapshot float64 + +// Snapshot returns the snapshot. +func (g GaugeFloat64Snapshot) Snapshot() GaugeFloat64 { return g } + +// Update panics. +func (GaugeFloat64Snapshot) Update(float64) { + panic("Update called on a GaugeFloat64Snapshot") +} + +// Value returns the value at the time the snapshot was taken. +func (g GaugeFloat64Snapshot) Value() float64 { return float64(g) } + +// NilGauge is a no-op Gauge. +type NilGaugeFloat64 struct{} + +// Snapshot is a no-op. +func (NilGaugeFloat64) Snapshot() GaugeFloat64 { return NilGaugeFloat64{} } + +// Update is a no-op. +func (NilGaugeFloat64) Update(v float64) {} + +// Value is a no-op. +func (NilGaugeFloat64) Value() float64 { return 0.0 } + +// StandardGaugeFloat64 is the standard implementation of a GaugeFloat64 and uses +// sync.Mutex to manage a single float64 value. +type StandardGaugeFloat64 struct { + mutex sync.Mutex + value float64 +} + +// Snapshot returns a read-only copy of the gauge. +func (g *StandardGaugeFloat64) Snapshot() GaugeFloat64 { + return GaugeFloat64Snapshot(g.Value()) +} + +// Update updates the gauge's value. +func (g *StandardGaugeFloat64) Update(v float64) { + g.mutex.Lock() + defer g.mutex.Unlock() + g.value = v +} + +// Value returns the gauge's current value. +func (g *StandardGaugeFloat64) Value() float64 { + g.mutex.Lock() + defer g.mutex.Unlock() + return g.value +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_float64_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_float64_test.go new file mode 100644 index 0000000000..5d0aae271b --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_float64_test.go @@ -0,0 +1,38 @@ +package metrics + +import "testing" + +func BenchmarkGuageFloat64(b *testing.B) { + g := NewGaugeFloat64() + b.ResetTimer() + for i := 0; i < b.N; i++ { + g.Update(float64(i)) + } +} + +func TestGaugeFloat64(t *testing.T) { + g := NewGaugeFloat64() + g.Update(float64(47.0)) + if v := g.Value(); float64(47.0) != v { + t.Errorf("g.Value(): 47.0 != %v\n", v) + } +} + +func TestGaugeFloat64Snapshot(t *testing.T) { + g := NewGaugeFloat64() + g.Update(float64(47.0)) + snapshot := g.Snapshot() + g.Update(float64(0)) + if v := snapshot.Value(); float64(47.0) != v { + t.Errorf("g.Value(): 47.0 != %v\n", v) + } +} + +func TestGetOrRegisterGaugeFloat64(t *testing.T) { + r := NewRegistry() + NewRegisteredGaugeFloat64("foo", r).Update(float64(47.0)) + t.Logf("registry: %v", r) + if g := GetOrRegisterGaugeFloat64("foo", r); float64(47.0) != g.Value() { + t.Fatal(g) + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_test.go new file mode 100644 index 0000000000..5084962918 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_test.go @@ -0,0 +1,37 @@ +package metrics + +import "testing" + +func BenchmarkGuage(b *testing.B) { + g := NewGauge() + b.ResetTimer() + for i := 0; i < b.N; i++ { + g.Update(int64(i)) + } +} + +func TestGauge(t *testing.T) { + g := NewGauge() + g.Update(int64(47)) + if v := g.Value(); 47 != v { + t.Errorf("g.Value(): 47 != %v\n", v) + } +} + +func TestGaugeSnapshot(t *testing.T) { + g := NewGauge() + g.Update(int64(47)) + snapshot := g.Snapshot() + g.Update(int64(0)) + if v := snapshot.Value(); 47 != v { + t.Errorf("g.Value(): 47 != %v\n", v) + } +} + +func TestGetOrRegisterGauge(t *testing.T) { + r := NewRegistry() + NewRegisteredGauge("foo", r).Update(47) + if g := GetOrRegisterGauge("foo", r); 47 != g.Value() { + t.Fatal(g) + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite.go new file mode 100644 index 0000000000..604b26da05 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite.go @@ -0,0 +1,111 @@ +package metrics + +import ( + "bufio" + "fmt" + "log" + "net" + "strconv" + "strings" + "time" +) + +// GraphiteConfig provides a container with configuration parameters for +// the Graphite exporter +type GraphiteConfig struct { + Addr *net.TCPAddr // Network address to connect to + Registry Registry // Registry to be exported + FlushInterval time.Duration // Flush interval + DurationUnit time.Duration // Time conversion unit for durations + Prefix string // Prefix to be prepended to metric names + Percentiles []float64 // Percentiles to export from timers and histograms +} + +// Graphite is a blocking exporter function which reports metrics in r +// to a graphite server located at addr, flushing them every d duration +// and prepending metric names with prefix. +func Graphite(r Registry, d time.Duration, prefix string, addr *net.TCPAddr) { + GraphiteWithConfig(GraphiteConfig{ + Addr: addr, + Registry: r, + FlushInterval: d, + DurationUnit: time.Nanosecond, + Prefix: prefix, + Percentiles: []float64{0.5, 0.75, 0.95, 0.99, 0.999}, + }) +} + +// GraphiteWithConfig is a blocking exporter function just like Graphite, +// but it takes a GraphiteConfig instead. +func GraphiteWithConfig(c GraphiteConfig) { + for _ = range time.Tick(c.FlushInterval) { + if err := graphite(&c); nil != err { + log.Println(err) + } + } +} + +// GraphiteOnce performs a single submission to Graphite, returning a +// non-nil error on failed connections. This can be used in a loop +// similar to GraphiteWithConfig for custom error handling. +func GraphiteOnce(c GraphiteConfig) error { + return graphite(&c) +} + +func graphite(c *GraphiteConfig) error { + now := time.Now().Unix() + du := float64(c.DurationUnit) + conn, err := net.DialTCP("tcp", nil, c.Addr) + if nil != err { + return err + } + defer conn.Close() + w := bufio.NewWriter(conn) + c.Registry.Each(func(name string, i interface{}) { + switch metric := i.(type) { + case Counter: + fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, metric.Count(), now) + case Gauge: + fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Value(), now) + case GaugeFloat64: + fmt.Fprintf(w, "%s.%s.value %f %d\n", c.Prefix, name, metric.Value(), now) + case Histogram: + h := metric.Snapshot() + ps := h.Percentiles(c.Percentiles) + fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, h.Count(), now) + fmt.Fprintf(w, "%s.%s.min %d %d\n", c.Prefix, name, h.Min(), now) + fmt.Fprintf(w, "%s.%s.max %d %d\n", c.Prefix, name, h.Max(), now) + fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, h.Mean(), now) + fmt.Fprintf(w, "%s.%s.std-dev %.2f %d\n", c.Prefix, name, h.StdDev(), now) + for psIdx, psKey := range c.Percentiles { + key := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1) + fmt.Fprintf(w, "%s.%s.%s-percentile %.2f %d\n", c.Prefix, name, key, ps[psIdx], now) + } + case Meter: + m := metric.Snapshot() + fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, m.Count(), now) + fmt.Fprintf(w, "%s.%s.one-minute %.2f %d\n", c.Prefix, name, m.Rate1(), now) + fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, m.Rate5(), now) + fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, m.Rate15(), now) + fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, m.RateMean(), now) + case Timer: + t := metric.Snapshot() + ps := t.Percentiles(c.Percentiles) + fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, t.Count(), now) + fmt.Fprintf(w, "%s.%s.min %d %d\n", c.Prefix, name, t.Min()/int64(du), now) + fmt.Fprintf(w, "%s.%s.max %d %d\n", c.Prefix, name, t.Max()/int64(du), now) + fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, t.Mean()/du, now) + fmt.Fprintf(w, "%s.%s.std-dev %.2f %d\n", c.Prefix, name, t.StdDev()/du, now) + for psIdx, psKey := range c.Percentiles { + key := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1) + fmt.Fprintf(w, "%s.%s.%s-percentile %.2f %d\n", c.Prefix, name, key, ps[psIdx], now) + } + fmt.Fprintf(w, "%s.%s.one-minute %.2f %d\n", c.Prefix, name, t.Rate1(), now) + fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, t.Rate5(), now) + fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, t.Rate15(), now) + fmt.Fprintf(w, "%s.%s.mean-rate %.2f %d\n", c.Prefix, name, t.RateMean(), now) + } + w.Flush() + }) + return nil +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite_test.go new file mode 100644 index 0000000000..b49dc4bb56 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite_test.go @@ -0,0 +1,22 @@ +package metrics + +import ( + "net" + "time" +) + +func ExampleGraphite() { + addr, _ := net.ResolveTCPAddr("net", ":2003") + go Graphite(DefaultRegistry, 1*time.Second, "some.prefix", addr) +} + +func ExampleGraphiteWithConfig() { + addr, _ := net.ResolveTCPAddr("net", ":2003") + go GraphiteWithConfig(GraphiteConfig{ + Addr: addr, + Registry: DefaultRegistry, + FlushInterval: 1 * time.Second, + DurationUnit: time.Millisecond, + Percentiles: []float64{ 0.5, 0.75, 0.99, 0.999 }, + }) +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/healthcheck.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/healthcheck.go new file mode 100644 index 0000000000..445131caee --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/healthcheck.go @@ -0,0 +1,61 @@ +package metrics + +// Healthchecks hold an error value describing an arbitrary up/down status. +type Healthcheck interface { + Check() + Error() error + Healthy() + Unhealthy(error) +} + +// NewHealthcheck constructs a new Healthcheck which will use the given +// function to update its status. +func NewHealthcheck(f func(Healthcheck)) Healthcheck { + if UseNilMetrics { + return NilHealthcheck{} + } + return &StandardHealthcheck{nil, f} +} + +// NilHealthcheck is a no-op. +type NilHealthcheck struct{} + +// Check is a no-op. +func (NilHealthcheck) Check() {} + +// Error is a no-op. +func (NilHealthcheck) Error() error { return nil } + +// Healthy is a no-op. +func (NilHealthcheck) Healthy() {} + +// Unhealthy is a no-op. +func (NilHealthcheck) Unhealthy(error) {} + +// StandardHealthcheck is the standard implementation of a Healthcheck and +// stores the status and a function to call to update the status. +type StandardHealthcheck struct { + err error + f func(Healthcheck) +} + +// Check runs the healthcheck function to update the healthcheck's status. +func (h *StandardHealthcheck) Check() { + h.f(h) +} + +// Error returns the healthcheck's status, which will be nil if it is healthy. +func (h *StandardHealthcheck) Error() error { + return h.err +} + +// Healthy marks the healthcheck as healthy. +func (h *StandardHealthcheck) Healthy() { + h.err = nil +} + +// Unhealthy marks the healthcheck as unhealthy. The error is stored and +// may be retrieved by the Error method. +func (h *StandardHealthcheck) Unhealthy(err error) { + h.err = err +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/histogram.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/histogram.go new file mode 100644 index 0000000000..dbc837fe4d --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/histogram.go @@ -0,0 +1,202 @@ +package metrics + +// Histograms calculate distribution statistics from a series of int64 values. +type Histogram interface { + Clear() + Count() int64 + Max() int64 + Mean() float64 + Min() int64 + Percentile(float64) float64 + Percentiles([]float64) []float64 + Sample() Sample + Snapshot() Histogram + StdDev() float64 + Sum() int64 + Update(int64) + Variance() float64 +} + +// GetOrRegisterHistogram returns an existing Histogram or constructs and +// registers a new StandardHistogram. +func GetOrRegisterHistogram(name string, r Registry, s Sample) Histogram { + if nil == r { + r = DefaultRegistry + } + return r.GetOrRegister(name, func() Histogram { return NewHistogram(s) }).(Histogram) +} + +// NewHistogram constructs a new StandardHistogram from a Sample. +func NewHistogram(s Sample) Histogram { + if UseNilMetrics { + return NilHistogram{} + } + return &StandardHistogram{sample: s} +} + +// NewRegisteredHistogram constructs and registers a new StandardHistogram from +// a Sample. +func NewRegisteredHistogram(name string, r Registry, s Sample) Histogram { + c := NewHistogram(s) + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + +// HistogramSnapshot is a read-only copy of another Histogram. +type HistogramSnapshot struct { + sample *SampleSnapshot +} + +// Clear panics. +func (*HistogramSnapshot) Clear() { + panic("Clear called on a HistogramSnapshot") +} + +// Count returns the number of samples recorded at the time the snapshot was +// taken. +func (h *HistogramSnapshot) Count() int64 { return h.sample.Count() } + +// Max returns the maximum value in the sample at the time the snapshot was +// taken. +func (h *HistogramSnapshot) Max() int64 { return h.sample.Max() } + +// Mean returns the mean of the values in the sample at the time the snapshot +// was taken. +func (h *HistogramSnapshot) Mean() float64 { return h.sample.Mean() } + +// Min returns the minimum value in the sample at the time the snapshot was +// taken. +func (h *HistogramSnapshot) Min() int64 { return h.sample.Min() } + +// Percentile returns an arbitrary percentile of values in the sample at the +// time the snapshot was taken. +func (h *HistogramSnapshot) Percentile(p float64) float64 { + return h.sample.Percentile(p) +} + +// Percentiles returns a slice of arbitrary percentiles of values in the sample +// at the time the snapshot was taken. +func (h *HistogramSnapshot) Percentiles(ps []float64) []float64 { + return h.sample.Percentiles(ps) +} + +// Sample returns the Sample underlying the histogram. +func (h *HistogramSnapshot) Sample() Sample { return h.sample } + +// Snapshot returns the snapshot. +func (h *HistogramSnapshot) Snapshot() Histogram { return h } + +// StdDev returns the standard deviation of the values in the sample at the +// time the snapshot was taken. +func (h *HistogramSnapshot) StdDev() float64 { return h.sample.StdDev() } + +// Sum returns the sum in the sample at the time the snapshot was taken. +func (h *HistogramSnapshot) Sum() int64 { return h.sample.Sum() } + +// Update panics. +func (*HistogramSnapshot) Update(int64) { + panic("Update called on a HistogramSnapshot") +} + +// Variance returns the variance of inputs at the time the snapshot was taken. +func (h *HistogramSnapshot) Variance() float64 { return h.sample.Variance() } + +// NilHistogram is a no-op Histogram. +type NilHistogram struct{} + +// Clear is a no-op. +func (NilHistogram) Clear() {} + +// Count is a no-op. +func (NilHistogram) Count() int64 { return 0 } + +// Max is a no-op. +func (NilHistogram) Max() int64 { return 0 } + +// Mean is a no-op. +func (NilHistogram) Mean() float64 { return 0.0 } + +// Min is a no-op. +func (NilHistogram) Min() int64 { return 0 } + +// Percentile is a no-op. +func (NilHistogram) Percentile(p float64) float64 { return 0.0 } + +// Percentiles is a no-op. +func (NilHistogram) Percentiles(ps []float64) []float64 { + return make([]float64, len(ps)) +} + +// Sample is a no-op. +func (NilHistogram) Sample() Sample { return NilSample{} } + +// Snapshot is a no-op. +func (NilHistogram) Snapshot() Histogram { return NilHistogram{} } + +// StdDev is a no-op. +func (NilHistogram) StdDev() float64 { return 0.0 } + +// Sum is a no-op. +func (NilHistogram) Sum() int64 { return 0 } + +// Update is a no-op. +func (NilHistogram) Update(v int64) {} + +// Variance is a no-op. +func (NilHistogram) Variance() float64 { return 0.0 } + +// StandardHistogram is the standard implementation of a Histogram and uses a +// Sample to bound its memory use. +type StandardHistogram struct { + sample Sample +} + +// Clear clears the histogram and its sample. +func (h *StandardHistogram) Clear() { h.sample.Clear() } + +// Count returns the number of samples recorded since the histogram was last +// cleared. +func (h *StandardHistogram) Count() int64 { return h.sample.Count() } + +// Max returns the maximum value in the sample. +func (h *StandardHistogram) Max() int64 { return h.sample.Max() } + +// Mean returns the mean of the values in the sample. +func (h *StandardHistogram) Mean() float64 { return h.sample.Mean() } + +// Min returns the minimum value in the sample. +func (h *StandardHistogram) Min() int64 { return h.sample.Min() } + +// Percentile returns an arbitrary percentile of the values in the sample. +func (h *StandardHistogram) Percentile(p float64) float64 { + return h.sample.Percentile(p) +} + +// Percentiles returns a slice of arbitrary percentiles of the values in the +// sample. +func (h *StandardHistogram) Percentiles(ps []float64) []float64 { + return h.sample.Percentiles(ps) +} + +// Sample returns the Sample underlying the histogram. +func (h *StandardHistogram) Sample() Sample { return h.sample } + +// Snapshot returns a read-only copy of the histogram. +func (h *StandardHistogram) Snapshot() Histogram { + return &HistogramSnapshot{sample: h.sample.Snapshot().(*SampleSnapshot)} +} + +// StdDev returns the standard deviation of the values in the sample. +func (h *StandardHistogram) StdDev() float64 { return h.sample.StdDev() } + +// Sum returns the sum in the sample. +func (h *StandardHistogram) Sum() int64 { return h.sample.Sum() } + +// Update samples a new value. +func (h *StandardHistogram) Update(v int64) { h.sample.Update(v) } + +// Variance returns the variance of the values in the sample. +func (h *StandardHistogram) Variance() float64 { return h.sample.Variance() } diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/histogram_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/histogram_test.go new file mode 100644 index 0000000000..d7f4f0171c --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/histogram_test.go @@ -0,0 +1,95 @@ +package metrics + +import "testing" + +func BenchmarkHistogram(b *testing.B) { + h := NewHistogram(NewUniformSample(100)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + h.Update(int64(i)) + } +} + +func TestGetOrRegisterHistogram(t *testing.T) { + r := NewRegistry() + s := NewUniformSample(100) + NewRegisteredHistogram("foo", r, s).Update(47) + if h := GetOrRegisterHistogram("foo", r, s); 1 != h.Count() { + t.Fatal(h) + } +} + +func TestHistogram10000(t *testing.T) { + h := NewHistogram(NewUniformSample(100000)) + for i := 1; i <= 10000; i++ { + h.Update(int64(i)) + } + testHistogram10000(t, h) +} + +func TestHistogramEmpty(t *testing.T) { + h := NewHistogram(NewUniformSample(100)) + if count := h.Count(); 0 != count { + t.Errorf("h.Count(): 0 != %v\n", count) + } + if min := h.Min(); 0 != min { + t.Errorf("h.Min(): 0 != %v\n", min) + } + if max := h.Max(); 0 != max { + t.Errorf("h.Max(): 0 != %v\n", max) + } + if mean := h.Mean(); 0.0 != mean { + t.Errorf("h.Mean(): 0.0 != %v\n", mean) + } + if stdDev := h.StdDev(); 0.0 != stdDev { + t.Errorf("h.StdDev(): 0.0 != %v\n", stdDev) + } + ps := h.Percentiles([]float64{0.5, 0.75, 0.99}) + if 0.0 != ps[0] { + t.Errorf("median: 0.0 != %v\n", ps[0]) + } + if 0.0 != ps[1] { + t.Errorf("75th percentile: 0.0 != %v\n", ps[1]) + } + if 0.0 != ps[2] { + t.Errorf("99th percentile: 0.0 != %v\n", ps[2]) + } +} + +func TestHistogramSnapshot(t *testing.T) { + h := NewHistogram(NewUniformSample(100000)) + for i := 1; i <= 10000; i++ { + h.Update(int64(i)) + } + snapshot := h.Snapshot() + h.Update(0) + testHistogram10000(t, snapshot) +} + +func testHistogram10000(t *testing.T, h Histogram) { + if count := h.Count(); 10000 != count { + t.Errorf("h.Count(): 10000 != %v\n", count) + } + if min := h.Min(); 1 != min { + t.Errorf("h.Min(): 1 != %v\n", min) + } + if max := h.Max(); 10000 != max { + t.Errorf("h.Max(): 10000 != %v\n", max) + } + if mean := h.Mean(); 5000.5 != mean { + t.Errorf("h.Mean(): 5000.5 != %v\n", mean) + } + if stdDev := h.StdDev(); 2886.751331514372 != stdDev { + t.Errorf("h.StdDev(): 2886.751331514372 != %v\n", stdDev) + } + ps := h.Percentiles([]float64{0.5, 0.75, 0.99}) + if 5000.5 != ps[0] { + t.Errorf("median: 5000.5 != %v\n", ps[0]) + } + if 7500.75 != ps[1] { + t.Errorf("75th percentile: 7500.75 != %v\n", ps[1]) + } + if 9900.99 != ps[2] { + t.Errorf("99th percentile: 9900.99 != %v\n", ps[2]) + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/influxdb/influxdb.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/influxdb/influxdb.go new file mode 100644 index 0000000000..0163c9b429 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/influxdb/influxdb.go @@ -0,0 +1,114 @@ +package influxdb + +import ( + "fmt" + influxClient "github.com/influxdb/influxdb/client" + "github.com/rcrowley/go-metrics" + "log" + "time" +) + +type Config struct { + Host string + Database string + Username string + Password string +} + +func Influxdb(r metrics.Registry, d time.Duration, config *Config) { + client, err := influxClient.NewClient(&influxClient.ClientConfig{ + Host: config.Host, + Database: config.Database, + Username: config.Username, + Password: config.Password, + }) + if err != nil { + log.Println(err) + return + } + + for _ = range time.Tick(d) { + if err := send(r, client); err != nil { + log.Println(err) + } + } +} + +func send(r metrics.Registry, client *influxClient.Client) error { + series := []*influxClient.Series{} + + r.Each(func(name string, i interface{}) { + now := getCurrentTime() + switch metric := i.(type) { + case metrics.Counter: + series = append(series, &influxClient.Series{ + Name: fmt.Sprintf("%s.count", name), + Columns: []string{"time", "count"}, + Points: [][]interface{}{ + {now, metric.Count()}, + }, + }) + case metrics.Gauge: + series = append(series, &influxClient.Series{ + Name: fmt.Sprintf("%s.value", name), + Columns: []string{"time", "value"}, + Points: [][]interface{}{ + {now, metric.Value()}, + }, + }) + case metrics.GaugeFloat64: + series = append(series, &influxClient.Series{ + Name: fmt.Sprintf("%s.value", name), + Columns: []string{"time", "value"}, + Points: [][]interface{}{ + {now, metric.Value()}, + }, + }) + case metrics.Histogram: + h := metric.Snapshot() + ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + series = append(series, &influxClient.Series{ + Name: fmt.Sprintf("%s.histogram", name), + Columns: []string{"time", "count", "min", "max", "mean", "std-dev", + "50-percentile", "75-percentile", "95-percentile", + "99-percentile", "999-percentile"}, + Points: [][]interface{}{ + {now, h.Count(), h.Min(), h.Max(), h.Mean(), h.StdDev(), + ps[0], ps[1], ps[2], ps[3], ps[4]}, + }, + }) + case metrics.Meter: + m := metric.Snapshot() + series = append(series, &influxClient.Series{ + Name: fmt.Sprintf("%s.meter", name), + Columns: []string{"count", "one-minute", + "five-minute", "fifteen-minute", "mean"}, + Points: [][]interface{}{ + {m.Count(), m.Rate1(), m.Rate5(), m.Rate15(), m.RateMean()}, + }, + }) + case metrics.Timer: + h := metric.Snapshot() + ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + series = append(series, &influxClient.Series{ + Name: fmt.Sprintf("%s.timer", name), + Columns: []string{"count", "min", "max", "mean", "std-dev", + "50-percentile", "75-percentile", "95-percentile", + "99-percentile", "999-percentile", "one-minute", "five-minute", "fifteen-minute", "mean-rate"}, + Points: [][]interface{}{ + {h.Count(), h.Min(), h.Max(), h.Mean(), h.StdDev(), + ps[0], ps[1], ps[2], ps[3], ps[4], + h.Rate1(), h.Rate5(), h.Rate15(), h.RateMean()}, + }, + }) + } + }) + if err := client.WriteSeries(series); err != nil { + log.Println(err) + } + return nil +} + +func getCurrentTime() int64 { + return time.Now().UnixNano() / 1000000 +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/json.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/json.go new file mode 100644 index 0000000000..04a9c91982 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/json.go @@ -0,0 +1,83 @@ +package metrics + +import ( + "encoding/json" + "io" + "time" +) + +// MarshalJSON returns a byte slice containing a JSON representation of all +// the metrics in the Registry. +func (r StandardRegistry) MarshalJSON() ([]byte, error) { + data := make(map[string]map[string]interface{}) + r.Each(func(name string, i interface{}) { + values := make(map[string]interface{}) + switch metric := i.(type) { + case Counter: + values["count"] = metric.Count() + case Gauge: + values["value"] = metric.Value() + case GaugeFloat64: + values["value"] = metric.Value() + case Healthcheck: + values["error"] = nil + metric.Check() + if err := metric.Error(); nil != err { + values["error"] = metric.Error().Error() + } + case Histogram: + h := metric.Snapshot() + ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + values["count"] = h.Count() + values["min"] = h.Min() + values["max"] = h.Max() + values["mean"] = h.Mean() + values["stddev"] = h.StdDev() + values["median"] = ps[0] + values["75%"] = ps[1] + values["95%"] = ps[2] + values["99%"] = ps[3] + values["99.9%"] = ps[4] + case Meter: + m := metric.Snapshot() + values["count"] = m.Count() + values["1m.rate"] = m.Rate1() + values["5m.rate"] = m.Rate5() + values["15m.rate"] = m.Rate15() + values["mean.rate"] = m.RateMean() + case Timer: + t := metric.Snapshot() + ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + values["count"] = t.Count() + values["min"] = t.Min() + values["max"] = t.Max() + values["mean"] = t.Mean() + values["stddev"] = t.StdDev() + values["median"] = ps[0] + values["75%"] = ps[1] + values["95%"] = ps[2] + values["99%"] = ps[3] + values["99.9%"] = ps[4] + values["1m.rate"] = t.Rate1() + values["5m.rate"] = t.Rate5() + values["15m.rate"] = t.Rate15() + values["mean.rate"] = t.RateMean() + } + data[name] = values + }) + return json.Marshal(data) +} + +// WriteJSON writes metrics from the given registry periodically to the +// specified io.Writer as JSON. +func WriteJSON(r Registry, d time.Duration, w io.Writer) { + for _ = range time.Tick(d) { + WriteJSONOnce(r, w) + } +} + +// WriteJSONOnce writes metrics from the given registry to the specified +// io.Writer as JSON. +func WriteJSONOnce(r Registry, w io.Writer) { + json.NewEncoder(w).Encode(r) +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/json_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/json_test.go new file mode 100644 index 0000000000..cf70051f7a --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/json_test.go @@ -0,0 +1,28 @@ +package metrics + +import ( + "bytes" + "encoding/json" + "testing" +) + +func TestRegistryMarshallJSON(t *testing.T) { + b := &bytes.Buffer{} + enc := json.NewEncoder(b) + r := NewRegistry() + r.Register("counter", NewCounter()) + enc.Encode(r) + if s := b.String(); "{\"counter\":{\"count\":0}}\n" != s { + t.Fatalf(s) + } +} + +func TestRegistryWriteJSONOnce(t *testing.T) { + r := NewRegistry() + r.Register("counter", NewCounter()) + b := &bytes.Buffer{} + WriteJSONOnce(r, b) + if s := b.String(); s != "{\"counter\":{\"count\":0}}\n" { + t.Fail() + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/librato/client.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/librato/client.go new file mode 100644 index 0000000000..8c0c850e38 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/librato/client.go @@ -0,0 +1,102 @@ +package librato + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" +) + +const Operations = "operations" +const OperationsShort = "ops" + +type LibratoClient struct { + Email, Token string +} + +// property strings +const ( + // display attributes + Color = "color" + DisplayMax = "display_max" + DisplayMin = "display_min" + DisplayUnitsLong = "display_units_long" + DisplayUnitsShort = "display_units_short" + DisplayStacked = "display_stacked" + DisplayTransform = "display_transform" + // special gauge display attributes + SummarizeFunction = "summarize_function" + Aggregate = "aggregate" + + // metric keys + Name = "name" + Period = "period" + Description = "description" + DisplayName = "display_name" + Attributes = "attributes" + + // measurement keys + MeasureTime = "measure_time" + Source = "source" + Value = "value" + + // special gauge keys + Count = "count" + Sum = "sum" + Max = "max" + Min = "min" + SumSquares = "sum_squares" + + // batch keys + Counters = "counters" + Gauges = "gauges" + + MetricsPostUrl = "https://metrics-api.librato.com/v1/metrics" +) + +type Measurement map[string]interface{} +type Metric map[string]interface{} + +type Batch struct { + Gauges []Measurement `json:"gauges,omitempty"` + Counters []Measurement `json:"counters,omitempty"` + MeasureTime int64 `json:"measure_time"` + Source string `json:"source"` +} + +func (self *LibratoClient) PostMetrics(batch Batch) (err error) { + var ( + js []byte + req *http.Request + resp *http.Response + ) + + if len(batch.Counters) == 0 && len(batch.Gauges) == 0 { + return nil + } + + if js, err = json.Marshal(batch); err != nil { + return + } + + if req, err = http.NewRequest("POST", MetricsPostUrl, bytes.NewBuffer(js)); err != nil { + return + } + + req.Header.Set("Content-Type", "application/json") + req.SetBasicAuth(self.Email, self.Token) + + if resp, err = http.DefaultClient.Do(req); err != nil { + return + } + + if resp.StatusCode != http.StatusOK { + var body []byte + if body, err = ioutil.ReadAll(resp.Body); err != nil { + body = []byte(fmt.Sprintf("(could not fetch response body for error: %s)", err)) + } + err = fmt.Errorf("Unable to post to Librato: %d %s %s", resp.StatusCode, resp.Status, string(body)) + } + return +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/librato/librato.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/librato/librato.go new file mode 100644 index 0000000000..dfaae2f286 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/librato/librato.go @@ -0,0 +1,230 @@ +package librato + +import ( + "fmt" + "log" + "math" + "regexp" + "time" + + "github.com/rcrowley/go-metrics" +) + +// a regexp for extracting the unit from time.Duration.String +var unitRegexp = regexp.MustCompile("[^\\d]+$") + +// a helper that turns a time.Duration into librato display attributes for timer metrics +func translateTimerAttributes(d time.Duration) (attrs map[string]interface{}) { + attrs = make(map[string]interface{}) + attrs[DisplayTransform] = fmt.Sprintf("x/%d", int64(d)) + attrs[DisplayUnitsShort] = string(unitRegexp.Find([]byte(d.String()))) + return +} + +type Reporter struct { + Email, Token string + Source string + Interval time.Duration + Registry metrics.Registry + Percentiles []float64 // percentiles to report on histogram metrics + TimerAttributes map[string]interface{} // units in which timers will be displayed + intervalSec int64 +} + +func NewReporter(r metrics.Registry, d time.Duration, e string, t string, s string, p []float64, u time.Duration) *Reporter { + return &Reporter{e, t, s, d, r, p, translateTimerAttributes(u), int64(d / time.Second)} +} + +func Librato(r metrics.Registry, d time.Duration, e string, t string, s string, p []float64, u time.Duration) { + NewReporter(r, d, e, t, s, p, u).Run() +} + +func (self *Reporter) Run() { + ticker := time.Tick(self.Interval) + metricsApi := &LibratoClient{self.Email, self.Token} + for now := range ticker { + var metrics Batch + var err error + if metrics, err = self.BuildRequest(now, self.Registry); err != nil { + log.Printf("ERROR constructing librato request body %s", err) + continue + } + if err := metricsApi.PostMetrics(metrics); err != nil { + log.Printf("ERROR sending metrics to librato %s", err) + continue + } + } +} + +// calculate sum of squares from data provided by metrics.Histogram +// see http://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods +func sumSquares(s metrics.Sample) float64 { + count := float64(s.Count()) + sumSquared := math.Pow(count*s.Mean(), 2) + sumSquares := math.Pow(count*s.StdDev(), 2) + sumSquared/count + if math.IsNaN(sumSquares) { + return 0.0 + } + return sumSquares +} +func sumSquaresTimer(t metrics.Timer) float64 { + count := float64(t.Count()) + sumSquared := math.Pow(count*t.Mean(), 2) + sumSquares := math.Pow(count*t.StdDev(), 2) + sumSquared/count + if math.IsNaN(sumSquares) { + return 0.0 + } + return sumSquares +} + +func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot Batch, err error) { + snapshot = Batch{ + // coerce timestamps to a stepping fn so that they line up in Librato graphs + MeasureTime: (now.Unix() / self.intervalSec) * self.intervalSec, + Source: self.Source, + } + snapshot.Gauges = make([]Measurement, 0) + snapshot.Counters = make([]Measurement, 0) + histogramGaugeCount := 1 + len(self.Percentiles) + r.Each(func(name string, metric interface{}) { + measurement := Measurement{} + measurement[Period] = self.Interval.Seconds() + switch m := metric.(type) { + case metrics.Counter: + if m.Count() > 0 { + measurement[Name] = fmt.Sprintf("%s.%s", name, "count") + measurement[Value] = float64(m.Count()) + measurement[Attributes] = map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + } + snapshot.Counters = append(snapshot.Counters, measurement) + } + case metrics.Gauge: + measurement[Name] = name + measurement[Value] = float64(m.Value()) + snapshot.Gauges = append(snapshot.Gauges, measurement) + case metrics.GaugeFloat64: + measurement[Name] = name + measurement[Value] = float64(m.Value()) + snapshot.Gauges = append(snapshot.Gauges, measurement) + case metrics.Histogram: + if m.Count() > 0 { + gauges := make([]Measurement, histogramGaugeCount, histogramGaugeCount) + s := m.Sample() + measurement[Name] = fmt.Sprintf("%s.%s", name, "hist") + measurement[Count] = uint64(s.Count()) + measurement[Max] = float64(s.Max()) + measurement[Min] = float64(s.Min()) + measurement[Sum] = float64(s.Sum()) + measurement[SumSquares] = sumSquares(s) + gauges[0] = measurement + for i, p := range self.Percentiles { + gauges[i+1] = Measurement{ + Name: fmt.Sprintf("%s.%.2f", measurement[Name], p), + Value: s.Percentile(p), + Period: measurement[Period], + } + } + snapshot.Gauges = append(snapshot.Gauges, gauges...) + } + case metrics.Meter: + measurement[Name] = name + measurement[Value] = float64(m.Count()) + snapshot.Counters = append(snapshot.Counters, measurement) + snapshot.Gauges = append(snapshot.Gauges, + Measurement{ + Name: fmt.Sprintf("%s.%s", name, "1min"), + Value: m.Rate1(), + Period: int64(self.Interval.Seconds()), + Attributes: map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + }, + }, + Measurement{ + Name: fmt.Sprintf("%s.%s", name, "5min"), + Value: m.Rate5(), + Period: int64(self.Interval.Seconds()), + Attributes: map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + }, + }, + Measurement{ + Name: fmt.Sprintf("%s.%s", name, "15min"), + Value: m.Rate15(), + Period: int64(self.Interval.Seconds()), + Attributes: map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + }, + }, + ) + case metrics.Timer: + measurement[Name] = name + measurement[Value] = float64(m.Count()) + snapshot.Counters = append(snapshot.Counters, measurement) + if m.Count() > 0 { + libratoName := fmt.Sprintf("%s.%s", name, "timer.mean") + gauges := make([]Measurement, histogramGaugeCount, histogramGaugeCount) + gauges[0] = Measurement{ + Name: libratoName, + Count: uint64(m.Count()), + Sum: m.Mean() * float64(m.Count()), + Max: float64(m.Max()), + Min: float64(m.Min()), + SumSquares: sumSquaresTimer(m), + Period: int64(self.Interval.Seconds()), + Attributes: self.TimerAttributes, + } + for i, p := range self.Percentiles { + gauges[i+1] = Measurement{ + Name: fmt.Sprintf("%s.timer.%2.0f", name, p*100), + Value: m.Percentile(p), + Period: int64(self.Interval.Seconds()), + Attributes: self.TimerAttributes, + } + } + snapshot.Gauges = append(snapshot.Gauges, gauges...) + snapshot.Gauges = append(snapshot.Gauges, + Measurement{ + Name: fmt.Sprintf("%s.%s", name, "rate.1min"), + Value: m.Rate1(), + Period: int64(self.Interval.Seconds()), + Attributes: map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + }, + }, + Measurement{ + Name: fmt.Sprintf("%s.%s", name, "rate.5min"), + Value: m.Rate5(), + Period: int64(self.Interval.Seconds()), + Attributes: map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + }, + }, + Measurement{ + Name: fmt.Sprintf("%s.%s", name, "rate.15min"), + Value: m.Rate15(), + Period: int64(self.Interval.Seconds()), + Attributes: map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + }, + }, + ) + } + } + }) + return +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/log.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/log.go new file mode 100644 index 0000000000..278a8a441c --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/log.go @@ -0,0 +1,70 @@ +package metrics + +import ( + "log" + "time" +) + +// Output each metric in the given registry periodically using the given +// logger. +func Log(r Registry, d time.Duration, l *log.Logger) { + for _ = range time.Tick(d) { + r.Each(func(name string, i interface{}) { + switch metric := i.(type) { + case Counter: + l.Printf("counter %s\n", name) + l.Printf(" count: %9d\n", metric.Count()) + case Gauge: + l.Printf("gauge %s\n", name) + l.Printf(" value: %9d\n", metric.Value()) + case GaugeFloat64: + l.Printf("gauge %s\n", name) + l.Printf(" value: %f\n", metric.Value()) + case Healthcheck: + metric.Check() + l.Printf("healthcheck %s\n", name) + l.Printf(" error: %v\n", metric.Error()) + case Histogram: + h := metric.Snapshot() + ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + l.Printf("histogram %s\n", name) + l.Printf(" count: %9d\n", h.Count()) + l.Printf(" min: %9d\n", h.Min()) + l.Printf(" max: %9d\n", h.Max()) + l.Printf(" mean: %12.2f\n", h.Mean()) + l.Printf(" stddev: %12.2f\n", h.StdDev()) + l.Printf(" median: %12.2f\n", ps[0]) + l.Printf(" 75%%: %12.2f\n", ps[1]) + l.Printf(" 95%%: %12.2f\n", ps[2]) + l.Printf(" 99%%: %12.2f\n", ps[3]) + l.Printf(" 99.9%%: %12.2f\n", ps[4]) + case Meter: + m := metric.Snapshot() + l.Printf("meter %s\n", name) + l.Printf(" count: %9d\n", m.Count()) + l.Printf(" 1-min rate: %12.2f\n", m.Rate1()) + l.Printf(" 5-min rate: %12.2f\n", m.Rate5()) + l.Printf(" 15-min rate: %12.2f\n", m.Rate15()) + l.Printf(" mean rate: %12.2f\n", m.RateMean()) + case Timer: + t := metric.Snapshot() + ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + l.Printf("timer %s\n", name) + l.Printf(" count: %9d\n", t.Count()) + l.Printf(" min: %9d\n", t.Min()) + l.Printf(" max: %9d\n", t.Max()) + l.Printf(" mean: %12.2f\n", t.Mean()) + l.Printf(" stddev: %12.2f\n", t.StdDev()) + l.Printf(" median: %12.2f\n", ps[0]) + l.Printf(" 75%%: %12.2f\n", ps[1]) + l.Printf(" 95%%: %12.2f\n", ps[2]) + l.Printf(" 99%%: %12.2f\n", ps[3]) + l.Printf(" 99.9%%: %12.2f\n", ps[4]) + l.Printf(" 1-min rate: %12.2f\n", t.Rate1()) + l.Printf(" 5-min rate: %12.2f\n", t.Rate5()) + l.Printf(" 15-min rate: %12.2f\n", t.Rate15()) + l.Printf(" mean rate: %12.2f\n", t.RateMean()) + } + }) + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/memory.md b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/memory.md new file mode 100644 index 0000000000..47454f54b6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/memory.md @@ -0,0 +1,285 @@ +Memory usage +============ + +(Highly unscientific.) + +Command used to gather static memory usage: + +```sh +grep ^Vm "/proc/$(ps fax | grep [m]etrics-bench | awk '{print $1}')/status" +``` + +Program used to gather baseline memory usage: + +```go +package main + +import "time" + +func main() { + time.Sleep(600e9) +} +``` + +Baseline +-------- + +``` +VmPeak: 42604 kB +VmSize: 42604 kB +VmLck: 0 kB +VmHWM: 1120 kB +VmRSS: 1120 kB +VmData: 35460 kB +VmStk: 136 kB +VmExe: 1020 kB +VmLib: 1848 kB +VmPTE: 36 kB +VmSwap: 0 kB +``` + +Program used to gather metric memory usage (with other metrics being similar): + +```go +package main + +import ( + "fmt" + "metrics" + "time" +) + +func main() { + fmt.Sprintf("foo") + metrics.NewRegistry() + time.Sleep(600e9) +} +``` + +1000 counters registered +------------------------ + +``` +VmPeak: 44016 kB +VmSize: 44016 kB +VmLck: 0 kB +VmHWM: 1928 kB +VmRSS: 1928 kB +VmData: 36868 kB +VmStk: 136 kB +VmExe: 1024 kB +VmLib: 1848 kB +VmPTE: 40 kB +VmSwap: 0 kB +``` + +**1.412 kB virtual, TODO 0.808 kB resident per counter.** + +100000 counters registered +-------------------------- + +``` +VmPeak: 55024 kB +VmSize: 55024 kB +VmLck: 0 kB +VmHWM: 12440 kB +VmRSS: 12440 kB +VmData: 47876 kB +VmStk: 136 kB +VmExe: 1024 kB +VmLib: 1848 kB +VmPTE: 64 kB +VmSwap: 0 kB +``` + +**0.1242 kB virtual, 0.1132 kB resident per counter.** + +1000 gauges registered +---------------------- + +``` +VmPeak: 44012 kB +VmSize: 44012 kB +VmLck: 0 kB +VmHWM: 1928 kB +VmRSS: 1928 kB +VmData: 36868 kB +VmStk: 136 kB +VmExe: 1020 kB +VmLib: 1848 kB +VmPTE: 40 kB +VmSwap: 0 kB +``` + +**1.408 kB virtual, 0.808 kB resident per counter.** + +100000 gauges registered +------------------------ + +``` +VmPeak: 55020 kB +VmSize: 55020 kB +VmLck: 0 kB +VmHWM: 12432 kB +VmRSS: 12432 kB +VmData: 47876 kB +VmStk: 136 kB +VmExe: 1020 kB +VmLib: 1848 kB +VmPTE: 60 kB +VmSwap: 0 kB +``` + +**0.12416 kB virtual, 0.11312 resident per gauge.** + +1000 histograms with a uniform sample size of 1028 +-------------------------------------------------- + +``` +VmPeak: 72272 kB +VmSize: 72272 kB +VmLck: 0 kB +VmHWM: 16204 kB +VmRSS: 16204 kB +VmData: 65100 kB +VmStk: 136 kB +VmExe: 1048 kB +VmLib: 1848 kB +VmPTE: 80 kB +VmSwap: 0 kB +``` + +**29.668 kB virtual, TODO 15.084 resident per histogram.** + +10000 histograms with a uniform sample size of 1028 +--------------------------------------------------- + +``` +VmPeak: 256912 kB +VmSize: 256912 kB +VmLck: 0 kB +VmHWM: 146204 kB +VmRSS: 146204 kB +VmData: 249740 kB +VmStk: 136 kB +VmExe: 1048 kB +VmLib: 1848 kB +VmPTE: 448 kB +VmSwap: 0 kB +``` + +**21.4308 kB virtual, 14.5084 kB resident per histogram.** + +50000 histograms with a uniform sample size of 1028 +--------------------------------------------------- + +``` +VmPeak: 908112 kB +VmSize: 908112 kB +VmLck: 0 kB +VmHWM: 645832 kB +VmRSS: 645588 kB +VmData: 900940 kB +VmStk: 136 kB +VmExe: 1048 kB +VmLib: 1848 kB +VmPTE: 1716 kB +VmSwap: 1544 kB +``` + +**17.31016 kB virtual, 12.88936 kB resident per histogram.** + +1000 histograms with an exponentially-decaying sample size of 1028 and alpha of 0.015 +------------------------------------------------------------------------------------- + +``` +VmPeak: 62480 kB +VmSize: 62480 kB +VmLck: 0 kB +VmHWM: 11572 kB +VmRSS: 11572 kB +VmData: 55308 kB +VmStk: 136 kB +VmExe: 1048 kB +VmLib: 1848 kB +VmPTE: 64 kB +VmSwap: 0 kB +``` + +**19.876 kB virtual, 10.452 kB resident per histogram.** + +10000 histograms with an exponentially-decaying sample size of 1028 and alpha of 0.015 +-------------------------------------------------------------------------------------- + +``` +VmPeak: 153296 kB +VmSize: 153296 kB +VmLck: 0 kB +VmHWM: 101176 kB +VmRSS: 101176 kB +VmData: 146124 kB +VmStk: 136 kB +VmExe: 1048 kB +VmLib: 1848 kB +VmPTE: 240 kB +VmSwap: 0 kB +``` + +**11.0692 kB virtual, 10.0056 kB resident per histogram.** + +50000 histograms with an exponentially-decaying sample size of 1028 and alpha of 0.015 +-------------------------------------------------------------------------------------- + +``` +VmPeak: 557264 kB +VmSize: 557264 kB +VmLck: 0 kB +VmHWM: 501056 kB +VmRSS: 501056 kB +VmData: 550092 kB +VmStk: 136 kB +VmExe: 1048 kB +VmLib: 1848 kB +VmPTE: 1032 kB +VmSwap: 0 kB +``` + +**10.2932 kB virtual, 9.99872 kB resident per histogram.** + +1000 meters +----------- + +``` +VmPeak: 74504 kB +VmSize: 74504 kB +VmLck: 0 kB +VmHWM: 24124 kB +VmRSS: 24124 kB +VmData: 67340 kB +VmStk: 136 kB +VmExe: 1040 kB +VmLib: 1848 kB +VmPTE: 92 kB +VmSwap: 0 kB +``` + +**31.9 kB virtual, 23.004 kB resident per meter.** + +10000 meters +------------ + +``` +VmPeak: 278920 kB +VmSize: 278920 kB +VmLck: 0 kB +VmHWM: 227300 kB +VmRSS: 227300 kB +VmData: 271756 kB +VmStk: 136 kB +VmExe: 1040 kB +VmLib: 1848 kB +VmPTE: 488 kB +VmSwap: 0 kB +``` + +**23.6316 kB virtual, 22.618 kB resident per meter.** diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/meter.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/meter.go new file mode 100644 index 0000000000..0389ab0b8f --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/meter.go @@ -0,0 +1,233 @@ +package metrics + +import ( + "sync" + "time" +) + +// Meters count events to produce exponentially-weighted moving average rates +// at one-, five-, and fifteen-minutes and a mean rate. +type Meter interface { + Count() int64 + Mark(int64) + Rate1() float64 + Rate5() float64 + Rate15() float64 + RateMean() float64 + Snapshot() Meter +} + +// GetOrRegisterMeter returns an existing Meter or constructs and registers a +// new StandardMeter. +func GetOrRegisterMeter(name string, r Registry) Meter { + if nil == r { + r = DefaultRegistry + } + return r.GetOrRegister(name, NewMeter).(Meter) +} + +// NewMeter constructs a new StandardMeter and launches a goroutine. +func NewMeter() Meter { + if UseNilMetrics { + return NilMeter{} + } + m := newStandardMeter() + arbiter.Lock() + defer arbiter.Unlock() + arbiter.meters = append(arbiter.meters, m) + if !arbiter.started { + arbiter.started = true + go arbiter.tick() + } + return m +} + +// NewMeter constructs and registers a new StandardMeter and launches a +// goroutine. +func NewRegisteredMeter(name string, r Registry) Meter { + c := NewMeter() + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + +// MeterSnapshot is a read-only copy of another Meter. +type MeterSnapshot struct { + count int64 + rate1, rate5, rate15, rateMean float64 +} + +// Count returns the count of events at the time the snapshot was taken. +func (m *MeterSnapshot) Count() int64 { return m.count } + +// Mark panics. +func (*MeterSnapshot) Mark(n int64) { + panic("Mark called on a MeterSnapshot") +} + +// Rate1 returns the one-minute moving average rate of events per second at the +// time the snapshot was taken. +func (m *MeterSnapshot) Rate1() float64 { return m.rate1 } + +// Rate5 returns the five-minute moving average rate of events per second at +// the time the snapshot was taken. +func (m *MeterSnapshot) Rate5() float64 { return m.rate5 } + +// Rate15 returns the fifteen-minute moving average rate of events per second +// at the time the snapshot was taken. +func (m *MeterSnapshot) Rate15() float64 { return m.rate15 } + +// RateMean returns the meter's mean rate of events per second at the time the +// snapshot was taken. +func (m *MeterSnapshot) RateMean() float64 { return m.rateMean } + +// Snapshot returns the snapshot. +func (m *MeterSnapshot) Snapshot() Meter { return m } + +// NilMeter is a no-op Meter. +type NilMeter struct{} + +// Count is a no-op. +func (NilMeter) Count() int64 { return 0 } + +// Mark is a no-op. +func (NilMeter) Mark(n int64) {} + +// Rate1 is a no-op. +func (NilMeter) Rate1() float64 { return 0.0 } + +// Rate5 is a no-op. +func (NilMeter) Rate5() float64 { return 0.0 } + +// Rate15is a no-op. +func (NilMeter) Rate15() float64 { return 0.0 } + +// RateMean is a no-op. +func (NilMeter) RateMean() float64 { return 0.0 } + +// Snapshot is a no-op. +func (NilMeter) Snapshot() Meter { return NilMeter{} } + +// StandardMeter is the standard implementation of a Meter. +type StandardMeter struct { + lock sync.RWMutex + snapshot *MeterSnapshot + a1, a5, a15 EWMA + startTime time.Time +} + +func newStandardMeter() *StandardMeter { + return &StandardMeter{ + snapshot: &MeterSnapshot{}, + a1: NewEWMA1(), + a5: NewEWMA5(), + a15: NewEWMA15(), + startTime: time.Now(), + } +} + +// Count returns the number of events recorded. +func (m *StandardMeter) Count() int64 { + m.lock.RLock() + count := m.snapshot.count + m.lock.RUnlock() + return count +} + +// Mark records the occurance of n events. +func (m *StandardMeter) Mark(n int64) { + m.lock.Lock() + defer m.lock.Unlock() + m.snapshot.count += n + m.a1.Update(n) + m.a5.Update(n) + m.a15.Update(n) + m.updateSnapshot() +} + +// Rate1 returns the one-minute moving average rate of events per second. +func (m *StandardMeter) Rate1() float64 { + m.lock.RLock() + rate1 := m.snapshot.rate1 + m.lock.RUnlock() + return rate1 +} + +// Rate5 returns the five-minute moving average rate of events per second. +func (m *StandardMeter) Rate5() float64 { + m.lock.RLock() + rate5 := m.snapshot.rate5 + m.lock.RUnlock() + return rate5 +} + +// Rate15 returns the fifteen-minute moving average rate of events per second. +func (m *StandardMeter) Rate15() float64 { + m.lock.RLock() + rate15 := m.snapshot.rate15 + m.lock.RUnlock() + return rate15 +} + +// RateMean returns the meter's mean rate of events per second. +func (m *StandardMeter) RateMean() float64 { + m.lock.RLock() + rateMean := m.snapshot.rateMean + m.lock.RUnlock() + return rateMean +} + +// Snapshot returns a read-only copy of the meter. +func (m *StandardMeter) Snapshot() Meter { + m.lock.RLock() + snapshot := *m.snapshot + m.lock.RUnlock() + return &snapshot +} + +func (m *StandardMeter) updateSnapshot() { + // should run with write lock held on m.lock + snapshot := m.snapshot + snapshot.rate1 = m.a1.Rate() + snapshot.rate5 = m.a5.Rate() + snapshot.rate15 = m.a15.Rate() + snapshot.rateMean = float64(snapshot.count) / time.Since(m.startTime).Seconds() +} + +func (m *StandardMeter) tick() { + m.lock.Lock() + defer m.lock.Unlock() + m.a1.Tick() + m.a5.Tick() + m.a15.Tick() + m.updateSnapshot() +} + +type meterArbiter struct { + sync.RWMutex + started bool + meters []*StandardMeter + ticker *time.Ticker +} + +var arbiter = meterArbiter{ticker: time.NewTicker(5e9)} + +// Ticks meters on the scheduled interval +func (ma *meterArbiter) tick() { + for { + select { + case <-ma.ticker.C: + ma.tickMeters() + } + } +} + +func (ma *meterArbiter) tickMeters() { + ma.RLock() + defer ma.RUnlock() + for _, meter := range ma.meters { + meter.tick() + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/meter_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/meter_test.go new file mode 100644 index 0000000000..26ce1398ac --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/meter_test.go @@ -0,0 +1,60 @@ +package metrics + +import ( + "testing" + "time" +) + +func BenchmarkMeter(b *testing.B) { + m := NewMeter() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.Mark(1) + } +} + +func TestGetOrRegisterMeter(t *testing.T) { + r := NewRegistry() + NewRegisteredMeter("foo", r).Mark(47) + if m := GetOrRegisterMeter("foo", r); 47 != m.Count() { + t.Fatal(m) + } +} + +func TestMeterDecay(t *testing.T) { + ma := meterArbiter{ + ticker: time.NewTicker(1), + } + m := newStandardMeter() + ma.meters = append(ma.meters, m) + go ma.tick() + m.Mark(1) + rateMean := m.RateMean() + time.Sleep(1) + if m.RateMean() >= rateMean { + t.Error("m.RateMean() didn't decrease") + } +} + +func TestMeterNonzero(t *testing.T) { + m := NewMeter() + m.Mark(3) + if count := m.Count(); 3 != count { + t.Errorf("m.Count(): 3 != %v\n", count) + } +} + +func TestMeterSnapshot(t *testing.T) { + m := NewMeter() + m.Mark(1) + if snapshot := m.Snapshot(); m.RateMean() != snapshot.RateMean() { + t.Fatal(snapshot) + } +} + +func TestMeterZero(t *testing.T) { + m := NewMeter() + if count := m.Count(); 0 != count { + t.Errorf("m.Count(): 0 != %v\n", count) + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/metrics.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/metrics.go new file mode 100644 index 0000000000..b97a49ed12 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/metrics.go @@ -0,0 +1,13 @@ +// Go port of Coda Hale's Metrics library +// +// +// +// Coda Hale's original work: +package metrics + +// UseNilMetrics is checked by the constructor functions for all of the +// standard metrics. If it is true, the metric returned is a stub. +// +// This global kill-switch helps quantify the observer effect and makes +// for less cluttered pprof profiles. +var UseNilMetrics bool = false diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/metrics_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/metrics_test.go new file mode 100644 index 0000000000..083f9676f4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/metrics_test.go @@ -0,0 +1,107 @@ +package metrics + +import ( + "io/ioutil" + "log" + "sync" + "testing" +) + +const FANOUT = 128 + +// Stop the compiler from complaining during debugging. +var ( + _ = ioutil.Discard + _ = log.LstdFlags +) + +func BenchmarkMetrics(b *testing.B) { + r := NewRegistry() + c := NewRegisteredCounter("counter", r) + g := NewRegisteredGauge("gauge", r) + gf := NewRegisteredGaugeFloat64("gaugefloat64", r) + h := NewRegisteredHistogram("histogram", r, NewUniformSample(100)) + m := NewRegisteredMeter("meter", r) + t := NewRegisteredTimer("timer", r) + RegisterDebugGCStats(r) + RegisterRuntimeMemStats(r) + b.ResetTimer() + ch := make(chan bool) + + wgD := &sync.WaitGroup{} + /* + wgD.Add(1) + go func() { + defer wgD.Done() + //log.Println("go CaptureDebugGCStats") + for { + select { + case <-ch: + //log.Println("done CaptureDebugGCStats") + return + default: + CaptureDebugGCStatsOnce(r) + } + } + }() + //*/ + + wgR := &sync.WaitGroup{} + //* + wgR.Add(1) + go func() { + defer wgR.Done() + //log.Println("go CaptureRuntimeMemStats") + for { + select { + case <-ch: + //log.Println("done CaptureRuntimeMemStats") + return + default: + CaptureRuntimeMemStatsOnce(r) + } + } + }() + //*/ + + wgW := &sync.WaitGroup{} + /* + wgW.Add(1) + go func() { + defer wgW.Done() + //log.Println("go Write") + for { + select { + case <-ch: + //log.Println("done Write") + return + default: + WriteOnce(r, ioutil.Discard) + } + } + }() + //*/ + + wg := &sync.WaitGroup{} + wg.Add(FANOUT) + for i := 0; i < FANOUT; i++ { + go func(i int) { + defer wg.Done() + //log.Println("go", i) + for i := 0; i < b.N; i++ { + c.Inc(1) + g.Update(int64(i)) + gf.Update(float64(i)) + h.Update(int64(i)) + m.Mark(1) + t.Update(1) + } + //log.Println("done", i) + }(i) + } + wg.Wait() + close(ch) + wgD.Wait() + wgR.Wait() + wgW.Wait() +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/opentsdb.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/opentsdb.go new file mode 100644 index 0000000000..266b6c93d2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/opentsdb.go @@ -0,0 +1,119 @@ +package metrics + +import ( + "bufio" + "fmt" + "log" + "net" + "os" + "strings" + "time" +) + +var shortHostName string = "" + +// OpenTSDBConfig provides a container with configuration parameters for +// the OpenTSDB exporter +type OpenTSDBConfig struct { + Addr *net.TCPAddr // Network address to connect to + Registry Registry // Registry to be exported + FlushInterval time.Duration // Flush interval + DurationUnit time.Duration // Time conversion unit for durations + Prefix string // Prefix to be prepended to metric names +} + +// OpenTSDB is a blocking exporter function which reports metrics in r +// to a TSDB server located at addr, flushing them every d duration +// and prepending metric names with prefix. +func OpenTSDB(r Registry, d time.Duration, prefix string, addr *net.TCPAddr) { + OpenTSDBWithConfig(OpenTSDBConfig{ + Addr: addr, + Registry: r, + FlushInterval: d, + DurationUnit: time.Nanosecond, + Prefix: prefix, + }) +} + +// OpenTSDBWithConfig is a blocking exporter function just like OpenTSDB, +// but it takes a OpenTSDBConfig instead. +func OpenTSDBWithConfig(c OpenTSDBConfig) { + for _ = range time.Tick(c.FlushInterval) { + if err := openTSDB(&c); nil != err { + log.Println(err) + } + } +} + +func getShortHostname() string { + if shortHostName == "" { + host, _ := os.Hostname() + if index := strings.Index(host, "."); index > 0 { + shortHostName = host[:index] + } else { + shortHostName = host + } + } + return shortHostName +} + +func openTSDB(c *OpenTSDBConfig) error { + shortHostname := getShortHostname() + now := time.Now().Unix() + du := float64(c.DurationUnit) + conn, err := net.DialTCP("tcp", nil, c.Addr) + if nil != err { + return err + } + defer conn.Close() + w := bufio.NewWriter(conn) + c.Registry.Each(func(name string, i interface{}) { + switch metric := i.(type) { + case Counter: + fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, metric.Count(), shortHostname) + case Gauge: + fmt.Fprintf(w, "put %s.%s.value %d %d host=%s\n", c.Prefix, name, now, metric.Value(), shortHostname) + case GaugeFloat64: + fmt.Fprintf(w, "put %s.%s.value %d %f host=%s\n", c.Prefix, name, now, metric.Value(), shortHostname) + case Histogram: + h := metric.Snapshot() + ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, h.Count(), shortHostname) + fmt.Fprintf(w, "put %s.%s.min %d %d host=%s\n", c.Prefix, name, now, h.Min(), shortHostname) + fmt.Fprintf(w, "put %s.%s.max %d %d host=%s\n", c.Prefix, name, now, h.Max(), shortHostname) + fmt.Fprintf(w, "put %s.%s.mean %d %.2f host=%s\n", c.Prefix, name, now, h.Mean(), shortHostname) + fmt.Fprintf(w, "put %s.%s.std-dev %d %.2f host=%s\n", c.Prefix, name, now, h.StdDev(), shortHostname) + fmt.Fprintf(w, "put %s.%s.50-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[0], shortHostname) + fmt.Fprintf(w, "put %s.%s.75-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[1], shortHostname) + fmt.Fprintf(w, "put %s.%s.95-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[2], shortHostname) + fmt.Fprintf(w, "put %s.%s.99-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[3], shortHostname) + fmt.Fprintf(w, "put %s.%s.999-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[4], shortHostname) + case Meter: + m := metric.Snapshot() + fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, m.Count(), shortHostname) + fmt.Fprintf(w, "put %s.%s.one-minute %d %.2f host=%s\n", c.Prefix, name, now, m.Rate1(), shortHostname) + fmt.Fprintf(w, "put %s.%s.five-minute %d %.2f host=%s\n", c.Prefix, name, now, m.Rate5(), shortHostname) + fmt.Fprintf(w, "put %s.%s.fifteen-minute %d %.2f host=%s\n", c.Prefix, name, now, m.Rate15(), shortHostname) + fmt.Fprintf(w, "put %s.%s.mean %d %.2f host=%s\n", c.Prefix, name, now, m.RateMean(), shortHostname) + case Timer: + t := metric.Snapshot() + ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, t.Count(), shortHostname) + fmt.Fprintf(w, "put %s.%s.min %d %d host=%s\n", c.Prefix, name, now, t.Min()/int64(du), shortHostname) + fmt.Fprintf(w, "put %s.%s.max %d %d host=%s\n", c.Prefix, name, now, t.Max()/int64(du), shortHostname) + fmt.Fprintf(w, "put %s.%s.mean %d %.2f host=%s\n", c.Prefix, name, now, t.Mean()/du, shortHostname) + fmt.Fprintf(w, "put %s.%s.std-dev %d %.2f host=%s\n", c.Prefix, name, now, t.StdDev()/du, shortHostname) + fmt.Fprintf(w, "put %s.%s.50-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[0]/du, shortHostname) + fmt.Fprintf(w, "put %s.%s.75-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[1]/du, shortHostname) + fmt.Fprintf(w, "put %s.%s.95-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[2]/du, shortHostname) + fmt.Fprintf(w, "put %s.%s.99-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[3]/du, shortHostname) + fmt.Fprintf(w, "put %s.%s.999-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[4]/du, shortHostname) + fmt.Fprintf(w, "put %s.%s.one-minute %d %.2f host=%s\n", c.Prefix, name, now, t.Rate1(), shortHostname) + fmt.Fprintf(w, "put %s.%s.five-minute %d %.2f host=%s\n", c.Prefix, name, now, t.Rate5(), shortHostname) + fmt.Fprintf(w, "put %s.%s.fifteen-minute %d %.2f host=%s\n", c.Prefix, name, now, t.Rate15(), shortHostname) + fmt.Fprintf(w, "put %s.%s.mean-rate %d %.2f host=%s\n", c.Prefix, name, now, t.RateMean(), shortHostname) + } + w.Flush() + }) + return nil +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/opentsdb_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/opentsdb_test.go new file mode 100644 index 0000000000..6173d61ab7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/opentsdb_test.go @@ -0,0 +1,22 @@ +package metrics + +import ( + "net" + "time" +) + +func ExampleOpenTSDB() { + addr, _ := net.ResolveTCPAddr("net", ":2003") + go OpenTSDB(DefaultRegistry, 1*time.Second, "some.prefix", addr) +} + +func ExampleOpenTSDBWithConfig() { + addr, _ := net.ResolveTCPAddr("net", ":2003") + go OpenTSDBWithConfig(OpenTSDBConfig{ + Addr: addr, + Registry: DefaultRegistry, + FlushInterval: 1 * time.Second, + DurationUnit: time.Millisecond, + }) +} + diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry.go new file mode 100644 index 0000000000..1f9d82c2a1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry.go @@ -0,0 +1,180 @@ +package metrics + +import ( + "fmt" + "reflect" + "sync" +) + +// DuplicateMetric is the error returned by Registry.Register when a metric +// already exists. If you mean to Register that metric you must first +// Unregister the existing metric. +type DuplicateMetric string + +func (err DuplicateMetric) Error() string { + return fmt.Sprintf("duplicate metric: %s", string(err)) +} + +// A Registry holds references to a set of metrics by name and can iterate +// over them, calling callback functions provided by the user. +// +// This is an interface so as to encourage other structs to implement +// the Registry API as appropriate. +type Registry interface { + + // Call the given function for each registered metric. + Each(func(string, interface{})) + + // Get the metric by the given name or nil if none is registered. + Get(string) interface{} + + // Gets an existing metric or registers the given one. + // The interface can be the metric to register if not found in registry, + // or a function returning the metric for lazy instantiation. + GetOrRegister(string, interface{}) interface{} + + // Register the given metric under the given name. + Register(string, interface{}) error + + // Run all registered healthchecks. + RunHealthchecks() + + // Unregister the metric with the given name. + Unregister(string) + + // Unregister all metrics. (Mostly for testing.) + UnregisterAll() +} + +// The standard implementation of a Registry is a mutex-protected map +// of names to metrics. +type StandardRegistry struct { + metrics map[string]interface{} + mutex sync.Mutex +} + +// Create a new registry. +func NewRegistry() Registry { + return &StandardRegistry{metrics: make(map[string]interface{})} +} + +// Call the given function for each registered metric. +func (r *StandardRegistry) Each(f func(string, interface{})) { + for name, i := range r.registered() { + f(name, i) + } +} + +// Get the metric by the given name or nil if none is registered. +func (r *StandardRegistry) Get(name string) interface{} { + r.mutex.Lock() + defer r.mutex.Unlock() + return r.metrics[name] +} + +// Gets an existing metric or creates and registers a new one. Threadsafe +// alternative to calling Get and Register on failure. +// The interface can be the metric to register if not found in registry, +// or a function returning the metric for lazy instantiation. +func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} { + r.mutex.Lock() + defer r.mutex.Unlock() + if metric, ok := r.metrics[name]; ok { + return metric + } + if v := reflect.ValueOf(i); v.Kind() == reflect.Func { + i = v.Call(nil)[0].Interface() + } + r.register(name, i) + return i +} + +// Register the given metric under the given name. Returns a DuplicateMetric +// if a metric by the given name is already registered. +func (r *StandardRegistry) Register(name string, i interface{}) error { + r.mutex.Lock() + defer r.mutex.Unlock() + return r.register(name, i) +} + +// Run all registered healthchecks. +func (r *StandardRegistry) RunHealthchecks() { + r.mutex.Lock() + defer r.mutex.Unlock() + for _, i := range r.metrics { + if h, ok := i.(Healthcheck); ok { + h.Check() + } + } +} + +// Unregister the metric with the given name. +func (r *StandardRegistry) Unregister(name string) { + r.mutex.Lock() + defer r.mutex.Unlock() + delete(r.metrics, name) +} + +// Unregister all metrics. (Mostly for testing.) +func (r *StandardRegistry) UnregisterAll() { + r.mutex.Lock() + defer r.mutex.Unlock() + for name, _ := range r.metrics { + delete(r.metrics, name) + } +} + +func (r *StandardRegistry) register(name string, i interface{}) error { + if _, ok := r.metrics[name]; ok { + return DuplicateMetric(name) + } + switch i.(type) { + case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer: + r.metrics[name] = i + } + return nil +} + +func (r *StandardRegistry) registered() map[string]interface{} { + r.mutex.Lock() + defer r.mutex.Unlock() + metrics := make(map[string]interface{}, len(r.metrics)) + for name, i := range r.metrics { + metrics[name] = i + } + return metrics +} + +var DefaultRegistry Registry = NewRegistry() + +// Call the given function for each registered metric. +func Each(f func(string, interface{})) { + DefaultRegistry.Each(f) +} + +// Get the metric by the given name or nil if none is registered. +func Get(name string) interface{} { + return DefaultRegistry.Get(name) +} + +// Gets an existing metric or creates and registers a new one. Threadsafe +// alternative to calling Get and Register on failure. +func GetOrRegister(name string, i interface{}) interface{} { + return DefaultRegistry.GetOrRegister(name, i) +} + +// Register the given metric under the given name. Returns a DuplicateMetric +// if a metric by the given name is already registered. +func Register(name string, i interface{}) error { + return DefaultRegistry.Register(name, i) +} + +// Run all registered healthchecks. +func RunHealthchecks() { + DefaultRegistry.RunHealthchecks() +} + +// Unregister the metric with the given name. +func Unregister(name string) { + DefaultRegistry.Unregister(name) +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry_test.go new file mode 100644 index 0000000000..9ba0a02054 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry_test.go @@ -0,0 +1,118 @@ +package metrics + +import "testing" + +func BenchmarkRegistry(b *testing.B) { + r := NewRegistry() + r.Register("foo", NewCounter()) + b.ResetTimer() + for i := 0; i < b.N; i++ { + r.Each(func(string, interface{}) {}) + } +} + +func TestRegistry(t *testing.T) { + r := NewRegistry() + r.Register("foo", NewCounter()) + i := 0 + r.Each(func(name string, iface interface{}) { + i++ + if "foo" != name { + t.Fatal(name) + } + if _, ok := iface.(Counter); !ok { + t.Fatal(iface) + } + }) + if 1 != i { + t.Fatal(i) + } + r.Unregister("foo") + i = 0 + r.Each(func(string, interface{}) { i++ }) + if 0 != i { + t.Fatal(i) + } +} + +func TestRegistryDuplicate(t *testing.T) { + r := NewRegistry() + if err := r.Register("foo", NewCounter()); nil != err { + t.Fatal(err) + } + if err := r.Register("foo", NewGauge()); nil == err { + t.Fatal(err) + } + i := 0 + r.Each(func(name string, iface interface{}) { + i++ + if _, ok := iface.(Counter); !ok { + t.Fatal(iface) + } + }) + if 1 != i { + t.Fatal(i) + } +} + +func TestRegistryGet(t *testing.T) { + r := NewRegistry() + r.Register("foo", NewCounter()) + if count := r.Get("foo").(Counter).Count(); 0 != count { + t.Fatal(count) + } + r.Get("foo").(Counter).Inc(1) + if count := r.Get("foo").(Counter).Count(); 1 != count { + t.Fatal(count) + } +} + +func TestRegistryGetOrRegister(t *testing.T) { + r := NewRegistry() + + // First metric wins with GetOrRegister + _ = r.GetOrRegister("foo", NewCounter()) + m := r.GetOrRegister("foo", NewGauge()) + if _, ok := m.(Counter); !ok { + t.Fatal(m) + } + + i := 0 + r.Each(func(name string, iface interface{}) { + i++ + if name != "foo" { + t.Fatal(name) + } + if _, ok := iface.(Counter); !ok { + t.Fatal(iface) + } + }) + if i != 1 { + t.Fatal(i) + } +} + +func TestRegistryGetOrRegisterWithLazyInstantiation(t *testing.T) { + r := NewRegistry() + + // First metric wins with GetOrRegister + _ = r.GetOrRegister("foo", NewCounter) + m := r.GetOrRegister("foo", NewGauge) + if _, ok := m.(Counter); !ok { + t.Fatal(m) + } + + i := 0 + r.Each(func(name string, iface interface{}) { + i++ + if name != "foo" { + t.Fatal(name) + } + if _, ok := iface.(Counter); !ok { + t.Fatal(iface) + } + }) + if i != 1 { + t.Fatal(i) + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime.go new file mode 100644 index 0000000000..82574bf251 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime.go @@ -0,0 +1,200 @@ +package metrics + +import ( + "runtime" + "time" +) + +var ( + memStats runtime.MemStats + runtimeMetrics struct { + MemStats struct { + Alloc Gauge + BuckHashSys Gauge + DebugGC Gauge + EnableGC Gauge + Frees Gauge + HeapAlloc Gauge + HeapIdle Gauge + HeapInuse Gauge + HeapObjects Gauge + HeapReleased Gauge + HeapSys Gauge + LastGC Gauge + Lookups Gauge + Mallocs Gauge + MCacheInuse Gauge + MCacheSys Gauge + MSpanInuse Gauge + MSpanSys Gauge + NextGC Gauge + NumGC Gauge + PauseNs Histogram + PauseTotalNs Gauge + StackInuse Gauge + StackSys Gauge + Sys Gauge + TotalAlloc Gauge + } + NumCgoCall Gauge + NumGoroutine Gauge + ReadMemStats Timer + } + frees uint64 + lookups uint64 + mallocs uint64 + numGC uint32 + numCgoCalls int64 +) + +// Capture new values for the Go runtime statistics exported in +// runtime.MemStats. This is designed to be called as a goroutine. +func CaptureRuntimeMemStats(r Registry, d time.Duration) { + for _ = range time.Tick(d) { + CaptureRuntimeMemStatsOnce(r) + } +} + +// Capture new values for the Go runtime statistics exported in +// runtime.MemStats. This is designed to be called in a background +// goroutine. Giving a registry which has not been given to +// RegisterRuntimeMemStats will panic. +// +// Be very careful with this because runtime.ReadMemStats calls the C +// functions runtime·semacquire(&runtime·worldsema) and runtime·stoptheworld() +// and that last one does what it says on the tin. +func CaptureRuntimeMemStatsOnce(r Registry) { + t := time.Now() + runtime.ReadMemStats(&memStats) // This takes 50-200us. + runtimeMetrics.ReadMemStats.UpdateSince(t) + + runtimeMetrics.MemStats.Alloc.Update(int64(memStats.Alloc)) + runtimeMetrics.MemStats.BuckHashSys.Update(int64(memStats.BuckHashSys)) + if memStats.DebugGC { + runtimeMetrics.MemStats.DebugGC.Update(1) + } else { + runtimeMetrics.MemStats.DebugGC.Update(0) + } + if memStats.EnableGC { + runtimeMetrics.MemStats.EnableGC.Update(1) + } else { + runtimeMetrics.MemStats.EnableGC.Update(0) + } + + runtimeMetrics.MemStats.Frees.Update(int64(memStats.Frees - frees)) + runtimeMetrics.MemStats.HeapAlloc.Update(int64(memStats.HeapAlloc)) + runtimeMetrics.MemStats.HeapIdle.Update(int64(memStats.HeapIdle)) + runtimeMetrics.MemStats.HeapInuse.Update(int64(memStats.HeapInuse)) + runtimeMetrics.MemStats.HeapObjects.Update(int64(memStats.HeapObjects)) + runtimeMetrics.MemStats.HeapReleased.Update(int64(memStats.HeapReleased)) + runtimeMetrics.MemStats.HeapSys.Update(int64(memStats.HeapSys)) + runtimeMetrics.MemStats.LastGC.Update(int64(memStats.LastGC)) + runtimeMetrics.MemStats.Lookups.Update(int64(memStats.Lookups - lookups)) + runtimeMetrics.MemStats.Mallocs.Update(int64(memStats.Mallocs - mallocs)) + runtimeMetrics.MemStats.MCacheInuse.Update(int64(memStats.MCacheInuse)) + runtimeMetrics.MemStats.MCacheSys.Update(int64(memStats.MCacheSys)) + runtimeMetrics.MemStats.MSpanInuse.Update(int64(memStats.MSpanInuse)) + runtimeMetrics.MemStats.MSpanSys.Update(int64(memStats.MSpanSys)) + runtimeMetrics.MemStats.NextGC.Update(int64(memStats.NextGC)) + runtimeMetrics.MemStats.NumGC.Update(int64(memStats.NumGC - numGC)) + + // + i := numGC % uint32(len(memStats.PauseNs)) + ii := memStats.NumGC % uint32(len(memStats.PauseNs)) + if memStats.NumGC-numGC >= uint32(len(memStats.PauseNs)) { + for i = 0; i < uint32(len(memStats.PauseNs)); i++ { + runtimeMetrics.MemStats.PauseNs.Update(int64(memStats.PauseNs[i])) + } + } else { + if i > ii { + for ; i < uint32(len(memStats.PauseNs)); i++ { + runtimeMetrics.MemStats.PauseNs.Update(int64(memStats.PauseNs[i])) + } + i = 0 + } + for ; i < ii; i++ { + runtimeMetrics.MemStats.PauseNs.Update(int64(memStats.PauseNs[i])) + } + } + frees = memStats.Frees + lookups = memStats.Lookups + mallocs = memStats.Mallocs + numGC = memStats.NumGC + + runtimeMetrics.MemStats.PauseTotalNs.Update(int64(memStats.PauseTotalNs)) + runtimeMetrics.MemStats.StackInuse.Update(int64(memStats.StackInuse)) + runtimeMetrics.MemStats.StackSys.Update(int64(memStats.StackSys)) + runtimeMetrics.MemStats.Sys.Update(int64(memStats.Sys)) + runtimeMetrics.MemStats.TotalAlloc.Update(int64(memStats.TotalAlloc)) + + currentNumCgoCalls := numCgoCall() + runtimeMetrics.NumCgoCall.Update(currentNumCgoCalls - numCgoCalls) + numCgoCalls = currentNumCgoCalls + + runtimeMetrics.NumGoroutine.Update(int64(runtime.NumGoroutine())) +} + +// Register runtimeMetrics for the Go runtime statistics exported in runtime and +// specifically runtime.MemStats. The runtimeMetrics are named by their +// fully-qualified Go symbols, i.e. runtime.MemStats.Alloc. +func RegisterRuntimeMemStats(r Registry) { + runtimeMetrics.MemStats.Alloc = NewGauge() + runtimeMetrics.MemStats.BuckHashSys = NewGauge() + runtimeMetrics.MemStats.DebugGC = NewGauge() + runtimeMetrics.MemStats.EnableGC = NewGauge() + runtimeMetrics.MemStats.Frees = NewGauge() + runtimeMetrics.MemStats.HeapAlloc = NewGauge() + runtimeMetrics.MemStats.HeapIdle = NewGauge() + runtimeMetrics.MemStats.HeapInuse = NewGauge() + runtimeMetrics.MemStats.HeapObjects = NewGauge() + runtimeMetrics.MemStats.HeapReleased = NewGauge() + runtimeMetrics.MemStats.HeapSys = NewGauge() + runtimeMetrics.MemStats.LastGC = NewGauge() + runtimeMetrics.MemStats.Lookups = NewGauge() + runtimeMetrics.MemStats.Mallocs = NewGauge() + runtimeMetrics.MemStats.MCacheInuse = NewGauge() + runtimeMetrics.MemStats.MCacheSys = NewGauge() + runtimeMetrics.MemStats.MSpanInuse = NewGauge() + runtimeMetrics.MemStats.MSpanSys = NewGauge() + runtimeMetrics.MemStats.NextGC = NewGauge() + runtimeMetrics.MemStats.NumGC = NewGauge() + runtimeMetrics.MemStats.PauseNs = NewHistogram(NewExpDecaySample(1028, 0.015)) + runtimeMetrics.MemStats.PauseTotalNs = NewGauge() + runtimeMetrics.MemStats.StackInuse = NewGauge() + runtimeMetrics.MemStats.StackSys = NewGauge() + runtimeMetrics.MemStats.Sys = NewGauge() + runtimeMetrics.MemStats.TotalAlloc = NewGauge() + runtimeMetrics.NumCgoCall = NewGauge() + runtimeMetrics.NumGoroutine = NewGauge() + runtimeMetrics.ReadMemStats = NewTimer() + + r.Register("runtime.MemStats.Alloc", runtimeMetrics.MemStats.Alloc) + r.Register("runtime.MemStats.BuckHashSys", runtimeMetrics.MemStats.BuckHashSys) + r.Register("runtime.MemStats.DebugGC", runtimeMetrics.MemStats.DebugGC) + r.Register("runtime.MemStats.EnableGC", runtimeMetrics.MemStats.EnableGC) + r.Register("runtime.MemStats.Frees", runtimeMetrics.MemStats.Frees) + r.Register("runtime.MemStats.HeapAlloc", runtimeMetrics.MemStats.HeapAlloc) + r.Register("runtime.MemStats.HeapIdle", runtimeMetrics.MemStats.HeapIdle) + r.Register("runtime.MemStats.HeapInuse", runtimeMetrics.MemStats.HeapInuse) + r.Register("runtime.MemStats.HeapObjects", runtimeMetrics.MemStats.HeapObjects) + r.Register("runtime.MemStats.HeapReleased", runtimeMetrics.MemStats.HeapReleased) + r.Register("runtime.MemStats.HeapSys", runtimeMetrics.MemStats.HeapSys) + r.Register("runtime.MemStats.LastGC", runtimeMetrics.MemStats.LastGC) + r.Register("runtime.MemStats.Lookups", runtimeMetrics.MemStats.Lookups) + r.Register("runtime.MemStats.Mallocs", runtimeMetrics.MemStats.Mallocs) + r.Register("runtime.MemStats.MCacheInuse", runtimeMetrics.MemStats.MCacheInuse) + r.Register("runtime.MemStats.MCacheSys", runtimeMetrics.MemStats.MCacheSys) + r.Register("runtime.MemStats.MSpanInuse", runtimeMetrics.MemStats.MSpanInuse) + r.Register("runtime.MemStats.MSpanSys", runtimeMetrics.MemStats.MSpanSys) + r.Register("runtime.MemStats.NextGC", runtimeMetrics.MemStats.NextGC) + r.Register("runtime.MemStats.NumGC", runtimeMetrics.MemStats.NumGC) + r.Register("runtime.MemStats.PauseNs", runtimeMetrics.MemStats.PauseNs) + r.Register("runtime.MemStats.PauseTotalNs", runtimeMetrics.MemStats.PauseTotalNs) + r.Register("runtime.MemStats.StackInuse", runtimeMetrics.MemStats.StackInuse) + r.Register("runtime.MemStats.StackSys", runtimeMetrics.MemStats.StackSys) + r.Register("runtime.MemStats.Sys", runtimeMetrics.MemStats.Sys) + r.Register("runtime.MemStats.TotalAlloc", runtimeMetrics.MemStats.TotalAlloc) + r.Register("runtime.NumCgoCall", runtimeMetrics.NumCgoCall) + r.Register("runtime.NumGoroutine", runtimeMetrics.NumGoroutine) + r.Register("runtime.ReadMemStats", runtimeMetrics.ReadMemStats) +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_cgo.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_cgo.go new file mode 100644 index 0000000000..e3391f4e89 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_cgo.go @@ -0,0 +1,10 @@ +// +build cgo +// +build !appengine + +package metrics + +import "runtime" + +func numCgoCall() int64 { + return runtime.NumCgoCall() +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_no_cgo.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_no_cgo.go new file mode 100644 index 0000000000..616a3b4751 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_no_cgo.go @@ -0,0 +1,7 @@ +// +build !cgo appengine + +package metrics + +func numCgoCall() int64 { + return 0 +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_test.go new file mode 100644 index 0000000000..a0ca894793 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_test.go @@ -0,0 +1,78 @@ +package metrics + +import ( + "runtime" + "testing" + "time" +) + +func BenchmarkRuntimeMemStats(b *testing.B) { + r := NewRegistry() + RegisterRuntimeMemStats(r) + b.ResetTimer() + for i := 0; i < b.N; i++ { + CaptureRuntimeMemStatsOnce(r) + } +} + +func TestRuntimeMemStats(t *testing.T) { + r := NewRegistry() + RegisterRuntimeMemStats(r) + CaptureRuntimeMemStatsOnce(r) + zero := runtimeMetrics.MemStats.PauseNs.Count() // Get a "zero" since GC may have run before these tests. + runtime.GC() + CaptureRuntimeMemStatsOnce(r) + if count := runtimeMetrics.MemStats.PauseNs.Count(); 1 != count-zero { + t.Fatal(count - zero) + } + runtime.GC() + runtime.GC() + CaptureRuntimeMemStatsOnce(r) + if count := runtimeMetrics.MemStats.PauseNs.Count(); 3 != count-zero { + t.Fatal(count - zero) + } + for i := 0; i < 256; i++ { + runtime.GC() + } + CaptureRuntimeMemStatsOnce(r) + if count := runtimeMetrics.MemStats.PauseNs.Count(); 259 != count-zero { + t.Fatal(count - zero) + } + for i := 0; i < 257; i++ { + runtime.GC() + } + CaptureRuntimeMemStatsOnce(r) + if count := runtimeMetrics.MemStats.PauseNs.Count(); 515 != count-zero { // We lost one because there were too many GCs between captures. + t.Fatal(count - zero) + } +} + +func TestRuntimeMemStatsBlocking(t *testing.T) { + if g := runtime.GOMAXPROCS(0); g < 2 { + t.Skipf("skipping TestRuntimeMemStatsBlocking with GOMAXPROCS=%d\n", g) + } + ch := make(chan int) + go testRuntimeMemStatsBlocking(ch) + var memStats runtime.MemStats + t0 := time.Now() + runtime.ReadMemStats(&memStats) + t1 := time.Now() + t.Log("i++ during runtime.ReadMemStats:", <-ch) + go testRuntimeMemStatsBlocking(ch) + d := t1.Sub(t0) + t.Log(d) + time.Sleep(d) + t.Log("i++ during time.Sleep:", <-ch) +} + +func testRuntimeMemStatsBlocking(ch chan int) { + i := 0 + for { + select { + case ch <- i: + return + default: + i++ + } + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/sample.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/sample.go new file mode 100644 index 0000000000..5f6a37788e --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/sample.go @@ -0,0 +1,609 @@ +package metrics + +import ( + "math" + "math/rand" + "sort" + "sync" + "time" +) + +const rescaleThreshold = time.Hour + +// Samples maintain a statistically-significant selection of values from +// a stream. +type Sample interface { + Clear() + Count() int64 + Max() int64 + Mean() float64 + Min() int64 + Percentile(float64) float64 + Percentiles([]float64) []float64 + Size() int + Snapshot() Sample + StdDev() float64 + Sum() int64 + Update(int64) + Values() []int64 + Variance() float64 +} + +// ExpDecaySample is an exponentially-decaying sample using a forward-decaying +// priority reservoir. See Cormode et al's "Forward Decay: A Practical Time +// Decay Model for Streaming Systems". +// +// +type ExpDecaySample struct { + alpha float64 + count int64 + mutex sync.Mutex + reservoirSize int + t0, t1 time.Time + values *expDecaySampleHeap +} + +// NewExpDecaySample constructs a new exponentially-decaying sample with the +// given reservoir size and alpha. +func NewExpDecaySample(reservoirSize int, alpha float64) Sample { + if UseNilMetrics { + return NilSample{} + } + s := &ExpDecaySample{ + alpha: alpha, + reservoirSize: reservoirSize, + t0: time.Now(), + values: newExpDecaySampleHeap(reservoirSize), + } + s.t1 = s.t0.Add(rescaleThreshold) + return s +} + +// Clear clears all samples. +func (s *ExpDecaySample) Clear() { + s.mutex.Lock() + defer s.mutex.Unlock() + s.count = 0 + s.t0 = time.Now() + s.t1 = s.t0.Add(rescaleThreshold) + s.values.Clear() +} + +// Count returns the number of samples recorded, which may exceed the +// reservoir size. +func (s *ExpDecaySample) Count() int64 { + s.mutex.Lock() + defer s.mutex.Unlock() + return s.count +} + +// Max returns the maximum value in the sample, which may not be the maximum +// value ever to be part of the sample. +func (s *ExpDecaySample) Max() int64 { + return SampleMax(s.Values()) +} + +// Mean returns the mean of the values in the sample. +func (s *ExpDecaySample) Mean() float64 { + return SampleMean(s.Values()) +} + +// Min returns the minimum value in the sample, which may not be the minimum +// value ever to be part of the sample. +func (s *ExpDecaySample) Min() int64 { + return SampleMin(s.Values()) +} + +// Percentile returns an arbitrary percentile of values in the sample. +func (s *ExpDecaySample) Percentile(p float64) float64 { + return SamplePercentile(s.Values(), p) +} + +// Percentiles returns a slice of arbitrary percentiles of values in the +// sample. +func (s *ExpDecaySample) Percentiles(ps []float64) []float64 { + return SamplePercentiles(s.Values(), ps) +} + +// Size returns the size of the sample, which is at most the reservoir size. +func (s *ExpDecaySample) Size() int { + s.mutex.Lock() + defer s.mutex.Unlock() + return s.values.Size() +} + +// Snapshot returns a read-only copy of the sample. +func (s *ExpDecaySample) Snapshot() Sample { + s.mutex.Lock() + defer s.mutex.Unlock() + vals := s.values.Values() + values := make([]int64, len(vals)) + for i, v := range vals { + values[i] = v.v + } + return &SampleSnapshot{ + count: s.count, + values: values, + } +} + +// StdDev returns the standard deviation of the values in the sample. +func (s *ExpDecaySample) StdDev() float64 { + return SampleStdDev(s.Values()) +} + +// Sum returns the sum of the values in the sample. +func (s *ExpDecaySample) Sum() int64 { + return SampleSum(s.Values()) +} + +// Update samples a new value. +func (s *ExpDecaySample) Update(v int64) { + s.update(time.Now(), v) +} + +// Values returns a copy of the values in the sample. +func (s *ExpDecaySample) Values() []int64 { + s.mutex.Lock() + defer s.mutex.Unlock() + vals := s.values.Values() + values := make([]int64, len(vals)) + for i, v := range vals { + values[i] = v.v + } + return values +} + +// Variance returns the variance of the values in the sample. +func (s *ExpDecaySample) Variance() float64 { + return SampleVariance(s.Values()) +} + +// update samples a new value at a particular timestamp. This is a method all +// its own to facilitate testing. +func (s *ExpDecaySample) update(t time.Time, v int64) { + s.mutex.Lock() + defer s.mutex.Unlock() + s.count++ + if s.values.Size() == s.reservoirSize { + s.values.Pop() + } + s.values.Push(expDecaySample{ + k: math.Exp(t.Sub(s.t0).Seconds()*s.alpha) / rand.Float64(), + v: v, + }) + if t.After(s.t1) { + values := s.values.Values() + t0 := s.t0 + s.values.Clear() + s.t0 = t + s.t1 = s.t0.Add(rescaleThreshold) + for _, v := range values { + v.k = v.k * math.Exp(-s.alpha*s.t0.Sub(t0).Seconds()) + s.values.Push(v) + } + } +} + +// NilSample is a no-op Sample. +type NilSample struct{} + +// Clear is a no-op. +func (NilSample) Clear() {} + +// Count is a no-op. +func (NilSample) Count() int64 { return 0 } + +// Max is a no-op. +func (NilSample) Max() int64 { return 0 } + +// Mean is a no-op. +func (NilSample) Mean() float64 { return 0.0 } + +// Min is a no-op. +func (NilSample) Min() int64 { return 0 } + +// Percentile is a no-op. +func (NilSample) Percentile(p float64) float64 { return 0.0 } + +// Percentiles is a no-op. +func (NilSample) Percentiles(ps []float64) []float64 { + return make([]float64, len(ps)) +} + +// Size is a no-op. +func (NilSample) Size() int { return 0 } + +// Sample is a no-op. +func (NilSample) Snapshot() Sample { return NilSample{} } + +// StdDev is a no-op. +func (NilSample) StdDev() float64 { return 0.0 } + +// Sum is a no-op. +func (NilSample) Sum() int64 { return 0 } + +// Update is a no-op. +func (NilSample) Update(v int64) {} + +// Values is a no-op. +func (NilSample) Values() []int64 { return []int64{} } + +// Variance is a no-op. +func (NilSample) Variance() float64 { return 0.0 } + +// SampleMax returns the maximum value of the slice of int64. +func SampleMax(values []int64) int64 { + if 0 == len(values) { + return 0 + } + var max int64 = math.MinInt64 + for _, v := range values { + if max < v { + max = v + } + } + return max +} + +// SampleMean returns the mean value of the slice of int64. +func SampleMean(values []int64) float64 { + if 0 == len(values) { + return 0.0 + } + return float64(SampleSum(values)) / float64(len(values)) +} + +// SampleMin returns the minimum value of the slice of int64. +func SampleMin(values []int64) int64 { + if 0 == len(values) { + return 0 + } + var min int64 = math.MaxInt64 + for _, v := range values { + if min > v { + min = v + } + } + return min +} + +// SamplePercentiles returns an arbitrary percentile of the slice of int64. +func SamplePercentile(values int64Slice, p float64) float64 { + return SamplePercentiles(values, []float64{p})[0] +} + +// SamplePercentiles returns a slice of arbitrary percentiles of the slice of +// int64. +func SamplePercentiles(values int64Slice, ps []float64) []float64 { + scores := make([]float64, len(ps)) + size := len(values) + if size > 0 { + sort.Sort(values) + for i, p := range ps { + pos := p * float64(size+1) + if pos < 1.0 { + scores[i] = float64(values[0]) + } else if pos >= float64(size) { + scores[i] = float64(values[size-1]) + } else { + lower := float64(values[int(pos)-1]) + upper := float64(values[int(pos)]) + scores[i] = lower + (pos-math.Floor(pos))*(upper-lower) + } + } + } + return scores +} + +// SampleSnapshot is a read-only copy of another Sample. +type SampleSnapshot struct { + count int64 + values []int64 +} + +// Clear panics. +func (*SampleSnapshot) Clear() { + panic("Clear called on a SampleSnapshot") +} + +// Count returns the count of inputs at the time the snapshot was taken. +func (s *SampleSnapshot) Count() int64 { return s.count } + +// Max returns the maximal value at the time the snapshot was taken. +func (s *SampleSnapshot) Max() int64 { return SampleMax(s.values) } + +// Mean returns the mean value at the time the snapshot was taken. +func (s *SampleSnapshot) Mean() float64 { return SampleMean(s.values) } + +// Min returns the minimal value at the time the snapshot was taken. +func (s *SampleSnapshot) Min() int64 { return SampleMin(s.values) } + +// Percentile returns an arbitrary percentile of values at the time the +// snapshot was taken. +func (s *SampleSnapshot) Percentile(p float64) float64 { + return SamplePercentile(s.values, p) +} + +// Percentiles returns a slice of arbitrary percentiles of values at the time +// the snapshot was taken. +func (s *SampleSnapshot) Percentiles(ps []float64) []float64 { + return SamplePercentiles(s.values, ps) +} + +// Size returns the size of the sample at the time the snapshot was taken. +func (s *SampleSnapshot) Size() int { return len(s.values) } + +// Snapshot returns the snapshot. +func (s *SampleSnapshot) Snapshot() Sample { return s } + +// StdDev returns the standard deviation of values at the time the snapshot was +// taken. +func (s *SampleSnapshot) StdDev() float64 { return SampleStdDev(s.values) } + +// Sum returns the sum of values at the time the snapshot was taken. +func (s *SampleSnapshot) Sum() int64 { return SampleSum(s.values) } + +// Update panics. +func (*SampleSnapshot) Update(int64) { + panic("Update called on a SampleSnapshot") +} + +// Values returns a copy of the values in the sample. +func (s *SampleSnapshot) Values() []int64 { + values := make([]int64, len(s.values)) + copy(values, s.values) + return values +} + +// Variance returns the variance of values at the time the snapshot was taken. +func (s *SampleSnapshot) Variance() float64 { return SampleVariance(s.values) } + +// SampleStdDev returns the standard deviation of the slice of int64. +func SampleStdDev(values []int64) float64 { + return math.Sqrt(SampleVariance(values)) +} + +// SampleSum returns the sum of the slice of int64. +func SampleSum(values []int64) int64 { + var sum int64 + for _, v := range values { + sum += v + } + return sum +} + +// SampleVariance returns the variance of the slice of int64. +func SampleVariance(values []int64) float64 { + if 0 == len(values) { + return 0.0 + } + m := SampleMean(values) + var sum float64 + for _, v := range values { + d := float64(v) - m + sum += d * d + } + return sum / float64(len(values)) +} + +// A uniform sample using Vitter's Algorithm R. +// +// +type UniformSample struct { + count int64 + mutex sync.Mutex + reservoirSize int + values []int64 +} + +// NewUniformSample constructs a new uniform sample with the given reservoir +// size. +func NewUniformSample(reservoirSize int) Sample { + if UseNilMetrics { + return NilSample{} + } + return &UniformSample{ + reservoirSize: reservoirSize, + values: make([]int64, 0, reservoirSize), + } +} + +// Clear clears all samples. +func (s *UniformSample) Clear() { + s.mutex.Lock() + defer s.mutex.Unlock() + s.count = 0 + s.values = make([]int64, 0, s.reservoirSize) +} + +// Count returns the number of samples recorded, which may exceed the +// reservoir size. +func (s *UniformSample) Count() int64 { + s.mutex.Lock() + defer s.mutex.Unlock() + return s.count +} + +// Max returns the maximum value in the sample, which may not be the maximum +// value ever to be part of the sample. +func (s *UniformSample) Max() int64 { + s.mutex.Lock() + defer s.mutex.Unlock() + return SampleMax(s.values) +} + +// Mean returns the mean of the values in the sample. +func (s *UniformSample) Mean() float64 { + s.mutex.Lock() + defer s.mutex.Unlock() + return SampleMean(s.values) +} + +// Min returns the minimum value in the sample, which may not be the minimum +// value ever to be part of the sample. +func (s *UniformSample) Min() int64 { + s.mutex.Lock() + defer s.mutex.Unlock() + return SampleMin(s.values) +} + +// Percentile returns an arbitrary percentile of values in the sample. +func (s *UniformSample) Percentile(p float64) float64 { + s.mutex.Lock() + defer s.mutex.Unlock() + return SamplePercentile(s.values, p) +} + +// Percentiles returns a slice of arbitrary percentiles of values in the +// sample. +func (s *UniformSample) Percentiles(ps []float64) []float64 { + s.mutex.Lock() + defer s.mutex.Unlock() + return SamplePercentiles(s.values, ps) +} + +// Size returns the size of the sample, which is at most the reservoir size. +func (s *UniformSample) Size() int { + s.mutex.Lock() + defer s.mutex.Unlock() + return len(s.values) +} + +// Snapshot returns a read-only copy of the sample. +func (s *UniformSample) Snapshot() Sample { + s.mutex.Lock() + defer s.mutex.Unlock() + values := make([]int64, len(s.values)) + copy(values, s.values) + return &SampleSnapshot{ + count: s.count, + values: values, + } +} + +// StdDev returns the standard deviation of the values in the sample. +func (s *UniformSample) StdDev() float64 { + s.mutex.Lock() + defer s.mutex.Unlock() + return SampleStdDev(s.values) +} + +// Sum returns the sum of the values in the sample. +func (s *UniformSample) Sum() int64 { + s.mutex.Lock() + defer s.mutex.Unlock() + return SampleSum(s.values) +} + +// Update samples a new value. +func (s *UniformSample) Update(v int64) { + s.mutex.Lock() + defer s.mutex.Unlock() + s.count++ + if len(s.values) < s.reservoirSize { + s.values = append(s.values, v) + } else { + r := rand.Int63n(s.count) + if r < int64(len(s.values)) { + s.values[int(r)] = v + } + } +} + +// Values returns a copy of the values in the sample. +func (s *UniformSample) Values() []int64 { + s.mutex.Lock() + defer s.mutex.Unlock() + values := make([]int64, len(s.values)) + copy(values, s.values) + return values +} + +// Variance returns the variance of the values in the sample. +func (s *UniformSample) Variance() float64 { + s.mutex.Lock() + defer s.mutex.Unlock() + return SampleVariance(s.values) +} + +// expDecaySample represents an individual sample in a heap. +type expDecaySample struct { + k float64 + v int64 +} + +func newExpDecaySampleHeap(reservoirSize int) *expDecaySampleHeap { + return &expDecaySampleHeap{make([]expDecaySample, 0, reservoirSize)} +} + +// expDecaySampleHeap is a min-heap of expDecaySamples. +// The internal implementation is copied from the standard library's container/heap +type expDecaySampleHeap struct { + s []expDecaySample +} + +func (h *expDecaySampleHeap) Clear() { + h.s = h.s[:0] +} + +func (h *expDecaySampleHeap) Push(s expDecaySample) { + n := len(h.s) + h.s = h.s[0 : n+1] + h.s[n] = s + h.up(n) +} + +func (h *expDecaySampleHeap) Pop() expDecaySample { + n := len(h.s) - 1 + h.s[0], h.s[n] = h.s[n], h.s[0] + h.down(0, n) + + n = len(h.s) + s := h.s[n-1] + h.s = h.s[0 : n-1] + return s +} + +func (h *expDecaySampleHeap) Size() int { + return len(h.s) +} + +func (h *expDecaySampleHeap) Values() []expDecaySample { + return h.s +} + +func (h *expDecaySampleHeap) up(j int) { + for { + i := (j - 1) / 2 // parent + if i == j || !(h.s[j].k < h.s[i].k) { + break + } + h.s[i], h.s[j] = h.s[j], h.s[i] + j = i + } +} + +func (h *expDecaySampleHeap) down(i, n int) { + for { + j1 := 2*i + 1 + if j1 >= n || j1 < 0 { // j1 < 0 after int overflow + break + } + j := j1 // left child + if j2 := j1 + 1; j2 < n && !(h.s[j1].k < h.s[j2].k) { + j = j2 // = 2*i + 2 // right child + } + if !(h.s[j].k < h.s[i].k) { + break + } + h.s[i], h.s[j] = h.s[j], h.s[i] + i = j + } +} + +type int64Slice []int64 + +func (p int64Slice) Len() int { return len(p) } +func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/sample_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/sample_test.go new file mode 100644 index 0000000000..d60e99c5bb --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/sample_test.go @@ -0,0 +1,363 @@ +package metrics + +import ( + "math/rand" + "runtime" + "testing" + "time" +) + +// Benchmark{Compute,Copy}{1000,1000000} demonstrate that, even for relatively +// expensive computations like Variance, the cost of copying the Sample, as +// approximated by a make and copy, is much greater than the cost of the +// computation for small samples and only slightly less for large samples. +func BenchmarkCompute1000(b *testing.B) { + s := make([]int64, 1000) + for i := 0; i < len(s); i++ { + s[i] = int64(i) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + SampleVariance(s) + } +} +func BenchmarkCompute1000000(b *testing.B) { + s := make([]int64, 1000000) + for i := 0; i < len(s); i++ { + s[i] = int64(i) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + SampleVariance(s) + } +} +func BenchmarkCopy1000(b *testing.B) { + s := make([]int64, 1000) + for i := 0; i < len(s); i++ { + s[i] = int64(i) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + sCopy := make([]int64, len(s)) + copy(sCopy, s) + } +} +func BenchmarkCopy1000000(b *testing.B) { + s := make([]int64, 1000000) + for i := 0; i < len(s); i++ { + s[i] = int64(i) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + sCopy := make([]int64, len(s)) + copy(sCopy, s) + } +} + +func BenchmarkExpDecaySample257(b *testing.B) { + benchmarkSample(b, NewExpDecaySample(257, 0.015)) +} + +func BenchmarkExpDecaySample514(b *testing.B) { + benchmarkSample(b, NewExpDecaySample(514, 0.015)) +} + +func BenchmarkExpDecaySample1028(b *testing.B) { + benchmarkSample(b, NewExpDecaySample(1028, 0.015)) +} + +func BenchmarkUniformSample257(b *testing.B) { + benchmarkSample(b, NewUniformSample(257)) +} + +func BenchmarkUniformSample514(b *testing.B) { + benchmarkSample(b, NewUniformSample(514)) +} + +func BenchmarkUniformSample1028(b *testing.B) { + benchmarkSample(b, NewUniformSample(1028)) +} + +func TestExpDecaySample10(t *testing.T) { + rand.Seed(1) + s := NewExpDecaySample(100, 0.99) + for i := 0; i < 10; i++ { + s.Update(int64(i)) + } + if size := s.Count(); 10 != size { + t.Errorf("s.Count(): 10 != %v\n", size) + } + if size := s.Size(); 10 != size { + t.Errorf("s.Size(): 10 != %v\n", size) + } + if l := len(s.Values()); 10 != l { + t.Errorf("len(s.Values()): 10 != %v\n", l) + } + for _, v := range s.Values() { + if v > 10 || v < 0 { + t.Errorf("out of range [0, 10): %v\n", v) + } + } +} + +func TestExpDecaySample100(t *testing.T) { + rand.Seed(1) + s := NewExpDecaySample(1000, 0.01) + for i := 0; i < 100; i++ { + s.Update(int64(i)) + } + if size := s.Count(); 100 != size { + t.Errorf("s.Count(): 100 != %v\n", size) + } + if size := s.Size(); 100 != size { + t.Errorf("s.Size(): 100 != %v\n", size) + } + if l := len(s.Values()); 100 != l { + t.Errorf("len(s.Values()): 100 != %v\n", l) + } + for _, v := range s.Values() { + if v > 100 || v < 0 { + t.Errorf("out of range [0, 100): %v\n", v) + } + } +} + +func TestExpDecaySample1000(t *testing.T) { + rand.Seed(1) + s := NewExpDecaySample(100, 0.99) + for i := 0; i < 1000; i++ { + s.Update(int64(i)) + } + if size := s.Count(); 1000 != size { + t.Errorf("s.Count(): 1000 != %v\n", size) + } + if size := s.Size(); 100 != size { + t.Errorf("s.Size(): 100 != %v\n", size) + } + if l := len(s.Values()); 100 != l { + t.Errorf("len(s.Values()): 100 != %v\n", l) + } + for _, v := range s.Values() { + if v > 1000 || v < 0 { + t.Errorf("out of range [0, 1000): %v\n", v) + } + } +} + +// This test makes sure that the sample's priority is not amplified by using +// nanosecond duration since start rather than second duration since start. +// The priority becomes +Inf quickly after starting if this is done, +// effectively freezing the set of samples until a rescale step happens. +func TestExpDecaySampleNanosecondRegression(t *testing.T) { + rand.Seed(1) + s := NewExpDecaySample(100, 0.99) + for i := 0; i < 100; i++ { + s.Update(10) + } + time.Sleep(1 * time.Millisecond) + for i := 0; i < 100; i++ { + s.Update(20) + } + v := s.Values() + avg := float64(0) + for i := 0; i < len(v); i++ { + avg += float64(v[i]) + } + avg /= float64(len(v)) + if avg > 16 || avg < 14 { + t.Errorf("out of range [14, 16]: %v\n", avg) + } +} + +func TestExpDecaySampleRescale(t *testing.T) { + s := NewExpDecaySample(2, 0.001).(*ExpDecaySample) + s.update(time.Now(), 1) + s.update(time.Now().Add(time.Hour+time.Microsecond), 1) + for _, v := range s.values.Values() { + if v.k == 0.0 { + t.Fatal("v.k == 0.0") + } + } +} + +func TestExpDecaySampleSnapshot(t *testing.T) { + now := time.Now() + rand.Seed(1) + s := NewExpDecaySample(100, 0.99) + for i := 1; i <= 10000; i++ { + s.(*ExpDecaySample).update(now.Add(time.Duration(i)), int64(i)) + } + snapshot := s.Snapshot() + s.Update(1) + testExpDecaySampleStatistics(t, snapshot) +} + +func TestExpDecaySampleStatistics(t *testing.T) { + now := time.Now() + rand.Seed(1) + s := NewExpDecaySample(100, 0.99) + for i := 1; i <= 10000; i++ { + s.(*ExpDecaySample).update(now.Add(time.Duration(i)), int64(i)) + } + testExpDecaySampleStatistics(t, s) +} + +func TestUniformSample(t *testing.T) { + rand.Seed(1) + s := NewUniformSample(100) + for i := 0; i < 1000; i++ { + s.Update(int64(i)) + } + if size := s.Count(); 1000 != size { + t.Errorf("s.Count(): 1000 != %v\n", size) + } + if size := s.Size(); 100 != size { + t.Errorf("s.Size(): 100 != %v\n", size) + } + if l := len(s.Values()); 100 != l { + t.Errorf("len(s.Values()): 100 != %v\n", l) + } + for _, v := range s.Values() { + if v > 1000 || v < 0 { + t.Errorf("out of range [0, 100): %v\n", v) + } + } +} + +func TestUniformSampleIncludesTail(t *testing.T) { + rand.Seed(1) + s := NewUniformSample(100) + max := 100 + for i := 0; i < max; i++ { + s.Update(int64(i)) + } + v := s.Values() + sum := 0 + exp := (max - 1) * max / 2 + for i := 0; i < len(v); i++ { + sum += int(v[i]) + } + if exp != sum { + t.Errorf("sum: %v != %v\n", exp, sum) + } +} + +func TestUniformSampleSnapshot(t *testing.T) { + s := NewUniformSample(100) + for i := 1; i <= 10000; i++ { + s.Update(int64(i)) + } + snapshot := s.Snapshot() + s.Update(1) + testUniformSampleStatistics(t, snapshot) +} + +func TestUniformSampleStatistics(t *testing.T) { + rand.Seed(1) + s := NewUniformSample(100) + for i := 1; i <= 10000; i++ { + s.Update(int64(i)) + } + testUniformSampleStatistics(t, s) +} + +func benchmarkSample(b *testing.B, s Sample) { + var memStats runtime.MemStats + runtime.ReadMemStats(&memStats) + pauseTotalNs := memStats.PauseTotalNs + b.ResetTimer() + for i := 0; i < b.N; i++ { + s.Update(1) + } + b.StopTimer() + runtime.GC() + runtime.ReadMemStats(&memStats) + b.Logf("GC cost: %d ns/op", int(memStats.PauseTotalNs-pauseTotalNs)/b.N) +} + +func testExpDecaySampleStatistics(t *testing.T, s Sample) { + if count := s.Count(); 10000 != count { + t.Errorf("s.Count(): 10000 != %v\n", count) + } + if min := s.Min(); 107 != min { + t.Errorf("s.Min(): 107 != %v\n", min) + } + if max := s.Max(); 10000 != max { + t.Errorf("s.Max(): 10000 != %v\n", max) + } + if mean := s.Mean(); 4965.98 != mean { + t.Errorf("s.Mean(): 4965.98 != %v\n", mean) + } + if stdDev := s.StdDev(); 2959.825156930727 != stdDev { + t.Errorf("s.StdDev(): 2959.825156930727 != %v\n", stdDev) + } + ps := s.Percentiles([]float64{0.5, 0.75, 0.99}) + if 4615 != ps[0] { + t.Errorf("median: 4615 != %v\n", ps[0]) + } + if 7672 != ps[1] { + t.Errorf("75th percentile: 7672 != %v\n", ps[1]) + } + if 9998.99 != ps[2] { + t.Errorf("99th percentile: 9998.99 != %v\n", ps[2]) + } +} + +func testUniformSampleStatistics(t *testing.T, s Sample) { + if count := s.Count(); 10000 != count { + t.Errorf("s.Count(): 10000 != %v\n", count) + } + if min := s.Min(); 37 != min { + t.Errorf("s.Min(): 37 != %v\n", min) + } + if max := s.Max(); 9989 != max { + t.Errorf("s.Max(): 9989 != %v\n", max) + } + if mean := s.Mean(); 4748.14 != mean { + t.Errorf("s.Mean(): 4748.14 != %v\n", mean) + } + if stdDev := s.StdDev(); 2826.684117548333 != stdDev { + t.Errorf("s.StdDev(): 2826.684117548333 != %v\n", stdDev) + } + ps := s.Percentiles([]float64{0.5, 0.75, 0.99}) + if 4599 != ps[0] { + t.Errorf("median: 4599 != %v\n", ps[0]) + } + if 7380.5 != ps[1] { + t.Errorf("75th percentile: 7380.5 != %v\n", ps[1]) + } + if 9986.429999999998 != ps[2] { + t.Errorf("99th percentile: 9986.429999999998 != %v\n", ps[2]) + } +} + +// TestUniformSampleConcurrentUpdateCount would expose data race problems with +// concurrent Update and Count calls on Sample when test is called with -race +// argument +func TestUniformSampleConcurrentUpdateCount(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + s := NewUniformSample(100) + for i := 0; i < 100; i++ { + s.Update(int64(i)) + } + quit := make(chan struct{}) + go func() { + t := time.NewTicker(10 * time.Millisecond) + for { + select { + case <-t.C: + s.Update(rand.Int63()) + case <-quit: + t.Stop() + return + } + } + }() + for i := 0; i < 1000; i++ { + s.Count() + time.Sleep(5 * time.Millisecond) + } + quit <- struct{}{} +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/stathat/stathat.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/stathat/stathat.go new file mode 100644 index 0000000000..0afcb48482 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/stathat/stathat.go @@ -0,0 +1,69 @@ +// Metrics output to StatHat. +package stathat + +import ( + "github.com/rcrowley/go-metrics" + "github.com/stathat/go" + "log" + "time" +) + +func Stathat(r metrics.Registry, d time.Duration, userkey string) { + for { + if err := sh(r, userkey); nil != err { + log.Println(err) + } + time.Sleep(d) + } +} + +func sh(r metrics.Registry, userkey string) error { + r.Each(func(name string, i interface{}) { + switch metric := i.(type) { + case metrics.Counter: + stathat.PostEZCount(name, userkey, int(metric.Count())) + case metrics.Gauge: + stathat.PostEZValue(name, userkey, float64(metric.Value())) + case metrics.GaugeFloat64: + stathat.PostEZValue(name, userkey, float64(metric.Value())) + case metrics.Histogram: + h := metric.Snapshot() + ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + stathat.PostEZCount(name+".count", userkey, int(h.Count())) + stathat.PostEZValue(name+".min", userkey, float64(h.Min())) + stathat.PostEZValue(name+".max", userkey, float64(h.Max())) + stathat.PostEZValue(name+".mean", userkey, float64(h.Mean())) + stathat.PostEZValue(name+".std-dev", userkey, float64(h.StdDev())) + stathat.PostEZValue(name+".50-percentile", userkey, float64(ps[0])) + stathat.PostEZValue(name+".75-percentile", userkey, float64(ps[1])) + stathat.PostEZValue(name+".95-percentile", userkey, float64(ps[2])) + stathat.PostEZValue(name+".99-percentile", userkey, float64(ps[3])) + stathat.PostEZValue(name+".999-percentile", userkey, float64(ps[4])) + case metrics.Meter: + m := metric.Snapshot() + stathat.PostEZCount(name+".count", userkey, int(m.Count())) + stathat.PostEZValue(name+".one-minute", userkey, float64(m.Rate1())) + stathat.PostEZValue(name+".five-minute", userkey, float64(m.Rate5())) + stathat.PostEZValue(name+".fifteen-minute", userkey, float64(m.Rate15())) + stathat.PostEZValue(name+".mean", userkey, float64(m.RateMean())) + case metrics.Timer: + t := metric.Snapshot() + ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + stathat.PostEZCount(name+".count", userkey, int(t.Count())) + stathat.PostEZValue(name+".min", userkey, float64(t.Min())) + stathat.PostEZValue(name+".max", userkey, float64(t.Max())) + stathat.PostEZValue(name+".mean", userkey, float64(t.Mean())) + stathat.PostEZValue(name+".std-dev", userkey, float64(t.StdDev())) + stathat.PostEZValue(name+".50-percentile", userkey, float64(ps[0])) + stathat.PostEZValue(name+".75-percentile", userkey, float64(ps[1])) + stathat.PostEZValue(name+".95-percentile", userkey, float64(ps[2])) + stathat.PostEZValue(name+".99-percentile", userkey, float64(ps[3])) + stathat.PostEZValue(name+".999-percentile", userkey, float64(ps[4])) + stathat.PostEZValue(name+".one-minute", userkey, float64(t.Rate1())) + stathat.PostEZValue(name+".five-minute", userkey, float64(t.Rate5())) + stathat.PostEZValue(name+".fifteen-minute", userkey, float64(t.Rate15())) + stathat.PostEZValue(name+".mean-rate", userkey, float64(t.RateMean())) + } + }) + return nil +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/syslog.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/syslog.go new file mode 100644 index 0000000000..693f190855 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/syslog.go @@ -0,0 +1,78 @@ +// +build !windows + +package metrics + +import ( + "fmt" + "log/syslog" + "time" +) + +// Output each metric in the given registry to syslog periodically using +// the given syslogger. +func Syslog(r Registry, d time.Duration, w *syslog.Writer) { + for _ = range time.Tick(d) { + r.Each(func(name string, i interface{}) { + switch metric := i.(type) { + case Counter: + w.Info(fmt.Sprintf("counter %s: count: %d", name, metric.Count())) + case Gauge: + w.Info(fmt.Sprintf("gauge %s: value: %d", name, metric.Value())) + case GaugeFloat64: + w.Info(fmt.Sprintf("gauge %s: value: %f", name, metric.Value())) + case Healthcheck: + metric.Check() + w.Info(fmt.Sprintf("healthcheck %s: error: %v", name, metric.Error())) + case Histogram: + h := metric.Snapshot() + ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + w.Info(fmt.Sprintf( + "histogram %s: count: %d min: %d max: %d mean: %.2f stddev: %.2f median: %.2f 75%%: %.2f 95%%: %.2f 99%%: %.2f 99.9%%: %.2f", + name, + h.Count(), + h.Min(), + h.Max(), + h.Mean(), + h.StdDev(), + ps[0], + ps[1], + ps[2], + ps[3], + ps[4], + )) + case Meter: + m := metric.Snapshot() + w.Info(fmt.Sprintf( + "meter %s: count: %d 1-min: %.2f 5-min: %.2f 15-min: %.2f mean: %.2f", + name, + m.Count(), + m.Rate1(), + m.Rate5(), + m.Rate15(), + m.RateMean(), + )) + case Timer: + t := metric.Snapshot() + ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + w.Info(fmt.Sprintf( + "timer %s: count: %d min: %d max: %d mean: %.2f stddev: %.2f median: %.2f 75%%: %.2f 95%%: %.2f 99%%: %.2f 99.9%%: %.2f 1-min: %.2f 5-min: %.2f 15-min: %.2f mean-rate: %.2f", + name, + t.Count(), + t.Min(), + t.Max(), + t.Mean(), + t.StdDev(), + ps[0], + ps[1], + ps[2], + ps[3], + ps[4], + t.Rate1(), + t.Rate5(), + t.Rate15(), + t.RateMean(), + )) + } + }) + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/timer.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/timer.go new file mode 100644 index 0000000000..17db8f8d20 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/timer.go @@ -0,0 +1,311 @@ +package metrics + +import ( + "sync" + "time" +) + +// Timers capture the duration and rate of events. +type Timer interface { + Count() int64 + Max() int64 + Mean() float64 + Min() int64 + Percentile(float64) float64 + Percentiles([]float64) []float64 + Rate1() float64 + Rate5() float64 + Rate15() float64 + RateMean() float64 + Snapshot() Timer + StdDev() float64 + Sum() int64 + Time(func()) + Update(time.Duration) + UpdateSince(time.Time) + Variance() float64 +} + +// GetOrRegisterTimer returns an existing Timer or constructs and registers a +// new StandardTimer. +func GetOrRegisterTimer(name string, r Registry) Timer { + if nil == r { + r = DefaultRegistry + } + return r.GetOrRegister(name, NewTimer).(Timer) +} + +// NewCustomTimer constructs a new StandardTimer from a Histogram and a Meter. +func NewCustomTimer(h Histogram, m Meter) Timer { + if UseNilMetrics { + return NilTimer{} + } + return &StandardTimer{ + histogram: h, + meter: m, + } +} + +// NewRegisteredTimer constructs and registers a new StandardTimer. +func NewRegisteredTimer(name string, r Registry) Timer { + c := NewTimer() + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + +// NewTimer constructs a new StandardTimer using an exponentially-decaying +// sample with the same reservoir size and alpha as UNIX load averages. +func NewTimer() Timer { + if UseNilMetrics { + return NilTimer{} + } + return &StandardTimer{ + histogram: NewHistogram(NewExpDecaySample(1028, 0.015)), + meter: NewMeter(), + } +} + +// NilTimer is a no-op Timer. +type NilTimer struct { + h Histogram + m Meter +} + +// Count is a no-op. +func (NilTimer) Count() int64 { return 0 } + +// Max is a no-op. +func (NilTimer) Max() int64 { return 0 } + +// Mean is a no-op. +func (NilTimer) Mean() float64 { return 0.0 } + +// Min is a no-op. +func (NilTimer) Min() int64 { return 0 } + +// Percentile is a no-op. +func (NilTimer) Percentile(p float64) float64 { return 0.0 } + +// Percentiles is a no-op. +func (NilTimer) Percentiles(ps []float64) []float64 { + return make([]float64, len(ps)) +} + +// Rate1 is a no-op. +func (NilTimer) Rate1() float64 { return 0.0 } + +// Rate5 is a no-op. +func (NilTimer) Rate5() float64 { return 0.0 } + +// Rate15 is a no-op. +func (NilTimer) Rate15() float64 { return 0.0 } + +// RateMean is a no-op. +func (NilTimer) RateMean() float64 { return 0.0 } + +// Snapshot is a no-op. +func (NilTimer) Snapshot() Timer { return NilTimer{} } + +// StdDev is a no-op. +func (NilTimer) StdDev() float64 { return 0.0 } + +// Sum is a no-op. +func (NilTimer) Sum() int64 { return 0 } + +// Time is a no-op. +func (NilTimer) Time(func()) {} + +// Update is a no-op. +func (NilTimer) Update(time.Duration) {} + +// UpdateSince is a no-op. +func (NilTimer) UpdateSince(time.Time) {} + +// Variance is a no-op. +func (NilTimer) Variance() float64 { return 0.0 } + +// StandardTimer is the standard implementation of a Timer and uses a Histogram +// and Meter. +type StandardTimer struct { + histogram Histogram + meter Meter + mutex sync.Mutex +} + +// Count returns the number of events recorded. +func (t *StandardTimer) Count() int64 { + return t.histogram.Count() +} + +// Max returns the maximum value in the sample. +func (t *StandardTimer) Max() int64 { + return t.histogram.Max() +} + +// Mean returns the mean of the values in the sample. +func (t *StandardTimer) Mean() float64 { + return t.histogram.Mean() +} + +// Min returns the minimum value in the sample. +func (t *StandardTimer) Min() int64 { + return t.histogram.Min() +} + +// Percentile returns an arbitrary percentile of the values in the sample. +func (t *StandardTimer) Percentile(p float64) float64 { + return t.histogram.Percentile(p) +} + +// Percentiles returns a slice of arbitrary percentiles of the values in the +// sample. +func (t *StandardTimer) Percentiles(ps []float64) []float64 { + return t.histogram.Percentiles(ps) +} + +// Rate1 returns the one-minute moving average rate of events per second. +func (t *StandardTimer) Rate1() float64 { + return t.meter.Rate1() +} + +// Rate5 returns the five-minute moving average rate of events per second. +func (t *StandardTimer) Rate5() float64 { + return t.meter.Rate5() +} + +// Rate15 returns the fifteen-minute moving average rate of events per second. +func (t *StandardTimer) Rate15() float64 { + return t.meter.Rate15() +} + +// RateMean returns the meter's mean rate of events per second. +func (t *StandardTimer) RateMean() float64 { + return t.meter.RateMean() +} + +// Snapshot returns a read-only copy of the timer. +func (t *StandardTimer) Snapshot() Timer { + t.mutex.Lock() + defer t.mutex.Unlock() + return &TimerSnapshot{ + histogram: t.histogram.Snapshot().(*HistogramSnapshot), + meter: t.meter.Snapshot().(*MeterSnapshot), + } +} + +// StdDev returns the standard deviation of the values in the sample. +func (t *StandardTimer) StdDev() float64 { + return t.histogram.StdDev() +} + +// Sum returns the sum in the sample. +func (t *StandardTimer) Sum() int64 { + return t.histogram.Sum() +} + +// Record the duration of the execution of the given function. +func (t *StandardTimer) Time(f func()) { + ts := time.Now() + f() + t.Update(time.Since(ts)) +} + +// Record the duration of an event. +func (t *StandardTimer) Update(d time.Duration) { + t.mutex.Lock() + defer t.mutex.Unlock() + t.histogram.Update(int64(d)) + t.meter.Mark(1) +} + +// Record the duration of an event that started at a time and ends now. +func (t *StandardTimer) UpdateSince(ts time.Time) { + t.mutex.Lock() + defer t.mutex.Unlock() + t.histogram.Update(int64(time.Since(ts))) + t.meter.Mark(1) +} + +// Variance returns the variance of the values in the sample. +func (t *StandardTimer) Variance() float64 { + return t.histogram.Variance() +} + +// TimerSnapshot is a read-only copy of another Timer. +type TimerSnapshot struct { + histogram *HistogramSnapshot + meter *MeterSnapshot +} + +// Count returns the number of events recorded at the time the snapshot was +// taken. +func (t *TimerSnapshot) Count() int64 { return t.histogram.Count() } + +// Max returns the maximum value at the time the snapshot was taken. +func (t *TimerSnapshot) Max() int64 { return t.histogram.Max() } + +// Mean returns the mean value at the time the snapshot was taken. +func (t *TimerSnapshot) Mean() float64 { return t.histogram.Mean() } + +// Min returns the minimum value at the time the snapshot was taken. +func (t *TimerSnapshot) Min() int64 { return t.histogram.Min() } + +// Percentile returns an arbitrary percentile of sampled values at the time the +// snapshot was taken. +func (t *TimerSnapshot) Percentile(p float64) float64 { + return t.histogram.Percentile(p) +} + +// Percentiles returns a slice of arbitrary percentiles of sampled values at +// the time the snapshot was taken. +func (t *TimerSnapshot) Percentiles(ps []float64) []float64 { + return t.histogram.Percentiles(ps) +} + +// Rate1 returns the one-minute moving average rate of events per second at the +// time the snapshot was taken. +func (t *TimerSnapshot) Rate1() float64 { return t.meter.Rate1() } + +// Rate5 returns the five-minute moving average rate of events per second at +// the time the snapshot was taken. +func (t *TimerSnapshot) Rate5() float64 { return t.meter.Rate5() } + +// Rate15 returns the fifteen-minute moving average rate of events per second +// at the time the snapshot was taken. +func (t *TimerSnapshot) Rate15() float64 { return t.meter.Rate15() } + +// RateMean returns the meter's mean rate of events per second at the time the +// snapshot was taken. +func (t *TimerSnapshot) RateMean() float64 { return t.meter.RateMean() } + +// Snapshot returns the snapshot. +func (t *TimerSnapshot) Snapshot() Timer { return t } + +// StdDev returns the standard deviation of the values at the time the snapshot +// was taken. +func (t *TimerSnapshot) StdDev() float64 { return t.histogram.StdDev() } + +// Sum returns the sum at the time the snapshot was taken. +func (t *TimerSnapshot) Sum() int64 { return t.histogram.Sum() } + +// Time panics. +func (*TimerSnapshot) Time(func()) { + panic("Time called on a TimerSnapshot") +} + +// Update panics. +func (*TimerSnapshot) Update(time.Duration) { + panic("Update called on a TimerSnapshot") +} + +// UpdateSince panics. +func (*TimerSnapshot) UpdateSince(time.Time) { + panic("UpdateSince called on a TimerSnapshot") +} + +// Variance returns the variance of the values at the time the snapshot was +// taken. +func (t *TimerSnapshot) Variance() float64 { return t.histogram.Variance() } diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/timer_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/timer_test.go new file mode 100644 index 0000000000..2fa415d40e --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/timer_test.go @@ -0,0 +1,81 @@ +package metrics + +import ( + "math" + "testing" + "time" +) + +func BenchmarkTimer(b *testing.B) { + tm := NewTimer() + b.ResetTimer() + for i := 0; i < b.N; i++ { + tm.Update(1) + } +} + +func TestGetOrRegisterTimer(t *testing.T) { + r := NewRegistry() + NewRegisteredTimer("foo", r).Update(47) + if tm := GetOrRegisterTimer("foo", r); 1 != tm.Count() { + t.Fatal(tm) + } +} + +func TestTimerExtremes(t *testing.T) { + tm := NewTimer() + tm.Update(math.MaxInt64) + tm.Update(0) + if stdDev := tm.StdDev(); 4.611686018427388e+18 != stdDev { + t.Errorf("tm.StdDev(): 4.611686018427388e+18 != %v\n", stdDev) + } +} + +func TestTimerFunc(t *testing.T) { + tm := NewTimer() + tm.Time(func() { time.Sleep(50e6) }) + if max := tm.Max(); 45e6 > max || max > 55e6 { + t.Errorf("tm.Max(): 45e6 > %v || %v > 55e6\n", max, max) + } +} + +func TestTimerZero(t *testing.T) { + tm := NewTimer() + if count := tm.Count(); 0 != count { + t.Errorf("tm.Count(): 0 != %v\n", count) + } + if min := tm.Min(); 0 != min { + t.Errorf("tm.Min(): 0 != %v\n", min) + } + if max := tm.Max(); 0 != max { + t.Errorf("tm.Max(): 0 != %v\n", max) + } + if mean := tm.Mean(); 0.0 != mean { + t.Errorf("tm.Mean(): 0.0 != %v\n", mean) + } + if stdDev := tm.StdDev(); 0.0 != stdDev { + t.Errorf("tm.StdDev(): 0.0 != %v\n", stdDev) + } + ps := tm.Percentiles([]float64{0.5, 0.75, 0.99}) + if 0.0 != ps[0] { + t.Errorf("median: 0.0 != %v\n", ps[0]) + } + if 0.0 != ps[1] { + t.Errorf("75th percentile: 0.0 != %v\n", ps[1]) + } + if 0.0 != ps[2] { + t.Errorf("99th percentile: 0.0 != %v\n", ps[2]) + } + if rate1 := tm.Rate1(); 0.0 != rate1 { + t.Errorf("tm.Rate1(): 0.0 != %v\n", rate1) + } + if rate5 := tm.Rate5(); 0.0 != rate5 { + t.Errorf("tm.Rate5(): 0.0 != %v\n", rate5) + } + if rate15 := tm.Rate15(); 0.0 != rate15 { + t.Errorf("tm.Rate15(): 0.0 != %v\n", rate15) + } + if rateMean := tm.RateMean(); 0.0 != rateMean { + t.Errorf("tm.RateMean(): 0.0 != %v\n", rateMean) + } +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/writer.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/writer.go new file mode 100644 index 0000000000..091e971d2e --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/writer.go @@ -0,0 +1,100 @@ +package metrics + +import ( + "fmt" + "io" + "sort" + "time" +) + +// Write sorts writes each metric in the given registry periodically to the +// given io.Writer. +func Write(r Registry, d time.Duration, w io.Writer) { + for _ = range time.Tick(d) { + WriteOnce(r, w) + } +} + +// WriteOnce sorts and writes metrics in the given registry to the given +// io.Writer. +func WriteOnce(r Registry, w io.Writer) { + var namedMetrics namedMetricSlice + r.Each(func(name string, i interface{}) { + namedMetrics = append(namedMetrics, namedMetric{name, i}) + }) + + sort.Sort(namedMetrics) + for _, namedMetric := range namedMetrics { + switch metric := namedMetric.m.(type) { + case Counter: + fmt.Fprintf(w, "counter %s\n", namedMetric.name) + fmt.Fprintf(w, " count: %9d\n", metric.Count()) + case Gauge: + fmt.Fprintf(w, "gauge %s\n", namedMetric.name) + fmt.Fprintf(w, " value: %9d\n", metric.Value()) + case GaugeFloat64: + fmt.Fprintf(w, "gauge %s\n", namedMetric.name) + fmt.Fprintf(w, " value: %f\n", metric.Value()) + case Healthcheck: + metric.Check() + fmt.Fprintf(w, "healthcheck %s\n", namedMetric.name) + fmt.Fprintf(w, " error: %v\n", metric.Error()) + case Histogram: + h := metric.Snapshot() + ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + fmt.Fprintf(w, "histogram %s\n", namedMetric.name) + fmt.Fprintf(w, " count: %9d\n", h.Count()) + fmt.Fprintf(w, " min: %9d\n", h.Min()) + fmt.Fprintf(w, " max: %9d\n", h.Max()) + fmt.Fprintf(w, " mean: %12.2f\n", h.Mean()) + fmt.Fprintf(w, " stddev: %12.2f\n", h.StdDev()) + fmt.Fprintf(w, " median: %12.2f\n", ps[0]) + fmt.Fprintf(w, " 75%%: %12.2f\n", ps[1]) + fmt.Fprintf(w, " 95%%: %12.2f\n", ps[2]) + fmt.Fprintf(w, " 99%%: %12.2f\n", ps[3]) + fmt.Fprintf(w, " 99.9%%: %12.2f\n", ps[4]) + case Meter: + m := metric.Snapshot() + fmt.Fprintf(w, "meter %s\n", namedMetric.name) + fmt.Fprintf(w, " count: %9d\n", m.Count()) + fmt.Fprintf(w, " 1-min rate: %12.2f\n", m.Rate1()) + fmt.Fprintf(w, " 5-min rate: %12.2f\n", m.Rate5()) + fmt.Fprintf(w, " 15-min rate: %12.2f\n", m.Rate15()) + fmt.Fprintf(w, " mean rate: %12.2f\n", m.RateMean()) + case Timer: + t := metric.Snapshot() + ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + fmt.Fprintf(w, "timer %s\n", namedMetric.name) + fmt.Fprintf(w, " count: %9d\n", t.Count()) + fmt.Fprintf(w, " min: %9d\n", t.Min()) + fmt.Fprintf(w, " max: %9d\n", t.Max()) + fmt.Fprintf(w, " mean: %12.2f\n", t.Mean()) + fmt.Fprintf(w, " stddev: %12.2f\n", t.StdDev()) + fmt.Fprintf(w, " median: %12.2f\n", ps[0]) + fmt.Fprintf(w, " 75%%: %12.2f\n", ps[1]) + fmt.Fprintf(w, " 95%%: %12.2f\n", ps[2]) + fmt.Fprintf(w, " 99%%: %12.2f\n", ps[3]) + fmt.Fprintf(w, " 99.9%%: %12.2f\n", ps[4]) + fmt.Fprintf(w, " 1-min rate: %12.2f\n", t.Rate1()) + fmt.Fprintf(w, " 5-min rate: %12.2f\n", t.Rate5()) + fmt.Fprintf(w, " 15-min rate: %12.2f\n", t.Rate15()) + fmt.Fprintf(w, " mean rate: %12.2f\n", t.RateMean()) + } + } +} + +type namedMetric struct { + name string + m interface{} +} + +// namedMetricSlice is a slice of namedMetrics that implements sort.Interface. +type namedMetricSlice []namedMetric + +func (nms namedMetricSlice) Len() int { return len(nms) } + +func (nms namedMetricSlice) Swap(i, j int) { nms[i], nms[j] = nms[j], nms[i] } + +func (nms namedMetricSlice) Less(i, j int) bool { + return nms[i].name < nms[j].name +} diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/writer_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/writer_test.go new file mode 100644 index 0000000000..1aacc28712 --- /dev/null +++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/writer_test.go @@ -0,0 +1,22 @@ +package metrics + +import ( + "sort" + "testing" +) + +func TestMetricsSorting(t *testing.T) { + var namedMetrics = namedMetricSlice{ + {name: "zzz"}, + {name: "bbb"}, + {name: "fff"}, + {name: "ggg"}, + } + + sort.Sort(namedMetrics) + for i, name := range []string{"bbb", "fff", "ggg", "zzz"} { + if namedMetrics[i].name != name { + t.Fail() + } + } +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/.gitignore b/Godeps/_workspace/src/github.com/robertkrimen/otto/.gitignore new file mode 100644 index 0000000000..8c2a16949e --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/.gitignore @@ -0,0 +1,5 @@ +/.test +/otto/otto +/otto/otto-* +/test/test-*.js +/test/tester diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/DESIGN.markdown b/Godeps/_workspace/src/github.com/robertkrimen/otto/DESIGN.markdown new file mode 100644 index 0000000000..2887529878 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/DESIGN.markdown @@ -0,0 +1 @@ +* Designate the filename of "anonymous" source code by the hash (md5/sha1, etc.) diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/LICENSE b/Godeps/_workspace/src/github.com/robertkrimen/otto/LICENSE new file mode 100644 index 0000000000..b6179fe387 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2012 Robert Krimen + +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/Godeps/_workspace/src/github.com/robertkrimen/otto/Makefile b/Godeps/_workspace/src/github.com/robertkrimen/otto/Makefile new file mode 100644 index 0000000000..8d74038eb2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/Makefile @@ -0,0 +1,63 @@ +.PHONY: test test-race test-release release release-check test-262 +.PHONY: parser +.PHONY: otto assets underscore + +TESTS := \ + ~ + +TEST := -v --run +TEST := -v +TEST := -v --run Test\($(subst $(eval) ,\|,$(TESTS))\) +TEST := . + +test: parser inline.go + go test -i + go test $(TEST) + @echo PASS + +parser: + $(MAKE) -C parser + +inline.go: inline + ./$< > $@ + +################# +# release, test # +################# + +release: test-race test-release + for package in . parser token ast file underscore registry; do (cd $$package && godocdown --signature > README.markdown); done + @echo \*\*\* make release-check + @echo PASS + +release-check: .test + $(MAKE) -C test build test + $(MAKE) -C .test/test262 build test + @echo PASS + +test-262: .test + $(MAKE) -C .test/test262 build test + @echo PASS + +test-release: + go test -i + go test + +test-race: + go test -race -i + go test -race + +################################# +# otto, assets, underscore, ... # +################################# + +otto: + $(MAKE) -C otto + +assets: + mkdir -p .assets + for file in underscore/test/*.js; do tr "\`" "_" < $$file > .assets/`basename $$file`; done + +underscore: + $(MAKE) -C $@ + diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/README.markdown b/Godeps/_workspace/src/github.com/robertkrimen/otto/README.markdown new file mode 100644 index 0000000000..571743bf13 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/README.markdown @@ -0,0 +1,825 @@ +# otto +-- + import "github.com/robertkrimen/otto" + +Package otto is a JavaScript parser and interpreter written natively in Go. + +http://godoc.org/github.com/robertkrimen/otto + + import ( + "github.com/robertkrimen/otto" + ) + +Run something in the VM + + vm := otto.New() + vm.Run(` + abc = 2 + 2; + console.log("The value of abc is " + abc); // 4 + `) + +Get a value out of the VM + + value, err := vm.Get("abc") + value, _ := value.ToInteger() + } + +Set a number + + vm.Set("def", 11) + vm.Run(` + console.log("The value of def is " + def); + // The value of def is 11 + `) + +Set a string + + vm.Set("xyzzy", "Nothing happens.") + vm.Run(` + console.log(xyzzy.length); // 16 + `) + +Get the value of an expression + + value, _ = vm.Run("xyzzy.length") + { + // value is an int64 with a value of 16 + value, _ := value.ToInteger() + } + +An error happens + + value, err = vm.Run("abcdefghijlmnopqrstuvwxyz.length") + if err != nil { + // err = ReferenceError: abcdefghijlmnopqrstuvwxyz is not defined + // If there is an error, then value.IsUndefined() is true + ... + } + +Set a Go function + + vm.Set("sayHello", func(call otto.FunctionCall) otto.Value { + fmt.Printf("Hello, %s.\n", call.Argument(0).String()) + return otto.Value{} + }) + +Set a Go function that returns something useful + + vm.Set("twoPlus", func(call otto.FunctionCall) otto.Value { + right, _ := call.Argument(0).ToInteger() + result, _ := vm.ToValue(2 + right) + return result + }) + +Use the functions in JavaScript + + result, _ = vm.Run(` + sayHello("Xyzzy"); // Hello, Xyzzy. + sayHello(); // Hello, undefined + + result = twoPlus(2.0); // 4 + `) + + +### Parser + +A separate parser is available in the parser package if you're just interested +in building an AST. + +http://godoc.org/github.com/robertkrimen/otto/parser + +Parse and return an AST + + filename := "" // A filename is optional + src := ` + // Sample xyzzy example + (function(){ + if (3.14159 > 0) { + console.log("Hello, World."); + return; + } + + var xyzzy = NaN; + console.log("Nothing happens."); + return xyzzy; + })(); + ` + + // Parse some JavaScript, yielding a *ast.Program and/or an ErrorList + program, err := parser.ParseFile(nil, filename, src, 0) + +### otto + +You can run (Go) JavaScript from the commandline with: +http://github.com/robertkrimen/otto/tree/master/otto + + $ go get -v github.com/robertkrimen/otto/otto + +Run JavaScript by entering some source on stdin or by giving otto a filename: + + $ otto example.js + +### underscore + +Optionally include the JavaScript utility-belt library, underscore, with this +import: + + import ( + "github.com/robertkrimen/otto" + _ "github.com/robertkrimen/otto/underscore" + ) + + // Now every otto runtime will come loaded with underscore + +For more information: http://github.com/robertkrimen/otto/tree/master/underscore + + +### Caveat Emptor + +The following are some limitations with otto: + + * "use strict" will parse, but does nothing. + * The regular expression engine (re2/regexp) is not fully compatible with the ECMA5 specification. + + +### Regular Expression Incompatibility + +Go translates JavaScript-style regular expressions into something that is +"regexp" compatible via `parser.TransformRegExp`. Unfortunately, RegExp requires +backtracking for some patterns, and backtracking is not supported by the +standard Go engine: https://code.google.com/p/re2/wiki/Syntax + +Therefore, the following syntax is incompatible: + + (?=) // Lookahead (positive), currently a parsing error + (?!) // Lookahead (backhead), currently a parsing error + \1 // Backreference (\1, \2, \3, ...), currently a parsing error + +A brief discussion of these limitations: "Regexp (?!re)" +https://groups.google.com/forum/?fromgroups=#%21topic/golang-nuts/7qgSDWPIh_E + +More information about re2: https://code.google.com/p/re2/ + +In addition to the above, re2 (Go) has a different definition for \s: [\t\n\f\r +]. The JavaScript definition, on the other hand, also includes \v, Unicode +"Separator, Space", etc. + + +### Halting Problem + +If you want to stop long running executions (like third-party code), you can use +the interrupt channel to do this: + + package main + + import ( + "errors" + "fmt" + "os" + "time" + + "github.com/robertkrimen/otto" + ) + + var halt = errors.New("Stahp") + + func main() { + runUnsafe(`var abc = [];`) + runUnsafe(` + while (true) { + // Loop forever + }`) + } + + func runUnsafe(unsafe string) { + start := time.Now() + defer func() { + duration := time.Since(start) + if caught := recover(); caught != nil { + if caught == halt { + fmt.Fprintf(os.Stderr, "Some code took to long! Stopping after: %v\n", duration) + return + } + panic(caught) // Something else happened, repanic! + } + fmt.Fprintf(os.Stderr, "Ran code successfully: %v\n", duration) + }() + + vm := otto.New() + vm.Interrupt = make(chan func(), 1) // The buffer prevents blocking + + go func() { + time.Sleep(2 * time.Second) // Stop after two seconds + vm.Interrupt <- func() { + panic(halt) + } + }() + + vm.Run(unsafe) // Here be dragons (risky code) + } + +Where is setTimeout/setInterval? + +These timing functions are not actually part of the ECMA-262 specification. +Typically, they belong to the `windows` object (in the browser). It would not be +difficult to provide something like these via Go, but you probably want to wrap +otto in an event loop in that case. + +For an example of how this could be done in Go with otto, see natto: + +http://github.com/robertkrimen/natto + +Here is some more discussion of the issue: + +* http://book.mixu.net/node/ch2.html + +* http://en.wikipedia.org/wiki/Reentrancy_%28computing%29 + +* http://aaroncrane.co.uk/2009/02/perl_safe_signals/ + +## Usage + +```go +var ErrVersion = errors.New("version mismatch") +``` + +#### type Error + +```go +type Error struct { +} +``` + +An Error represents a runtime error, e.g. a TypeError, a ReferenceError, etc. + +#### func (Error) Error + +```go +func (err Error) Error() string +``` +Error returns a description of the error + + TypeError: 'def' is not a function + +#### func (Error) String + +```go +func (err Error) String() string +``` +String returns a description of the error and a trace of where the error +occurred. + + TypeError: 'def' is not a function + at xyz (:3:9) + at :7:1/ + +#### type FunctionCall + +```go +type FunctionCall struct { + This Value + ArgumentList []Value + Otto *Otto +} +``` + +FunctionCall is an encapsulation of a JavaScript function call. + +#### func (FunctionCall) Argument + +```go +func (self FunctionCall) Argument(index int) Value +``` +Argument will return the value of the argument at the given index. + +If no such argument exists, undefined is returned. + +#### type Object + +```go +type Object struct { +} +``` + +Object is the representation of a JavaScript object. + +#### func (Object) Call + +```go +func (self Object) Call(name string, argumentList ...interface{}) (Value, error) +``` +Call a method on the object. + +It is essentially equivalent to: + + var method, _ := object.Get(name) + method.Call(object, argumentList...) + +An undefined value and an error will result if: + + 1. There is an error during conversion of the argument list + 2. The property is not actually a function + 3. An (uncaught) exception is thrown + +#### func (Object) Class + +```go +func (self Object) Class() string +``` +Class will return the class string of the object. + +The return value will (generally) be one of: + + Object + Function + Array + String + Number + Boolean + Date + RegExp + +#### func (Object) Get + +```go +func (self Object) Get(name string) (Value, error) +``` +Get the value of the property with the given name. + +#### func (Object) Keys + +```go +func (self Object) Keys() []string +``` +Get the keys for the object + +Equivalent to calling Object.keys on the object + +#### func (Object) Set + +```go +func (self Object) Set(name string, value interface{}) error +``` +Set the property of the given name to the given value. + +An error will result if the setting the property triggers an exception (i.e. +read-only), or there is an error during conversion of the given value. + +#### func (Object) Value + +```go +func (self Object) Value() Value +``` +Value will return self as a value. + +#### type Otto + +```go +type Otto struct { + // Interrupt is a channel for interrupting the runtime. You can use this to halt a long running execution, for example. + // See "Halting Problem" for more information. + Interrupt chan func() +} +``` + +Otto is the representation of the JavaScript runtime. Each instance of Otto has +a self-contained namespace. + +#### func New + +```go +func New() *Otto +``` +New will allocate a new JavaScript runtime + +#### func Run + +```go +func Run(src interface{}) (*Otto, Value, error) +``` +Run will allocate a new JavaScript runtime, run the given source on the +allocated runtime, and return the runtime, resulting value, and error (if any). + +src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST +always be in UTF-8. + +src may also be a Script. + +src may also be a Program, but if the AST has been modified, then runtime +behavior is undefined. + +#### func (Otto) Call + +```go +func (self Otto) Call(source string, this interface{}, argumentList ...interface{}) (Value, error) +``` +Call the given JavaScript with a given this and arguments. + +If this is nil, then some special handling takes place to determine the proper +this value, falling back to a "standard" invocation if necessary (where this is +undefined). + +If source begins with "new " (A lowercase new followed by a space), then Call +will invoke the function constructor rather than performing a function call. In +this case, the this argument has no effect. + + // value is a String object + value, _ := vm.Call("Object", nil, "Hello, World.") + + // Likewise... + value, _ := vm.Call("new Object", nil, "Hello, World.") + + // This will perform a concat on the given array and return the result + // value is [ 1, 2, 3, undefined, 4, 5, 6, 7, "abc" ] + value, _ := vm.Call(`[ 1, 2, 3, undefined, 4 ].concat`, nil, 5, 6, 7, "abc") + +#### func (*Otto) Compile + +```go +func (self *Otto) Compile(filename string, src interface{}) (*Script, error) +``` +Compile will parse the given source and return a Script value or nil and an +error if there was a problem during compilation. + + script, err := vm.Compile("", `var abc; if (!abc) abc = 0; abc += 2; abc;`) + vm.Run(script) + +#### func (*Otto) Copy + +```go +func (in *Otto) Copy() *Otto +``` +Copy will create a copy/clone of the runtime. + +Copy is useful for saving some time when creating many similar runtimes. + +This method works by walking the original runtime and cloning each object, +scope, stash, etc. into a new runtime. + +Be on the lookout for memory leaks or inadvertent sharing of resources. + +#### func (Otto) Get + +```go +func (self Otto) Get(name string) (Value, error) +``` +Get the value of the top-level binding of the given name. + +If there is an error (like the binding does not exist), then the value will be +undefined. + +#### func (Otto) Object + +```go +func (self Otto) Object(source string) (*Object, error) +``` +Object will run the given source and return the result as an object. + +For example, accessing an existing object: + + object, _ := vm.Object(`Number`) + +Or, creating a new object: + + object, _ := vm.Object(`({ xyzzy: "Nothing happens." })`) + +Or, creating and assigning an object: + + object, _ := vm.Object(`xyzzy = {}`) + object.Set("volume", 11) + +If there is an error (like the source does not result in an object), then nil +and an error is returned. + +#### func (Otto) Run + +```go +func (self Otto) Run(src interface{}) (Value, error) +``` +Run will run the given source (parsing it first if necessary), returning the +resulting value and error (if any) + +src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST +always be in UTF-8. + +If the runtime is unable to parse source, then this function will return +undefined and the parse error (nothing will be evaluated in this case). + +src may also be a Script. + +src may also be a Program, but if the AST has been modified, then runtime +behavior is undefined. + +#### func (Otto) Set + +```go +func (self Otto) Set(name string, value interface{}) error +``` +Set the top-level binding of the given name to the given value. + +Set will automatically apply ToValue to the given value in order to convert it +to a JavaScript value (type Value). + +If there is an error (like the binding is read-only, or the ToValue conversion +fails), then an error is returned. + +If the top-level binding does not exist, it will be created. + +#### func (Otto) ToValue + +```go +func (self Otto) ToValue(value interface{}) (Value, error) +``` +ToValue will convert an interface{} value to a value digestible by +otto/JavaScript. + +#### type Script + +```go +type Script struct { +} +``` + +Script is a handle for some (reusable) JavaScript. Passing a Script value to a +run method will evaluate the JavaScript. + +#### func (*Script) String + +```go +func (self *Script) String() string +``` + +#### type Value + +```go +type Value struct { +} +``` + +Value is the representation of a JavaScript value. + +#### func FalseValue + +```go +func FalseValue() Value +``` +FalseValue will return a value representing false. + +It is equivalent to: + + ToValue(false) + +#### func NaNValue + +```go +func NaNValue() Value +``` +NaNValue will return a value representing NaN. + +It is equivalent to: + + ToValue(math.NaN()) + +#### func NullValue + +```go +func NullValue() Value +``` +NullValue will return a Value representing null. + +#### func ToValue + +```go +func ToValue(value interface{}) (Value, error) +``` +ToValue will convert an interface{} value to a value digestible by +otto/JavaScript + +This function will not work for advanced types (struct, map, slice/array, etc.) +and you should use Otto.ToValue instead. + +#### func TrueValue + +```go +func TrueValue() Value +``` +TrueValue will return a value representing true. + +It is equivalent to: + + ToValue(true) + +#### func UndefinedValue + +```go +func UndefinedValue() Value +``` +UndefinedValue will return a Value representing undefined. + +#### func (Value) Call + +```go +func (value Value) Call(this Value, argumentList ...interface{}) (Value, error) +``` +Call the value as a function with the given this value and argument list and +return the result of invocation. It is essentially equivalent to: + + value.apply(thisValue, argumentList) + +An undefined value and an error will result if: + + 1. There is an error during conversion of the argument list + 2. The value is not actually a function + 3. An (uncaught) exception is thrown + +#### func (Value) Class + +```go +func (value Value) Class() string +``` +Class will return the class string of the value or the empty string if value is +not an object. + +The return value will (generally) be one of: + + Object + Function + Array + String + Number + Boolean + Date + RegExp + +#### func (Value) Export + +```go +func (self Value) Export() (interface{}, error) +``` +Export will attempt to convert the value to a Go representation and return it +via an interface{} kind. + +Export returns an error, but it will always be nil. It is present for backwards +compatibility. + +If a reasonable conversion is not possible, then the original value is returned. + + undefined -> nil (FIXME?: Should be Value{}) + null -> nil + boolean -> bool + number -> A number type (int, float32, uint64, ...) + string -> string + Array -> []interface{} + Object -> map[string]interface{} + +#### func (Value) IsBoolean + +```go +func (value Value) IsBoolean() bool +``` +IsBoolean will return true if value is a boolean (primitive). + +#### func (Value) IsDefined + +```go +func (value Value) IsDefined() bool +``` +IsDefined will return false if the value is undefined, and true otherwise. + +#### func (Value) IsFunction + +```go +func (value Value) IsFunction() bool +``` +IsFunction will return true if value is a function. + +#### func (Value) IsNaN + +```go +func (value Value) IsNaN() bool +``` +IsNaN will return true if value is NaN (or would convert to NaN). + +#### func (Value) IsNull + +```go +func (value Value) IsNull() bool +``` +IsNull will return true if the value is null, and false otherwise. + +#### func (Value) IsNumber + +```go +func (value Value) IsNumber() bool +``` +IsNumber will return true if value is a number (primitive). + +#### func (Value) IsObject + +```go +func (value Value) IsObject() bool +``` +IsObject will return true if value is an object. + +#### func (Value) IsPrimitive + +```go +func (value Value) IsPrimitive() bool +``` +IsPrimitive will return true if value is a primitive (any kind of primitive). + +#### func (Value) IsString + +```go +func (value Value) IsString() bool +``` +IsString will return true if value is a string (primitive). + +#### func (Value) IsUndefined + +```go +func (value Value) IsUndefined() bool +``` +IsUndefined will return true if the value is undefined, and false otherwise. + +#### func (Value) Object + +```go +func (value Value) Object() *Object +``` +Object will return the object of the value, or nil if value is not an object. + +This method will not do any implicit conversion. For example, calling this +method on a string primitive value will not return a String object. + +#### func (Value) String + +```go +func (value Value) String() string +``` +String will return the value as a string. + +This method will make return the empty string if there is an error. + +#### func (Value) ToBoolean + +```go +func (value Value) ToBoolean() (bool, error) +``` +ToBoolean will convert the value to a boolean (bool). + + ToValue(0).ToBoolean() => false + ToValue("").ToBoolean() => false + ToValue(true).ToBoolean() => true + ToValue(1).ToBoolean() => true + ToValue("Nothing happens").ToBoolean() => true + +If there is an error during the conversion process (like an uncaught exception), +then the result will be false and an error. + +#### func (Value) ToFloat + +```go +func (value Value) ToFloat() (float64, error) +``` +ToFloat will convert the value to a number (float64). + + ToValue(0).ToFloat() => 0. + ToValue(1.1).ToFloat() => 1.1 + ToValue("11").ToFloat() => 11. + +If there is an error during the conversion process (like an uncaught exception), +then the result will be 0 and an error. + +#### func (Value) ToInteger + +```go +func (value Value) ToInteger() (int64, error) +``` +ToInteger will convert the value to a number (int64). + + ToValue(0).ToInteger() => 0 + ToValue(1.1).ToInteger() => 1 + ToValue("11").ToInteger() => 11 + +If there is an error during the conversion process (like an uncaught exception), +then the result will be 0 and an error. + +#### func (Value) ToString + +```go +func (value Value) ToString() (string, error) +``` +ToString will convert the value to a string (string). + + ToValue(0).ToString() => "0" + ToValue(false).ToString() => "false" + ToValue(1.1).ToString() => "1.1" + ToValue("11").ToString() => "11" + ToValue('Nothing happens.').ToString() => "Nothing happens." + +If there is an error during the conversion process (like an uncaught exception), +then the result will be the empty string ("") and an error. + +-- +**godocdown** http://github.com/robertkrimen/godocdown diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/array_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/array_test.go new file mode 100644 index 0000000000..06f481bd48 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/array_test.go @@ -0,0 +1,716 @@ +package otto + +import ( + "testing" +) + +func TestArray(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = [ undefined, "Nothing happens." ]; + abc.length; + `, 2) + + test(` + abc = ""+[0, 1, 2, 3]; + def = [].toString(); + ghi = [null, 4, "null"].toString(); + [ abc, def, ghi ]; + `, "0,1,2,3,,,4,null") + + test(`new Array(0).length`, 0) + + test(`new Array(11).length`, 11) + + test(`new Array(11, 1).length`, 2) + + test(` + abc = [0, 1, 2, 3]; + abc.xyzzy = "Nothing happens."; + delete abc[1]; + var xyzzy = delete abc.xyzzy; + [ abc, xyzzy, abc.xyzzy ]; + `, "0,,2,3,true,") + + test(` + var abc = [0, 1, 2, 3, 4]; + abc.length = 2; + abc; + `, "0,1") + + test(`raise: + [].length = 3.14159; + `, "RangeError") + + test(`raise: + new Array(3.14159); + `, "RangeError") + + test(` + Object.defineProperty(Array.prototype, "0", { + value: 100, + writable: false, + configurable: true + }); + abc = [101]; + abc.hasOwnProperty("0") && abc[0] === 101; + `, true) + + test(` + abc = [,,undefined]; + [ abc.hasOwnProperty(0), abc.hasOwnProperty(1), abc.hasOwnProperty(2) ]; + `, "false,false,true") + + test(` + abc = Object.getOwnPropertyDescriptor(Array, "prototype"); + [ [ typeof Array.prototype ], + [ abc.writable, abc.enumerable, abc.configurable ] ]; + `, "object,false,false,false") + }) +} + +func TestArray_toString(t *testing.T) { + tt(t, func() { + { + test(` + Array.prototype.toString = function() { + return "Nothing happens."; + } + abc = Array.prototype.toString(); + def = [].toString(); + ghi = [null, 4, "null"].toString(); + + [ abc, def, ghi ].join(","); + `, "Nothing happens.,Nothing happens.,Nothing happens.") + } + + { + test(` + Array.prototype.join = undefined + abc = Array.prototype.toString() + def = [].toString() + ghi = [null, 4, "null"].toString() + + abc + "," + def + "," + ghi; + `, "[object Array],[object Array],[object Array]") + } + }) +} + +func TestArray_toLocaleString(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + [ 3.14159, "abc", undefined, new Date(0) ].toLocaleString(); + `, "3.14159,abc,,1970-01-01 00:00:00") + + test(`raise: + [ { toLocaleString: undefined } ].toLocaleString(); + `, "TypeError") + }) +} + +func TestArray_concat(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = [0, 1, 2]; + def = [-1, -2, -3]; + ghi = abc.concat(def); + jkl = abc.concat(def, 3, 4, 5); + mno = def.concat(-4, -5, abc); + + [ ghi, jkl, mno ].join(";"); + `, "0,1,2,-1,-2,-3;0,1,2,-1,-2,-3,3,4,5;-1,-2,-3,-4,-5,0,1,2") + + test(` + var abc = [,1]; + var def = abc.concat([], [,]); + + def.getClass = Object.prototype.toString; + + [ def.getClass(), typeof def[0], def[1], typeof def[2], def.length ]; + `, "[object Array],undefined,1,undefined,3") + + test(` + Object.defineProperty(Array.prototype, "0", { + value: 100, + writable: false, + configurable: true + }); + + var abc = Array.prototype.concat.call(101); + + var hasProperty = abc.hasOwnProperty("0"); + var instanceOfVerify = typeof abc[0] === "object"; + var verifyValue = false; + verifyValue = abc[0] == 101; + + var verifyEnumerable = false; + for (var property in abc) { + if (property === "0" && abc.hasOwnProperty("0")) { + verifyEnumerable = true; + } + } + + var verifyWritable = false; + abc[0] = 12; + verifyWritable = abc[0] === 12; + + var verifyConfigurable = false; + delete abc[0]; + verifyConfigurable = abc.hasOwnProperty("0"); + + [ hasProperty, instanceOfVerify, verifyValue, !verifyConfigurable, verifyEnumerable, verifyWritable ]; + `, "true,true,true,true,true,true") + }) +} + +func TestArray_splice(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = [0, 1, 2]; + def = abc.splice(1, 2, 3, 4, 5); + ghi = [].concat(abc); + jkl = ghi.splice(17, 21, 7, 8, 9); + [ abc, def, ghi, jkl ].join(";"); + `, "0,3,4,5;1,2;0,3,4,5,7,8,9;") + }) +} + +func TestArray_shift(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = [0, 1, 2]; + def = abc.shift(); + ghi = [].concat(abc); + jkl = abc.shift(); + mno = [].concat(abc); + pqr = abc.shift(); + stu = [].concat(abc); + vwx = abc.shift(); + + [ abc, def, ghi, jkl, mno, pqr, stu, vwx ].join(";"); + `, ";0;1,2;1;2;2;;") + }) +} + +func TestArray_push(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = [0]; + def = abc.push(1); + ghi = [].concat(abc); + jkl = abc.push(2,3,4); + + [ abc, def, ghi, jkl ].join(";"); + `, "0,1,2,3,4;2;0,1;5") + }) +} + +func TestArray_pop(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = [0,1]; + def = abc.pop(); + ghi = [].concat(abc); + jkl = abc.pop(); + mno = [].concat(abc); + pqr = abc.pop(); + + [ abc, def, ghi, jkl, mno, pqr ].join(";"); + `, ";1;0;0;;") + }) +} + +func TestArray_slice(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = [0,1,2,3]; + def = abc.slice(); + ghi = abc.slice(1); + jkl = abc.slice(3,-1); + mno = abc.slice(2,-1); + pqr = abc.slice(-1, -10); + + [ abc, def, ghi, jkl, mno, pqr ].join(";"); + `, "0,1,2,3;0,1,2,3;1,2,3;;2;") + + // Array.protoype.slice is generic + test(` + abc = { 0: 0, 1: 1, 2: 2, 3: 3 }; + abc.length = 4; + def = Array.prototype.slice.call(abc); + ghi = Array.prototype.slice.call(abc,1); + jkl = Array.prototype.slice.call(abc,3,-1); + mno = Array.prototype.slice.call(abc,2,-1); + pqr = Array.prototype.slice.call(abc,-1,-10); + + [ abc, def, ghi, jkl, pqr ].join(";"); + `, "[object Object];0,1,2,3;1,2,3;;") + }) +} + +func TestArray_sliceArguments(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + (function(){ + return Array.prototype.slice.call(arguments, 1) + })({}, 1, 2, 3); + `, "1,2,3") + }) +} + +func TestArray_unshift(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = []; + def = abc.unshift(0); + ghi = [].concat(abc); + jkl = abc.unshift(1,2,3,4); + + [ abc, def, ghi, jkl ].join(";"); + `, "1,2,3,4,0;1;0;5") + }) +} + +func TestArray_reverse(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = [0,1,2,3].reverse(); + def = [0,1,2].reverse(); + + [ abc, def ]; + `, "3,2,1,0,2,1,0") + }) +} + +func TestArray_sort(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = [0,1,2,3].sort(); + def = [3,2,1,0].sort(); + ghi = [].sort(); + jkl = [0].sort(); + mno = [1,0].sort(); + pqr = [1,5,-10, 100, 8, 72, 401, 0.05].sort(); + stu = [1,5,-10, 100, 8, 72, 401, 0.05].sort(function(x, y){ + return x == y ? 0 : x < y ? -1 : 1 + }); + + [ abc, def, ghi, jkl, mno, pqr, stu ].join(";"); + `, "0,1,2,3;0,1,2,3;;0;0,1;-10,0.05,1,100,401,5,72,8;-10,0.05,1,5,8,72,100,401") + + test(`Array.prototype.sort.length`, 1) + }) +} + +func TestArray_isArray(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ Array.isArray.length, Array.isArray(), Array.isArray([]), Array.isArray({}) ]; + `, "1,false,true,false") + + test(`Array.isArray(Math)`, false) + }) +} + +func TestArray_indexOf(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`['a', 'b', 'c', 'b'].indexOf('b')`, 1) + + test(`['a', 'b', 'c', 'b'].indexOf('b', 2)`, 3) + + test(`['a', 'b', 'c', 'b'].indexOf('b', -2)`, 3) + + test(` + Object.prototype.indexOf = Array.prototype.indexOf; + var abc = {0: 'a', 1: 'b', 2: 'c', length: 3}; + abc.indexOf('c'); + `, 2) + + test(`[true].indexOf(true, "-Infinity")`, 0) + + test(` + var target = {}; + Math[3] = target; + Math.length = 5; + Array.prototype.indexOf.call(Math, target) === 3; + `, true) + + test(` + var _NaN = NaN; + var abc = new Array("NaN", undefined, 0, false, null, {toString:function(){return NaN}}, "false", _NaN, NaN); + abc.indexOf(NaN); + `, -1) + + test(` + var abc = {toString:function (){return 0}}; + var def = 1; + var ghi = -(4/3); + var jkl = new Array(false, undefined, null, "0", abc, -1.3333333333333, "string", -0, true, +0, def, 1, 0, false, ghi, -(4/3)); + [ jkl.indexOf(-(4/3)), jkl.indexOf(0), jkl.indexOf(-0), jkl.indexOf(1) ]; + `, "14,7,7,10") + }) +} + +func TestArray_lastIndexOf(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`['a', 'b', 'c', 'b'].lastIndexOf('b')`, 3) + + test(`['a', 'b', 'c', 'b'].lastIndexOf('b', 2)`, 1) + + test(`['a', 'b', 'c', 'b'].lastIndexOf('b', -2)`, 1) + + test(` + Object.prototype.lastIndexOf = Array.prototype.lastIndexOf; + var abc = {0: 'a', 1: 'b', 2: 'c', 3: 'b', length: 4}; + abc.lastIndexOf('b'); + `, 3) + + test(` + var target = {}; + Math[3] = target; + Math.length = 5; + [ Array.prototype.lastIndexOf.call(Math, target) === 3 ]; + `, "true") + + test(` + var _NaN = NaN; + var abc = new Array("NaN", undefined, 0, false, null, {toString:function(){return NaN}}, "false", _NaN, NaN); + abc.lastIndexOf(NaN); + `, -1) + + test(` + var abc = {toString:function (){return 0}}; + var def = 1; + var ghi = -(4/3); + var jkl = new Array(false, undefined, null, "0", abc, -1.3333333333333, "string", -0, true, +0, def, 1, 0, false, ghi, -(4/3)); + [ jkl.lastIndexOf(-(4/3)), jkl.indexOf(0), jkl.indexOf(-0), jkl.indexOf(1) ]; + `, "15,7,7,10") + }) +} + +func TestArray_every(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: [].every()`, "TypeError") + + test(`raise: [].every("abc")`, "TypeError") + + test(`[].every(function() { return false })`, true) + + test(`[1,2,3].every(function() { return false })`, false) + + test(`[1,2,3].every(function() { return true })`, true) + + test(`[1,2,3].every(function(_, index) { if (index === 1) return true })`, false) + + test(` + var abc = function(value, index, object) { + return ('[object Math]' !== Object.prototype.toString.call(object)); + }; + + Math.length = 1; + Math[0] = 1; + !Array.prototype.every.call(Math, abc); + `, true) + + test(` + var def = false; + + var abc = function(value, index, object) { + def = true; + return this === Math; + }; + + [11].every(abc, Math) && def; + `, true) + + test(` + var def = false; + + var abc = function(value, index, object) { + def = true; + return Math; + }; + + [11].every(abc) && def; + `, true) + }) +} + +func TestArray_some(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: [].some("abc")`, "TypeError") + + test(`[].some(function() { return true })`, false) + + test(`[1,2,3].some(function() { return false })`, false) + + test(`[1,2,3].some(function() { return true })`, true) + + test(`[1,2,3].some(function(_, index) { if (index === 1) return true })`, true) + + test(` + var abc = function(value, index, object) { + return ('[object Math]' !== Object.prototype.toString.call(object)); + }; + + Math.length = 1; + Math[0] = 1; + !Array.prototype.some.call(Math, abc); + `, true) + + test(` + var abc = function(value, index, object) { + return this === Math; + }; + + [11].some(abc, Math); + `, true) + + test(` + var abc = function(value, index, object) { + return Math; + }; + + [11].some(abc); + `, true) + }) +} + +func TestArray_forEach(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: [].forEach("abc")`, "TypeError") + + test(` + var abc = 0; + [].forEach(function(value) { + abc += value; + }); + abc; + `, 0) + + test(` + abc = 0; + var def = []; + [1,2,3].forEach(function(value, index) { + abc += value; + def.push(index); + }); + [ abc, def ]; + `, "6,0,1,2") + + test(` + var def = false; + var abc = function(value, index, object) { + def = ('[object Math]' === Object.prototype.toString.call(object)); + }; + + Math.length = 1; + Math[0] = 1; + Array.prototype.forEach.call(Math, abc); + def; + `, true) + + test(` + var def = false; + var abc = function(value, index, object) { + def = this === Math; + }; + + [11].forEach(abc, Math); + def; + `, true) + }) +} + +func TestArray_indexing(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = new Array(0, 1); + var def = abc.length; + abc[4294967296] = 10; // 2^32 => 0 + abc[4294967297] = 11; // 2^32+1 => 1 + [ def, abc.length, abc[0], abc[1], abc[4294967296] ]; + `, "2,2,0,1,10") + + test(` + abc = new Array(0, 1); + def = abc.length; + abc[4294967295] = 10; + var ghi = abc.length; + abc[4294967299] = 12; + var jkl = abc.length; + abc[4294967294] = 11; + [ def, ghi, jkl, abc.length, abc[4294967295], abc[4294967299] ]; + `, "2,2,2,4294967295,10,12") + }) +} + +func TestArray_map(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: [].map("abc")`, "TypeError") + + test(`[].map(function() { return 1 }).length`, 0) + + test(`[1,2,3].map(function(value) { return value * value })`, "1,4,9") + + test(`[1,2,3].map(function(value) { return 1 })`, "1,1,1") + + test(` + var abc = function(value, index, object) { + return ('[object Math]' === Object.prototype.toString.call(object)); + }; + + Math.length = 1; + Math[0] = 1; + Array.prototype.map.call(Math, abc)[0]; + `, true) + + test(` + var abc = function(value, index, object) { + return this === Math; + }; + + [11].map(abc, Math)[0]; + `, true) + }) +} + +func TestArray_filter(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: [].filter("abc")`, "TypeError") + + test(`[].filter(function() { return 1 }).length`, 0) + + test(`[1,2,3].filter(function() { return false }).length`, 0) + + test(`[1,2,3].filter(function() { return true })`, "1,2,3") + }) +} + +func TestArray_reduce(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: [].reduce("abc")`, "TypeError") + + test(`raise: [].reduce(function() {})`, "TypeError") + + test(`[].reduce(function() {}, 0)`, 0) + + test(`[].reduce(function() {}, undefined)`, "undefined") + + test(`['a','b','c'].reduce(function(result, value) { return result+', '+value })`, "a, b, c") + + test(`[1,2,3].reduce(function(result, value) { return result + value }, 4)`, 10) + + test(`[1,2,3].reduce(function(result, value) { return result + value })`, 6) + }) +} + +func TestArray_reduceRight(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: [].reduceRight("abc")`, "TypeError") + + test(`raise: [].reduceRight(function() {})`, "TypeError") + + test(`[].reduceRight(function() {}, 0)`, 0) + + test(`[].reduceRight(function() {}, undefined)`, "undefined") + + test(`['a','b','c'].reduceRight(function(result, value) { return result+', '+value })`, "c, b, a") + + test(`[1,2,3].reduceRight(function(result, value) { return result + value }, 4)`, 10) + + test(`[1,2,3].reduceRight(function(result, value) { return result + value })`, 6) + }) +} + +func TestArray_defineOwnProperty(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = []; + Object.defineProperty(abc, "length", { + writable: false + }); + abc.length; + `, 0) + + test(`raise: + var abc = []; + var exception; + Object.defineProperty(abc, "length", { + writable: false + }); + Object.defineProperty(abc, "length", { + writable: true + }); + `, "TypeError") + }) +} + +func TestArray_new(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = new Array(null); + var def = new Array(undefined); + [ abc.length, abc[0] === null, def.length, def[0] === undefined ] + `, "1,true,1,true") + + test(` + var abc = new Array(new Number(0)); + var def = new Array(new Number(4294967295)); + [ abc.length, typeof abc[0], abc[0] == 0, def.length, typeof def[0], def[0] == 4294967295 ] + `, "1,object,true,1,object,true") + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/ast/README.markdown b/Godeps/_workspace/src/github.com/robertkrimen/otto/ast/README.markdown new file mode 100644 index 0000000000..a785da9112 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/ast/README.markdown @@ -0,0 +1,1068 @@ +# ast +-- + import "github.com/robertkrimen/otto/ast" + +Package ast declares types representing a JavaScript AST. + + +### Warning + +The parser and AST interfaces are still works-in-progress (particularly where +node types are concerned) and may change in the future. + +## Usage + +#### type ArrayLiteral + +```go +type ArrayLiteral struct { + LeftBracket file.Idx + RightBracket file.Idx + Value []Expression +} +``` + + +#### func (*ArrayLiteral) Idx0 + +```go +func (self *ArrayLiteral) Idx0() file.Idx +``` + +#### func (*ArrayLiteral) Idx1 + +```go +func (self *ArrayLiteral) Idx1() file.Idx +``` + +#### type AssignExpression + +```go +type AssignExpression struct { + Operator token.Token + Left Expression + Right Expression +} +``` + + +#### func (*AssignExpression) Idx0 + +```go +func (self *AssignExpression) Idx0() file.Idx +``` + +#### func (*AssignExpression) Idx1 + +```go +func (self *AssignExpression) Idx1() file.Idx +``` + +#### type BadExpression + +```go +type BadExpression struct { + From file.Idx + To file.Idx +} +``` + + +#### func (*BadExpression) Idx0 + +```go +func (self *BadExpression) Idx0() file.Idx +``` + +#### func (*BadExpression) Idx1 + +```go +func (self *BadExpression) Idx1() file.Idx +``` + +#### type BadStatement + +```go +type BadStatement struct { + From file.Idx + To file.Idx +} +``` + + +#### func (*BadStatement) Idx0 + +```go +func (self *BadStatement) Idx0() file.Idx +``` + +#### func (*BadStatement) Idx1 + +```go +func (self *BadStatement) Idx1() file.Idx +``` + +#### type BinaryExpression + +```go +type BinaryExpression struct { + Operator token.Token + Left Expression + Right Expression + Comparison bool +} +``` + + +#### func (*BinaryExpression) Idx0 + +```go +func (self *BinaryExpression) Idx0() file.Idx +``` + +#### func (*BinaryExpression) Idx1 + +```go +func (self *BinaryExpression) Idx1() file.Idx +``` + +#### type BlockStatement + +```go +type BlockStatement struct { + LeftBrace file.Idx + List []Statement + RightBrace file.Idx +} +``` + + +#### func (*BlockStatement) Idx0 + +```go +func (self *BlockStatement) Idx0() file.Idx +``` + +#### func (*BlockStatement) Idx1 + +```go +func (self *BlockStatement) Idx1() file.Idx +``` + +#### type BooleanLiteral + +```go +type BooleanLiteral struct { + Idx file.Idx + Literal string + Value bool +} +``` + + +#### func (*BooleanLiteral) Idx0 + +```go +func (self *BooleanLiteral) Idx0() file.Idx +``` + +#### func (*BooleanLiteral) Idx1 + +```go +func (self *BooleanLiteral) Idx1() file.Idx +``` + +#### type BracketExpression + +```go +type BracketExpression struct { + Left Expression + Member Expression + LeftBracket file.Idx + RightBracket file.Idx +} +``` + + +#### func (*BracketExpression) Idx0 + +```go +func (self *BracketExpression) Idx0() file.Idx +``` + +#### func (*BracketExpression) Idx1 + +```go +func (self *BracketExpression) Idx1() file.Idx +``` + +#### type BranchStatement + +```go +type BranchStatement struct { + Idx file.Idx + Token token.Token + Label *Identifier +} +``` + + +#### func (*BranchStatement) Idx0 + +```go +func (self *BranchStatement) Idx0() file.Idx +``` + +#### func (*BranchStatement) Idx1 + +```go +func (self *BranchStatement) Idx1() file.Idx +``` + +#### type CallExpression + +```go +type CallExpression struct { + Callee Expression + LeftParenthesis file.Idx + ArgumentList []Expression + RightParenthesis file.Idx +} +``` + + +#### func (*CallExpression) Idx0 + +```go +func (self *CallExpression) Idx0() file.Idx +``` + +#### func (*CallExpression) Idx1 + +```go +func (self *CallExpression) Idx1() file.Idx +``` + +#### type CaseStatement + +```go +type CaseStatement struct { + Case file.Idx + Test Expression + Consequent []Statement +} +``` + + +#### func (*CaseStatement) Idx0 + +```go +func (self *CaseStatement) Idx0() file.Idx +``` + +#### func (*CaseStatement) Idx1 + +```go +func (self *CaseStatement) Idx1() file.Idx +``` + +#### type CatchStatement + +```go +type CatchStatement struct { + Catch file.Idx + Parameter *Identifier + Body Statement +} +``` + + +#### func (*CatchStatement) Idx0 + +```go +func (self *CatchStatement) Idx0() file.Idx +``` + +#### func (*CatchStatement) Idx1 + +```go +func (self *CatchStatement) Idx1() file.Idx +``` + +#### type ConditionalExpression + +```go +type ConditionalExpression struct { + Test Expression + Consequent Expression + Alternate Expression +} +``` + + +#### func (*ConditionalExpression) Idx0 + +```go +func (self *ConditionalExpression) Idx0() file.Idx +``` + +#### func (*ConditionalExpression) Idx1 + +```go +func (self *ConditionalExpression) Idx1() file.Idx +``` + +#### type DebuggerStatement + +```go +type DebuggerStatement struct { + Debugger file.Idx +} +``` + + +#### func (*DebuggerStatement) Idx0 + +```go +func (self *DebuggerStatement) Idx0() file.Idx +``` + +#### func (*DebuggerStatement) Idx1 + +```go +func (self *DebuggerStatement) Idx1() file.Idx +``` + +#### type Declaration + +```go +type Declaration interface { + // contains filtered or unexported methods +} +``` + +All declaration nodes implement the Declaration interface. + +#### type DoWhileStatement + +```go +type DoWhileStatement struct { + Do file.Idx + Test Expression + Body Statement +} +``` + + +#### func (*DoWhileStatement) Idx0 + +```go +func (self *DoWhileStatement) Idx0() file.Idx +``` + +#### func (*DoWhileStatement) Idx1 + +```go +func (self *DoWhileStatement) Idx1() file.Idx +``` + +#### type DotExpression + +```go +type DotExpression struct { + Left Expression + Identifier Identifier +} +``` + + +#### func (*DotExpression) Idx0 + +```go +func (self *DotExpression) Idx0() file.Idx +``` + +#### func (*DotExpression) Idx1 + +```go +func (self *DotExpression) Idx1() file.Idx +``` + +#### type EmptyStatement + +```go +type EmptyStatement struct { + Semicolon file.Idx +} +``` + + +#### func (*EmptyStatement) Idx0 + +```go +func (self *EmptyStatement) Idx0() file.Idx +``` + +#### func (*EmptyStatement) Idx1 + +```go +func (self *EmptyStatement) Idx1() file.Idx +``` + +#### type Expression + +```go +type Expression interface { + Node + // contains filtered or unexported methods +} +``` + +All expression nodes implement the Expression interface. + +#### type ExpressionStatement + +```go +type ExpressionStatement struct { + Expression Expression +} +``` + + +#### func (*ExpressionStatement) Idx0 + +```go +func (self *ExpressionStatement) Idx0() file.Idx +``` + +#### func (*ExpressionStatement) Idx1 + +```go +func (self *ExpressionStatement) Idx1() file.Idx +``` + +#### type ForInStatement + +```go +type ForInStatement struct { + For file.Idx + Into Expression + Source Expression + Body Statement +} +``` + + +#### func (*ForInStatement) Idx0 + +```go +func (self *ForInStatement) Idx0() file.Idx +``` + +#### func (*ForInStatement) Idx1 + +```go +func (self *ForInStatement) Idx1() file.Idx +``` + +#### type ForStatement + +```go +type ForStatement struct { + For file.Idx + Initializer Expression + Update Expression + Test Expression + Body Statement +} +``` + + +#### func (*ForStatement) Idx0 + +```go +func (self *ForStatement) Idx0() file.Idx +``` + +#### func (*ForStatement) Idx1 + +```go +func (self *ForStatement) Idx1() file.Idx +``` + +#### type FunctionDeclaration + +```go +type FunctionDeclaration struct { + Function *FunctionLiteral +} +``` + + +#### type FunctionLiteral + +```go +type FunctionLiteral struct { + Function file.Idx + Name *Identifier + ParameterList *ParameterList + Body Statement + Source string + + DeclarationList []Declaration +} +``` + + +#### func (*FunctionLiteral) Idx0 + +```go +func (self *FunctionLiteral) Idx0() file.Idx +``` + +#### func (*FunctionLiteral) Idx1 + +```go +func (self *FunctionLiteral) Idx1() file.Idx +``` + +#### type Identifier + +```go +type Identifier struct { + Name string + Idx file.Idx +} +``` + + +#### func (*Identifier) Idx0 + +```go +func (self *Identifier) Idx0() file.Idx +``` + +#### func (*Identifier) Idx1 + +```go +func (self *Identifier) Idx1() file.Idx +``` + +#### type IfStatement + +```go +type IfStatement struct { + If file.Idx + Test Expression + Consequent Statement + Alternate Statement +} +``` + + +#### func (*IfStatement) Idx0 + +```go +func (self *IfStatement) Idx0() file.Idx +``` + +#### func (*IfStatement) Idx1 + +```go +func (self *IfStatement) Idx1() file.Idx +``` + +#### type LabelledStatement + +```go +type LabelledStatement struct { + Label *Identifier + Colon file.Idx + Statement Statement +} +``` + + +#### func (*LabelledStatement) Idx0 + +```go +func (self *LabelledStatement) Idx0() file.Idx +``` + +#### func (*LabelledStatement) Idx1 + +```go +func (self *LabelledStatement) Idx1() file.Idx +``` + +#### type NewExpression + +```go +type NewExpression struct { + New file.Idx + Callee Expression + LeftParenthesis file.Idx + ArgumentList []Expression + RightParenthesis file.Idx +} +``` + + +#### func (*NewExpression) Idx0 + +```go +func (self *NewExpression) Idx0() file.Idx +``` + +#### func (*NewExpression) Idx1 + +```go +func (self *NewExpression) Idx1() file.Idx +``` + +#### type Node + +```go +type Node interface { + Idx0() file.Idx // The index of the first character belonging to the node + Idx1() file.Idx // The index of the first character immediately after the node +} +``` + +All nodes implement the Node interface. + +#### type NullLiteral + +```go +type NullLiteral struct { + Idx file.Idx + Literal string +} +``` + + +#### func (*NullLiteral) Idx0 + +```go +func (self *NullLiteral) Idx0() file.Idx +``` + +#### func (*NullLiteral) Idx1 + +```go +func (self *NullLiteral) Idx1() file.Idx +``` + +#### type NumberLiteral + +```go +type NumberLiteral struct { + Idx file.Idx + Literal string + Value interface{} +} +``` + + +#### func (*NumberLiteral) Idx0 + +```go +func (self *NumberLiteral) Idx0() file.Idx +``` + +#### func (*NumberLiteral) Idx1 + +```go +func (self *NumberLiteral) Idx1() file.Idx +``` + +#### type ObjectLiteral + +```go +type ObjectLiteral struct { + LeftBrace file.Idx + RightBrace file.Idx + Value []Property +} +``` + + +#### func (*ObjectLiteral) Idx0 + +```go +func (self *ObjectLiteral) Idx0() file.Idx +``` + +#### func (*ObjectLiteral) Idx1 + +```go +func (self *ObjectLiteral) Idx1() file.Idx +``` + +#### type ParameterList + +```go +type ParameterList struct { + Opening file.Idx + List []*Identifier + Closing file.Idx +} +``` + + +#### type Program + +```go +type Program struct { + Body []Statement + + DeclarationList []Declaration + + File *file.File +} +``` + + +#### func (*Program) Idx0 + +```go +func (self *Program) Idx0() file.Idx +``` + +#### func (*Program) Idx1 + +```go +func (self *Program) Idx1() file.Idx +``` + +#### type Property + +```go +type Property struct { + Key string + Kind string + Value Expression +} +``` + + +#### type RegExpLiteral + +```go +type RegExpLiteral struct { + Idx file.Idx + Literal string + Pattern string + Flags string + Value string +} +``` + + +#### func (*RegExpLiteral) Idx0 + +```go +func (self *RegExpLiteral) Idx0() file.Idx +``` + +#### func (*RegExpLiteral) Idx1 + +```go +func (self *RegExpLiteral) Idx1() file.Idx +``` + +#### type ReturnStatement + +```go +type ReturnStatement struct { + Return file.Idx + Argument Expression +} +``` + + +#### func (*ReturnStatement) Idx0 + +```go +func (self *ReturnStatement) Idx0() file.Idx +``` + +#### func (*ReturnStatement) Idx1 + +```go +func (self *ReturnStatement) Idx1() file.Idx +``` + +#### type SequenceExpression + +```go +type SequenceExpression struct { + Sequence []Expression +} +``` + + +#### func (*SequenceExpression) Idx0 + +```go +func (self *SequenceExpression) Idx0() file.Idx +``` + +#### func (*SequenceExpression) Idx1 + +```go +func (self *SequenceExpression) Idx1() file.Idx +``` + +#### type Statement + +```go +type Statement interface { + Node + // contains filtered or unexported methods +} +``` + +All statement nodes implement the Statement interface. + +#### type StringLiteral + +```go +type StringLiteral struct { + Idx file.Idx + Literal string + Value string +} +``` + + +#### func (*StringLiteral) Idx0 + +```go +func (self *StringLiteral) Idx0() file.Idx +``` + +#### func (*StringLiteral) Idx1 + +```go +func (self *StringLiteral) Idx1() file.Idx +``` + +#### type SwitchStatement + +```go +type SwitchStatement struct { + Switch file.Idx + Discriminant Expression + Default int + Body []*CaseStatement +} +``` + + +#### func (*SwitchStatement) Idx0 + +```go +func (self *SwitchStatement) Idx0() file.Idx +``` + +#### func (*SwitchStatement) Idx1 + +```go +func (self *SwitchStatement) Idx1() file.Idx +``` + +#### type ThisExpression + +```go +type ThisExpression struct { + Idx file.Idx +} +``` + + +#### func (*ThisExpression) Idx0 + +```go +func (self *ThisExpression) Idx0() file.Idx +``` + +#### func (*ThisExpression) Idx1 + +```go +func (self *ThisExpression) Idx1() file.Idx +``` + +#### type ThrowStatement + +```go +type ThrowStatement struct { + Throw file.Idx + Argument Expression +} +``` + + +#### func (*ThrowStatement) Idx0 + +```go +func (self *ThrowStatement) Idx0() file.Idx +``` + +#### func (*ThrowStatement) Idx1 + +```go +func (self *ThrowStatement) Idx1() file.Idx +``` + +#### type TryStatement + +```go +type TryStatement struct { + Try file.Idx + Body Statement + Catch *CatchStatement + Finally Statement +} +``` + + +#### func (*TryStatement) Idx0 + +```go +func (self *TryStatement) Idx0() file.Idx +``` + +#### func (*TryStatement) Idx1 + +```go +func (self *TryStatement) Idx1() file.Idx +``` + +#### type UnaryExpression + +```go +type UnaryExpression struct { + Operator token.Token + Idx file.Idx // If a prefix operation + Operand Expression + Postfix bool +} +``` + + +#### func (*UnaryExpression) Idx0 + +```go +func (self *UnaryExpression) Idx0() file.Idx +``` + +#### func (*UnaryExpression) Idx1 + +```go +func (self *UnaryExpression) Idx1() file.Idx +``` + +#### type VariableDeclaration + +```go +type VariableDeclaration struct { + Var file.Idx + List []*VariableExpression +} +``` + + +#### type VariableExpression + +```go +type VariableExpression struct { + Name string + Idx file.Idx + Initializer Expression +} +``` + + +#### func (*VariableExpression) Idx0 + +```go +func (self *VariableExpression) Idx0() file.Idx +``` + +#### func (*VariableExpression) Idx1 + +```go +func (self *VariableExpression) Idx1() file.Idx +``` + +#### type VariableStatement + +```go +type VariableStatement struct { + Var file.Idx + List []Expression +} +``` + + +#### func (*VariableStatement) Idx0 + +```go +func (self *VariableStatement) Idx0() file.Idx +``` + +#### func (*VariableStatement) Idx1 + +```go +func (self *VariableStatement) Idx1() file.Idx +``` + +#### type WhileStatement + +```go +type WhileStatement struct { + While file.Idx + Test Expression + Body Statement +} +``` + + +#### func (*WhileStatement) Idx0 + +```go +func (self *WhileStatement) Idx0() file.Idx +``` + +#### func (*WhileStatement) Idx1 + +```go +func (self *WhileStatement) Idx1() file.Idx +``` + +#### type WithStatement + +```go +type WithStatement struct { + With file.Idx + Object Expression + Body Statement +} +``` + + +#### func (*WithStatement) Idx0 + +```go +func (self *WithStatement) Idx0() file.Idx +``` + +#### func (*WithStatement) Idx1 + +```go +func (self *WithStatement) Idx1() file.Idx +``` + +-- +**godocdown** http://github.com/robertkrimen/godocdown diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/ast/node.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/ast/node.go new file mode 100644 index 0000000000..eb46f86019 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/ast/node.go @@ -0,0 +1,498 @@ +/* +Package ast declares types representing a JavaScript AST. + +Warning + +The parser and AST interfaces are still works-in-progress (particularly where +node types are concerned) and may change in the future. + +*/ +package ast + +import ( + "github.com/robertkrimen/otto/file" + "github.com/robertkrimen/otto/token" +) + +// All nodes implement the Node interface. +type Node interface { + Idx0() file.Idx // The index of the first character belonging to the node + Idx1() file.Idx // The index of the first character immediately after the node +} + +// ========== // +// Expression // +// ========== // + +type ( + // All expression nodes implement the Expression interface. + Expression interface { + Node + _expressionNode() + } + + ArrayLiteral struct { + LeftBracket file.Idx + RightBracket file.Idx + Value []Expression + } + + AssignExpression struct { + Operator token.Token + Left Expression + Right Expression + } + + BadExpression struct { + From file.Idx + To file.Idx + } + + BinaryExpression struct { + Operator token.Token + Left Expression + Right Expression + Comparison bool + } + + BooleanLiteral struct { + Idx file.Idx + Literal string + Value bool + } + + BracketExpression struct { + Left Expression + Member Expression + LeftBracket file.Idx + RightBracket file.Idx + } + + CallExpression struct { + Callee Expression + LeftParenthesis file.Idx + ArgumentList []Expression + RightParenthesis file.Idx + } + + ConditionalExpression struct { + Test Expression + Consequent Expression + Alternate Expression + } + + DotExpression struct { + Left Expression + Identifier Identifier + } + + FunctionLiteral struct { + Function file.Idx + Name *Identifier + ParameterList *ParameterList + Body Statement + Source string + + DeclarationList []Declaration + } + + Identifier struct { + Name string + Idx file.Idx + } + + NewExpression struct { + New file.Idx + Callee Expression + LeftParenthesis file.Idx + ArgumentList []Expression + RightParenthesis file.Idx + } + + NullLiteral struct { + Idx file.Idx + Literal string + } + + NumberLiteral struct { + Idx file.Idx + Literal string + Value interface{} + } + + ObjectLiteral struct { + LeftBrace file.Idx + RightBrace file.Idx + Value []Property + } + + ParameterList struct { + Opening file.Idx + List []*Identifier + Closing file.Idx + } + + Property struct { + Key string + Kind string + Value Expression + } + + RegExpLiteral struct { + Idx file.Idx + Literal string + Pattern string + Flags string + Value string + } + + SequenceExpression struct { + Sequence []Expression + } + + StringLiteral struct { + Idx file.Idx + Literal string + Value string + } + + ThisExpression struct { + Idx file.Idx + } + + UnaryExpression struct { + Operator token.Token + Idx file.Idx // If a prefix operation + Operand Expression + Postfix bool + } + + VariableExpression struct { + Name string + Idx file.Idx + Initializer Expression + } +) + +// _expressionNode + +func (*ArrayLiteral) _expressionNode() {} +func (*AssignExpression) _expressionNode() {} +func (*BadExpression) _expressionNode() {} +func (*BinaryExpression) _expressionNode() {} +func (*BooleanLiteral) _expressionNode() {} +func (*BracketExpression) _expressionNode() {} +func (*CallExpression) _expressionNode() {} +func (*ConditionalExpression) _expressionNode() {} +func (*DotExpression) _expressionNode() {} +func (*FunctionLiteral) _expressionNode() {} +func (*Identifier) _expressionNode() {} +func (*NewExpression) _expressionNode() {} +func (*NullLiteral) _expressionNode() {} +func (*NumberLiteral) _expressionNode() {} +func (*ObjectLiteral) _expressionNode() {} +func (*RegExpLiteral) _expressionNode() {} +func (*SequenceExpression) _expressionNode() {} +func (*StringLiteral) _expressionNode() {} +func (*ThisExpression) _expressionNode() {} +func (*UnaryExpression) _expressionNode() {} +func (*VariableExpression) _expressionNode() {} + +// ========= // +// Statement // +// ========= // + +type ( + // All statement nodes implement the Statement interface. + Statement interface { + Node + _statementNode() + } + + BadStatement struct { + From file.Idx + To file.Idx + } + + BlockStatement struct { + LeftBrace file.Idx + List []Statement + RightBrace file.Idx + } + + BranchStatement struct { + Idx file.Idx + Token token.Token + Label *Identifier + } + + CaseStatement struct { + Case file.Idx + Test Expression + Consequent []Statement + } + + CatchStatement struct { + Catch file.Idx + Parameter *Identifier + Body Statement + } + + DebuggerStatement struct { + Debugger file.Idx + } + + DoWhileStatement struct { + Do file.Idx + Test Expression + Body Statement + } + + EmptyStatement struct { + Semicolon file.Idx + } + + ExpressionStatement struct { + Expression Expression + } + + ForInStatement struct { + For file.Idx + Into Expression + Source Expression + Body Statement + } + + ForStatement struct { + For file.Idx + Initializer Expression + Update Expression + Test Expression + Body Statement + } + + IfStatement struct { + If file.Idx + Test Expression + Consequent Statement + Alternate Statement + } + + LabelledStatement struct { + Label *Identifier + Colon file.Idx + Statement Statement + } + + ReturnStatement struct { + Return file.Idx + Argument Expression + } + + SwitchStatement struct { + Switch file.Idx + Discriminant Expression + Default int + Body []*CaseStatement + } + + ThrowStatement struct { + Throw file.Idx + Argument Expression + } + + TryStatement struct { + Try file.Idx + Body Statement + Catch *CatchStatement + Finally Statement + } + + VariableStatement struct { + Var file.Idx + List []Expression + } + + WhileStatement struct { + While file.Idx + Test Expression + Body Statement + } + + WithStatement struct { + With file.Idx + Object Expression + Body Statement + } +) + +// _statementNode + +func (*BadStatement) _statementNode() {} +func (*BlockStatement) _statementNode() {} +func (*BranchStatement) _statementNode() {} +func (*CaseStatement) _statementNode() {} +func (*CatchStatement) _statementNode() {} +func (*DebuggerStatement) _statementNode() {} +func (*DoWhileStatement) _statementNode() {} +func (*EmptyStatement) _statementNode() {} +func (*ExpressionStatement) _statementNode() {} +func (*ForInStatement) _statementNode() {} +func (*ForStatement) _statementNode() {} +func (*IfStatement) _statementNode() {} +func (*LabelledStatement) _statementNode() {} +func (*ReturnStatement) _statementNode() {} +func (*SwitchStatement) _statementNode() {} +func (*ThrowStatement) _statementNode() {} +func (*TryStatement) _statementNode() {} +func (*VariableStatement) _statementNode() {} +func (*WhileStatement) _statementNode() {} +func (*WithStatement) _statementNode() {} + +// =========== // +// Declaration // +// =========== // + +type ( + // All declaration nodes implement the Declaration interface. + Declaration interface { + _declarationNode() + } + + FunctionDeclaration struct { + Function *FunctionLiteral + } + + VariableDeclaration struct { + Var file.Idx + List []*VariableExpression + } +) + +// _declarationNode + +func (*FunctionDeclaration) _declarationNode() {} +func (*VariableDeclaration) _declarationNode() {} + +// ==== // +// Node // +// ==== // + +type Program struct { + Body []Statement + + DeclarationList []Declaration + + File *file.File +} + +// ==== // +// Idx0 // +// ==== // + +func (self *ArrayLiteral) Idx0() file.Idx { return self.LeftBracket } +func (self *AssignExpression) Idx0() file.Idx { return self.Left.Idx0() } +func (self *BadExpression) Idx0() file.Idx { return self.From } +func (self *BinaryExpression) Idx0() file.Idx { return self.Left.Idx0() } +func (self *BooleanLiteral) Idx0() file.Idx { return self.Idx } +func (self *BracketExpression) Idx0() file.Idx { return self.Left.Idx0() } +func (self *CallExpression) Idx0() file.Idx { return self.Callee.Idx0() } +func (self *ConditionalExpression) Idx0() file.Idx { return self.Test.Idx0() } +func (self *DotExpression) Idx0() file.Idx { return self.Left.Idx0() } +func (self *FunctionLiteral) Idx0() file.Idx { return self.Function } +func (self *Identifier) Idx0() file.Idx { return self.Idx } +func (self *NewExpression) Idx0() file.Idx { return self.New } +func (self *NullLiteral) Idx0() file.Idx { return self.Idx } +func (self *NumberLiteral) Idx0() file.Idx { return self.Idx } +func (self *ObjectLiteral) Idx0() file.Idx { return self.LeftBrace } +func (self *RegExpLiteral) Idx0() file.Idx { return self.Idx } +func (self *SequenceExpression) Idx0() file.Idx { return self.Sequence[0].Idx0() } +func (self *StringLiteral) Idx0() file.Idx { return self.Idx } +func (self *ThisExpression) Idx0() file.Idx { return self.Idx } +func (self *UnaryExpression) Idx0() file.Idx { return self.Idx } +func (self *VariableExpression) Idx0() file.Idx { return self.Idx } + +func (self *BadStatement) Idx0() file.Idx { return self.From } +func (self *BlockStatement) Idx0() file.Idx { return self.LeftBrace } +func (self *BranchStatement) Idx0() file.Idx { return self.Idx } +func (self *CaseStatement) Idx0() file.Idx { return self.Case } +func (self *CatchStatement) Idx0() file.Idx { return self.Catch } +func (self *DebuggerStatement) Idx0() file.Idx { return self.Debugger } +func (self *DoWhileStatement) Idx0() file.Idx { return self.Do } +func (self *EmptyStatement) Idx0() file.Idx { return self.Semicolon } +func (self *ExpressionStatement) Idx0() file.Idx { return self.Expression.Idx0() } +func (self *ForInStatement) Idx0() file.Idx { return self.For } +func (self *ForStatement) Idx0() file.Idx { return self.For } +func (self *IfStatement) Idx0() file.Idx { return self.If } +func (self *LabelledStatement) Idx0() file.Idx { return self.Label.Idx0() } +func (self *Program) Idx0() file.Idx { return self.Body[0].Idx0() } +func (self *ReturnStatement) Idx0() file.Idx { return self.Return } +func (self *SwitchStatement) Idx0() file.Idx { return self.Switch } +func (self *ThrowStatement) Idx0() file.Idx { return self.Throw } +func (self *TryStatement) Idx0() file.Idx { return self.Try } +func (self *VariableStatement) Idx0() file.Idx { return self.Var } +func (self *WhileStatement) Idx0() file.Idx { return self.While } +func (self *WithStatement) Idx0() file.Idx { return self.With } + +// ==== // +// Idx1 // +// ==== // + +func (self *ArrayLiteral) Idx1() file.Idx { return self.RightBracket } +func (self *AssignExpression) Idx1() file.Idx { return self.Right.Idx1() } +func (self *BadExpression) Idx1() file.Idx { return self.To } +func (self *BinaryExpression) Idx1() file.Idx { return self.Right.Idx1() } +func (self *BooleanLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) } +func (self *BracketExpression) Idx1() file.Idx { return self.RightBracket + 1 } +func (self *CallExpression) Idx1() file.Idx { return self.RightParenthesis + 1 } +func (self *ConditionalExpression) Idx1() file.Idx { return self.Test.Idx1() } +func (self *DotExpression) Idx1() file.Idx { return self.Identifier.Idx1() } +func (self *FunctionLiteral) Idx1() file.Idx { return self.Body.Idx1() } +func (self *Identifier) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Name)) } +func (self *NewExpression) Idx1() file.Idx { return self.RightParenthesis + 1 } +func (self *NullLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + 4) } // "null" +func (self *NumberLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) } +func (self *ObjectLiteral) Idx1() file.Idx { return self.RightBrace } +func (self *RegExpLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) } +func (self *SequenceExpression) Idx1() file.Idx { return self.Sequence[0].Idx1() } +func (self *StringLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) } +func (self *ThisExpression) Idx1() file.Idx { return self.Idx } +func (self *UnaryExpression) Idx1() file.Idx { + if self.Postfix { + return self.Operand.Idx1() + 2 // ++ -- + } + return self.Operand.Idx1() +} +func (self *VariableExpression) Idx1() file.Idx { + if self.Initializer == nil { + return file.Idx(int(self.Idx) + len(self.Name) + 1) + } + return self.Initializer.Idx1() +} + +func (self *BadStatement) Idx1() file.Idx { return self.To } +func (self *BlockStatement) Idx1() file.Idx { return self.RightBrace + 1 } +func (self *BranchStatement) Idx1() file.Idx { return self.Idx } +func (self *CaseStatement) Idx1() file.Idx { return self.Consequent[len(self.Consequent)-1].Idx1() } +func (self *CatchStatement) Idx1() file.Idx { return self.Body.Idx1() } +func (self *DebuggerStatement) Idx1() file.Idx { return self.Debugger + 8 } +func (self *DoWhileStatement) Idx1() file.Idx { return self.Test.Idx1() } +func (self *EmptyStatement) Idx1() file.Idx { return self.Semicolon + 1 } +func (self *ExpressionStatement) Idx1() file.Idx { return self.Expression.Idx1() } +func (self *ForInStatement) Idx1() file.Idx { return self.Body.Idx1() } +func (self *ForStatement) Idx1() file.Idx { return self.Body.Idx1() } +func (self *IfStatement) Idx1() file.Idx { + if self.Alternate != nil { + return self.Alternate.Idx1() + } + return self.Consequent.Idx1() +} +func (self *LabelledStatement) Idx1() file.Idx { return self.Colon + 1 } +func (self *Program) Idx1() file.Idx { return self.Body[len(self.Body)-1].Idx1() } +func (self *ReturnStatement) Idx1() file.Idx { return self.Return } +func (self *SwitchStatement) Idx1() file.Idx { return self.Body[len(self.Body)-1].Idx1() } +func (self *ThrowStatement) Idx1() file.Idx { return self.Throw } +func (self *TryStatement) Idx1() file.Idx { return self.Try } +func (self *VariableStatement) Idx1() file.Idx { return self.List[len(self.List)-1].Idx1() } +func (self *WhileStatement) Idx1() file.Idx { return self.Body.Idx1() } +func (self *WithStatement) Idx1() file.Idx { return self.Body.Idx1() } diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/bug_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/bug_test.go new file mode 100644 index 0000000000..5e4d90baec --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/bug_test.go @@ -0,0 +1,617 @@ +package otto + +import ( + "testing" + "time" +) + +func Test_262(t *testing.T) { + tt(t, func() { + test, _ := test() + + // 11.13.1-1-1 + test(`raise: + eval("42 = 42;"); + `, "ReferenceError: Invalid left-hand side in assignment") + }) +} + +func Test_issue5(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`'abc' === 'def'`, false) + test(`'\t' === '\r'`, false) + }) +} + +func Test_issue13(t *testing.T) { + tt(t, func() { + test, tester := test() + vm := tester.vm + + value, err := vm.ToValue(map[string]interface{}{ + "string": "Xyzzy", + "number": 42, + "array": []string{"def", "ghi"}, + }) + if err != nil { + t.Error(err) + t.FailNow() + } + + fn, err := vm.Object(` + (function(value){ + return ""+[value.string, value.number, value.array] + }) + `) + if err != nil { + t.Error(err) + t.FailNow() + } + + result, err := fn.Value().Call(fn.Value(), value) + if err != nil { + t.Error(err) + t.FailNow() + } + is(result.string(), "Xyzzy,42,def,ghi") + + anything := struct { + Abc interface{} + }{ + Abc: map[string]interface{}{ + "def": []interface{}{ + []interface{}{ + "a", "b", "c", "", "d", "e", + }, + map[string]interface{}{ + "jkl": "Nothing happens.", + }, + }, + "ghi": -1, + }, + } + + vm.Set("anything", anything) + test(` + [ + anything, + "~", + anything.Abc, + "~", + anything.Abc.def, + "~", + anything.Abc.def[1].jkl, + "~", + anything.Abc.ghi, + ]; + `, "[object Object],~,[object Object],~,a,b,c,,d,e,[object Object],~,Nothing happens.,~,-1") + }) +} + +func Test_issue16(t *testing.T) { + tt(t, func() { + test, vm := test() + + test(` + var def = { + "abc": ["abc"], + "xyz": ["xyz"] + }; + def.abc.concat(def.xyz); + `, "abc,xyz") + + vm.Set("ghi", []string{"jkl", "mno"}) + + test(` + def.abc.concat(def.xyz).concat(ghi); + `, "abc,xyz,jkl,mno") + + test(` + ghi.concat(def.abc.concat(def.xyz)); + `, "jkl,mno,abc,xyz") + + vm.Set("pqr", []interface{}{"jkl", 42, 3.14159, true}) + + test(` + pqr.concat(ghi, def.abc, def, def.xyz); + `, "jkl,42,3.14159,true,jkl,mno,abc,[object Object],xyz") + + test(` + pqr.concat(ghi, def.abc, def, def.xyz).length; + `, 9) + }) +} + +func Test_issue21(t *testing.T) { + tt(t, func() { + vm1 := New() + vm1.Run(` + abc = {} + abc.ghi = "Nothing happens."; + var jkl = 0; + abc.def = function() { + jkl += 1; + return 1; + } + `) + abc, err := vm1.Get("abc") + is(err, nil) + + vm2 := New() + vm2.Set("cba", abc) + _, err = vm2.Run(` + var pqr = 0; + cba.mno = function() { + pqr -= 1; + return 1; + } + cba.def(); + cba.def(); + cba.def(); + `) + is(err, nil) + + jkl, err := vm1.Get("jkl") + is(err, nil) + is(jkl, 3) + + _, err = vm1.Run(` + abc.mno(); + abc.mno(); + abc.mno(); + `) + is(err, nil) + + pqr, err := vm2.Get("pqr") + is(err, nil) + is(pqr, -3) + }) +} + +func Test_issue24(t *testing.T) { + tt(t, func() { + _, vm := test() + + { + vm.Set("abc", []string{"abc", "def", "ghi"}) + value, err := vm.Get("abc") + is(err, nil) + export, _ := value.Export() + { + value, valid := export.([]string) + is(valid, true) + + is(value[0], "abc") + is(value[2], "ghi") + } + } + + { + vm.Set("abc", [...]string{"abc", "def", "ghi"}) + value, err := vm.Get("abc") + is(err, nil) + export, _ := value.Export() + { + value, valid := export.([3]string) + is(valid, true) + + is(value[0], "abc") + is(value[2], "ghi") + } + } + + { + vm.Set("abc", &[...]string{"abc", "def", "ghi"}) + value, err := vm.Get("abc") + is(err, nil) + export, _ := value.Export() + { + value, valid := export.(*[3]string) + is(valid, true) + + is(value[0], "abc") + is(value[2], "ghi") + } + } + + { + vm.Set("abc", map[int]string{0: "abc", 1: "def", 2: "ghi"}) + value, err := vm.Get("abc") + is(err, nil) + export, _ := value.Export() + { + value, valid := export.(map[int]string) + is(valid, true) + + is(value[0], "abc") + is(value[2], "ghi") + } + } + + { + vm.Set("abc", _abcStruct{Abc: true, Ghi: "Nothing happens."}) + value, err := vm.Get("abc") + is(err, nil) + export, _ := value.Export() + { + value, valid := export.(_abcStruct) + is(valid, true) + + is(value.Abc, true) + is(value.Ghi, "Nothing happens.") + } + } + + { + vm.Set("abc", &_abcStruct{Abc: true, Ghi: "Nothing happens."}) + value, err := vm.Get("abc") + is(err, nil) + export, _ := value.Export() + { + value, valid := export.(*_abcStruct) + is(valid, true) + + is(value.Abc, true) + is(value.Ghi, "Nothing happens.") + } + } + }) +} + +func Test_issue39(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = 0, def = [], ghi = function() { + if (abc < 10) return ++abc; + return undefined; + } + for (var jkl; (jkl = ghi());) def.push(jkl); + def; + `, "1,2,3,4,5,6,7,8,9,10") + + test(` + var abc = ["1", "2", "3", "4"]; + var def = []; + for (var ghi; (ghi = abc.shift());) { + def.push(ghi); + } + def; + `, "1,2,3,4") + }) +} + +func Test_issue64(t *testing.T) { + tt(t, func() { + test, vm := test() + + defer mockTimeLocal(time.UTC)() + + abc := map[string]interface{}{ + "time": time.Unix(0, 0), + } + vm.Set("abc", abc) + + def := struct { + Public string + private string + }{ + "Public", "private", + } + vm.Set("def", def) + + test(`"sec" in abc.time`, false) + + test(` + [ "Public" in def, "private" in def, def.Public, def.private ]; + `, "true,false,Public,") + + test(`JSON.stringify(abc)`, `{"time":"1970-01-01T00:00:00Z"}`) + }) +} + +func Test_issue73(t *testing.T) { + tt(t, func() { + test, vm := test() + + vm.Set("abc", [4]int{3, 2, 1, 0}) + + test(` + var def = [ 0, 1, 2, 3 ]; + JSON.stringify(def) + JSON.stringify(abc); + `, "[0,1,2,3][3,2,1,0]") + }) +} + +func Test_7_3_1(t *testing.T) { + tt(t, func() { + test(` + eval("var test7_3_1\u2028abc = 66;"); + [ abc, typeof test7_3_1 ]; + `, "66,undefined") + }) +} + +func Test_7_3_3(t *testing.T) { + tt(t, func() { + test(`raise: + eval("//\u2028 =;"); + `, "SyntaxError: Unexpected token =") + }) +} + +func Test_S7_3_A2_1_T1(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: + eval("'\u000Astr\u000Aing\u000A'") + `, "SyntaxError: Unexpected token ILLEGAL") + }) +} + +func Test_S7_8_3_A2_1_T1(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ .0 === 0.0, .0, .1 === 0.1, .1 ] + `, "true,0,true,0.1") + }) +} + +func Test_S7_8_4_A4_2_T3(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + "\a" + `, "a") + }) +} + +func Test_S7_9_A1(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var def; + abc: for (var i = 0; i <= 0; i++) { + for (var j = 0; j <= 1; j++) { + if (j === 0) { + continue abc; + } else { + def = true; + } + } + } + [ def, i, j ]; + `, ",1,0") + }) +} + +func Test_S7_9_A3(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + (function(){ + return + 1; + })() + `, "undefined") + }) +} + +func Test_7_3_10(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + eval("var \u0061\u0062\u0063 = 3.14159;"); + abc; + `, 3.14159) + + test(` + abc = undefined; + eval("var \\u0061\\u0062\\u0063 = 3.14159;"); + abc; + `, 3.14159) + }) +} + +func Test_bug(t *testing.T) { + tt(t, func() { + test, _ := test() + + // 10.4.2-1-5 + test(` + "abc\ +def" + `, "abcdef") + + test(` + eval("'abc';\ + 'def'") + `, "def") + + // S12.6.1_A10 + test(` + var abc = 0; + do { + if(typeof(def) === "function"){ + abc = -1; + break; + } else { + abc = 1; + break; + } + } while(function def(){}); + abc; + `, 1) + + // S12.7_A7 + test(`raise: + abc: + while (true) { + eval("continue abc"); + } + `, "SyntaxError: Undefined label 'abc'") + + // S15.1.2.1_A3.3_T3 + test(`raise: + eval("return"); + `, "SyntaxError: Illegal return statement") + + // 15.2.3.3-2-33 + test(` + var abc = { "AB\n\\cd": 1 }; + Object.getOwnPropertyDescriptor(abc, "AB\n\\cd").value; + `, 1) + + // S15.3_A2_T1 + test(`raise: + Function.call(this, "var x / = 1;"); + `, "SyntaxError: Unexpected token /") + + // ? + test(` + (function(){ + var abc = []; + (function(){ + abc.push(0); + abc.push(1); + })(undefined); + if ((function(){ return true; })()) { + (function(){ + abc.push(2); + })(); + } + return abc; + })(); + `, "0,1,2") + + if false { + // 15.9.5.43-0-10 + // Should be an invalid date + test(` + date = new Date(1970, 0, -99999999, 0, 0, 0, 1); + `, "") + } + + // S7.8.3_A1.2_T1 + test(` + [ 0e1, 1e1, 2e1, 3e1, 4e1, 5e1, 6e1, 7e1, 8e1, 9e1 ]; + `, "0,10,20,30,40,50,60,70,80,90") + + // S15.10.2.7_A3_T2 + test(` + var abc = /\s+abc\s+/.exec("\t abc def"); + [ abc.length, abc.index, abc.input, abc ]; + `, "1,0,\t abc def,\t abc ") + }) +} + +func Test_issue79(t *testing.T) { + tt(t, func() { + test, vm := test() + + vm.Set("abc", []_abcStruct{ + { + Ghi: "一", + Def: 1, + }, + { + Def: 3, + Ghi: "三", + }, + { + Def: 2, + Ghi: "二", + }, + { + Def: 4, + Ghi: "四", + }, + }) + + test(` + abc.sort(function(a,b){ return b.Def-a.Def }); + def = []; + for (i = 0; i < abc.length; i++) { + def.push(abc[i].String()) + } + def; + `, "四,三,二,一") + }) +} + +func Test_issue80(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + JSON.stringify([ + 1401868959, + 14018689591, + 140186895901, + 1401868959001, + 14018689590001, + 140186895900001, + 1401868959000001, + 1401868959000001.5, + 14018689590000001, + 140186895900000001, + 1401868959000000001, + 14018689590000000001, + 140186895900000000001, + 140186895900000000001.5 + ]); + `, "[1401868959,14018689591,140186895901,1401868959001,14018689590001,140186895900001,1401868959000001,1.4018689590000015e+15,14018689590000001,140186895900000001,1401868959000000001,1.401868959e+19,1.401868959e+20,1.401868959e+20]") + }) +} + +func Test_issue87(t *testing.T) { + tt(t, func() { + test, vm := test() + + test(` + var def = 0; + abc: { + for (;;) { + def = !1; + break abc; + } + def = !0; + } + def; + `, false) + + _, err := vm.Run(` +/* +CryptoJS v3.1.2 +code.google.com/p/crypto-js +(c) 2009-2013 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +var CryptoJS=CryptoJS||function(h,s){var f={},g=f.lib={},q=function(){},m=g.Base={extend:function(a){q.prototype=this;var c=new q;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}}, +r=g.WordArray=m.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=s?c:4*a.length},toString:function(a){return(a||k).stringify(this)},concat:function(a){var c=this.words,d=a.words,b=this.sigBytes;a=a.sigBytes;this.clamp();if(b%4)for(var e=0;e>>2]|=(d[e>>>2]>>>24-8*(e%4)&255)<<24-8*((b+e)%4);else if(65535>>2]=d[e>>>2];else c.push.apply(c,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<< +32-8*(c%4);a.length=h.ceil(c/4)},clone:function(){var a=m.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],d=0;d>>2]>>>24-8*(b%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b>>3]|=parseInt(a.substr(b, +2),16)<<24-4*(b%8);return new r.init(d,c/2)}},n=l.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b>>2]>>>24-8*(b%4)&255));return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b>>2]|=(a.charCodeAt(b)&255)<<24-8*(b%4);return new r.init(d,c)}},j=l.Utf8={stringify:function(a){try{return decodeURIComponent(escape(n.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return n.parse(unescape(encodeURIComponent(a)))}}, +u=g.BufferedBlockAlgorithm=m.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=j.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,d=c.words,b=c.sigBytes,e=this.blockSize,f=b/(4*e),f=a?h.ceil(f):h.max((f|0)-this._minBufferSize,0);a=f*e;b=h.min(4*a,b);if(a){for(var g=0;gn;){var j;a:{j=k;for(var u=h.sqrt(j),t=2;t<=u;t++)if(!(j%t)){j=!1;break a}j=!0}j&&(8>n&&(m[n]=l(h.pow(k,0.5))),r[n]=l(h.pow(k,1/3)),n++);k++}var a=[],f=f.SHA256=q.extend({_doReset:function(){this._hash=new g.init(m.slice(0))},_doProcessBlock:function(c,d){for(var b=this._hash.words,e=b[0],f=b[1],g=b[2],j=b[3],h=b[4],m=b[5],n=b[6],q=b[7],p=0;64>p;p++){if(16>p)a[p]= +c[d+p]|0;else{var k=a[p-15],l=a[p-2];a[p]=((k<<25|k>>>7)^(k<<14|k>>>18)^k>>>3)+a[p-7]+((l<<15|l>>>17)^(l<<13|l>>>19)^l>>>10)+a[p-16]}k=q+((h<<26|h>>>6)^(h<<21|h>>>11)^(h<<7|h>>>25))+(h&m^~h&n)+r[p]+a[p];l=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&f^e&g^f&g);q=n;n=m;m=h;h=j+k|0;j=g;g=f;f=e;e=k+l|0}b[0]=b[0]+e|0;b[1]=b[1]+f|0;b[2]=b[2]+g|0;b[3]=b[3]+j|0;b[4]=b[4]+h|0;b[5]=b[5]+m|0;b[6]=b[6]+n|0;b[7]=b[7]+q|0},_doFinalize:function(){var a=this._data,d=a.words,b=8*this._nDataBytes,e=8*a.sigBytes; +d[e>>>5]|=128<<24-e%32;d[(e+64>>>9<<4)+14]=h.floor(b/4294967296);d[(e+64>>>9<<4)+15]=b;a.sigBytes=4*d.length;this._process();return this._hash},clone:function(){var a=q.clone.call(this);a._hash=this._hash.clone();return a}});s.SHA256=q._createHelper(f);s.HmacSHA256=q._createHmacHelper(f)})(Math); +(function(){var h=CryptoJS,s=h.enc.Utf8;h.algo.HMAC=h.lib.Base.extend({init:function(f,g){f=this._hasher=new f.init;"string"==typeof g&&(g=s.parse(g));var h=f.blockSize,m=4*h;g.sigBytes>m&&(g=f.finalize(g));g.clamp();for(var r=this._oKey=g.clone(),l=this._iKey=g.clone(),k=r.words,n=l.words,j=0;j 2 (ASCII 50) +47 +// radix 11 => A/a (ASCII 65/97) +54/+86 +var parseInt_alphabetTable = func() []string { + table := []string{"", "", "01"} + for radix := 3; radix <= 36; radix += 1 { + alphabet := table[radix-1] + if radix <= 10 { + alphabet += string(radix + 47) + } else { + alphabet += string(radix+54) + string(radix+86) + } + table = append(table, alphabet) + } + return table +}() + +func digitValue(chr rune) int { + switch { + case '0' <= chr && chr <= '9': + return int(chr - '0') + case 'a' <= chr && chr <= 'z': + return int(chr - 'a' + 10) + case 'A' <= chr && chr <= 'Z': + return int(chr - 'A' + 10) + } + return 36 // Larger than any legal digit value +} + +func builtinGlobal_parseInt(call FunctionCall) Value { + input := strings.TrimSpace(call.Argument(0).string()) + if len(input) == 0 { + return NaNValue() + } + + radix := int(toInt32(call.Argument(1))) + + negative := false + switch input[0] { + case '+': + input = input[1:] + case '-': + negative = true + input = input[1:] + } + + strip := true + if radix == 0 { + radix = 10 + } else { + if radix < 2 || radix > 36 { + return NaNValue() + } else if radix != 16 { + strip = false + } + } + + switch len(input) { + case 0: + return NaNValue() + case 1: + default: + if strip { + if input[0] == '0' && (input[1] == 'x' || input[1] == 'X') { + input = input[2:] + radix = 16 + } + } + } + + base := radix + index := 0 + for ; index < len(input); index++ { + digit := digitValue(rune(input[index])) // If not ASCII, then an error anyway + if digit >= base { + break + } + } + input = input[0:index] + + value, err := strconv.ParseInt(input, radix, 64) + if err != nil { + if err.(*strconv.NumError).Err == strconv.ErrRange { + base := float64(base) + // Could just be a very large number (e.g. 0x8000000000000000) + var value float64 + for _, chr := range input { + digit := float64(digitValue(chr)) + if digit >= base { + goto error + } + value = value*base + digit + } + if negative { + value *= -1 + } + return toValue_float64(value) + } + error: + return NaNValue() + } + if negative { + value *= -1 + } + + return toValue_int64(value) +} + +var parseFloat_matchBadSpecial = regexp.MustCompile(`[\+\-]?(?:[Ii]nf$|infinity)`) +var parseFloat_matchValid = regexp.MustCompile(`[0-9eE\+\-\.]|Infinity`) + +func builtinGlobal_parseFloat(call FunctionCall) Value { + // Caveat emptor: This implementation does NOT match the specification + input := strings.TrimSpace(call.Argument(0).string()) + if parseFloat_matchBadSpecial.MatchString(input) { + return NaNValue() + } + value, err := strconv.ParseFloat(input, 64) + if err != nil { + for end := len(input); end > 0; end -= 1 { + input := input[0:end] + if !parseFloat_matchValid.MatchString(input) { + return NaNValue() + } + value, err = strconv.ParseFloat(input, 64) + if err == nil { + break + } + } + if err != nil { + return NaNValue() + } + } + return toValue_float64(value) +} + +// encodeURI/decodeURI + +func _builtinGlobal_encodeURI(call FunctionCall, escape *regexp.Regexp) Value { + value := call.Argument(0) + var input []uint16 + switch vl := value.value.(type) { + case []uint16: + input = vl + default: + input = utf16.Encode([]rune(value.string())) + } + if len(input) == 0 { + return toValue_string("") + } + output := []byte{} + length := len(input) + encode := make([]byte, 4) + for index := 0; index < length; { + value := input[index] + decode := utf16.Decode(input[index : index+1]) + if value >= 0xDC00 && value <= 0xDFFF { + panic(call.runtime.panicURIError("URI malformed")) + } + if value >= 0xD800 && value <= 0xDBFF { + index += 1 + if index >= length { + panic(call.runtime.panicURIError("URI malformed")) + } + // input = ..., value, value1, ... + value1 := input[index] + if value1 < 0xDC00 || value1 > 0xDFFF { + panic(call.runtime.panicURIError("URI malformed")) + } + decode = []rune{((rune(value) - 0xD800) * 0x400) + (rune(value1) - 0xDC00) + 0x10000} + } + index += 1 + size := utf8.EncodeRune(encode, decode[0]) + encode := encode[0:size] + output = append(output, encode...) + } + { + value := escape.ReplaceAllFunc(output, func(target []byte) []byte { + // Probably a better way of doing this + if target[0] == ' ' { + return []byte("%20") + } + return []byte(url.QueryEscape(string(target))) + }) + return toValue_string(string(value)) + } +} + +var encodeURI_Regexp = regexp.MustCompile(`([^~!@#$&*()=:/,;?+'])`) + +func builtinGlobal_encodeURI(call FunctionCall) Value { + return _builtinGlobal_encodeURI(call, encodeURI_Regexp) +} + +var encodeURIComponent_Regexp = regexp.MustCompile(`([^~!*()'])`) + +func builtinGlobal_encodeURIComponent(call FunctionCall) Value { + return _builtinGlobal_encodeURI(call, encodeURIComponent_Regexp) +} + +// 3B/2F/3F/3A/40/26/3D/2B/24/2C/23 +var decodeURI_guard = regexp.MustCompile(`(?i)(?:%)(3B|2F|3F|3A|40|26|3D|2B|24|2C|23)`) + +func _decodeURI(input string, reserve bool) (string, bool) { + if reserve { + input = decodeURI_guard.ReplaceAllString(input, "%25$1") + } + input = strings.Replace(input, "+", "%2B", -1) // Ugly hack to make QueryUnescape work with our use case + output, err := url.QueryUnescape(input) + if err != nil || !utf8.ValidString(output) { + return "", true + } + return output, false +} + +func builtinGlobal_decodeURI(call FunctionCall) Value { + output, err := _decodeURI(call.Argument(0).string(), true) + if err { + panic(call.runtime.panicURIError("URI malformed")) + } + return toValue_string(output) +} + +func builtinGlobal_decodeURIComponent(call FunctionCall) Value { + output, err := _decodeURI(call.Argument(0).string(), false) + if err { + panic(call.runtime.panicURIError("URI malformed")) + } + return toValue_string(output) +} + +// escape/unescape + +func builtin_shouldEscape(chr byte) bool { + if 'A' <= chr && chr <= 'Z' || 'a' <= chr && chr <= 'z' || '0' <= chr && chr <= '9' { + return false + } + return !strings.ContainsRune("*_+-./", rune(chr)) +} + +const escapeBase16 = "0123456789ABCDEF" + +func builtin_escape(input string) string { + output := make([]byte, 0, len(input)) + length := len(input) + for index := 0; index < length; { + if builtin_shouldEscape(input[index]) { + chr, width := utf8.DecodeRuneInString(input[index:]) + chr16 := utf16.Encode([]rune{chr})[0] + if 256 > chr16 { + output = append(output, '%', + escapeBase16[chr16>>4], + escapeBase16[chr16&15], + ) + } else { + output = append(output, '%', 'u', + escapeBase16[chr16>>12], + escapeBase16[(chr16>>8)&15], + escapeBase16[(chr16>>4)&15], + escapeBase16[chr16&15], + ) + } + index += width + + } else { + output = append(output, input[index]) + index += 1 + } + } + return string(output) +} + +func builtin_unescape(input string) string { + output := make([]rune, 0, len(input)) + length := len(input) + for index := 0; index < length; { + if input[index] == '%' { + if index <= length-6 && input[index+1] == 'u' { + byte16, err := hex.DecodeString(input[index+2 : index+6]) + if err == nil { + value := uint16(byte16[0])<<8 + uint16(byte16[1]) + chr := utf16.Decode([]uint16{value})[0] + output = append(output, chr) + index += 6 + continue + } + } + if index <= length-3 { + byte8, err := hex.DecodeString(input[index+1 : index+3]) + if err == nil { + value := uint16(byte8[0]) + chr := utf16.Decode([]uint16{value})[0] + output = append(output, chr) + index += 3 + continue + } + } + } + output = append(output, rune(input[index])) + index += 1 + } + return string(output) +} + +func builtinGlobal_escape(call FunctionCall) Value { + return toValue_string(builtin_escape(call.Argument(0).string())) +} + +func builtinGlobal_unescape(call FunctionCall) Value { + return toValue_string(builtin_unescape(call.Argument(0).string())) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_array.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_array.go new file mode 100644 index 0000000000..44bf88569f --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_array.go @@ -0,0 +1,672 @@ +package otto + +import ( + "strconv" + "strings" +) + +// Array + +func builtinArray(call FunctionCall) Value { + return toValue_object(builtinNewArrayNative(call.runtime, call.ArgumentList)) +} + +func builtinNewArray(self *_object, argumentList []Value) Value { + return toValue_object(builtinNewArrayNative(self.runtime, argumentList)) +} + +func builtinNewArrayNative(runtime *_runtime, argumentList []Value) *_object { + if len(argumentList) == 1 { + firstArgument := argumentList[0] + if firstArgument.IsNumber() { + return runtime.newArray(arrayUint32(runtime, firstArgument)) + } + } + return runtime.newArrayOf(argumentList) +} + +func builtinArray_toString(call FunctionCall) Value { + thisObject := call.thisObject() + join := thisObject.get("join") + if join.isCallable() { + join := join._object() + return join.call(call.This, call.ArgumentList, false, nativeFrame) + } + return builtinObject_toString(call) +} + +func builtinArray_toLocaleString(call FunctionCall) Value { + separator := "," + thisObject := call.thisObject() + length := int64(toUint32(thisObject.get("length"))) + if length == 0 { + return toValue_string("") + } + stringList := make([]string, 0, length) + for index := int64(0); index < length; index += 1 { + value := thisObject.get(arrayIndexToString(index)) + stringValue := "" + switch value.kind { + case valueEmpty, valueUndefined, valueNull: + default: + object := call.runtime.toObject(value) + toLocaleString := object.get("toLocaleString") + if !toLocaleString.isCallable() { + panic(call.runtime.panicTypeError()) + } + stringValue = toLocaleString.call(call.runtime, toValue_object(object)).string() + } + stringList = append(stringList, stringValue) + } + return toValue_string(strings.Join(stringList, separator)) +} + +func builtinArray_concat(call FunctionCall) Value { + thisObject := call.thisObject() + valueArray := []Value{} + source := append([]Value{toValue_object(thisObject)}, call.ArgumentList...) + for _, item := range source { + switch item.kind { + case valueObject: + object := item._object() + if isArray(object) { + length := object.get("length").number().int64 + for index := int64(0); index < length; index += 1 { + name := strconv.FormatInt(index, 10) + if object.hasProperty(name) { + valueArray = append(valueArray, object.get(name)) + } else { + valueArray = append(valueArray, Value{}) + } + } + continue + } + fallthrough + default: + valueArray = append(valueArray, item) + } + } + return toValue_object(call.runtime.newArrayOf(valueArray)) +} + +func builtinArray_shift(call FunctionCall) Value { + thisObject := call.thisObject() + length := int64(toUint32(thisObject.get("length"))) + if 0 == length { + thisObject.put("length", toValue_int64(0), true) + return Value{} + } + first := thisObject.get("0") + for index := int64(1); index < length; index++ { + from := arrayIndexToString(index) + to := arrayIndexToString(index - 1) + if thisObject.hasProperty(from) { + thisObject.put(to, thisObject.get(from), true) + } else { + thisObject.delete(to, true) + } + } + thisObject.delete(arrayIndexToString(length-1), true) + thisObject.put("length", toValue_int64(length-1), true) + return first +} + +func builtinArray_push(call FunctionCall) Value { + thisObject := call.thisObject() + itemList := call.ArgumentList + index := int64(toUint32(thisObject.get("length"))) + for len(itemList) > 0 { + thisObject.put(arrayIndexToString(index), itemList[0], true) + itemList = itemList[1:] + index += 1 + } + length := toValue_int64(index) + thisObject.put("length", length, true) + return length +} + +func builtinArray_pop(call FunctionCall) Value { + thisObject := call.thisObject() + length := int64(toUint32(thisObject.get("length"))) + if 0 == length { + thisObject.put("length", toValue_uint32(0), true) + return Value{} + } + last := thisObject.get(arrayIndexToString(length - 1)) + thisObject.delete(arrayIndexToString(length-1), true) + thisObject.put("length", toValue_int64(length-1), true) + return last +} + +func builtinArray_join(call FunctionCall) Value { + separator := "," + { + argument := call.Argument(0) + if argument.IsDefined() { + separator = argument.string() + } + } + thisObject := call.thisObject() + length := int64(toUint32(thisObject.get("length"))) + if length == 0 { + return toValue_string("") + } + stringList := make([]string, 0, length) + for index := int64(0); index < length; index += 1 { + value := thisObject.get(arrayIndexToString(index)) + stringValue := "" + switch value.kind { + case valueEmpty, valueUndefined, valueNull: + default: + stringValue = value.string() + } + stringList = append(stringList, stringValue) + } + return toValue_string(strings.Join(stringList, separator)) +} + +func builtinArray_splice(call FunctionCall) Value { + thisObject := call.thisObject() + length := int64(toUint32(thisObject.get("length"))) + + start := valueToRangeIndex(call.Argument(0), length, false) + deleteCount := valueToRangeIndex(call.Argument(1), int64(length)-start, true) + valueArray := make([]Value, deleteCount) + + for index := int64(0); index < deleteCount; index++ { + indexString := arrayIndexToString(int64(start + index)) + if thisObject.hasProperty(indexString) { + valueArray[index] = thisObject.get(indexString) + } + } + + // 0, <1, 2, 3, 4>, 5, 6, 7 + // a, b + // length 8 - delete 4 @ start 1 + + itemList := []Value{} + itemCount := int64(len(call.ArgumentList)) + if itemCount > 2 { + itemCount -= 2 // Less the first two arguments + itemList = call.ArgumentList[2:] + } else { + itemCount = 0 + } + if itemCount < deleteCount { + // The Object/Array is shrinking + stop := int64(length) - deleteCount + // The new length of the Object/Array before + // appending the itemList remainder + // Stopping at the lower bound of the insertion: + // Move an item from the after the deleted portion + // to a position after the inserted portion + for index := start; index < stop; index++ { + from := arrayIndexToString(index + deleteCount) // Position just after deletion + to := arrayIndexToString(index + itemCount) // Position just after splice (insertion) + if thisObject.hasProperty(from) { + thisObject.put(to, thisObject.get(from), true) + } else { + thisObject.delete(to, true) + } + } + // Delete off the end + // We don't bother to delete below (if any) since those + // will be overwritten anyway + for index := int64(length); index > (stop + itemCount); index-- { + thisObject.delete(arrayIndexToString(index-1), true) + } + } else if itemCount > deleteCount { + // The Object/Array is growing + // The itemCount is greater than the deleteCount, so we do + // not have to worry about overwriting what we should be moving + // --- + // Starting from the upper bound of the deletion: + // Move an item from the after the deleted portion + // to a position after the inserted portion + for index := int64(length) - deleteCount; index > start; index-- { + from := arrayIndexToString(index + deleteCount - 1) + to := arrayIndexToString(index + itemCount - 1) + if thisObject.hasProperty(from) { + thisObject.put(to, thisObject.get(from), true) + } else { + thisObject.delete(to, true) + } + } + } + + for index := int64(0); index < itemCount; index++ { + thisObject.put(arrayIndexToString(index+start), itemList[index], true) + } + thisObject.put("length", toValue_int64(int64(length)+itemCount-deleteCount), true) + + return toValue_object(call.runtime.newArrayOf(valueArray)) +} + +func builtinArray_slice(call FunctionCall) Value { + thisObject := call.thisObject() + + length := int64(toUint32(thisObject.get("length"))) + start, end := rangeStartEnd(call.ArgumentList, length, false) + + if start >= end { + // Always an empty array + return toValue_object(call.runtime.newArray(0)) + } + sliceLength := end - start + sliceValueArray := make([]Value, sliceLength) + + for index := int64(0); index < sliceLength; index++ { + from := arrayIndexToString(index + start) + if thisObject.hasProperty(from) { + sliceValueArray[index] = thisObject.get(from) + } + } + + return toValue_object(call.runtime.newArrayOf(sliceValueArray)) +} + +func builtinArray_unshift(call FunctionCall) Value { + thisObject := call.thisObject() + length := int64(toUint32(thisObject.get("length"))) + itemList := call.ArgumentList + itemCount := int64(len(itemList)) + + for index := length; index > 0; index-- { + from := arrayIndexToString(index - 1) + to := arrayIndexToString(index + itemCount - 1) + if thisObject.hasProperty(from) { + thisObject.put(to, thisObject.get(from), true) + } else { + thisObject.delete(to, true) + } + } + + for index := int64(0); index < itemCount; index++ { + thisObject.put(arrayIndexToString(index), itemList[index], true) + } + + newLength := toValue_int64(length + itemCount) + thisObject.put("length", newLength, true) + return newLength +} + +func builtinArray_reverse(call FunctionCall) Value { + thisObject := call.thisObject() + length := int64(toUint32(thisObject.get("length"))) + + lower := struct { + name string + index int64 + exists bool + }{} + upper := lower + + lower.index = 0 + middle := length / 2 // Division will floor + + for lower.index != middle { + lower.name = arrayIndexToString(lower.index) + upper.index = length - lower.index - 1 + upper.name = arrayIndexToString(upper.index) + + lower.exists = thisObject.hasProperty(lower.name) + upper.exists = thisObject.hasProperty(upper.name) + + if lower.exists && upper.exists { + lowerValue := thisObject.get(lower.name) + upperValue := thisObject.get(upper.name) + thisObject.put(lower.name, upperValue, true) + thisObject.put(upper.name, lowerValue, true) + } else if !lower.exists && upper.exists { + value := thisObject.get(upper.name) + thisObject.delete(upper.name, true) + thisObject.put(lower.name, value, true) + } else if lower.exists && !upper.exists { + value := thisObject.get(lower.name) + thisObject.delete(lower.name, true) + thisObject.put(upper.name, value, true) + } else { + // Nothing happens. + } + + lower.index += 1 + } + + return call.This +} + +func sortCompare(thisObject *_object, index0, index1 uint, compare *_object) int { + j := struct { + name string + exists bool + defined bool + value string + }{} + k := j + j.name = arrayIndexToString(int64(index0)) + j.exists = thisObject.hasProperty(j.name) + k.name = arrayIndexToString(int64(index1)) + k.exists = thisObject.hasProperty(k.name) + + if !j.exists && !k.exists { + return 0 + } else if !j.exists { + return 1 + } else if !k.exists { + return -1 + } + + x := thisObject.get(j.name) + y := thisObject.get(k.name) + j.defined = x.IsDefined() + k.defined = y.IsDefined() + + if !j.defined && !k.defined { + return 0 + } else if !j.defined { + return 1 + } else if !k.defined { + return -1 + } + + if compare == nil { + j.value = x.string() + k.value = y.string() + + if j.value == k.value { + return 0 + } else if j.value < k.value { + return -1 + } + + return 1 + } + + return int(toInt32(compare.call(Value{}, []Value{x, y}, false, nativeFrame))) +} + +func arraySortSwap(thisObject *_object, index0, index1 uint) { + + j := struct { + name string + exists bool + }{} + k := j + + j.name = arrayIndexToString(int64(index0)) + j.exists = thisObject.hasProperty(j.name) + k.name = arrayIndexToString(int64(index1)) + k.exists = thisObject.hasProperty(k.name) + + if j.exists && k.exists { + jValue := thisObject.get(j.name) + kValue := thisObject.get(k.name) + thisObject.put(j.name, kValue, true) + thisObject.put(k.name, jValue, true) + } else if !j.exists && k.exists { + value := thisObject.get(k.name) + thisObject.delete(k.name, true) + thisObject.put(j.name, value, true) + } else if j.exists && !k.exists { + value := thisObject.get(j.name) + thisObject.delete(j.name, true) + thisObject.put(k.name, value, true) + } else { + // Nothing happens. + } +} + +func arraySortQuickPartition(thisObject *_object, left, right, pivot uint, compare *_object) uint { + arraySortSwap(thisObject, pivot, right) // Right is now the pivot value + cursor := left + for index := left; index < right; index++ { + if sortCompare(thisObject, index, right, compare) == -1 { // Compare to the pivot value + arraySortSwap(thisObject, index, cursor) + cursor += 1 + } + } + arraySortSwap(thisObject, cursor, right) + return cursor +} + +func arraySortQuickSort(thisObject *_object, left, right uint, compare *_object) { + if left < right { + pivot := left + (right-left)/2 + pivot = arraySortQuickPartition(thisObject, left, right, pivot, compare) + if pivot > 0 { + arraySortQuickSort(thisObject, left, pivot-1, compare) + } + arraySortQuickSort(thisObject, pivot+1, right, compare) + } +} + +func builtinArray_sort(call FunctionCall) Value { + thisObject := call.thisObject() + length := uint(toUint32(thisObject.get("length"))) + compareValue := call.Argument(0) + compare := compareValue._object() + if compareValue.IsUndefined() { + } else if !compareValue.isCallable() { + panic(call.runtime.panicTypeError()) + } + if length > 1 { + arraySortQuickSort(thisObject, 0, length-1, compare) + } + return call.This +} + +func builtinArray_isArray(call FunctionCall) Value { + return toValue_bool(isArray(call.Argument(0)._object())) +} + +func builtinArray_indexOf(call FunctionCall) Value { + thisObject, matchValue := call.thisObject(), call.Argument(0) + if length := int64(toUint32(thisObject.get("length"))); length > 0 { + index := int64(0) + if len(call.ArgumentList) > 1 { + index = call.Argument(1).number().int64 + } + if index < 0 { + if index += length; index < 0 { + index = 0 + } + } else if index >= length { + index = -1 + } + for ; index >= 0 && index < length; index++ { + name := arrayIndexToString(int64(index)) + if !thisObject.hasProperty(name) { + continue + } + value := thisObject.get(name) + if strictEqualityComparison(matchValue, value) { + return toValue_uint32(uint32(index)) + } + } + } + return toValue_int(-1) +} + +func builtinArray_lastIndexOf(call FunctionCall) Value { + thisObject, matchValue := call.thisObject(), call.Argument(0) + length := int64(toUint32(thisObject.get("length"))) + index := length - 1 + if len(call.ArgumentList) > 1 { + index = call.Argument(1).number().int64 + } + if 0 > index { + index += length + } + if index > length { + index = length - 1 + } else if 0 > index { + return toValue_int(-1) + } + for ; index >= 0; index-- { + name := arrayIndexToString(int64(index)) + if !thisObject.hasProperty(name) { + continue + } + value := thisObject.get(name) + if strictEqualityComparison(matchValue, value) { + return toValue_uint32(uint32(index)) + } + } + return toValue_int(-1) +} + +func builtinArray_every(call FunctionCall) Value { + thisObject := call.thisObject() + this := toValue_object(thisObject) + if iterator := call.Argument(0); iterator.isCallable() { + length := int64(toUint32(thisObject.get("length"))) + callThis := call.Argument(1) + for index := int64(0); index < length; index++ { + if key := arrayIndexToString(index); thisObject.hasProperty(key) { + if value := thisObject.get(key); iterator.call(call.runtime, callThis, value, toValue_int64(index), this).bool() { + continue + } + return falseValue + } + } + return trueValue + } + panic(call.runtime.panicTypeError()) +} + +func builtinArray_some(call FunctionCall) Value { + thisObject := call.thisObject() + this := toValue_object(thisObject) + if iterator := call.Argument(0); iterator.isCallable() { + length := int64(toUint32(thisObject.get("length"))) + callThis := call.Argument(1) + for index := int64(0); index < length; index++ { + if key := arrayIndexToString(index); thisObject.hasProperty(key) { + if value := thisObject.get(key); iterator.call(call.runtime, callThis, value, toValue_int64(index), this).bool() { + return trueValue + } + } + } + return falseValue + } + panic(call.runtime.panicTypeError()) +} + +func builtinArray_forEach(call FunctionCall) Value { + thisObject := call.thisObject() + this := toValue_object(thisObject) + if iterator := call.Argument(0); iterator.isCallable() { + length := int64(toUint32(thisObject.get("length"))) + callThis := call.Argument(1) + for index := int64(0); index < length; index++ { + if key := arrayIndexToString(index); thisObject.hasProperty(key) { + iterator.call(call.runtime, callThis, thisObject.get(key), toValue_int64(index), this) + } + } + return Value{} + } + panic(call.runtime.panicTypeError()) +} + +func builtinArray_map(call FunctionCall) Value { + thisObject := call.thisObject() + this := toValue_object(thisObject) + if iterator := call.Argument(0); iterator.isCallable() { + length := int64(toUint32(thisObject.get("length"))) + callThis := call.Argument(1) + values := make([]Value, length) + for index := int64(0); index < length; index++ { + if key := arrayIndexToString(index); thisObject.hasProperty(key) { + values[index] = iterator.call(call.runtime, callThis, thisObject.get(key), index, this) + } else { + values[index] = Value{} + } + } + return toValue_object(call.runtime.newArrayOf(values)) + } + panic(call.runtime.panicTypeError()) +} + +func builtinArray_filter(call FunctionCall) Value { + thisObject := call.thisObject() + this := toValue_object(thisObject) + if iterator := call.Argument(0); iterator.isCallable() { + length := int64(toUint32(thisObject.get("length"))) + callThis := call.Argument(1) + values := make([]Value, 0) + for index := int64(0); index < length; index++ { + if key := arrayIndexToString(index); thisObject.hasProperty(key) { + value := thisObject.get(key) + if iterator.call(call.runtime, callThis, value, index, this).bool() { + values = append(values, value) + } + } + } + return toValue_object(call.runtime.newArrayOf(values)) + } + panic(call.runtime.panicTypeError()) +} + +func builtinArray_reduce(call FunctionCall) Value { + thisObject := call.thisObject() + this := toValue_object(thisObject) + if iterator := call.Argument(0); iterator.isCallable() { + initial := len(call.ArgumentList) > 1 + start := call.Argument(1) + length := int64(toUint32(thisObject.get("length"))) + index := int64(0) + if length > 0 || initial { + var accumulator Value + if !initial { + for ; index < length; index++ { + if key := arrayIndexToString(index); thisObject.hasProperty(key) { + accumulator = thisObject.get(key) + index++ + break + } + } + } else { + accumulator = start + } + for ; index < length; index++ { + if key := arrayIndexToString(index); thisObject.hasProperty(key) { + accumulator = iterator.call(call.runtime, Value{}, accumulator, thisObject.get(key), key, this) + } + } + return accumulator + } + } + panic(call.runtime.panicTypeError()) +} + +func builtinArray_reduceRight(call FunctionCall) Value { + thisObject := call.thisObject() + this := toValue_object(thisObject) + if iterator := call.Argument(0); iterator.isCallable() { + initial := len(call.ArgumentList) > 1 + start := call.Argument(1) + length := int64(toUint32(thisObject.get("length"))) + if length > 0 || initial { + index := length - 1 + var accumulator Value + if !initial { + for ; index >= 0; index-- { + if key := arrayIndexToString(index); thisObject.hasProperty(key) { + accumulator = thisObject.get(key) + index -= 1 + break + } + } + } else { + accumulator = start + } + for ; index >= 0; index-- { + if key := arrayIndexToString(index); thisObject.hasProperty(key) { + accumulator = iterator.call(call.runtime, Value{}, accumulator, thisObject.get(key), key, this) + } + } + return accumulator + } + } + panic(call.runtime.panicTypeError()) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_boolean.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_boolean.go new file mode 100644 index 0000000000..59b8e789b3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_boolean.go @@ -0,0 +1,28 @@ +package otto + +// Boolean + +func builtinBoolean(call FunctionCall) Value { + return toValue_bool(call.Argument(0).bool()) +} + +func builtinNewBoolean(self *_object, argumentList []Value) Value { + return toValue_object(self.runtime.newBoolean(valueOfArrayIndex(argumentList, 0))) +} + +func builtinBoolean_toString(call FunctionCall) Value { + value := call.This + if !value.IsBoolean() { + // Will throw a TypeError if ThisObject is not a Boolean + value = call.thisClassObject("Boolean").primitiveValue() + } + return toValue_string(value.string()) +} + +func builtinBoolean_valueOf(call FunctionCall) Value { + value := call.This + if !value.IsBoolean() { + value = call.thisClassObject("Boolean").primitiveValue() + } + return value +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_date.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_date.go new file mode 100644 index 0000000000..f20bf8e3fa --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_date.go @@ -0,0 +1,615 @@ +package otto + +import ( + "math" + Time "time" +) + +// Date + +const ( + // TODO Be like V8? + // builtinDate_goDateTimeLayout = "Mon Jan 2 2006 15:04:05 GMT-0700 (MST)" + builtinDate_goDateTimeLayout = Time.RFC1123 // "Mon, 02 Jan 2006 15:04:05 MST" + builtinDate_goDateLayout = "Mon, 02 Jan 2006" + builtinDate_goTimeLayout = "15:04:05 MST" +) + +func builtinDate(call FunctionCall) Value { + date := &_dateObject{} + date.Set(newDateTime([]Value{}, Time.Local)) + return toValue_string(date.Time().Format(builtinDate_goDateTimeLayout)) +} + +func builtinNewDate(self *_object, argumentList []Value) Value { + return toValue_object(self.runtime.newDate(newDateTime(argumentList, Time.Local))) +} + +func builtinDate_toString(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return toValue_string("Invalid Date") + } + return toValue_string(date.Time().Local().Format(builtinDate_goDateTimeLayout)) +} + +func builtinDate_toDateString(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return toValue_string("Invalid Date") + } + return toValue_string(date.Time().Local().Format(builtinDate_goDateLayout)) +} + +func builtinDate_toTimeString(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return toValue_string("Invalid Date") + } + return toValue_string(date.Time().Local().Format(builtinDate_goTimeLayout)) +} + +func builtinDate_toUTCString(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return toValue_string("Invalid Date") + } + return toValue_string(date.Time().Format(builtinDate_goDateTimeLayout)) +} + +func builtinDate_toISOString(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return toValue_string("Invalid Date") + } + return toValue_string(date.Time().Format("2006-01-02T15:04:05.000Z")) +} + +func builtinDate_toJSON(call FunctionCall) Value { + object := call.thisObject() + value := object.DefaultValue(defaultValueHintNumber) // FIXME object.primitiveNumberValue + { // FIXME value.isFinite + value := value.float64() + if math.IsNaN(value) || math.IsInf(value, 0) { + return nullValue + } + } + toISOString := object.get("toISOString") + if !toISOString.isCallable() { + // FIXME + panic(call.runtime.panicTypeError()) + } + return toISOString.call(call.runtime, toValue_object(object), []Value{}) +} + +func builtinDate_toGMTString(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return toValue_string("Invalid Date") + } + return toValue_string(date.Time().Format("Mon, 02 Jan 2006 15:04:05 GMT")) +} + +func builtinDate_getTime(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + // We do this (convert away from a float) so the user + // does not get something back in exponential notation + return toValue_int64(int64(date.Epoch())) +} + +func builtinDate_setTime(call FunctionCall) Value { + object := call.thisObject() + date := dateObjectOf(call.runtime, call.thisObject()) + date.Set(call.Argument(0).float64()) + object.value = date + return date.Value() +} + +func _builtinDate_beforeSet(call FunctionCall, argumentLimit int, timeLocal bool) (*_object, *_dateObject, *_ecmaTime, []int) { + object := call.thisObject() + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return nil, nil, nil, nil + } + + if argumentLimit > len(call.ArgumentList) { + argumentLimit = len(call.ArgumentList) + } + + if argumentLimit == 0 { + object.value = invalidDateObject + return nil, nil, nil, nil + } + + valueList := make([]int, argumentLimit) + for index := 0; index < argumentLimit; index++ { + value := call.ArgumentList[index] + nm := value.number() + switch nm.kind { + case numberInteger, numberFloat: + default: + object.value = invalidDateObject + return nil, nil, nil, nil + } + valueList[index] = int(nm.int64) + } + baseTime := date.Time() + if timeLocal { + baseTime = baseTime.Local() + } + ecmaTime := ecmaTime(baseTime) + return object, &date, &ecmaTime, valueList +} + +func builtinDate_parse(call FunctionCall) Value { + date := call.Argument(0).string() + return toValue_float64(dateParse(date)) +} + +func builtinDate_UTC(call FunctionCall) Value { + return toValue_float64(newDateTime(call.ArgumentList, Time.UTC)) +} + +func builtinDate_now(call FunctionCall) Value { + call.ArgumentList = []Value(nil) + return builtinDate_UTC(call) +} + +// This is a placeholder +func builtinDate_toLocaleString(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return toValue_string("Invalid Date") + } + return toValue_string(date.Time().Local().Format("2006-01-02 15:04:05")) +} + +// This is a placeholder +func builtinDate_toLocaleDateString(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return toValue_string("Invalid Date") + } + return toValue_string(date.Time().Local().Format("2006-01-02")) +} + +// This is a placeholder +func builtinDate_toLocaleTimeString(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return toValue_string("Invalid Date") + } + return toValue_string(date.Time().Local().Format("15:04:05")) +} + +func builtinDate_valueOf(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return date.Value() +} + +func builtinDate_getYear(call FunctionCall) Value { + // Will throw a TypeError is ThisObject is nil or + // does not have Class of "Date" + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(date.Time().Local().Year() - 1900) +} + +func builtinDate_getFullYear(call FunctionCall) Value { + // Will throw a TypeError is ThisObject is nil or + // does not have Class of "Date" + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(date.Time().Local().Year()) +} + +func builtinDate_getUTCFullYear(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(date.Time().Year()) +} + +func builtinDate_getMonth(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(dateFromGoMonth(date.Time().Local().Month())) +} + +func builtinDate_getUTCMonth(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(dateFromGoMonth(date.Time().Month())) +} + +func builtinDate_getDate(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(date.Time().Local().Day()) +} + +func builtinDate_getUTCDate(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(date.Time().Day()) +} + +func builtinDate_getDay(call FunctionCall) Value { + // Actually day of the week + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(dateFromGoDay(date.Time().Local().Weekday())) +} + +func builtinDate_getUTCDay(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(dateFromGoDay(date.Time().Weekday())) +} + +func builtinDate_getHours(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(date.Time().Local().Hour()) +} + +func builtinDate_getUTCHours(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(date.Time().Hour()) +} + +func builtinDate_getMinutes(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(date.Time().Local().Minute()) +} + +func builtinDate_getUTCMinutes(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(date.Time().Minute()) +} + +func builtinDate_getSeconds(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(date.Time().Local().Second()) +} + +func builtinDate_getUTCSeconds(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(date.Time().Second()) +} + +func builtinDate_getMilliseconds(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(date.Time().Local().Nanosecond() / (100 * 100 * 100)) +} + +func builtinDate_getUTCMilliseconds(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + return toValue_int(date.Time().Nanosecond() / (100 * 100 * 100)) +} + +func builtinDate_getTimezoneOffset(call FunctionCall) Value { + date := dateObjectOf(call.runtime, call.thisObject()) + if date.isNaN { + return NaNValue() + } + timeLocal := date.Time().Local() + // Is this kosher? + timeLocalAsUTC := Time.Date( + timeLocal.Year(), + timeLocal.Month(), + timeLocal.Day(), + timeLocal.Hour(), + timeLocal.Minute(), + timeLocal.Second(), + timeLocal.Nanosecond(), + Time.UTC, + ) + return toValue_float64(date.Time().Sub(timeLocalAsUTC).Seconds() / 60) +} + +func builtinDate_setMilliseconds(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 1, true) + if ecmaTime == nil { + return NaNValue() + } + + ecmaTime.millisecond = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setUTCMilliseconds(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 1, false) + if ecmaTime == nil { + return NaNValue() + } + + ecmaTime.millisecond = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setSeconds(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 2, true) + if ecmaTime == nil { + return NaNValue() + } + + if len(value) > 1 { + ecmaTime.millisecond = value[1] + } + ecmaTime.second = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setUTCSeconds(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 2, false) + if ecmaTime == nil { + return NaNValue() + } + + if len(value) > 1 { + ecmaTime.millisecond = value[1] + } + ecmaTime.second = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setMinutes(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 3, true) + if ecmaTime == nil { + return NaNValue() + } + + if len(value) > 2 { + ecmaTime.millisecond = value[2] + ecmaTime.second = value[1] + } else if len(value) > 1 { + ecmaTime.second = value[1] + } + ecmaTime.minute = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setUTCMinutes(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 3, false) + if ecmaTime == nil { + return NaNValue() + } + + if len(value) > 2 { + ecmaTime.millisecond = value[2] + ecmaTime.second = value[1] + } else if len(value) > 1 { + ecmaTime.second = value[1] + } + ecmaTime.minute = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setHours(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 4, true) + if ecmaTime == nil { + return NaNValue() + } + + if len(value) > 3 { + ecmaTime.millisecond = value[3] + ecmaTime.second = value[2] + ecmaTime.minute = value[1] + } else if len(value) > 2 { + ecmaTime.second = value[2] + ecmaTime.minute = value[1] + } else if len(value) > 1 { + ecmaTime.minute = value[1] + } + ecmaTime.hour = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setUTCHours(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 4, false) + if ecmaTime == nil { + return NaNValue() + } + + if len(value) > 3 { + ecmaTime.millisecond = value[3] + ecmaTime.second = value[2] + ecmaTime.minute = value[1] + } else if len(value) > 2 { + ecmaTime.second = value[2] + ecmaTime.minute = value[1] + } else if len(value) > 1 { + ecmaTime.minute = value[1] + } + ecmaTime.hour = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setDate(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 1, true) + if ecmaTime == nil { + return NaNValue() + } + + ecmaTime.day = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setUTCDate(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 1, false) + if ecmaTime == nil { + return NaNValue() + } + + ecmaTime.day = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setMonth(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 2, true) + if ecmaTime == nil { + return NaNValue() + } + + if len(value) > 1 { + ecmaTime.day = value[1] + } + ecmaTime.month = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setUTCMonth(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 2, false) + if ecmaTime == nil { + return NaNValue() + } + + if len(value) > 1 { + ecmaTime.day = value[1] + } + ecmaTime.month = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setYear(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 1, true) + if ecmaTime == nil { + return NaNValue() + } + + year := value[0] + if 0 <= year && year <= 99 { + year += 1900 + } + ecmaTime.year = year + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setFullYear(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 3, true) + if ecmaTime == nil { + return NaNValue() + } + + if len(value) > 2 { + ecmaTime.day = value[2] + ecmaTime.month = value[1] + } else if len(value) > 1 { + ecmaTime.month = value[1] + } + ecmaTime.year = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +func builtinDate_setUTCFullYear(call FunctionCall) Value { + object, date, ecmaTime, value := _builtinDate_beforeSet(call, 3, false) + if ecmaTime == nil { + return NaNValue() + } + + if len(value) > 2 { + ecmaTime.day = value[2] + ecmaTime.month = value[1] + } else if len(value) > 1 { + ecmaTime.month = value[1] + } + ecmaTime.year = value[0] + + date.SetTime(ecmaTime.goTime()) + object.value = *date + return date.Value() +} + +// toUTCString +// toISOString +// toJSONString +// toJSON diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_error.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_error.go new file mode 100644 index 0000000000..4c054fbea8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_error.go @@ -0,0 +1,126 @@ +package otto + +import ( + "fmt" +) + +func builtinError(call FunctionCall) Value { + return toValue_object(call.runtime.newError("", call.Argument(0))) +} + +func builtinNewError(self *_object, argumentList []Value) Value { + return toValue_object(self.runtime.newError("", valueOfArrayIndex(argumentList, 0))) +} + +func builtinError_toString(call FunctionCall) Value { + thisObject := call.thisObject() + if thisObject == nil { + panic(call.runtime.panicTypeError()) + } + + name := "Error" + nameValue := thisObject.get("name") + if nameValue.IsDefined() { + name = nameValue.string() + } + + message := "" + messageValue := thisObject.get("message") + if messageValue.IsDefined() { + message = messageValue.string() + } + + if len(name) == 0 { + return toValue_string(message) + } + + if len(message) == 0 { + return toValue_string(name) + } + + return toValue_string(fmt.Sprintf("%s: %s", name, message)) +} + +func (runtime *_runtime) newEvalError(message Value) *_object { + self := runtime.newErrorObject("EvalError", message) + self.prototype = runtime.global.EvalErrorPrototype + return self +} + +func builtinEvalError(call FunctionCall) Value { + return toValue_object(call.runtime.newEvalError(call.Argument(0))) +} + +func builtinNewEvalError(self *_object, argumentList []Value) Value { + return toValue_object(self.runtime.newEvalError(valueOfArrayIndex(argumentList, 0))) +} + +func (runtime *_runtime) newTypeError(message Value) *_object { + self := runtime.newErrorObject("TypeError", message) + self.prototype = runtime.global.TypeErrorPrototype + return self +} + +func builtinTypeError(call FunctionCall) Value { + return toValue_object(call.runtime.newTypeError(call.Argument(0))) +} + +func builtinNewTypeError(self *_object, argumentList []Value) Value { + return toValue_object(self.runtime.newTypeError(valueOfArrayIndex(argumentList, 0))) +} + +func (runtime *_runtime) newRangeError(message Value) *_object { + self := runtime.newErrorObject("RangeError", message) + self.prototype = runtime.global.RangeErrorPrototype + return self +} + +func builtinRangeError(call FunctionCall) Value { + return toValue_object(call.runtime.newRangeError(call.Argument(0))) +} + +func builtinNewRangeError(self *_object, argumentList []Value) Value { + return toValue_object(self.runtime.newRangeError(valueOfArrayIndex(argumentList, 0))) +} + +func (runtime *_runtime) newURIError(message Value) *_object { + self := runtime.newErrorObject("URIError", message) + self.prototype = runtime.global.URIErrorPrototype + return self +} + +func (runtime *_runtime) newReferenceError(message Value) *_object { + self := runtime.newErrorObject("ReferenceError", message) + self.prototype = runtime.global.ReferenceErrorPrototype + return self +} + +func builtinReferenceError(call FunctionCall) Value { + return toValue_object(call.runtime.newReferenceError(call.Argument(0))) +} + +func builtinNewReferenceError(self *_object, argumentList []Value) Value { + return toValue_object(self.runtime.newReferenceError(valueOfArrayIndex(argumentList, 0))) +} + +func (runtime *_runtime) newSyntaxError(message Value) *_object { + self := runtime.newErrorObject("SyntaxError", message) + self.prototype = runtime.global.SyntaxErrorPrototype + return self +} + +func builtinSyntaxError(call FunctionCall) Value { + return toValue_object(call.runtime.newSyntaxError(call.Argument(0))) +} + +func builtinNewSyntaxError(self *_object, argumentList []Value) Value { + return toValue_object(self.runtime.newSyntaxError(valueOfArrayIndex(argumentList, 0))) +} + +func builtinURIError(call FunctionCall) Value { + return toValue_object(call.runtime.newURIError(call.Argument(0))) +} + +func builtinNewURIError(self *_object, argumentList []Value) Value { + return toValue_object(self.runtime.newURIError(valueOfArrayIndex(argumentList, 0))) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_function.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_function.go new file mode 100644 index 0000000000..3d07566c6b --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_function.go @@ -0,0 +1,129 @@ +package otto + +import ( + "fmt" + "regexp" + "strings" + "unicode" + + "github.com/robertkrimen/otto/parser" +) + +// Function + +func builtinFunction(call FunctionCall) Value { + return toValue_object(builtinNewFunctionNative(call.runtime, call.ArgumentList)) +} + +func builtinNewFunction(self *_object, argumentList []Value) Value { + return toValue_object(builtinNewFunctionNative(self.runtime, argumentList)) +} + +func argumentList2parameterList(argumentList []Value) []string { + parameterList := make([]string, 0, len(argumentList)) + for _, value := range argumentList { + tmp := strings.FieldsFunc(value.string(), func(chr rune) bool { + return chr == ',' || unicode.IsSpace(chr) + }) + parameterList = append(parameterList, tmp...) + } + return parameterList +} + +var matchIdentifier = regexp.MustCompile(`^[$_\p{L}][$_\p{L}\d}]*$`) + +func builtinNewFunctionNative(runtime *_runtime, argumentList []Value) *_object { + var parameterList, body string + count := len(argumentList) + if count > 0 { + tmp := make([]string, 0, count-1) + for _, value := range argumentList[0 : count-1] { + tmp = append(tmp, value.string()) + } + parameterList = strings.Join(tmp, ",") + body = argumentList[count-1].string() + } + + // FIXME + function, err := parser.ParseFunction(parameterList, body) + runtime.parseThrow(err) // Will panic/throw appropriately + cmpl := _compiler{} + cmpl_function := cmpl.parseExpression(function) + + return runtime.newNodeFunction(cmpl_function.(*_nodeFunctionLiteral), runtime.globalStash) +} + +func builtinFunction_toString(call FunctionCall) Value { + object := call.thisClassObject("Function") // Should throw a TypeError unless Function + switch fn := object.value.(type) { + case _nativeFunctionObject: + return toValue_string(fmt.Sprintf("function %s() { [native code] }", fn.name)) + case _nodeFunctionObject: + return toValue_string(fn.node.source) + case _bindFunctionObject: + return toValue_string("function () { [native code] }") + } + + panic(call.runtime.panicTypeError("Function.toString()")) +} + +func builtinFunction_apply(call FunctionCall) Value { + if !call.This.isCallable() { + panic(call.runtime.panicTypeError()) + } + this := call.Argument(0) + if this.IsUndefined() { + // FIXME Not ECMA5 + this = toValue_object(call.runtime.globalObject) + } + argumentList := call.Argument(1) + switch argumentList.kind { + case valueUndefined, valueNull: + return call.thisObject().call(this, nil, false, nativeFrame) + case valueObject: + default: + panic(call.runtime.panicTypeError()) + } + + arrayObject := argumentList._object() + thisObject := call.thisObject() + length := int64(toUint32(arrayObject.get("length"))) + valueArray := make([]Value, length) + for index := int64(0); index < length; index++ { + valueArray[index] = arrayObject.get(arrayIndexToString(index)) + } + return thisObject.call(this, valueArray, false, nativeFrame) +} + +func builtinFunction_call(call FunctionCall) Value { + if !call.This.isCallable() { + panic(call.runtime.panicTypeError()) + } + thisObject := call.thisObject() + this := call.Argument(0) + if this.IsUndefined() { + // FIXME Not ECMA5 + this = toValue_object(call.runtime.globalObject) + } + if len(call.ArgumentList) >= 1 { + return thisObject.call(this, call.ArgumentList[1:], false, nativeFrame) + } + return thisObject.call(this, nil, false, nativeFrame) +} + +func builtinFunction_bind(call FunctionCall) Value { + target := call.This + if !target.isCallable() { + panic(call.runtime.panicTypeError()) + } + targetObject := target._object() + + this := call.Argument(0) + argumentList := call.slice(1) + if this.IsUndefined() { + // FIXME Do this elsewhere? + this = toValue_object(call.runtime.globalObject) + } + + return toValue_object(call.runtime.newBoundFunction(targetObject, this, argumentList)) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_json.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_json.go new file mode 100644 index 0000000000..aed54bf126 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_json.go @@ -0,0 +1,299 @@ +package otto + +import ( + "bytes" + "encoding/json" + "fmt" + "strings" +) + +type _builtinJSON_parseContext struct { + call FunctionCall + reviver Value +} + +func builtinJSON_parse(call FunctionCall) Value { + ctx := _builtinJSON_parseContext{ + call: call, + } + revive := false + if reviver := call.Argument(1); reviver.isCallable() { + revive = true + ctx.reviver = reviver + } + + var root interface{} + err := json.Unmarshal([]byte(call.Argument(0).string()), &root) + if err != nil { + panic(call.runtime.panicSyntaxError(err.Error())) + } + value, exists := builtinJSON_parseWalk(ctx, root) + if !exists { + value = Value{} + } + if revive { + root := ctx.call.runtime.newObject() + root.put("", value, false) + return builtinJSON_reviveWalk(ctx, root, "") + } + return value +} + +func builtinJSON_reviveWalk(ctx _builtinJSON_parseContext, holder *_object, name string) Value { + value := holder.get(name) + if object := value._object(); object != nil { + if isArray(object) { + length := int64(objectLength(object)) + for index := int64(0); index < length; index += 1 { + name := arrayIndexToString(index) + value := builtinJSON_reviveWalk(ctx, object, name) + if value.IsUndefined() { + object.delete(name, false) + } else { + object.defineProperty(name, value, 0111, false) + } + } + } else { + object.enumerate(false, func(name string) bool { + value := builtinJSON_reviveWalk(ctx, object, name) + if value.IsUndefined() { + object.delete(name, false) + } else { + object.defineProperty(name, value, 0111, false) + } + return true + }) + } + } + return ctx.reviver.call(ctx.call.runtime, toValue_object(holder), name, value) +} + +func builtinJSON_parseWalk(ctx _builtinJSON_parseContext, rawValue interface{}) (Value, bool) { + switch value := rawValue.(type) { + case nil: + return nullValue, true + case bool: + return toValue_bool(value), true + case string: + return toValue_string(value), true + case float64: + return toValue_float64(value), true + case []interface{}: + arrayValue := make([]Value, len(value)) + for index, rawValue := range value { + if value, exists := builtinJSON_parseWalk(ctx, rawValue); exists { + arrayValue[index] = value + } + } + return toValue_object(ctx.call.runtime.newArrayOf(arrayValue)), true + case map[string]interface{}: + object := ctx.call.runtime.newObject() + for name, rawValue := range value { + if value, exists := builtinJSON_parseWalk(ctx, rawValue); exists { + object.put(name, value, false) + } + } + return toValue_object(object), true + } + return Value{}, false +} + +type _builtinJSON_stringifyContext struct { + call FunctionCall + stack []*_object + propertyList []string + replacerFunction *Value + gap string +} + +func builtinJSON_stringify(call FunctionCall) Value { + ctx := _builtinJSON_stringifyContext{ + call: call, + stack: []*_object{nil}, + } + replacer := call.Argument(1)._object() + if replacer != nil { + if isArray(replacer) { + length := objectLength(replacer) + seen := map[string]bool{} + propertyList := make([]string, length) + length = 0 + for index, _ := range propertyList { + value := replacer.get(arrayIndexToString(int64(index))) + switch value.kind { + case valueObject: + switch value.value.(*_object).class { + case "String": + case "Number": + default: + continue + } + case valueString: + case valueNumber: + default: + continue + } + name := value.string() + if seen[name] { + continue + } + seen[name] = true + length += 1 + propertyList[index] = name + } + ctx.propertyList = propertyList[0:length] + } else if replacer.class == "Function" { + value := toValue_object(replacer) + ctx.replacerFunction = &value + } + } + if spaceValue, exists := call.getArgument(2); exists { + if spaceValue.kind == valueObject { + switch spaceValue.value.(*_object).class { + case "String": + spaceValue = toValue_string(spaceValue.string()) + case "Number": + spaceValue = spaceValue.numberValue() + } + } + switch spaceValue.kind { + case valueString: + value := spaceValue.string() + if len(value) > 10 { + ctx.gap = value[0:10] + } else { + ctx.gap = value + } + case valueNumber: + value := spaceValue.number().int64 + if value > 10 { + value = 10 + } else if value < 0 { + value = 0 + } + ctx.gap = strings.Repeat(" ", int(value)) + } + } + holder := call.runtime.newObject() + holder.put("", call.Argument(0), false) + value, exists := builtinJSON_stringifyWalk(ctx, "", holder) + if !exists { + return Value{} + } + valueJSON, err := json.Marshal(value) + if err != nil { + panic(call.runtime.panicTypeError(err.Error())) + } + if ctx.gap != "" { + valueJSON1 := bytes.Buffer{} + json.Indent(&valueJSON1, valueJSON, "", ctx.gap) + valueJSON = valueJSON1.Bytes() + } + return toValue_string(string(valueJSON)) +} + +func builtinJSON_stringifyWalk(ctx _builtinJSON_stringifyContext, key string, holder *_object) (interface{}, bool) { + value := holder.get(key) + + if value.IsObject() { + object := value._object() + if toJSON := object.get("toJSON"); toJSON.IsFunction() { + value = toJSON.call(ctx.call.runtime, value, key) + } else { + // If the object is a GoStruct or something that implements json.Marshaler + if object.objectClass.marshalJSON != nil { + marshaler := object.objectClass.marshalJSON(object) + if marshaler != nil { + return marshaler, true + } + } + } + } + + if ctx.replacerFunction != nil { + value = (*ctx.replacerFunction).call(ctx.call.runtime, toValue_object(holder), key, value) + } + + if value.kind == valueObject { + switch value.value.(*_object).class { + case "Boolean": + value = value._object().value.(Value) + case "String": + value = toValue_string(value.string()) + case "Number": + value = value.numberValue() + } + } + + switch value.kind { + case valueBoolean: + return value.bool(), true + case valueString: + return value.string(), true + case valueNumber: + integer := value.number() + switch integer.kind { + case numberInteger: + return integer.int64, true + case numberFloat: + return integer.float64, true + default: + return nil, true + } + case valueNull: + return nil, true + case valueObject: + holder := value._object() + if value := value._object(); nil != value { + for _, object := range ctx.stack { + if holder == object { + panic(ctx.call.runtime.panicTypeError("Converting circular structure to JSON")) + } + } + ctx.stack = append(ctx.stack, value) + defer func() { ctx.stack = ctx.stack[:len(ctx.stack)-1] }() + } + if isArray(holder) { + var length uint32 + switch value := holder.get("length").value.(type) { + case uint32: + length = value + case int: + if value >= 0 { + length = uint32(value) + } + default: + panic(ctx.call.runtime.panicTypeError(fmt.Sprintf("JSON.stringify: invalid length: %v (%[1]T)", value))) + } + array := make([]interface{}, length) + for index, _ := range array { + name := arrayIndexToString(int64(index)) + value, _ := builtinJSON_stringifyWalk(ctx, name, holder) + array[index] = value + } + return array, true + } else if holder.class != "Function" { + object := map[string]interface{}{} + if ctx.propertyList != nil { + for _, name := range ctx.propertyList { + value, exists := builtinJSON_stringifyWalk(ctx, name, holder) + if exists { + object[name] = value + } + } + } else { + // Go maps are without order, so this doesn't conform to the ECMA ordering + // standard, but oh well... + holder.enumerate(false, func(name string) bool { + value, exists := builtinJSON_stringifyWalk(ctx, name, holder) + if exists { + object[name] = value + } + return true + }) + } + return object, true + } + } + return nil, false +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_math.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_math.go new file mode 100644 index 0000000000..a9f4a55c1a --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_math.go @@ -0,0 +1,145 @@ +package otto + +import ( + "math" + "math/rand" +) + +// Math + +func builtinMath_abs(call FunctionCall) Value { + number := call.Argument(0).float64() + return toValue_float64(math.Abs(number)) +} + +func builtinMath_acos(call FunctionCall) Value { + number := call.Argument(0).float64() + return toValue_float64(math.Acos(number)) +} + +func builtinMath_asin(call FunctionCall) Value { + number := call.Argument(0).float64() + return toValue_float64(math.Asin(number)) +} + +func builtinMath_atan(call FunctionCall) Value { + number := call.Argument(0).float64() + return toValue_float64(math.Atan(number)) +} + +func builtinMath_atan2(call FunctionCall) Value { + y := call.Argument(0).float64() + if math.IsNaN(y) { + return NaNValue() + } + x := call.Argument(1).float64() + if math.IsNaN(x) { + return NaNValue() + } + return toValue_float64(math.Atan2(y, x)) +} + +func builtinMath_cos(call FunctionCall) Value { + number := call.Argument(0).float64() + return toValue_float64(math.Cos(number)) +} + +func builtinMath_ceil(call FunctionCall) Value { + number := call.Argument(0).float64() + return toValue_float64(math.Ceil(number)) +} + +func builtinMath_exp(call FunctionCall) Value { + number := call.Argument(0).float64() + return toValue_float64(math.Exp(number)) +} + +func builtinMath_floor(call FunctionCall) Value { + number := call.Argument(0).float64() + return toValue_float64(math.Floor(number)) +} + +func builtinMath_log(call FunctionCall) Value { + number := call.Argument(0).float64() + return toValue_float64(math.Log(number)) +} + +func builtinMath_max(call FunctionCall) Value { + switch len(call.ArgumentList) { + case 0: + return negativeInfinityValue() + case 1: + return toValue_float64(call.ArgumentList[0].float64()) + } + result := call.ArgumentList[0].float64() + if math.IsNaN(result) { + return NaNValue() + } + for _, value := range call.ArgumentList[1:] { + value := value.float64() + if math.IsNaN(value) { + return NaNValue() + } + result = math.Max(result, value) + } + return toValue_float64(result) +} + +func builtinMath_min(call FunctionCall) Value { + switch len(call.ArgumentList) { + case 0: + return positiveInfinityValue() + case 1: + return toValue_float64(call.ArgumentList[0].float64()) + } + result := call.ArgumentList[0].float64() + if math.IsNaN(result) { + return NaNValue() + } + for _, value := range call.ArgumentList[1:] { + value := value.float64() + if math.IsNaN(value) { + return NaNValue() + } + result = math.Min(result, value) + } + return toValue_float64(result) +} + +func builtinMath_pow(call FunctionCall) Value { + // TODO Make sure this works according to the specification (15.8.2.13) + x := call.Argument(0).float64() + y := call.Argument(1).float64() + if math.Abs(x) == 1 && math.IsInf(y, 0) { + return NaNValue() + } + return toValue_float64(math.Pow(x, y)) +} + +func builtinMath_random(call FunctionCall) Value { + return toValue_float64(rand.Float64()) +} + +func builtinMath_round(call FunctionCall) Value { + number := call.Argument(0).float64() + value := math.Floor(number + 0.5) + if value == 0 { + value = math.Copysign(0, number) + } + return toValue_float64(value) +} + +func builtinMath_sin(call FunctionCall) Value { + number := call.Argument(0).float64() + return toValue_float64(math.Sin(number)) +} + +func builtinMath_sqrt(call FunctionCall) Value { + number := call.Argument(0).float64() + return toValue_float64(math.Sqrt(number)) +} + +func builtinMath_tan(call FunctionCall) Value { + number := call.Argument(0).float64() + return toValue_float64(math.Tan(number)) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_number.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_number.go new file mode 100644 index 0000000000..26a03e7b61 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_number.go @@ -0,0 +1,93 @@ +package otto + +import ( + "math" + "strconv" +) + +// Number + +func numberValueFromNumberArgumentList(argumentList []Value) Value { + if len(argumentList) > 0 { + return argumentList[0].numberValue() + } + return toValue_int(0) +} + +func builtinNumber(call FunctionCall) Value { + return numberValueFromNumberArgumentList(call.ArgumentList) +} + +func builtinNewNumber(self *_object, argumentList []Value) Value { + return toValue_object(self.runtime.newNumber(numberValueFromNumberArgumentList(argumentList))) +} + +func builtinNumber_toString(call FunctionCall) Value { + // Will throw a TypeError if ThisObject is not a Number + value := call.thisClassObject("Number").primitiveValue() + radix := 10 + radixArgument := call.Argument(0) + if radixArgument.IsDefined() { + integer := toIntegerFloat(radixArgument) + if integer < 2 || integer > 36 { + panic(call.runtime.panicRangeError("RangeError: toString() radix must be between 2 and 36")) + } + radix = int(integer) + } + if radix == 10 { + return toValue_string(value.string()) + } + return toValue_string(numberToStringRadix(value, radix)) +} + +func builtinNumber_valueOf(call FunctionCall) Value { + return call.thisClassObject("Number").primitiveValue() +} + +func builtinNumber_toFixed(call FunctionCall) Value { + precision := toIntegerFloat(call.Argument(0)) + if 20 < precision || 0 > precision { + panic(call.runtime.panicRangeError("toFixed() precision must be between 0 and 20")) + } + if call.This.IsNaN() { + return toValue_string("NaN") + } + value := call.This.float64() + if math.Abs(value) >= 1e21 { + return toValue_string(floatToString(value, 64)) + } + return toValue_string(strconv.FormatFloat(call.This.float64(), 'f', int(precision), 64)) +} + +func builtinNumber_toExponential(call FunctionCall) Value { + if call.This.IsNaN() { + return toValue_string("NaN") + } + precision := float64(-1) + if value := call.Argument(0); value.IsDefined() { + precision = toIntegerFloat(value) + if 0 > precision { + panic(call.runtime.panicRangeError("RangeError: toString() radix must be between 2 and 36")) + } + } + return toValue_string(strconv.FormatFloat(call.This.float64(), 'e', int(precision), 64)) +} + +func builtinNumber_toPrecision(call FunctionCall) Value { + if call.This.IsNaN() { + return toValue_string("NaN") + } + value := call.Argument(0) + if value.IsUndefined() { + return toValue_string(call.This.string()) + } + precision := toIntegerFloat(value) + if 1 > precision { + panic(call.runtime.panicRangeError("RangeError: toPrecision() precision must be greater than 1")) + } + return toValue_string(strconv.FormatFloat(call.This.float64(), 'g', int(precision), 64)) +} + +func builtinNumber_toLocaleString(call FunctionCall) Value { + return builtinNumber_toString(call) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_object.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_object.go new file mode 100644 index 0000000000..c2433f7be2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_object.go @@ -0,0 +1,289 @@ +package otto + +import ( + "fmt" +) + +// Object + +func builtinObject(call FunctionCall) Value { + value := call.Argument(0) + switch value.kind { + case valueUndefined, valueNull: + return toValue_object(call.runtime.newObject()) + } + + return toValue_object(call.runtime.toObject(value)) +} + +func builtinNewObject(self *_object, argumentList []Value) Value { + value := valueOfArrayIndex(argumentList, 0) + switch value.kind { + case valueNull, valueUndefined: + case valueNumber, valueString, valueBoolean: + return toValue_object(self.runtime.toObject(value)) + case valueObject: + return value + default: + } + return toValue_object(self.runtime.newObject()) +} + +func builtinObject_valueOf(call FunctionCall) Value { + return toValue_object(call.thisObject()) +} + +func builtinObject_hasOwnProperty(call FunctionCall) Value { + propertyName := call.Argument(0).string() + thisObject := call.thisObject() + return toValue_bool(thisObject.hasOwnProperty(propertyName)) +} + +func builtinObject_isPrototypeOf(call FunctionCall) Value { + value := call.Argument(0) + if !value.IsObject() { + return falseValue + } + prototype := call.toObject(value).prototype + thisObject := call.thisObject() + for prototype != nil { + if thisObject == prototype { + return trueValue + } + prototype = prototype.prototype + } + return falseValue +} + +func builtinObject_propertyIsEnumerable(call FunctionCall) Value { + propertyName := call.Argument(0).string() + thisObject := call.thisObject() + property := thisObject.getOwnProperty(propertyName) + if property != nil && property.enumerable() { + return trueValue + } + return falseValue +} + +func builtinObject_toString(call FunctionCall) Value { + result := "" + if call.This.IsUndefined() { + result = "[object Undefined]" + } else if call.This.IsNull() { + result = "[object Null]" + } else { + result = fmt.Sprintf("[object %s]", call.thisObject().class) + } + return toValue_string(result) +} + +func builtinObject_toLocaleString(call FunctionCall) Value { + toString := call.thisObject().get("toString") + if !toString.isCallable() { + panic(call.runtime.panicTypeError()) + } + return toString.call(call.runtime, call.This) +} + +func builtinObject_getPrototypeOf(call FunctionCall) Value { + objectValue := call.Argument(0) + object := objectValue._object() + if object == nil { + panic(call.runtime.panicTypeError()) + } + + if object.prototype == nil { + return nullValue + } + + return toValue_object(object.prototype) +} + +func builtinObject_getOwnPropertyDescriptor(call FunctionCall) Value { + objectValue := call.Argument(0) + object := objectValue._object() + if object == nil { + panic(call.runtime.panicTypeError()) + } + + name := call.Argument(1).string() + descriptor := object.getOwnProperty(name) + if descriptor == nil { + return Value{} + } + return toValue_object(call.runtime.fromPropertyDescriptor(*descriptor)) +} + +func builtinObject_defineProperty(call FunctionCall) Value { + objectValue := call.Argument(0) + object := objectValue._object() + if object == nil { + panic(call.runtime.panicTypeError()) + } + name := call.Argument(1).string() + descriptor := toPropertyDescriptor(call.runtime, call.Argument(2)) + object.defineOwnProperty(name, descriptor, true) + return objectValue +} + +func builtinObject_defineProperties(call FunctionCall) Value { + objectValue := call.Argument(0) + object := objectValue._object() + if object == nil { + panic(call.runtime.panicTypeError()) + } + + properties := call.runtime.toObject(call.Argument(1)) + properties.enumerate(false, func(name string) bool { + descriptor := toPropertyDescriptor(call.runtime, properties.get(name)) + object.defineOwnProperty(name, descriptor, true) + return true + }) + + return objectValue +} + +func builtinObject_create(call FunctionCall) Value { + prototypeValue := call.Argument(0) + if !prototypeValue.IsNull() && !prototypeValue.IsObject() { + panic(call.runtime.panicTypeError()) + } + + object := call.runtime.newObject() + object.prototype = prototypeValue._object() + + propertiesValue := call.Argument(1) + if propertiesValue.IsDefined() { + properties := call.runtime.toObject(propertiesValue) + properties.enumerate(false, func(name string) bool { + descriptor := toPropertyDescriptor(call.runtime, properties.get(name)) + object.defineOwnProperty(name, descriptor, true) + return true + }) + } + + return toValue_object(object) +} + +func builtinObject_isExtensible(call FunctionCall) Value { + object := call.Argument(0) + if object := object._object(); object != nil { + return toValue_bool(object.extensible) + } + panic(call.runtime.panicTypeError()) +} + +func builtinObject_preventExtensions(call FunctionCall) Value { + object := call.Argument(0) + if object := object._object(); object != nil { + object.extensible = false + } else { + panic(call.runtime.panicTypeError()) + } + return object +} + +func builtinObject_isSealed(call FunctionCall) Value { + object := call.Argument(0) + if object := object._object(); object != nil { + if object.extensible { + return toValue_bool(false) + } + result := true + object.enumerate(true, func(name string) bool { + property := object.getProperty(name) + if property.configurable() { + result = false + } + return true + }) + return toValue_bool(result) + } + panic(call.runtime.panicTypeError()) +} + +func builtinObject_seal(call FunctionCall) Value { + object := call.Argument(0) + if object := object._object(); object != nil { + object.enumerate(true, func(name string) bool { + if property := object.getOwnProperty(name); nil != property && property.configurable() { + property.configureOff() + object.defineOwnProperty(name, *property, true) + } + return true + }) + object.extensible = false + } else { + panic(call.runtime.panicTypeError()) + } + return object +} + +func builtinObject_isFrozen(call FunctionCall) Value { + object := call.Argument(0) + if object := object._object(); object != nil { + if object.extensible { + return toValue_bool(false) + } + result := true + object.enumerate(true, func(name string) bool { + property := object.getProperty(name) + if property.configurable() || property.writable() { + result = false + } + return true + }) + return toValue_bool(result) + } + panic(call.runtime.panicTypeError()) +} + +func builtinObject_freeze(call FunctionCall) Value { + object := call.Argument(0) + if object := object._object(); object != nil { + object.enumerate(true, func(name string) bool { + if property, update := object.getOwnProperty(name), false; nil != property { + if property.isDataDescriptor() && property.writable() { + property.writeOff() + update = true + } + if property.configurable() { + property.configureOff() + update = true + } + if update { + object.defineOwnProperty(name, *property, true) + } + } + return true + }) + object.extensible = false + } else { + panic(call.runtime.panicTypeError()) + } + return object +} + +func builtinObject_keys(call FunctionCall) Value { + if object, keys := call.Argument(0)._object(), []Value(nil); nil != object { + object.enumerate(false, func(name string) bool { + keys = append(keys, toValue_string(name)) + return true + }) + return toValue_object(call.runtime.newArrayOf(keys)) + } + panic(call.runtime.panicTypeError()) +} + +func builtinObject_getOwnPropertyNames(call FunctionCall) Value { + if object, propertyNames := call.Argument(0)._object(), []Value(nil); nil != object { + object.enumerate(true, func(name string) bool { + if object.hasOwnProperty(name) { + propertyNames = append(propertyNames, toValue_string(name)) + } + return true + }) + return toValue_object(call.runtime.newArrayOf(propertyNames)) + } + panic(call.runtime.panicTypeError()) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_regexp.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_regexp.go new file mode 100644 index 0000000000..99422510d3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_regexp.go @@ -0,0 +1,65 @@ +package otto + +import ( + "fmt" +) + +// RegExp + +func builtinRegExp(call FunctionCall) Value { + pattern := call.Argument(0) + flags := call.Argument(1) + if object := pattern._object(); object != nil { + if object.class == "RegExp" && flags.IsUndefined() { + return pattern + } + } + return toValue_object(call.runtime.newRegExp(pattern, flags)) +} + +func builtinNewRegExp(self *_object, argumentList []Value) Value { + return toValue_object(self.runtime.newRegExp( + valueOfArrayIndex(argumentList, 0), + valueOfArrayIndex(argumentList, 1), + )) +} + +func builtinRegExp_toString(call FunctionCall) Value { + thisObject := call.thisObject() + source := thisObject.get("source").string() + flags := []byte{} + if thisObject.get("global").bool() { + flags = append(flags, 'g') + } + if thisObject.get("ignoreCase").bool() { + flags = append(flags, 'i') + } + if thisObject.get("multiline").bool() { + flags = append(flags, 'm') + } + return toValue_string(fmt.Sprintf("/%s/%s", source, flags)) +} + +func builtinRegExp_exec(call FunctionCall) Value { + thisObject := call.thisObject() + target := call.Argument(0).string() + match, result := execRegExp(thisObject, target) + if !match { + return nullValue + } + return toValue_object(execResultToArray(call.runtime, target, result)) +} + +func builtinRegExp_test(call FunctionCall) Value { + thisObject := call.thisObject() + target := call.Argument(0).string() + match, _ := execRegExp(thisObject, target) + return toValue_bool(match) +} + +func builtinRegExp_compile(call FunctionCall) Value { + // This (useless) function is deprecated, but is here to provide some + // semblance of compatibility. + // Caveat emptor: it may not be around for long. + return Value{} +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_string.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_string.go new file mode 100644 index 0000000000..6a17184589 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_string.go @@ -0,0 +1,500 @@ +package otto + +import ( + "bytes" + "regexp" + "strconv" + "strings" + "unicode/utf8" +) + +// String + +func stringValueFromStringArgumentList(argumentList []Value) Value { + if len(argumentList) > 0 { + return toValue_string(argumentList[0].string()) + } + return toValue_string("") +} + +func builtinString(call FunctionCall) Value { + return stringValueFromStringArgumentList(call.ArgumentList) +} + +func builtinNewString(self *_object, argumentList []Value) Value { + return toValue_object(self.runtime.newString(stringValueFromStringArgumentList(argumentList))) +} + +func builtinString_toString(call FunctionCall) Value { + return call.thisClassObject("String").primitiveValue() +} +func builtinString_valueOf(call FunctionCall) Value { + return call.thisClassObject("String").primitiveValue() +} + +func builtinString_fromCharCode(call FunctionCall) Value { + chrList := make([]uint16, len(call.ArgumentList)) + for index, value := range call.ArgumentList { + chrList[index] = toUint16(value) + } + return toValue_string16(chrList) +} + +func builtinString_charAt(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + idx := int(call.Argument(0).number().int64) + chr := stringAt(call.This._object().stringValue(), idx) + if chr == utf8.RuneError { + return toValue_string("") + } + return toValue_string(string(chr)) +} + +func builtinString_charCodeAt(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + idx := int(call.Argument(0).number().int64) + chr := stringAt(call.This._object().stringValue(), idx) + if chr == utf8.RuneError { + return NaNValue() + } + return toValue_uint16(uint16(chr)) +} + +func builtinString_concat(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + var value bytes.Buffer + value.WriteString(call.This.string()) + for _, item := range call.ArgumentList { + value.WriteString(item.string()) + } + return toValue_string(value.String()) +} + +func builtinString_indexOf(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + value := call.This.string() + target := call.Argument(0).string() + if 2 > len(call.ArgumentList) { + return toValue_int(strings.Index(value, target)) + } + start := toIntegerFloat(call.Argument(1)) + if 0 > start { + start = 0 + } else if start >= float64(len(value)) { + if target == "" { + return toValue_int(len(value)) + } + return toValue_int(-1) + } + index := strings.Index(value[int(start):], target) + if index >= 0 { + index += int(start) + } + return toValue_int(index) +} + +func builtinString_lastIndexOf(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + value := call.This.string() + target := call.Argument(0).string() + if 2 > len(call.ArgumentList) || call.ArgumentList[1].IsUndefined() { + return toValue_int(strings.LastIndex(value, target)) + } + length := len(value) + if length == 0 { + return toValue_int(strings.LastIndex(value, target)) + } + start := call.ArgumentList[1].number() + if start.kind == numberInfinity { // FIXME + // startNumber is infinity, so start is the end of string (start = length) + return toValue_int(strings.LastIndex(value, target)) + } + if 0 > start.int64 { + start.int64 = 0 + } + end := int(start.int64) + len(target) + if end > length { + end = length + } + return toValue_int(strings.LastIndex(value[:end], target)) +} + +func builtinString_match(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + target := call.This.string() + matcherValue := call.Argument(0) + matcher := matcherValue._object() + if !matcherValue.IsObject() || matcher.class != "RegExp" { + matcher = call.runtime.newRegExp(matcherValue, Value{}) + } + global := matcher.get("global").bool() + if !global { + match, result := execRegExp(matcher, target) + if !match { + return nullValue + } + return toValue_object(execResultToArray(call.runtime, target, result)) + } + + { + result := matcher.regExpValue().regularExpression.FindAllStringIndex(target, -1) + matchCount := len(result) + if result == nil { + matcher.put("lastIndex", toValue_int(0), true) + return Value{} // !match + } + matchCount = len(result) + valueArray := make([]Value, matchCount) + for index := 0; index < matchCount; index++ { + valueArray[index] = toValue_string(target[result[index][0]:result[index][1]]) + } + matcher.put("lastIndex", toValue_int(result[matchCount-1][1]), true) + return toValue_object(call.runtime.newArrayOf(valueArray)) + } +} + +var builtinString_replace_Regexp = regexp.MustCompile("\\$(?:[\\$\\&\\'\\`1-9]|0[1-9]|[1-9][0-9])") + +func builtinString_findAndReplaceString(input []byte, lastIndex int, match []int, target []byte, replaceValue []byte) (output []byte) { + matchCount := len(match) / 2 + output = input + if match[0] != lastIndex { + output = append(output, target[lastIndex:match[0]]...) + } + replacement := builtinString_replace_Regexp.ReplaceAllFunc(replaceValue, func(part []byte) []byte { + // TODO Check if match[0] or match[1] can be -1 in this scenario + switch part[1] { + case '$': + return []byte{'$'} + case '&': + return target[match[0]:match[1]] + case '`': + return target[:match[0]] + case '\'': + return target[match[1]:len(target)] + } + matchNumberParse, error := strconv.ParseInt(string(part[1:]), 10, 64) + matchNumber := int(matchNumberParse) + if error != nil || matchNumber >= matchCount { + return []byte{} + } + offset := 2 * matchNumber + if match[offset] != -1 { + return target[match[offset]:match[offset+1]] + } + return []byte{} // The empty string + }) + output = append(output, replacement...) + return output +} + +func builtinString_replace(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + target := []byte(call.This.string()) + searchValue := call.Argument(0) + searchObject := searchValue._object() + + // TODO If a capture is -1? + var search *regexp.Regexp + global := false + find := 1 + if searchValue.IsObject() && searchObject.class == "RegExp" { + regExp := searchObject.regExpValue() + search = regExp.regularExpression + if regExp.global { + find = -1 + } + } else { + search = regexp.MustCompile(regexp.QuoteMeta(searchValue.string())) + } + + found := search.FindAllSubmatchIndex(target, find) + if found == nil { + return toValue_string(string(target)) // !match + } + + { + lastIndex := 0 + result := []byte{} + + replaceValue := call.Argument(1) + if replaceValue.isCallable() { + target := string(target) + replace := replaceValue._object() + for _, match := range found { + if match[0] != lastIndex { + result = append(result, target[lastIndex:match[0]]...) + } + matchCount := len(match) / 2 + argumentList := make([]Value, matchCount+2) + for index := 0; index < matchCount; index++ { + offset := 2 * index + if match[offset] != -1 { + argumentList[index] = toValue_string(target[match[offset]:match[offset+1]]) + } else { + argumentList[index] = Value{} + } + } + argumentList[matchCount+0] = toValue_int(match[0]) + argumentList[matchCount+1] = toValue_string(target) + replacement := replace.call(Value{}, argumentList, false, nativeFrame).string() + result = append(result, []byte(replacement)...) + lastIndex = match[1] + } + + } else { + replace := []byte(replaceValue.string()) + for _, match := range found { + result = builtinString_findAndReplaceString(result, lastIndex, match, target, replace) + lastIndex = match[1] + } + } + + if lastIndex != len(target) { + result = append(result, target[lastIndex:]...) + } + + if global && searchObject != nil { + searchObject.put("lastIndex", toValue_int(lastIndex), true) + } + + return toValue_string(string(result)) + } +} + +func builtinString_search(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + target := call.This.string() + searchValue := call.Argument(0) + search := searchValue._object() + if !searchValue.IsObject() || search.class != "RegExp" { + search = call.runtime.newRegExp(searchValue, Value{}) + } + result := search.regExpValue().regularExpression.FindStringIndex(target) + if result == nil { + return toValue_int(-1) + } + return toValue_int(result[0]) +} + +func stringSplitMatch(target string, targetLength int64, index uint, search string, searchLength int64) (bool, uint) { + if int64(index)+searchLength > searchLength { + return false, 0 + } + found := strings.Index(target[index:], search) + if 0 > found { + return false, 0 + } + return true, uint(found) +} + +func builtinString_split(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + target := call.This.string() + + separatorValue := call.Argument(0) + limitValue := call.Argument(1) + limit := -1 + if limitValue.IsDefined() { + limit = int(toUint32(limitValue)) + } + + if limit == 0 { + return toValue_object(call.runtime.newArray(0)) + } + + if separatorValue.IsUndefined() { + return toValue_object(call.runtime.newArrayOf([]Value{toValue_string(target)})) + } + + if separatorValue.isRegExp() { + targetLength := len(target) + search := separatorValue._object().regExpValue().regularExpression + valueArray := []Value{} + result := search.FindAllStringSubmatchIndex(target, -1) + lastIndex := 0 + found := 0 + + for _, match := range result { + if match[0] == match[1] { + // FIXME Ugh, this is a hack + if match[0] == 0 || match[0] == targetLength { + continue + } + } + + if lastIndex != match[0] { + valueArray = append(valueArray, toValue_string(target[lastIndex:match[0]])) + found++ + } else if lastIndex == match[0] { + if lastIndex != -1 { + valueArray = append(valueArray, toValue_string("")) + found++ + } + } + + lastIndex = match[1] + if found == limit { + goto RETURN + } + + captureCount := len(match) / 2 + for index := 1; index < captureCount; index++ { + offset := index * 2 + value := Value{} + if match[offset] != -1 { + value = toValue_string(target[match[offset]:match[offset+1]]) + } + valueArray = append(valueArray, value) + found++ + if found == limit { + goto RETURN + } + } + } + + if found != limit { + if lastIndex != targetLength { + valueArray = append(valueArray, toValue_string(target[lastIndex:targetLength])) + } else { + valueArray = append(valueArray, toValue_string("")) + } + } + + RETURN: + return toValue_object(call.runtime.newArrayOf(valueArray)) + + } else { + separator := separatorValue.string() + + splitLimit := limit + excess := false + if limit > 0 { + splitLimit = limit + 1 + excess = true + } + + split := strings.SplitN(target, separator, splitLimit) + + if excess && len(split) > limit { + split = split[:limit] + } + + valueArray := make([]Value, len(split)) + for index, value := range split { + valueArray[index] = toValue_string(value) + } + + return toValue_object(call.runtime.newArrayOf(valueArray)) + } +} + +func builtinString_slice(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + target := call.This.string() + + length := int64(len(target)) + start, end := rangeStartEnd(call.ArgumentList, length, false) + if end-start <= 0 { + return toValue_string("") + } + return toValue_string(target[start:end]) +} + +func builtinString_substring(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + target := call.This.string() + + length := int64(len(target)) + start, end := rangeStartEnd(call.ArgumentList, length, true) + if start > end { + start, end = end, start + } + return toValue_string(target[start:end]) +} + +func builtinString_substr(call FunctionCall) Value { + target := call.This.string() + + size := int64(len(target)) + start, length := rangeStartLength(call.ArgumentList, size) + + if start >= size { + return toValue_string("") + } + + if length <= 0 { + return toValue_string("") + } + + if start+length >= size { + // Cap length to be to the end of the string + // start = 3, length = 5, size = 4 [0, 1, 2, 3] + // 4 - 3 = 1 + // target[3:4] + length = size - start + } + + return toValue_string(target[start : start+length]) +} + +func builtinString_toLowerCase(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + return toValue_string(strings.ToLower(call.This.string())) +} + +func builtinString_toUpperCase(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + return toValue_string(strings.ToUpper(call.This.string())) +} + +// 7.2 Table 2 — Whitespace Characters & 7.3 Table 3 - Line Terminator Characters +const builtinString_trim_whitespace = "\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF" + +func builtinString_trim(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + return toValue(strings.Trim(call.This.string(), + builtinString_trim_whitespace)) +} + +// Mozilla extension, not ECMAScript 5 +func builtinString_trimLeft(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + return toValue(strings.TrimLeft(call.This.string(), + builtinString_trim_whitespace)) +} + +// Mozilla extension, not ECMAScript 5 +func builtinString_trimRight(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + return toValue(strings.TrimRight(call.This.string(), + builtinString_trim_whitespace)) +} + +func builtinString_localeCompare(call FunctionCall) Value { + checkObjectCoercible(call.runtime, call.This) + this := call.This.string() + that := call.Argument(0).string() + if this < that { + return toValue_int(-1) + } else if this == that { + return toValue_int(0) + } + return toValue_int(1) +} + +/* +An alternate version of String.trim +func builtinString_trim(call FunctionCall) Value { + checkObjectCoercible(call.This) + return toValue_string(strings.TrimFunc(call.string(.This), isWhiteSpaceOrLineTerminator)) +} +*/ + +func builtinString_toLocaleLowerCase(call FunctionCall) Value { + return builtinString_toLowerCase(call) +} + +func builtinString_toLocaleUpperCase(call FunctionCall) Value { + return builtinString_toUpperCase(call) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_test.go new file mode 100644 index 0000000000..f5be00ab6e --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_test.go @@ -0,0 +1,136 @@ +package otto + +import ( + "testing" +) + +func TestString_substr(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ + "abc".substr(0,1), // "a" + "abc".substr(0,2), // "ab" + "abc".substr(0,3), // "abc" + "abc".substr(0,4), // "abc" + "abc".substr(0,9), // "abc" + ]; + `, "a,ab,abc,abc,abc") + + test(` + [ + "abc".substr(1,1), // "b" + "abc".substr(1,2), // "bc" + "abc".substr(1,3), // "bc" + "abc".substr(1,4), // "bc" + "abc".substr(1,9), // "bc" + ]; + `, "b,bc,bc,bc,bc") + + test(` + [ + "abc".substr(2,1), // "c" + "abc".substr(2,2), // "c" + "abc".substr(2,3), // "c" + "abc".substr(2,4), // "c" + "abc".substr(2,9), // "c" + ]; + `, "c,c,c,c,c") + + test(` + [ + "abc".substr(3,1), // "" + "abc".substr(3,2), // "" + "abc".substr(3,3), // "" + "abc".substr(3,4), // "" + "abc".substr(3,9), // "" + ]; + `, ",,,,") + + test(` + [ + "abc".substr(0), // "abc" + "abc".substr(1), // "bc" + "abc".substr(2), // "c" + "abc".substr(3), // "" + "abc".substr(9), // "" + ]; + `, "abc,bc,c,,") + + test(` + [ + "abc".substr(-9), // "abc" + "abc".substr(-3), // "abc" + "abc".substr(-2), // "bc" + "abc".substr(-1), // "c" + ]; + `, "abc,abc,bc,c") + + test(` + [ + "abc".substr(-9, 1), // "a" + "abc".substr(-3, 1), // "a" + "abc".substr(-2, 1), // "b" + "abc".substr(-1, 1), // "c" + "abc".substr(-1, 2), // "c" + ]; + `, "a,a,b,c,c") + + test(`"abcd".substr(3, 5)`, "d") + }) +} + +func Test_builtin_escape(t *testing.T) { + tt(t, func() { + is(builtin_escape("abc"), "abc") + + is(builtin_escape("="), "%3D") + + is(builtin_escape("abc=%+32"), "abc%3D%25+32") + + is(builtin_escape("世界"), "%u4E16%u754C") + }) +} + +func Test_builtin_unescape(t *testing.T) { + tt(t, func() { + is(builtin_unescape("abc"), "abc") + + is(builtin_unescape("=%3D"), "==") + + is(builtin_unescape("abc%3D%25+32"), "abc=%+32") + + is(builtin_unescape("%u4E16%u754C"), "世界") + }) +} + +func TestGlobal_escape(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ + escape("abc"), // "abc" + escape("="), // "%3D" + escape("abc=%+32"), // "abc%3D%25+32" + escape("\u4e16\u754c"), // "%u4E16%u754C" + ]; + `, "abc,%3D,abc%3D%25+32,%u4E16%u754C") + }) +} + +func TestGlobal_unescape(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ + unescape("abc"), // "abc" + unescape("=%3D"), // "==" + unescape("abc%3D%25+32"), // "abc=%+32" + unescape("%u4E16%u754C"), // "世界" + ]; + `, "abc,==,abc=%+32,世界") + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/clone.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/clone.go new file mode 100644 index 0000000000..f79901b357 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/clone.go @@ -0,0 +1,155 @@ +package otto + +import ( + "fmt" +) + +type _clone struct { + runtime *_runtime + _object map[*_object]*_object + _objectStash map[*_objectStash]*_objectStash + _dclStash map[*_dclStash]*_dclStash + _fnStash map[*_fnStash]*_fnStash +} + +func (in *_runtime) clone() *_runtime { + + in.lck.Lock() + defer in.lck.Unlock() + + out := &_runtime{} + clone := _clone{ + runtime: out, + _object: make(map[*_object]*_object), + _objectStash: make(map[*_objectStash]*_objectStash), + _dclStash: make(map[*_dclStash]*_dclStash), + _fnStash: make(map[*_fnStash]*_fnStash), + } + + globalObject := clone.object(in.globalObject) + out.globalStash = out.newObjectStash(globalObject, nil) + out.globalObject = globalObject + out.global = _global{ + clone.object(in.global.Object), + clone.object(in.global.Function), + clone.object(in.global.Array), + clone.object(in.global.String), + clone.object(in.global.Boolean), + clone.object(in.global.Number), + clone.object(in.global.Math), + clone.object(in.global.Date), + clone.object(in.global.RegExp), + clone.object(in.global.Error), + clone.object(in.global.EvalError), + clone.object(in.global.TypeError), + clone.object(in.global.RangeError), + clone.object(in.global.ReferenceError), + clone.object(in.global.SyntaxError), + clone.object(in.global.URIError), + clone.object(in.global.JSON), + + clone.object(in.global.ObjectPrototype), + clone.object(in.global.FunctionPrototype), + clone.object(in.global.ArrayPrototype), + clone.object(in.global.StringPrototype), + clone.object(in.global.BooleanPrototype), + clone.object(in.global.NumberPrototype), + clone.object(in.global.DatePrototype), + clone.object(in.global.RegExpPrototype), + clone.object(in.global.ErrorPrototype), + clone.object(in.global.EvalErrorPrototype), + clone.object(in.global.TypeErrorPrototype), + clone.object(in.global.RangeErrorPrototype), + clone.object(in.global.ReferenceErrorPrototype), + clone.object(in.global.SyntaxErrorPrototype), + clone.object(in.global.URIErrorPrototype), + } + + out.eval = out.globalObject.property["eval"].value.(Value).value.(*_object) + out.globalObject.prototype = out.global.ObjectPrototype + + // Not sure if this is necessary, but give some help to the GC + clone.runtime = nil + clone._object = nil + clone._objectStash = nil + clone._dclStash = nil + clone._fnStash = nil + + return out +} + +func (clone *_clone) object(in *_object) *_object { + if out, exists := clone._object[in]; exists { + return out + } + out := &_object{} + clone._object[in] = out + return in.objectClass.clone(in, out, clone) +} + +func (clone *_clone) dclStash(in *_dclStash) (*_dclStash, bool) { + if out, exists := clone._dclStash[in]; exists { + return out, true + } + out := &_dclStash{} + clone._dclStash[in] = out + return out, false +} + +func (clone *_clone) objectStash(in *_objectStash) (*_objectStash, bool) { + if out, exists := clone._objectStash[in]; exists { + return out, true + } + out := &_objectStash{} + clone._objectStash[in] = out + return out, false +} + +func (clone *_clone) fnStash(in *_fnStash) (*_fnStash, bool) { + if out, exists := clone._fnStash[in]; exists { + return out, true + } + out := &_fnStash{} + clone._fnStash[in] = out + return out, false +} + +func (clone *_clone) value(in Value) Value { + out := in + switch value := in.value.(type) { + case *_object: + out.value = clone.object(value) + } + return out +} + +func (clone *_clone) valueArray(in []Value) []Value { + out := make([]Value, len(in)) + for index, value := range in { + out[index] = clone.value(value) + } + return out +} + +func (clone *_clone) stash(in _stash) _stash { + if in == nil { + return nil + } + return in.clone(clone) +} + +func (clone *_clone) property(in _property) _property { + out := in + if value, valid := in.value.(Value); valid { + out.value = clone.value(value) + } else { + panic(fmt.Errorf("in.value.(Value) != true")) + } + return out +} + +func (clone *_clone) dclProperty(in _dclProperty) _dclProperty { + out := in + out.value = clone.value(in.value) + return out +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl.go new file mode 100644 index 0000000000..c191b45279 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl.go @@ -0,0 +1,24 @@ +package otto + +import ( + "github.com/robertkrimen/otto/ast" + "github.com/robertkrimen/otto/file" +) + +type _file struct { + name string + src string + base int // This will always be 1 or greater +} + +type _compiler struct { + file *file.File + program *ast.Program +} + +func (cmpl *_compiler) parse() *_nodeProgram { + if cmpl.program != nil { + cmpl.file = cmpl.program.File + } + return cmpl._parse(cmpl.program) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate.go new file mode 100644 index 0000000000..6741bf3945 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate.go @@ -0,0 +1,96 @@ +package otto + +import ( + "strconv" +) + +func (self *_runtime) cmpl_evaluate_nodeProgram(node *_nodeProgram, eval bool) Value { + if !eval { + self.enterGlobalScope() + defer func() { + self.leaveScope() + }() + } + self.cmpl_functionDeclaration(node.functionList) + self.cmpl_variableDeclaration(node.varList) + self.scope.frame.file = node.file + return self.cmpl_evaluate_nodeStatementList(node.body) +} + +func (self *_runtime) cmpl_call_nodeFunction(function *_object, stash *_fnStash, node *_nodeFunctionLiteral, this Value, argumentList []Value) Value { + + indexOfParameterName := make([]string, len(argumentList)) + // function(abc, def, ghi) + // indexOfParameterName[0] = "abc" + // indexOfParameterName[1] = "def" + // indexOfParameterName[2] = "ghi" + // ... + + argumentsFound := false + for index, name := range node.parameterList { + if name == "arguments" { + argumentsFound = true + } + value := Value{} + if index < len(argumentList) { + value = argumentList[index] + indexOfParameterName[index] = name + } + // strict = false + self.scope.lexical.setValue(name, value, false) + } + + if !argumentsFound { + arguments := self.newArgumentsObject(indexOfParameterName, stash, len(argumentList)) + arguments.defineProperty("callee", toValue_object(function), 0101, false) + stash.arguments = arguments + // strict = false + self.scope.lexical.setValue("arguments", toValue_object(arguments), false) + for index, _ := range argumentList { + if index < len(node.parameterList) { + continue + } + indexAsString := strconv.FormatInt(int64(index), 10) + arguments.defineProperty(indexAsString, argumentList[index], 0111, false) + } + } + + self.cmpl_functionDeclaration(node.functionList) + self.cmpl_variableDeclaration(node.varList) + + result := self.cmpl_evaluate_nodeStatement(node.body) + if result.kind == valueResult { + return result + } + + return Value{} +} + +func (self *_runtime) cmpl_functionDeclaration(list []*_nodeFunctionLiteral) { + executionContext := self.scope + eval := executionContext.eval + stash := executionContext.variable + + for _, function := range list { + name := function.name + value := self.cmpl_evaluate_nodeExpression(function) + if !stash.hasBinding(name) { + stash.createBinding(name, eval == true, value) + } else { + // TODO 10.5.5.e + stash.setBinding(name, value, false) // TODO strict + } + } +} + +func (self *_runtime) cmpl_variableDeclaration(list []string) { + executionContext := self.scope + eval := executionContext.eval + stash := executionContext.variable + + for _, name := range list { + if !stash.hasBinding(name) { + stash.createBinding(name, eval == true, Value{}) // TODO strict? + } + } +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_expression.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_expression.go new file mode 100644 index 0000000000..34449970ef --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_expression.go @@ -0,0 +1,456 @@ +package otto + +import ( + "fmt" + "math" + "runtime" + + "github.com/robertkrimen/otto/token" +) + +func (self *_runtime) cmpl_evaluate_nodeExpression(node _nodeExpression) Value { + // Allow interpreter interruption + // If the Interrupt channel is nil, then + // we avoid runtime.Gosched() overhead (if any) + // FIXME: Test this + if self.otto.Interrupt != nil { + runtime.Gosched() + select { + case value := <-self.otto.Interrupt: + value() + default: + } + } + + switch node := node.(type) { + + case *_nodeArrayLiteral: + return self.cmpl_evaluate_nodeArrayLiteral(node) + + case *_nodeAssignExpression: + return self.cmpl_evaluate_nodeAssignExpression(node) + + case *_nodeBinaryExpression: + if node.comparison { + return self.cmpl_evaluate_nodeBinaryExpression_comparison(node) + } else { + return self.cmpl_evaluate_nodeBinaryExpression(node) + } + + case *_nodeBracketExpression: + return self.cmpl_evaluate_nodeBracketExpression(node) + + case *_nodeCallExpression: + return self.cmpl_evaluate_nodeCallExpression(node, nil) + + case *_nodeConditionalExpression: + return self.cmpl_evaluate_nodeConditionalExpression(node) + + case *_nodeDotExpression: + return self.cmpl_evaluate_nodeDotExpression(node) + + case *_nodeFunctionLiteral: + var local = self.scope.lexical + if node.name != "" { + local = self.newDeclarationStash(local) + } + + value := toValue_object(self.newNodeFunction(node, local)) + if node.name != "" { + local.createBinding(node.name, false, value) + } + return value + + case *_nodeIdentifier: + name := node.name + // TODO Should be true or false (strictness) depending on context + // getIdentifierReference should not return nil, but we check anyway and panic + // so as not to propagate the nil into something else + reference := getIdentifierReference(self, self.scope.lexical, name, false, _at(node.idx)) + if reference == nil { + // Should never get here! + panic(hereBeDragons("referenceError == nil: " + name)) + } + return toValue(reference) + + case *_nodeLiteral: + return node.value + + case *_nodeNewExpression: + return self.cmpl_evaluate_nodeNewExpression(node) + + case *_nodeObjectLiteral: + return self.cmpl_evaluate_nodeObjectLiteral(node) + + case *_nodeRegExpLiteral: + return toValue_object(self._newRegExp(node.pattern, node.flags)) + + case *_nodeSequenceExpression: + return self.cmpl_evaluate_nodeSequenceExpression(node) + + case *_nodeThisExpression: + return toValue_object(self.scope.this) + + case *_nodeUnaryExpression: + return self.cmpl_evaluate_nodeUnaryExpression(node) + + case *_nodeVariableExpression: + return self.cmpl_evaluate_nodeVariableExpression(node) + } + + panic(fmt.Errorf("Here be dragons: evaluate_nodeExpression(%T)", node)) +} + +func (self *_runtime) cmpl_evaluate_nodeArrayLiteral(node *_nodeArrayLiteral) Value { + + valueArray := []Value{} + + for _, node := range node.value { + if node == nil { + valueArray = append(valueArray, emptyValue) + } else { + valueArray = append(valueArray, self.cmpl_evaluate_nodeExpression(node).resolve()) + } + } + + result := self.newArrayOf(valueArray) + + return toValue_object(result) +} + +func (self *_runtime) cmpl_evaluate_nodeAssignExpression(node *_nodeAssignExpression) Value { + + left := self.cmpl_evaluate_nodeExpression(node.left) + right := self.cmpl_evaluate_nodeExpression(node.right) + rightValue := right.resolve() + + result := rightValue + if node.operator != token.ASSIGN { + result = self.calculateBinaryExpression(node.operator, left, rightValue) + } + + self.putValue(left.reference(), result) + + return result +} + +func (self *_runtime) cmpl_evaluate_nodeBinaryExpression(node *_nodeBinaryExpression) Value { + + left := self.cmpl_evaluate_nodeExpression(node.left) + leftValue := left.resolve() + + switch node.operator { + // Logical + case token.LOGICAL_AND: + if !leftValue.bool() { + return leftValue + } + right := self.cmpl_evaluate_nodeExpression(node.right) + return right.resolve() + case token.LOGICAL_OR: + if leftValue.bool() { + return leftValue + } + right := self.cmpl_evaluate_nodeExpression(node.right) + return right.resolve() + } + + return self.calculateBinaryExpression(node.operator, leftValue, self.cmpl_evaluate_nodeExpression(node.right)) +} + +func (self *_runtime) cmpl_evaluate_nodeBinaryExpression_comparison(node *_nodeBinaryExpression) Value { + + left := self.cmpl_evaluate_nodeExpression(node.left).resolve() + right := self.cmpl_evaluate_nodeExpression(node.right).resolve() + + return toValue_bool(self.calculateComparison(node.operator, left, right)) +} + +func (self *_runtime) cmpl_evaluate_nodeBracketExpression(node *_nodeBracketExpression) Value { + target := self.cmpl_evaluate_nodeExpression(node.left) + targetValue := target.resolve() + member := self.cmpl_evaluate_nodeExpression(node.member) + memberValue := member.resolve() + + // TODO Pass in base value as-is, and defer toObject till later? + return toValue(newPropertyReference(self, self.toObject(targetValue), memberValue.string(), false, _at(node.idx))) +} + +func (self *_runtime) cmpl_evaluate_nodeCallExpression(node *_nodeCallExpression, withArgumentList []interface{}) Value { + rt := self + this := Value{} + callee := self.cmpl_evaluate_nodeExpression(node.callee) + + argumentList := []Value{} + if withArgumentList != nil { + argumentList = self.toValueArray(withArgumentList...) + } else { + for _, argumentNode := range node.argumentList { + argumentList = append(argumentList, self.cmpl_evaluate_nodeExpression(argumentNode).resolve()) + } + } + + rf := callee.reference() + vl := callee.resolve() + + eval := false // Whether this call is a (candidate for) direct call to eval + name := "" + if rf != nil { + switch rf := rf.(type) { + case *_propertyReference: + name = rf.name + object := rf.base + this = toValue_object(object) + eval = rf.name == "eval" // Possible direct eval + case *_stashReference: + // TODO ImplicitThisValue + name = rf.name + eval = rf.name == "eval" // Possible direct eval + default: + // FIXME? + panic(rt.panicTypeError("Here be dragons")) + } + } + + at := _at(-1) + switch callee := node.callee.(type) { + case *_nodeIdentifier: + at = _at(callee.idx) + case *_nodeDotExpression: + at = _at(callee.idx) + case *_nodeBracketExpression: + at = _at(callee.idx) + } + + frame := _frame{ + callee: name, + file: self.scope.frame.file, + } + + if !vl.IsFunction() { + if name == "" { + // FIXME Maybe typeof? + panic(rt.panicTypeError("%v is not a function", vl, at)) + } + panic(rt.panicTypeError("'%s' is not a function", name, at)) + } + + self.scope.frame.offset = int(at) + + return vl._object().call(this, argumentList, eval, frame) +} + +func (self *_runtime) cmpl_evaluate_nodeConditionalExpression(node *_nodeConditionalExpression) Value { + test := self.cmpl_evaluate_nodeExpression(node.test) + testValue := test.resolve() + if testValue.bool() { + return self.cmpl_evaluate_nodeExpression(node.consequent) + } + return self.cmpl_evaluate_nodeExpression(node.alternate) +} + +func (self *_runtime) cmpl_evaluate_nodeDotExpression(node *_nodeDotExpression) Value { + target := self.cmpl_evaluate_nodeExpression(node.left) + targetValue := target.resolve() + // TODO Pass in base value as-is, and defer toObject till later? + object, err := self.objectCoerce(targetValue) + if err != nil { + panic(self.panicTypeError("Cannot access member '%s' of %s", node.identifier, err.Error())) + } + return toValue(newPropertyReference(self, object, node.identifier, false, _at(node.idx))) +} + +func (self *_runtime) cmpl_evaluate_nodeNewExpression(node *_nodeNewExpression) Value { + rt := self + callee := self.cmpl_evaluate_nodeExpression(node.callee) + + argumentList := []Value{} + for _, argumentNode := range node.argumentList { + argumentList = append(argumentList, self.cmpl_evaluate_nodeExpression(argumentNode).resolve()) + } + + rf := callee.reference() + vl := callee.resolve() + + name := "" + if rf != nil { + switch rf := rf.(type) { + case *_propertyReference: + name = rf.name + case *_stashReference: + name = rf.name + default: + panic(rt.panicTypeError("Here be dragons")) + } + } + + at := _at(-1) + switch callee := node.callee.(type) { + case *_nodeIdentifier: + at = _at(callee.idx) + case *_nodeDotExpression: + at = _at(callee.idx) + case *_nodeBracketExpression: + at = _at(callee.idx) + } + + if !vl.IsFunction() { + if name == "" { + // FIXME Maybe typeof? + panic(rt.panicTypeError("%v is not a function", vl, at)) + } + panic(rt.panicTypeError("'%s' is not a function", name, at)) + } + + self.scope.frame.offset = int(at) + + return vl._object().construct(argumentList) +} + +func (self *_runtime) cmpl_evaluate_nodeObjectLiteral(node *_nodeObjectLiteral) Value { + + result := self.newObject() + + for _, property := range node.value { + switch property.kind { + case "value": + result.defineProperty(property.key, self.cmpl_evaluate_nodeExpression(property.value).resolve(), 0111, false) + case "get": + getter := self.newNodeFunction(property.value.(*_nodeFunctionLiteral), self.scope.lexical) + descriptor := _property{} + descriptor.mode = 0211 + descriptor.value = _propertyGetSet{getter, nil} + result.defineOwnProperty(property.key, descriptor, false) + case "set": + setter := self.newNodeFunction(property.value.(*_nodeFunctionLiteral), self.scope.lexical) + descriptor := _property{} + descriptor.mode = 0211 + descriptor.value = _propertyGetSet{nil, setter} + result.defineOwnProperty(property.key, descriptor, false) + default: + panic(fmt.Errorf("Here be dragons: evaluate_nodeObjectLiteral: invalid property.Kind: %v", property.kind)) + } + } + + return toValue_object(result) +} + +func (self *_runtime) cmpl_evaluate_nodeSequenceExpression(node *_nodeSequenceExpression) Value { + var result Value + for _, node := range node.sequence { + result = self.cmpl_evaluate_nodeExpression(node) + result = result.resolve() + } + return result +} + +func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpression) Value { + + target := self.cmpl_evaluate_nodeExpression(node.operand) + switch node.operator { + case token.TYPEOF, token.DELETE: + if target.kind == valueReference && target.reference().invalid() { + if node.operator == token.TYPEOF { + return toValue_string("undefined") + } + return trueValue + } + } + + switch node.operator { + case token.NOT: + targetValue := target.resolve() + if targetValue.bool() { + return falseValue + } + return trueValue + case token.BITWISE_NOT: + targetValue := target.resolve() + integerValue := toInt32(targetValue) + return toValue_int32(^integerValue) + case token.PLUS: + targetValue := target.resolve() + return toValue_float64(targetValue.float64()) + case token.MINUS: + targetValue := target.resolve() + value := targetValue.float64() + // TODO Test this + sign := float64(-1) + if math.Signbit(value) { + sign = 1 + } + return toValue_float64(math.Copysign(value, sign)) + case token.INCREMENT: + targetValue := target.resolve() + if node.postfix { + // Postfix++ + oldValue := targetValue.float64() + newValue := toValue_float64(+1 + oldValue) + self.putValue(target.reference(), newValue) + return toValue_float64(oldValue) + } else { + // ++Prefix + newValue := toValue_float64(+1 + targetValue.float64()) + self.putValue(target.reference(), newValue) + return newValue + } + case token.DECREMENT: + targetValue := target.resolve() + if node.postfix { + // Postfix-- + oldValue := targetValue.float64() + newValue := toValue_float64(-1 + oldValue) + self.putValue(target.reference(), newValue) + return toValue_float64(oldValue) + } else { + // --Prefix + newValue := toValue_float64(-1 + targetValue.float64()) + self.putValue(target.reference(), newValue) + return newValue + } + case token.VOID: + target.resolve() // FIXME Side effect? + return Value{} + case token.DELETE: + reference := target.reference() + if reference == nil { + return trueValue + } + return toValue_bool(target.reference().delete()) + case token.TYPEOF: + targetValue := target.resolve() + switch targetValue.kind { + case valueUndefined: + return toValue_string("undefined") + case valueNull: + return toValue_string("object") + case valueBoolean: + return toValue_string("boolean") + case valueNumber: + return toValue_string("number") + case valueString: + return toValue_string("string") + case valueObject: + if targetValue._object().isCall() { + return toValue_string("function") + } + return toValue_string("object") + default: + // FIXME ? + } + } + + panic(hereBeDragons()) +} + +func (self *_runtime) cmpl_evaluate_nodeVariableExpression(node *_nodeVariableExpression) Value { + if node.initializer != nil { + // FIXME If reference is nil + left := getIdentifierReference(self, self.scope.lexical, node.name, false, _at(node.idx)) + right := self.cmpl_evaluate_nodeExpression(node.initializer) + rightValue := right.resolve() + + self.putValue(left, rightValue) + } + return toValue_string(node.name) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go new file mode 100644 index 0000000000..7be1584870 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go @@ -0,0 +1,421 @@ +package otto + +import ( + "fmt" + "runtime" + + "github.com/robertkrimen/otto/token" +) + +func (self *_runtime) cmpl_evaluate_nodeStatement(node _nodeStatement) Value { + // Allow interpreter interruption + // If the Interrupt channel is nil, then + // we avoid runtime.Gosched() overhead (if any) + // FIXME: Test this + if self.otto.Interrupt != nil { + runtime.Gosched() + select { + case value := <-self.otto.Interrupt: + value() + default: + } + } + + switch node := node.(type) { + + case *_nodeBlockStatement: + labels := self.labels + self.labels = nil + + value := self.cmpl_evaluate_nodeStatementList(node.list) + switch value.kind { + case valueResult: + switch value.evaluateBreak(labels) { + case resultBreak: + return emptyValue + } + } + return value + + case *_nodeBranchStatement: + target := node.label + switch node.branch { // FIXME Maybe node.kind? node.operator? + case token.BREAK: + return toValue(newBreakResult(target)) + case token.CONTINUE: + return toValue(newContinueResult(target)) + } + + case *_nodeDebuggerStatement: + return emptyValue // Nothing happens. + + case *_nodeDoWhileStatement: + return self.cmpl_evaluate_nodeDoWhileStatement(node) + + case *_nodeEmptyStatement: + return emptyValue + + case *_nodeExpressionStatement: + return self.cmpl_evaluate_nodeExpression(node.expression) + + case *_nodeForInStatement: + return self.cmpl_evaluate_nodeForInStatement(node) + + case *_nodeForStatement: + return self.cmpl_evaluate_nodeForStatement(node) + + case *_nodeIfStatement: + return self.cmpl_evaluate_nodeIfStatement(node) + + case *_nodeLabelledStatement: + self.labels = append(self.labels, node.label) + defer func() { + if len(self.labels) > 0 { + self.labels = self.labels[:len(self.labels)-1] // Pop the label + } else { + self.labels = nil + } + }() + return self.cmpl_evaluate_nodeStatement(node.statement) + + case *_nodeReturnStatement: + if node.argument != nil { + return toValue(newReturnResult(self.cmpl_evaluate_nodeExpression(node.argument).resolve())) + } + return toValue(newReturnResult(Value{})) + + case *_nodeSwitchStatement: + return self.cmpl_evaluate_nodeSwitchStatement(node) + + case *_nodeThrowStatement: + value := self.cmpl_evaluate_nodeExpression(node.argument).resolve() + panic(newException(value)) + + case *_nodeTryStatement: + return self.cmpl_evaluate_nodeTryStatement(node) + + case *_nodeVariableStatement: + // Variables are already defined, this is initialization only + for _, variable := range node.list { + self.cmpl_evaluate_nodeVariableExpression(variable.(*_nodeVariableExpression)) + } + return emptyValue + + case *_nodeWhileStatement: + return self.cmpl_evaluate_nodeWhileStatement(node) + + case *_nodeWithStatement: + return self.cmpl_evaluate_nodeWithStatement(node) + + } + + panic(fmt.Errorf("Here be dragons: evaluate_nodeStatement(%T)", node)) +} + +func (self *_runtime) cmpl_evaluate_nodeStatementList(list []_nodeStatement) Value { + var result Value + for _, node := range list { + value := self.cmpl_evaluate_nodeStatement(node) + switch value.kind { + case valueResult: + return value + case valueEmpty: + default: + // We have getValue here to (for example) trigger a + // ReferenceError (of the not defined variety) + // Not sure if this is the best way to error out early + // for such errors or if there is a better way + // TODO Do we still need this? + result = value.resolve() + } + } + return result +} + +func (self *_runtime) cmpl_evaluate_nodeDoWhileStatement(node *_nodeDoWhileStatement) Value { + + labels := append(self.labels, "") + self.labels = nil + + test := node.test + + result := emptyValue +resultBreak: + for { + for _, node := range node.body { + value := self.cmpl_evaluate_nodeStatement(node) + switch value.kind { + case valueResult: + switch value.evaluateBreakContinue(labels) { + case resultReturn: + return value + case resultBreak: + break resultBreak + case resultContinue: + goto resultContinue + } + case valueEmpty: + default: + result = value + } + } + resultContinue: + if !self.cmpl_evaluate_nodeExpression(test).resolve().bool() { + // Stahp: do ... while (false) + break + } + } + return result +} + +func (self *_runtime) cmpl_evaluate_nodeForInStatement(node *_nodeForInStatement) Value { + + labels := append(self.labels, "") + self.labels = nil + + source := self.cmpl_evaluate_nodeExpression(node.source) + sourceValue := source.resolve() + + switch sourceValue.kind { + case valueUndefined, valueNull: + return emptyValue + } + + sourceObject := self.toObject(sourceValue) + + into := node.into + body := node.body + + result := emptyValue + object := sourceObject + for object != nil { + enumerateValue := emptyValue + object.enumerate(false, func(name string) bool { + into := self.cmpl_evaluate_nodeExpression(into) + // In the case of: for (var abc in def) ... + if into.reference() == nil { + identifier := into.string() + // TODO Should be true or false (strictness) depending on context + into = toValue(getIdentifierReference(self, self.scope.lexical, identifier, false, -1)) + } + self.putValue(into.reference(), toValue_string(name)) + for _, node := range body { + value := self.cmpl_evaluate_nodeStatement(node) + switch value.kind { + case valueResult: + switch value.evaluateBreakContinue(labels) { + case resultReturn: + enumerateValue = value + return false + case resultBreak: + object = nil + return false + case resultContinue: + return true + } + case valueEmpty: + default: + enumerateValue = value + } + } + return true + }) + if object == nil { + break + } + object = object.prototype + if !enumerateValue.isEmpty() { + result = enumerateValue + } + } + return result +} + +func (self *_runtime) cmpl_evaluate_nodeForStatement(node *_nodeForStatement) Value { + + labels := append(self.labels, "") + self.labels = nil + + initializer := node.initializer + test := node.test + update := node.update + body := node.body + + if initializer != nil { + initialResult := self.cmpl_evaluate_nodeExpression(initializer) + initialResult.resolve() // Side-effect trigger + } + + result := emptyValue +resultBreak: + for { + if test != nil { + testResult := self.cmpl_evaluate_nodeExpression(test) + testResultValue := testResult.resolve() + if testResultValue.bool() == false { + break + } + } + for _, node := range body { + value := self.cmpl_evaluate_nodeStatement(node) + switch value.kind { + case valueResult: + switch value.evaluateBreakContinue(labels) { + case resultReturn: + return value + case resultBreak: + break resultBreak + case resultContinue: + goto resultContinue + } + case valueEmpty: + default: + result = value + } + } + resultContinue: + if update != nil { + updateResult := self.cmpl_evaluate_nodeExpression(update) + updateResult.resolve() // Side-effect trigger + } + } + return result +} + +func (self *_runtime) cmpl_evaluate_nodeIfStatement(node *_nodeIfStatement) Value { + test := self.cmpl_evaluate_nodeExpression(node.test) + testValue := test.resolve() + if testValue.bool() { + return self.cmpl_evaluate_nodeStatement(node.consequent) + } else if node.alternate != nil { + return self.cmpl_evaluate_nodeStatement(node.alternate) + } + + return emptyValue +} + +func (self *_runtime) cmpl_evaluate_nodeSwitchStatement(node *_nodeSwitchStatement) Value { + + labels := append(self.labels, "") + self.labels = nil + + discriminantResult := self.cmpl_evaluate_nodeExpression(node.discriminant) + target := node.default_ + + for index, clause := range node.body { + test := clause.test + if test != nil { + if self.calculateComparison(token.STRICT_EQUAL, discriminantResult, self.cmpl_evaluate_nodeExpression(test)) { + target = index + break + } + } + } + + result := emptyValue + if target != -1 { + for _, clause := range node.body[target:] { + for _, statement := range clause.consequent { + value := self.cmpl_evaluate_nodeStatement(statement) + switch value.kind { + case valueResult: + switch value.evaluateBreak(labels) { + case resultReturn: + return value + case resultBreak: + return emptyValue + } + case valueEmpty: + default: + result = value + } + } + } + } + + return result +} + +func (self *_runtime) cmpl_evaluate_nodeTryStatement(node *_nodeTryStatement) Value { + tryCatchValue, exception := self.tryCatchEvaluate(func() Value { + return self.cmpl_evaluate_nodeStatement(node.body) + }) + + if exception && node.catch != nil { + outer := self.scope.lexical + self.scope.lexical = self.newDeclarationStash(outer) + defer func() { + self.scope.lexical = outer + }() + // TODO If necessary, convert TypeError => TypeError + // That, is, such errors can be thrown despite not being JavaScript "native" + // strict = false + self.scope.lexical.setValue(node.catch.parameter, tryCatchValue, false) + + // FIXME node.CatchParameter + // FIXME node.Catch + tryCatchValue, exception = self.tryCatchEvaluate(func() Value { + return self.cmpl_evaluate_nodeStatement(node.catch.body) + }) + } + + if node.finally != nil { + finallyValue := self.cmpl_evaluate_nodeStatement(node.finally) + if finallyValue.kind == valueResult { + return finallyValue + } + } + + if exception { + panic(newException(tryCatchValue)) + } + + return tryCatchValue +} + +func (self *_runtime) cmpl_evaluate_nodeWhileStatement(node *_nodeWhileStatement) Value { + + test := node.test + body := node.body + labels := append(self.labels, "") + self.labels = nil + + result := emptyValue +resultBreakContinue: + for { + if !self.cmpl_evaluate_nodeExpression(test).resolve().bool() { + // Stahp: while (false) ... + break + } + for _, node := range body { + value := self.cmpl_evaluate_nodeStatement(node) + switch value.kind { + case valueResult: + switch value.evaluateBreakContinue(labels) { + case resultReturn: + return value + case resultBreak: + break resultBreakContinue + case resultContinue: + continue resultBreakContinue + } + case valueEmpty: + default: + result = value + } + } + } + return result +} + +func (self *_runtime) cmpl_evaluate_nodeWithStatement(node *_nodeWithStatement) Value { + object := self.cmpl_evaluate_nodeExpression(node.object) + outer := self.scope.lexical + lexical := self.newObjectStash(self.toObject(object.resolve()), outer) + self.scope.lexical = lexical + defer func() { + self.scope.lexical = outer + }() + + return self.cmpl_evaluate_nodeStatement(node.body) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_parse.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_parse.go new file mode 100644 index 0000000000..e758a52301 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_parse.go @@ -0,0 +1,650 @@ +package otto + +import ( + "fmt" + "regexp" + + "github.com/robertkrimen/otto/ast" + "github.com/robertkrimen/otto/file" + "github.com/robertkrimen/otto/token" +) + +var trueLiteral = &_nodeLiteral{value: toValue_bool(true)} +var falseLiteral = &_nodeLiteral{value: toValue_bool(false)} +var nullLiteral = &_nodeLiteral{value: nullValue} +var emptyStatement = &_nodeEmptyStatement{} + +func (cmpl *_compiler) parseExpression(in ast.Expression) _nodeExpression { + if in == nil { + return nil + } + + switch in := in.(type) { + + case *ast.ArrayLiteral: + out := &_nodeArrayLiteral{ + value: make([]_nodeExpression, len(in.Value)), + } + for i, value := range in.Value { + out.value[i] = cmpl.parseExpression(value) + } + return out + + case *ast.AssignExpression: + return &_nodeAssignExpression{ + operator: in.Operator, + left: cmpl.parseExpression(in.Left), + right: cmpl.parseExpression(in.Right), + } + + case *ast.BinaryExpression: + return &_nodeBinaryExpression{ + operator: in.Operator, + left: cmpl.parseExpression(in.Left), + right: cmpl.parseExpression(in.Right), + comparison: in.Comparison, + } + + case *ast.BooleanLiteral: + if in.Value { + return trueLiteral + } + return falseLiteral + + case *ast.BracketExpression: + return &_nodeBracketExpression{ + idx: in.Left.Idx0(), + left: cmpl.parseExpression(in.Left), + member: cmpl.parseExpression(in.Member), + } + + case *ast.CallExpression: + out := &_nodeCallExpression{ + callee: cmpl.parseExpression(in.Callee), + argumentList: make([]_nodeExpression, len(in.ArgumentList)), + } + for i, value := range in.ArgumentList { + out.argumentList[i] = cmpl.parseExpression(value) + } + return out + + case *ast.ConditionalExpression: + return &_nodeConditionalExpression{ + test: cmpl.parseExpression(in.Test), + consequent: cmpl.parseExpression(in.Consequent), + alternate: cmpl.parseExpression(in.Alternate), + } + + case *ast.DotExpression: + return &_nodeDotExpression{ + idx: in.Left.Idx0(), + left: cmpl.parseExpression(in.Left), + identifier: in.Identifier.Name, + } + + case *ast.FunctionLiteral: + name := "" + if in.Name != nil { + name = in.Name.Name + } + out := &_nodeFunctionLiteral{ + name: name, + body: cmpl.parseStatement(in.Body), + source: in.Source, + file: cmpl.file, + } + if in.ParameterList != nil { + list := in.ParameterList.List + out.parameterList = make([]string, len(list)) + for i, value := range list { + out.parameterList[i] = value.Name + } + } + for _, value := range in.DeclarationList { + switch value := value.(type) { + case *ast.FunctionDeclaration: + out.functionList = append(out.functionList, cmpl.parseExpression(value.Function).(*_nodeFunctionLiteral)) + case *ast.VariableDeclaration: + for _, value := range value.List { + out.varList = append(out.varList, value.Name) + } + default: + panic(fmt.Errorf("Here be dragons: parseProgram.declaration(%T)", value)) + } + } + return out + + case *ast.Identifier: + return &_nodeIdentifier{ + idx: in.Idx, + name: in.Name, + } + + case *ast.NewExpression: + out := &_nodeNewExpression{ + callee: cmpl.parseExpression(in.Callee), + argumentList: make([]_nodeExpression, len(in.ArgumentList)), + } + for i, value := range in.ArgumentList { + out.argumentList[i] = cmpl.parseExpression(value) + } + return out + + case *ast.NullLiteral: + return nullLiteral + + case *ast.NumberLiteral: + return &_nodeLiteral{ + value: toValue(in.Value), + } + + case *ast.ObjectLiteral: + out := &_nodeObjectLiteral{ + value: make([]_nodeProperty, len(in.Value)), + } + for i, value := range in.Value { + out.value[i] = _nodeProperty{ + key: value.Key, + kind: value.Kind, + value: cmpl.parseExpression(value.Value), + } + } + return out + + case *ast.RegExpLiteral: + return &_nodeRegExpLiteral{ + flags: in.Flags, + pattern: in.Pattern, + } + + case *ast.SequenceExpression: + out := &_nodeSequenceExpression{ + sequence: make([]_nodeExpression, len(in.Sequence)), + } + for i, value := range in.Sequence { + out.sequence[i] = cmpl.parseExpression(value) + } + return out + + case *ast.StringLiteral: + return &_nodeLiteral{ + value: toValue_string(in.Value), + } + + case *ast.ThisExpression: + return &_nodeThisExpression{} + + case *ast.UnaryExpression: + return &_nodeUnaryExpression{ + operator: in.Operator, + operand: cmpl.parseExpression(in.Operand), + postfix: in.Postfix, + } + + case *ast.VariableExpression: + return &_nodeVariableExpression{ + idx: in.Idx0(), + name: in.Name, + initializer: cmpl.parseExpression(in.Initializer), + } + + } + + panic(fmt.Errorf("Here be dragons: cmpl.parseExpression(%T)", in)) +} + +func (cmpl *_compiler) parseStatement(in ast.Statement) _nodeStatement { + if in == nil { + return nil + } + + switch in := in.(type) { + + case *ast.BlockStatement: + out := &_nodeBlockStatement{ + list: make([]_nodeStatement, len(in.List)), + } + for i, value := range in.List { + out.list[i] = cmpl.parseStatement(value) + } + return out + + case *ast.BranchStatement: + out := &_nodeBranchStatement{ + branch: in.Token, + } + if in.Label != nil { + out.label = in.Label.Name + } + return out + + case *ast.DebuggerStatement: + return &_nodeDebuggerStatement{} + + case *ast.DoWhileStatement: + out := &_nodeDoWhileStatement{ + test: cmpl.parseExpression(in.Test), + } + body := cmpl.parseStatement(in.Body) + if block, ok := body.(*_nodeBlockStatement); ok { + out.body = block.list + } else { + out.body = append(out.body, body) + } + return out + + case *ast.EmptyStatement: + return emptyStatement + + case *ast.ExpressionStatement: + return &_nodeExpressionStatement{ + expression: cmpl.parseExpression(in.Expression), + } + + case *ast.ForInStatement: + out := &_nodeForInStatement{ + into: cmpl.parseExpression(in.Into), + source: cmpl.parseExpression(in.Source), + } + body := cmpl.parseStatement(in.Body) + if block, ok := body.(*_nodeBlockStatement); ok { + out.body = block.list + } else { + out.body = append(out.body, body) + } + return out + + case *ast.ForStatement: + out := &_nodeForStatement{ + initializer: cmpl.parseExpression(in.Initializer), + update: cmpl.parseExpression(in.Update), + test: cmpl.parseExpression(in.Test), + } + body := cmpl.parseStatement(in.Body) + if block, ok := body.(*_nodeBlockStatement); ok { + out.body = block.list + } else { + out.body = append(out.body, body) + } + return out + + case *ast.IfStatement: + return &_nodeIfStatement{ + test: cmpl.parseExpression(in.Test), + consequent: cmpl.parseStatement(in.Consequent), + alternate: cmpl.parseStatement(in.Alternate), + } + + case *ast.LabelledStatement: + return &_nodeLabelledStatement{ + label: in.Label.Name, + statement: cmpl.parseStatement(in.Statement), + } + + case *ast.ReturnStatement: + return &_nodeReturnStatement{ + argument: cmpl.parseExpression(in.Argument), + } + + case *ast.SwitchStatement: + out := &_nodeSwitchStatement{ + discriminant: cmpl.parseExpression(in.Discriminant), + default_: in.Default, + body: make([]*_nodeCaseStatement, len(in.Body)), + } + for i, clause := range in.Body { + out.body[i] = &_nodeCaseStatement{ + test: cmpl.parseExpression(clause.Test), + consequent: make([]_nodeStatement, len(clause.Consequent)), + } + for j, value := range clause.Consequent { + out.body[i].consequent[j] = cmpl.parseStatement(value) + } + } + return out + + case *ast.ThrowStatement: + return &_nodeThrowStatement{ + argument: cmpl.parseExpression(in.Argument), + } + + case *ast.TryStatement: + out := &_nodeTryStatement{ + body: cmpl.parseStatement(in.Body), + finally: cmpl.parseStatement(in.Finally), + } + if in.Catch != nil { + out.catch = &_nodeCatchStatement{ + parameter: in.Catch.Parameter.Name, + body: cmpl.parseStatement(in.Catch.Body), + } + } + return out + + case *ast.VariableStatement: + out := &_nodeVariableStatement{ + list: make([]_nodeExpression, len(in.List)), + } + for i, value := range in.List { + out.list[i] = cmpl.parseExpression(value) + } + return out + + case *ast.WhileStatement: + out := &_nodeWhileStatement{ + test: cmpl.parseExpression(in.Test), + } + body := cmpl.parseStatement(in.Body) + if block, ok := body.(*_nodeBlockStatement); ok { + out.body = block.list + } else { + out.body = append(out.body, body) + } + return out + + case *ast.WithStatement: + return &_nodeWithStatement{ + object: cmpl.parseExpression(in.Object), + body: cmpl.parseStatement(in.Body), + } + + } + + panic(fmt.Errorf("Here be dragons: cmpl.parseStatement(%T)", in)) +} + +func cmpl_parse(in *ast.Program) *_nodeProgram { + cmpl := _compiler{ + program: in, + } + return cmpl.parse() +} + +func (cmpl *_compiler) _parse(in *ast.Program) *_nodeProgram { + out := &_nodeProgram{ + body: make([]_nodeStatement, len(in.Body)), + file: in.File, + } + for i, value := range in.Body { + out.body[i] = cmpl.parseStatement(value) + } + for _, value := range in.DeclarationList { + switch value := value.(type) { + case *ast.FunctionDeclaration: + out.functionList = append(out.functionList, cmpl.parseExpression(value.Function).(*_nodeFunctionLiteral)) + case *ast.VariableDeclaration: + for _, value := range value.List { + out.varList = append(out.varList, value.Name) + } + default: + panic(fmt.Errorf("Here be dragons: cmpl.parseProgram.DeclarationList(%T)", value)) + } + } + return out +} + +type _nodeProgram struct { + body []_nodeStatement + + varList []string + functionList []*_nodeFunctionLiteral + + variableList []_nodeDeclaration + + file *file.File +} + +type _nodeDeclaration struct { + name string + definition _node +} + +type _node interface { +} + +type ( + _nodeExpression interface { + _node + _expressionNode() + } + + _nodeArrayLiteral struct { + value []_nodeExpression + } + + _nodeAssignExpression struct { + operator token.Token + left _nodeExpression + right _nodeExpression + } + + _nodeBinaryExpression struct { + operator token.Token + left _nodeExpression + right _nodeExpression + comparison bool + } + + _nodeBracketExpression struct { + idx file.Idx + left _nodeExpression + member _nodeExpression + } + + _nodeCallExpression struct { + callee _nodeExpression + argumentList []_nodeExpression + } + + _nodeConditionalExpression struct { + test _nodeExpression + consequent _nodeExpression + alternate _nodeExpression + } + + _nodeDotExpression struct { + idx file.Idx + left _nodeExpression + identifier string + } + + _nodeFunctionLiteral struct { + name string + body _nodeStatement + source string + parameterList []string + varList []string + functionList []*_nodeFunctionLiteral + file *file.File + } + + _nodeIdentifier struct { + idx file.Idx + name string + } + + _nodeLiteral struct { + value Value + } + + _nodeNewExpression struct { + callee _nodeExpression + argumentList []_nodeExpression + } + + _nodeObjectLiteral struct { + value []_nodeProperty + } + + _nodeProperty struct { + key string + kind string + value _nodeExpression + } + + _nodeRegExpLiteral struct { + flags string + pattern string // Value? + regexp *regexp.Regexp + } + + _nodeSequenceExpression struct { + sequence []_nodeExpression + } + + _nodeThisExpression struct { + } + + _nodeUnaryExpression struct { + operator token.Token + operand _nodeExpression + postfix bool + } + + _nodeVariableExpression struct { + idx file.Idx + name string + initializer _nodeExpression + } +) + +type ( + _nodeStatement interface { + _node + _statementNode() + } + + _nodeBlockStatement struct { + list []_nodeStatement + } + + _nodeBranchStatement struct { + branch token.Token + label string + } + + _nodeCaseStatement struct { + test _nodeExpression + consequent []_nodeStatement + } + + _nodeCatchStatement struct { + parameter string + body _nodeStatement + } + + _nodeDebuggerStatement struct { + } + + _nodeDoWhileStatement struct { + test _nodeExpression + body []_nodeStatement + } + + _nodeEmptyStatement struct { + } + + _nodeExpressionStatement struct { + expression _nodeExpression + } + + _nodeForInStatement struct { + into _nodeExpression + source _nodeExpression + body []_nodeStatement + } + + _nodeForStatement struct { + initializer _nodeExpression + update _nodeExpression + test _nodeExpression + body []_nodeStatement + } + + _nodeIfStatement struct { + test _nodeExpression + consequent _nodeStatement + alternate _nodeStatement + } + + _nodeLabelledStatement struct { + label string + statement _nodeStatement + } + + _nodeReturnStatement struct { + argument _nodeExpression + } + + _nodeSwitchStatement struct { + discriminant _nodeExpression + default_ int + body []*_nodeCaseStatement + } + + _nodeThrowStatement struct { + argument _nodeExpression + } + + _nodeTryStatement struct { + body _nodeStatement + catch *_nodeCatchStatement + finally _nodeStatement + } + + _nodeVariableStatement struct { + list []_nodeExpression + } + + _nodeWhileStatement struct { + test _nodeExpression + body []_nodeStatement + } + + _nodeWithStatement struct { + object _nodeExpression + body _nodeStatement + } +) + +// _expressionNode + +func (*_nodeArrayLiteral) _expressionNode() {} +func (*_nodeAssignExpression) _expressionNode() {} +func (*_nodeBinaryExpression) _expressionNode() {} +func (*_nodeBracketExpression) _expressionNode() {} +func (*_nodeCallExpression) _expressionNode() {} +func (*_nodeConditionalExpression) _expressionNode() {} +func (*_nodeDotExpression) _expressionNode() {} +func (*_nodeFunctionLiteral) _expressionNode() {} +func (*_nodeIdentifier) _expressionNode() {} +func (*_nodeLiteral) _expressionNode() {} +func (*_nodeNewExpression) _expressionNode() {} +func (*_nodeObjectLiteral) _expressionNode() {} +func (*_nodeRegExpLiteral) _expressionNode() {} +func (*_nodeSequenceExpression) _expressionNode() {} +func (*_nodeThisExpression) _expressionNode() {} +func (*_nodeUnaryExpression) _expressionNode() {} +func (*_nodeVariableExpression) _expressionNode() {} + +// _statementNode + +func (*_nodeBlockStatement) _statementNode() {} +func (*_nodeBranchStatement) _statementNode() {} +func (*_nodeCaseStatement) _statementNode() {} +func (*_nodeCatchStatement) _statementNode() {} +func (*_nodeDebuggerStatement) _statementNode() {} +func (*_nodeDoWhileStatement) _statementNode() {} +func (*_nodeEmptyStatement) _statementNode() {} +func (*_nodeExpressionStatement) _statementNode() {} +func (*_nodeForInStatement) _statementNode() {} +func (*_nodeForStatement) _statementNode() {} +func (*_nodeIfStatement) _statementNode() {} +func (*_nodeLabelledStatement) _statementNode() {} +func (*_nodeReturnStatement) _statementNode() {} +func (*_nodeSwitchStatement) _statementNode() {} +func (*_nodeThrowStatement) _statementNode() {} +func (*_nodeTryStatement) _statementNode() {} +func (*_nodeVariableStatement) _statementNode() {} +func (*_nodeWhileStatement) _statementNode() {} +func (*_nodeWithStatement) _statementNode() {} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_test.go new file mode 100644 index 0000000000..34b050f003 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_test.go @@ -0,0 +1,54 @@ +package otto + +import ( + "testing" + + "github.com/robertkrimen/otto/parser" +) + +func Test_cmpl(t *testing.T) { + tt(t, func() { + vm := New() + + test := func(src string, expect ...interface{}) { + program, err := parser.ParseFile(nil, "", src, 0) + is(err, nil) + { + program := cmpl_parse(program) + value := vm.runtime.cmpl_evaluate_nodeProgram(program, false) + if len(expect) > 0 { + is(value, expect[0]) + } + } + } + + test(``, Value{}) + + test(`var abc = 1; abc;`, 1) + + test(`var abc = 1 + 1; abc;`, 2) + + test(`1 + 2;`, 3) + }) +} + +func TestParse_cmpl(t *testing.T) { + tt(t, func() { + + test := func(src string) { + program, err := parser.ParseFile(nil, "", src, 0) + is(err, nil) + is(cmpl_parse(program), "!=", nil) + } + + test(``) + + test(`var abc = 1; abc;`) + + test(` + function abc() { + return; + } + `) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/console.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/console.go new file mode 100644 index 0000000000..948face775 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/console.go @@ -0,0 +1,51 @@ +package otto + +import ( + "fmt" + "os" + "strings" +) + +func formatForConsole(argumentList []Value) string { + output := []string{} + for _, argument := range argumentList { + output = append(output, fmt.Sprintf("%v", argument)) + } + return strings.Join(output, " ") +} + +func builtinConsole_log(call FunctionCall) Value { + fmt.Fprintln(os.Stdout, formatForConsole(call.ArgumentList)) + return Value{} +} + +func builtinConsole_error(call FunctionCall) Value { + fmt.Fprintln(os.Stdout, formatForConsole(call.ArgumentList)) + return Value{} +} + +// Nothing happens. +func builtinConsole_dir(call FunctionCall) Value { + return Value{} +} + +func builtinConsole_time(call FunctionCall) Value { + return Value{} +} + +func builtinConsole_timeEnd(call FunctionCall) Value { + return Value{} +} + +func builtinConsole_trace(call FunctionCall) Value { + return Value{} +} + +func builtinConsole_assert(call FunctionCall) Value { + return Value{} +} + +func (runtime *_runtime) newConsole() *_object { + + return newConsoleObject(runtime) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/date_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/date_test.go new file mode 100644 index 0000000000..a9c71edde4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/date_test.go @@ -0,0 +1,481 @@ +package otto + +import ( + "math" + "testing" + "time" +) + +func mockTimeLocal(location *time.Location) func() { + local := time.Local + time.Local = location + return func() { + time.Local = local + } +} + +// Passing or failing should not be dependent on what time zone we're in +func mockUTC() func() { + return mockTimeLocal(time.UTC) +} + +func TestDate(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + time0 := time.Unix(1348616313, 47*1000*1000).Local() + + test(`Date`, "function Date() { [native code] }") + test(`new Date(0).toUTCString()`, "Thu, 01 Jan 1970 00:00:00 UTC") + test(`new Date(0).toGMTString()`, "Thu, 01 Jan 1970 00:00:00 GMT") + if false { + // TODO toLocale{Date,Time}String + test(`new Date(0).toLocaleString()`, "") + test(`new Date(0).toLocaleDateString()`, "") + test(`new Date(0).toLocaleTimeString()`, "") + } + test(`new Date(1348616313).getTime()`, 1348616313) + test(`new Date(1348616313).toUTCString()`, "Fri, 16 Jan 1970 14:36:56 UTC") + test(`abc = new Date(1348616313047); abc.toUTCString()`, "Tue, 25 Sep 2012 23:38:33 UTC") + test(`abc.getYear()`, time0.Year()-1900) + test(`abc.getFullYear()`, time0.Year()) + test(`abc.getUTCFullYear()`, 2012) + test(`abc.getMonth()`, int(time0.Month())-1) // Remember, the JavaScript month is 0-based + test(`abc.getUTCMonth()`, 8) + test(`abc.getDate()`, time0.Day()) + test(`abc.getUTCDate()`, 25) + test(`abc.getDay()`, int(time0.Weekday())) + test(`abc.getUTCDay()`, 2) + test(`abc.getHours()`, time0.Hour()) + test(`abc.getUTCHours()`, 23) + test(`abc.getMinutes()`, time0.Minute()) + test(`abc.getUTCMinutes()`, 38) + test(`abc.getSeconds()`, time0.Second()) + test(`abc.getUTCSeconds()`, 33) + test(`abc.getMilliseconds()`, time0.Nanosecond()/(1000*1000)) // In honor of the 47% + test(`abc.getUTCMilliseconds()`, 47) + _, offset := time0.Zone() + test(`abc.getTimezoneOffset()`, offset/-60) + + test(`new Date("Xyzzy").getTime()`, math.NaN()) + + test(`abc.setFullYear(2011); abc.toUTCString()`, "Sun, 25 Sep 2011 23:38:33 UTC") + test(`new Date(12564504e5).toUTCString()`, "Sun, 25 Oct 2009 06:00:00 UTC") + test(`new Date(2009, 9, 25).toUTCString()`, "Sun, 25 Oct 2009 00:00:00 UTC") + test(`+(new Date(2009, 9, 25))`, 1256428800000) + + format := "Mon, 2 Jan 2006 15:04:05 MST" + + time1 := time.Unix(1256450400, 0) + time0 = time.Date(time1.Year(), time1.Month(), time1.Day(), time1.Hour(), time1.Minute(), time1.Second(), time1.Nanosecond(), time1.Location()).UTC() + + time0 = time.Date(time1.Year(), time1.Month(), time1.Day(), time1.Hour(), time1.Minute(), time1.Second(), 2001*1000*1000, time1.Location()).UTC() + test(`abc = new Date(12564504e5); abc.setMilliseconds(2001); abc.toUTCString()`, time0.Format(format)) + + time0 = time.Date(time1.Year(), time1.Month(), time1.Day(), time1.Hour(), time1.Minute(), 61, time1.Nanosecond(), time1.Location()).UTC() + test(`abc = new Date(12564504e5); abc.setSeconds("61"); abc.toUTCString()`, time0.Format(format)) + + time0 = time.Date(time1.Year(), time1.Month(), time1.Day(), time1.Hour(), 61, time1.Second(), time1.Nanosecond(), time1.Location()).UTC() + test(`abc = new Date(12564504e5); abc.setMinutes("61"); abc.toUTCString()`, time0.Format(format)) + + time0 = time.Date(time1.Year(), time1.Month(), time1.Day(), 5, time1.Minute(), time1.Second(), time1.Nanosecond(), time1.Location()).UTC() + test(`abc = new Date(12564504e5); abc.setHours("5"); abc.toUTCString()`, time0.Format(format)) + + time0 = time.Date(time1.Year(), time1.Month(), 26, time1.Hour(), time1.Minute(), time1.Second(), time1.Nanosecond(), time1.Location()).UTC() + test(`abc = new Date(12564504e5); abc.setDate("26"); abc.toUTCString()`, time0.Format(format)) + + time0 = time.Date(time1.Year(), 10, time1.Day(), time1.Hour(), time1.Minute(), time1.Second(), time1.Nanosecond(), time1.Location()).UTC() + test(`abc = new Date(12564504e5); abc.setMonth(9); abc.toUTCString()`, time0.Format(format)) + test(`abc = new Date(12564504e5); abc.setMonth("09"); abc.toUTCString()`, time0.Format(format)) + + time0 = time.Date(time1.Year(), 11, time1.Day(), time1.Hour(), time1.Minute(), time1.Second(), time1.Nanosecond(), time1.Location()).UTC() + test(`abc = new Date(12564504e5); abc.setMonth("10"); abc.toUTCString()`, time0.Format(format)) + + time0 = time.Date(2010, time1.Month(), time1.Day(), time1.Hour(), time1.Minute(), time1.Second(), time1.Nanosecond(), time1.Location()).UTC() + test(`abc = new Date(12564504e5); abc.setFullYear(2010); abc.toUTCString()`, time0.Format(format)) + + test(`new Date("2001-01-01T10:01:02.000").getTime()`, 978343262000) + + // Date() + test(`typeof Date()`, "string") + test(`typeof Date(2006, 1, 2)`, "string") + + test(` + abc = Object.getOwnPropertyDescriptor(Date, "parse"); + [ abc.value === Date.parse, abc.writable, abc.enumerable, abc.configurable ]; + `, "true,true,false,true") + + test(` + abc = Object.getOwnPropertyDescriptor(Date.prototype, "toTimeString"); + [ abc.value === Date.prototype.toTimeString, abc.writable, abc.enumerable, abc.configurable ]; + `, "true,true,false,true") + + test(` + var abc = Object.getOwnPropertyDescriptor(Date, "prototype"); + [ [ typeof Date.prototype ], + [ abc.writable, abc.enumerable, abc.configurable ] ]; + `, "object,false,false,false") + }) +} + +func TestDate_parse(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(`Date.parse("2001-01-01T10:01:02.000")`, 978343262000) + + test(`Date.parse("2006-01-02T15:04:05.000")`, 1136214245000) + + test(`Date.parse("2006")`, 1136073600000) + + test(`Date.parse("1970-01-16T14:36:56+00:00")`, 1348616000) + + test(`Date.parse("1970-01-16T14:36:56.313+00:00")`, 1348616313) + + test(`Date.parse("1970-01-16T14:36:56.000")`, 1348616000) + + test(`Date.parse.length`, 1) + }) +} + +func TestDate_UTC(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(`Date.UTC(2009, 9, 25)`, 1256428800000) + + test(`Date.UTC.length`, 7) + }) +} + +func TestDate_now(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + // FIXME I think this too risky + test(`+(""+Date.now()).substr(0, 10)`, float64(epochToInteger(timeToEpoch(time.Now()))/1000)) + + test(`Date.now() - Date.now(1,2,3) < 24 * 60 * 60`, true) + }) +} + +func TestDate_toISOString(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(`new Date(0).toISOString()`, "1970-01-01T00:00:00.000Z") + }) +} + +func TestDate_toJSON(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(`new Date(0).toJSON()`, "1970-01-01T00:00:00.000Z") + }) +} + +func TestDate_setYear(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(`new Date(12564504e5).setYear(96)`, 846223200000) + + test(`new Date(12564504e5).setYear(1996)`, 846223200000) + + test(`new Date(12564504e5).setYear(2000)`, 972453600000) + }) +} + +func TestDateDefaultValue(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + var date = new Date(); + date + 0 === date.toString() + "0"; + `, true) + }) +} + +func TestDate_April1978(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + var abc = new Date(1978,3); + [ abc.getYear(), abc.getMonth(), abc.valueOf() ]; + `, "78,3,260236800000") + }) +} + +func TestDate_setMilliseconds(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + abc = new Date(); + def = abc.setMilliseconds(); + [ abc, def ]; + `, "Invalid Date,NaN") + }) +} + +func TestDate_new(t *testing.T) { + // FIXME? + // This is probably incorrect, due to differences in Go date/time handling + // versus ECMA date/time handling, but we'll leave this here for + // future reference + + if true { + return + } + + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + [ + new Date(1899, 11).valueOf(), + new Date(1899, 12).valueOf(), + new Date(1900, 0).valueOf() + ] + `, "-2211638400000,-2208960000000,-2208960000000") + }) +} + +func TestDateComparison(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + var now0 = Date.now(); + var now1 = (new Date()).toString(); + [ now0 === now1, Math.abs(now0 - Date.parse(now1)) <= 1000 ]; + `, "false,true") + }) +} + +func TestDate_setSeconds(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + abc = new Date(1980, 10); + def = new Date(abc); + + abc.setSeconds(10, 12); + + def.setSeconds(10); + def.setMilliseconds(12); + + abc.valueOf() === def.valueOf(); + `, true) + + test(` + abc = new Date(1980, 10); + def = new Date(abc); + + abc.setUTCSeconds(10, 12); + + def.setUTCSeconds(10); + def.setUTCMilliseconds(12); + + abc.valueOf() === def.valueOf(); + `, true) + + test(`Date.prototype.setSeconds.length`, 2) + test(`Date.prototype.setUTCSeconds.length`, 2) + }) +} + +func TestDate_setMinutes(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + abc = new Date(1980, 10); + def = new Date(abc); + + abc.setMinutes(8, 10, 12); + + def.setMinutes(8); + def.setSeconds(10); + def.setMilliseconds(12); + + abc.valueOf() === def.valueOf(); + `, true) + + test(` + abc = new Date(1980, 10); + def = new Date(abc); + + abc.setUTCMinutes(8, 10, 12); + + def.setUTCMinutes(8); + def.setUTCSeconds(10); + def.setUTCMilliseconds(12); + + abc.valueOf() === def.valueOf(); + `, true) + + test(`Date.prototype.setMinutes.length`, 3) + test(`Date.prototype.setUTCMinutes.length`, 3) + }) +} + +func TestDate_setHours(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + abc = new Date(1980, 10); + def = new Date(abc); + + abc.setHours(6, 8, 10, 12); + + def.setHours(6); + def.setMinutes(8); + def.setSeconds(10); + def.setMilliseconds(12); + + abc.valueOf() === def.valueOf(); + `, true) + + test(` + abc = new Date(1980, 10); + def = new Date(abc); + + abc.setUTCHours(6, 8, 10, 12); + + def.setUTCHours(6); + def.setUTCMinutes(8); + def.setUTCSeconds(10); + def.setUTCMilliseconds(12); + + abc.valueOf() === def.valueOf(); + `, true) + + test(`Date.prototype.setHours.length`, 4) + test(`Date.prototype.setUTCHours.length`, 4) + }) +} + +func TestDate_setMonth(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + abc = new Date(1980, 10); + def = new Date(abc); + + abc.setMonth(6, 8); + + def.setMonth(6); + def.setDate(8); + + abc.valueOf() === def.valueOf(); + `, true) + + test(` + abc = new Date(1980, 10); + def = new Date(abc); + + abc.setUTCMonth(6, 8); + + def.setUTCMonth(6); + def.setUTCDate(8); + + abc.valueOf() === def.valueOf(); + `, true) + + test(`Date.prototype.setMonth.length`, 2) + test(`Date.prototype.setUTCMonth.length`, 2) + }) +} + +func TestDate_setFullYear(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + abc = new Date(1980, 10); + def = new Date(abc); + + abc.setFullYear(1981, 6, 8); + + def.setFullYear(1981); + def.setMonth(6); + def.setDate(8); + + abc.valueOf() === def.valueOf(); + `, true) + + test(` + abc = new Date(1980, 10); + def = new Date(abc); + + abc.setUTCFullYear(1981, 6, 8); + + def.setUTCFullYear(1981); + def.setUTCMonth(6); + def.setUTCDate(8); + + abc.valueOf() === def.valueOf(); + `, true) + + test(`Date.prototype.setFullYear.length`, 3) + test(`Date.prototype.setUTCFullYear.length`, 3) + }) +} + +func TestDate_setTime(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + var abc = new Date(1999, 6, 1); + var def = new Date(); + def.setTime(abc.getTime()); + [ def, abc.valueOf() == def.valueOf() ]; + `, "Thu, 01 Jul 1999 00:00:00 UTC,true") + + test(`Date.prototype.setTime.length`, 1) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/dbg.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/dbg.go new file mode 100644 index 0000000000..51fbdc2063 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/dbg.go @@ -0,0 +1,9 @@ +// This file was AUTOMATICALLY GENERATED by dbg-import (smuggol) for github.com/robertkrimen/dbg + +package otto + +import ( + Dbg "github.com/robertkrimen/otto/dbg" +) + +var dbg, dbgf = Dbg.New() diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/dbg/dbg.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/dbg/dbg.go new file mode 100644 index 0000000000..83bf6c5734 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/dbg/dbg.go @@ -0,0 +1,387 @@ +// This file was AUTOMATICALLY GENERATED by dbg-import (smuggol) from github.com/robertkrimen/dbg + +/* +Package dbg is a println/printf/log-debugging utility library. + + import ( + Dbg "github.com/robertkrimen/dbg" + ) + + dbg, dbgf := Dbg.New() + + dbg("Emit some debug stuff", []byte{120, 121, 122, 122, 121}, math.Pi) + # "2013/01/28 16:50:03 Emit some debug stuff [120 121 122 122 121] 3.141592653589793" + + dbgf("With a %s formatting %.2f", "little", math.Pi) + # "2013/01/28 16:51:55 With a little formatting (3.14)" + + dbgf("%/fatal//A fatal debug statement: should not be here") + # "A fatal debug statement: should not be here" + # ...and then, os.Exit(1) + + dbgf("%/panic//Can also panic %s", "this") + # "Can also panic this" + # ...as a panic, equivalent to: panic("Can also panic this") + + dbgf("Any %s arguments without a corresponding %%", "extra", "are treated like arguments to dbg()") + # "2013/01/28 17:14:40 Any extra arguments (without a corresponding %) are treated like arguments to dbg()" + + dbgf("%d %d", 1, 2, 3, 4, 5) + # "2013/01/28 17:16:32 Another example: 1 2 3 4 5" + + dbgf("%@: Include the function name for a little context (via %s)", "%@") + # "2013... github.com/robertkrimen/dbg.TestSynopsis: Include the function name for a little context (via %@)" + +By default, dbg uses log (log.Println, log.Printf, log.Panic, etc.) for output. +However, you can also provide your own output destination by invoking dbg.New with +a customization function: + + import ( + "bytes" + Dbg "github.com/robertkrimen/dbg" + "os" + ) + + # dbg to os.Stderr + dbg, dbgf := Dbg.New(func(dbgr *Dbgr) { + dbgr.SetOutput(os.Stderr) + }) + + # A slightly contrived example: + var buffer bytes.Buffer + dbg, dbgf := New(func(dbgr *Dbgr) { + dbgr.SetOutput(&buffer) + }) + +*/ +package dbg + +import ( + "bytes" + "fmt" + "io" + "log" + "os" + "regexp" + "runtime" + "strings" + "unicode" +) + +type _frmt struct { + ctl string + format string + operandCount int + panic bool + fatal bool + check bool +} + +var ( + ctlTest = regexp.MustCompile(`^\s*%/`) + ctlScan = regexp.MustCompile(`%?/(panic|fatal|check)(?:\s|$)`) +) + +func operandCount(format string) int { + count := 0 + end := len(format) + for at := 0; at < end; { + for at < end && format[at] != '%' { + at++ + } + at++ + if at < end { + if format[at] != '%' && format[at] != '@' { + count++ + } + at++ + } + } + return count +} + +func parseFormat(format string) (frmt _frmt) { + if ctlTest.MatchString(format) { + format = strings.TrimLeftFunc(format, unicode.IsSpace) + index := strings.Index(format, "//") + if index != -1 { + frmt.ctl = format[0:index] + format = format[index+2:] // Skip the second slash via +2 (instead of +1) + } else { + frmt.ctl = format + format = "" + } + for _, tmp := range ctlScan.FindAllStringSubmatch(frmt.ctl, -1) { + for _, value := range tmp[1:] { + switch value { + case "panic": + frmt.panic = true + case "fatal": + frmt.fatal = true + case "check": + frmt.check = true + } + } + } + } + frmt.format = format + frmt.operandCount = operandCount(format) + return +} + +type Dbgr struct { + emit _emit +} + +type DbgFunction func(values ...interface{}) + +func NewDbgr() *Dbgr { + self := &Dbgr{} + return self +} + +/* +New will create and return a pair of debugging functions. You can customize where +they output to by passing in an (optional) customization function: + + import ( + Dbg "github.com/robertkrimen/dbg" + "os" + ) + + # dbg to os.Stderr + dbg, dbgf := Dbg.New(func(dbgr *Dbgr) { + dbgr.SetOutput(os.Stderr) + }) + +*/ +func New(options ...interface{}) (dbg DbgFunction, dbgf DbgFunction) { + dbgr := NewDbgr() + if len(options) > 0 { + if fn, ok := options[0].(func(*Dbgr)); ok { + fn(dbgr) + } + } + return dbgr.DbgDbgf() +} + +func (self Dbgr) Dbg(values ...interface{}) { + self.getEmit().emit(_frmt{}, "", values...) +} + +func (self Dbgr) Dbgf(values ...interface{}) { + self.dbgf(values...) +} + +func (self Dbgr) DbgDbgf() (dbg DbgFunction, dbgf DbgFunction) { + dbg = func(vl ...interface{}) { + self.Dbg(vl...) + } + dbgf = func(vl ...interface{}) { + self.dbgf(vl...) + } + return dbg, dbgf // Redundant, but... +} + +func (self Dbgr) dbgf(values ...interface{}) { + + var frmt _frmt + if len(values) > 0 { + tmp := fmt.Sprint(values[0]) + frmt = parseFormat(tmp) + values = values[1:] + } + + buffer_f := bytes.Buffer{} + format := frmt.format + end := len(format) + for at := 0; at < end; { + last := at + for at < end && format[at] != '%' { + at++ + } + if at > last { + buffer_f.WriteString(format[last:at]) + } + if at >= end { + break + } + // format[at] == '%' + at++ + // format[at] == ? + if format[at] == '@' { + depth := 2 + pc, _, _, _ := runtime.Caller(depth) + name := runtime.FuncForPC(pc).Name() + buffer_f.WriteString(name) + } else { + buffer_f.WriteString(format[at-1 : at+1]) + } + at++ + } + + //values_f := append([]interface{}{}, values[0:frmt.operandCount]...) + values_f := values[0:frmt.operandCount] + values_dbg := values[frmt.operandCount:] + if len(values_dbg) > 0 { + // Adjust frmt.format: + // (%v instead of %s because: frmt.check) + { + tmp := format + if len(tmp) > 0 { + if unicode.IsSpace(rune(tmp[len(tmp)-1])) { + buffer_f.WriteString("%v") + } else { + buffer_f.WriteString(" %v") + } + } else if frmt.check { + // Performing a check, so no output + } else { + buffer_f.WriteString("%v") + } + } + + // Adjust values_f: + if !frmt.check { + tmp := []string{} + for _, value := range values_dbg { + tmp = append(tmp, fmt.Sprintf("%v", value)) + } + // First, make a copy of values_f, so we avoid overwriting values_dbg when appending + values_f = append([]interface{}{}, values_f...) + values_f = append(values_f, strings.Join(tmp, " ")) + } + } + + format = buffer_f.String() + if frmt.check { + // We do not actually emit to the log, but panic if + // a non-nil value is detected (e.g. a non-nil error) + for _, value := range values_dbg { + if value != nil { + if format == "" { + panic(value) + } else { + panic(fmt.Sprintf(format, append(values_f, value)...)) + } + } + } + } else { + self.getEmit().emit(frmt, format, values_f...) + } +} + +// Idiot-proof &Dbgr{}, etc. +func (self *Dbgr) getEmit() _emit { + if self.emit == nil { + self.emit = standardEmit() + } + return self.emit +} + +// SetOutput will accept the following as a destination for output: +// +// *log.Logger Print*/Panic*/Fatal* of the logger +// io.Writer - +// nil Reset to the default output (os.Stderr) +// "log" Print*/Panic*/Fatal* via the "log" package +// +func (self *Dbgr) SetOutput(output interface{}) { + if output == nil { + self.emit = standardEmit() + return + } + switch output := output.(type) { + case *log.Logger: + self.emit = _emitLogger{ + logger: output, + } + return + case io.Writer: + self.emit = _emitWriter{ + writer: output, + } + return + case string: + if output == "log" { + self.emit = _emitLog{} + return + } + } + panic(output) +} + +// ======== // +// = emit = // +// ======== // + +func standardEmit() _emit { + return _emitWriter{ + writer: os.Stderr, + } +} + +func ln(tmp string) string { + length := len(tmp) + if length > 0 && tmp[length-1] != '\n' { + return tmp + "\n" + } + return tmp +} + +type _emit interface { + emit(_frmt, string, ...interface{}) +} + +type _emitWriter struct { + writer io.Writer +} + +func (self _emitWriter) emit(frmt _frmt, format string, values ...interface{}) { + if format == "" { + fmt.Fprintln(self.writer, values...) + } else { + if frmt.panic { + panic(fmt.Sprintf(format, values...)) + } + fmt.Fprintf(self.writer, ln(format), values...) + if frmt.fatal { + os.Exit(1) + } + } +} + +type _emitLogger struct { + logger *log.Logger +} + +func (self _emitLogger) emit(frmt _frmt, format string, values ...interface{}) { + if format == "" { + self.logger.Println(values...) + } else { + if frmt.panic { + self.logger.Panicf(format, values...) + } else if frmt.fatal { + self.logger.Fatalf(format, values...) + } else { + self.logger.Printf(format, values...) + } + } +} + +type _emitLog struct { +} + +func (self _emitLog) emit(frmt _frmt, format string, values ...interface{}) { + if format == "" { + log.Println(values...) + } else { + if frmt.panic { + log.Panicf(format, values...) + } else if frmt.fatal { + log.Fatalf(format, values...) + } else { + log.Printf(format, values...) + } + } +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/documentation_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/documentation_test.go new file mode 100644 index 0000000000..04646117fc --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/documentation_test.go @@ -0,0 +1,95 @@ +package otto + +import ( + "fmt" +) + +func ExampleSynopsis() { + + vm := New() + vm.Run(` + abc = 2 + 2; + console.log("The value of abc is " + abc); // 4 + `) + + value, _ := vm.Get("abc") + { + value, _ := value.ToInteger() + fmt.Println(value) + } + + vm.Set("def", 11) + vm.Run(` + console.log("The value of def is " + def); + `) + + vm.Set("xyzzy", "Nothing happens.") + vm.Run(` + console.log(xyzzy.length); + `) + + value, _ = vm.Run("xyzzy.length") + { + value, _ := value.ToInteger() + fmt.Println(value) + } + + value, err := vm.Run("abcdefghijlmnopqrstuvwxyz.length") + fmt.Println(value) + fmt.Println(err) + + vm.Set("sayHello", func(call FunctionCall) Value { + fmt.Printf("Hello, %s.\n", call.Argument(0).String()) + return UndefinedValue() + }) + + vm.Set("twoPlus", func(call FunctionCall) Value { + right, _ := call.Argument(0).ToInteger() + result, _ := vm.ToValue(2 + right) + return result + }) + + value, _ = vm.Run(` + sayHello("Xyzzy"); + sayHello(); + + result = twoPlus(2.0); + `) + fmt.Println(value) + + // Output: + // The value of abc is 4 + // 4 + // The value of def is 11 + // 16 + // 16 + // undefined + // ReferenceError: 'abcdefghijlmnopqrstuvwxyz' is not defined + // Hello, Xyzzy. + // Hello, undefined. + // 4 +} + +func ExampleConsole() { + + vm := New() + console := map[string]interface{}{ + "log": func(call FunctionCall) Value { + fmt.Println("console.log:", formatForConsole(call.ArgumentList)) + return UndefinedValue() + }, + } + + err := vm.Set("console", console) + + value, err := vm.Run(` + console.log("Hello, World."); + `) + fmt.Println(value) + fmt.Println(err) + + // Output: + // console.log: Hello, World. + // undefined + // +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/error.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/error.go new file mode 100644 index 0000000000..1114710444 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/error.go @@ -0,0 +1,245 @@ +package otto + +import ( + "errors" + "fmt" + "strings" + + "github.com/robertkrimen/otto/file" +) + +type _exception struct { + value interface{} +} + +func newException(value interface{}) *_exception { + return &_exception{ + value: value, + } +} + +func (self *_exception) eject() interface{} { + value := self.value + self.value = nil // Prevent Go from holding on to the value, whatever it is + return value +} + +type _error struct { + name string + message string + trace []_frame + + offset int +} + +type _frame struct { + file *file.File + offset int + callee string +} + +var ( + nativeFrame = _frame{} +) + +type _at int + +func (fr _frame) location() string { + if fr.file == nil { + return "" + } + path := fr.file.Name() + line, column := _position(fr.file, fr.offset) + + if path == "" { + path = "" + } + + str := fmt.Sprintf("%s:%d:%d", path, line, column) + + if fr.callee != "" { + str = fmt.Sprintf("%s (%s)", fr.callee, str) + } + + return str +} + +func _position(file *file.File, offset int) (line, column int) { + { + offset := offset - file.Base() + if offset < 0 { + return -offset, -1 + } + + src := file.Source() + if offset >= len(src) { + return -offset, -len(src) + } + src = src[:offset] + + line := 1 + strings.Count(src, "\n") + column := 0 + if index := strings.LastIndex(src, "\n"); index >= 0 { + column = offset - index + } else { + column = 1 + len(src) + } + return line, column + } +} + +// An Error represents a runtime error, e.g. a TypeError, a ReferenceError, etc. +type Error struct { + _error +} + +// Error returns a description of the error +// +// TypeError: 'def' is not a function +// +func (err Error) Error() string { + if len(err.name) == 0 { + return err.message + } + if len(err.message) == 0 { + return err.name + } + return fmt.Sprintf("%s: %s", err.name, err.message) +} + +// String returns a description of the error and a trace of where the +// error occurred. +// +// TypeError: 'def' is not a function +// at xyz (:3:9) +// at :7:1/ +// +func (err Error) String() string { + str := err.Error() + "\n" + for _, frame := range err.trace { + str += " at " + frame.location() + "\n" + } + return str +} + +func (err _error) describe(format string, in ...interface{}) string { + return fmt.Sprintf(format, in...) +} + +func (self _error) messageValue() Value { + if self.message == "" { + return Value{} + } + return toValue_string(self.message) +} + +func (rt *_runtime) typeErrorResult(throw bool) bool { + if throw { + panic(rt.panicTypeError()) + } + return false +} + +func newError(rt *_runtime, name string, in ...interface{}) _error { + err := _error{ + name: name, + offset: -1, + } + description := "" + length := len(in) + + if rt != nil { + scope := rt.scope + frame := scope.frame + if length > 0 { + if at, ok := in[length-1].(_at); ok { + in = in[0 : length-1] + if scope != nil { + frame.offset = int(at) + } + length -= 1 + } + if length > 0 { + description, in = in[0].(string), in[1:] + } + } + limit := 10 + err.trace = append(err.trace, frame) + if scope != nil { + for limit > 0 { + scope = scope.outer + if scope == nil { + break + } + if scope.frame.offset >= 0 { + err.trace = append(err.trace, scope.frame) + } + limit-- + } + } + } else { + if length > 0 { + description, in = in[0].(string), in[1:] + } + } + err.message = err.describe(description, in...) + return err +} + +func (rt *_runtime) panicTypeError(argumentList ...interface{}) *_exception { + return &_exception{ + value: newError(rt, "TypeError", argumentList...), + } +} + +func (rt *_runtime) panicReferenceError(argumentList ...interface{}) *_exception { + return &_exception{ + value: newError(rt, "ReferenceError", argumentList...), + } +} + +func (rt *_runtime) panicURIError(argumentList ...interface{}) *_exception { + return &_exception{ + value: newError(rt, "URIError", argumentList...), + } +} + +func (rt *_runtime) panicSyntaxError(argumentList ...interface{}) *_exception { + return &_exception{ + value: newError(rt, "SyntaxError", argumentList...), + } +} + +func (rt *_runtime) panicRangeError(argumentList ...interface{}) *_exception { + return &_exception{ + value: newError(rt, "RangeError", argumentList...), + } +} + +func catchPanic(function func()) (err error) { + defer func() { + if caught := recover(); caught != nil { + if exception, ok := caught.(*_exception); ok { + caught = exception.eject() + } + switch caught := caught.(type) { + case _error: + err = &Error{caught} + return + case Value: + if vl := caught._object(); vl != nil { + switch vl := vl.value.(type) { + case _error: + err = &Error{vl} + return + } + } + err = errors.New(caught.string()) + return + } + panic(caught) + } + }() + function() + return nil +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/error_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/error_test.go new file mode 100644 index 0000000000..7f1b16af74 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/error_test.go @@ -0,0 +1,192 @@ +package otto + +import ( + "testing" +) + +func TestError(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ Error.prototype.name, Error.prototype.message, Error.prototype.hasOwnProperty("message") ]; + `, "Error,,true") + }) +} + +func TestError_instanceof(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`(new TypeError()) instanceof Error`, true) + }) +} + +func TestPanicValue(t *testing.T) { + tt(t, func() { + test, vm := test() + + vm.Set("abc", func(call FunctionCall) Value { + value, err := call.Otto.Run(`({ def: 3.14159 })`) + is(err, nil) + panic(value) + }) + + test(` + try { + abc(); + } + catch (err) { + error = err; + } + [ error instanceof Error, error.message, error.def ]; + `, "false,,3.14159") + }) +} + +func Test_catchPanic(t *testing.T) { + tt(t, func() { + vm := New() + + _, err := vm.Run(` + A syntax error that + does not define + var; + abc; + `) + is(err, "!=", nil) + + _, err = vm.Call(`abc.def`, nil) + is(err, "!=", nil) + }) +} + +func TestErrorContext(t *testing.T) { + tt(t, func() { + vm := New() + + _, err := vm.Run(` + undefined(); + `) + { + err := err.(*Error) + is(err.message, "'undefined' is not a function") + is(len(err.trace), 1) + is(err.trace[0].location(), ":2:13") + } + + _, err = vm.Run(` + ({}).abc(); + `) + { + err := err.(*Error) + is(err.message, "'abc' is not a function") + is(len(err.trace), 1) + is(err.trace[0].location(), ":2:14") + } + + _, err = vm.Run(` + ("abc").abc(); + `) + { + err := err.(*Error) + is(err.message, "'abc' is not a function") + is(len(err.trace), 1) + is(err.trace[0].location(), ":2:14") + } + + _, err = vm.Run(` + var ghi = "ghi"; + ghi(); + `) + { + err := err.(*Error) + is(err.message, "'ghi' is not a function") + is(len(err.trace), 1) + is(err.trace[0].location(), ":3:13") + } + + _, err = vm.Run(` + function def() { + undefined(); + } + function abc() { + def(); + } + abc(); + `) + { + err := err.(*Error) + is(err.message, "'undefined' is not a function") + is(len(err.trace), 3) + is(err.trace[0].location(), "def (:3:17)") + is(err.trace[1].location(), "abc (:6:17)") + is(err.trace[2].location(), ":8:13") + } + + _, err = vm.Run(` + function abc() { + xyz(); + } + abc(); + `) + { + err := err.(*Error) + is(err.message, "'xyz' is not defined") + is(len(err.trace), 2) + is(err.trace[0].location(), "abc (:3:17)") + is(err.trace[1].location(), ":5:13") + } + + _, err = vm.Run(` + mno + 1; + `) + { + err := err.(*Error) + is(err.message, "'mno' is not defined") + is(len(err.trace), 1) + is(err.trace[0].location(), ":2:13") + } + + _, err = vm.Run(` + eval("xyz();"); + `) + { + err := err.(*Error) + is(err.message, "'xyz' is not defined") + is(len(err.trace), 1) + is(err.trace[0].location(), ":1:1") + } + + _, err = vm.Run(` + xyzzy = "Nothing happens." + eval("xyzzy();"); + `) + { + err := err.(*Error) + is(err.message, "'xyzzy' is not a function") + is(len(err.trace), 1) + is(err.trace[0].location(), ":1:1") + } + + _, err = vm.Run(` + throw Error("xyzzy"); + `) + { + err := err.(*Error) + is(err.message, "xyzzy") + is(len(err.trace), 1) + is(err.trace[0].location(), ":2:19") + } + + _, err = vm.Run(` + throw new Error("xyzzy"); + `) + { + err := err.(*Error) + is(err.message, "xyzzy") + is(len(err.trace), 1) + is(err.trace[0].location(), ":2:23") + } + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/evaluate.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/evaluate.go new file mode 100644 index 0000000000..093054cc31 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/evaluate.go @@ -0,0 +1,318 @@ +package otto + +import ( + "fmt" + "math" + "strings" + + "github.com/robertkrimen/otto/token" +) + +func (self *_runtime) evaluateMultiply(left float64, right float64) Value { + // TODO 11.5.1 + return Value{} +} + +func (self *_runtime) evaluateDivide(left float64, right float64) Value { + if math.IsNaN(left) || math.IsNaN(right) { + return NaNValue() + } + if math.IsInf(left, 0) && math.IsInf(right, 0) { + return NaNValue() + } + if left == 0 && right == 0 { + return NaNValue() + } + if math.IsInf(left, 0) { + if math.Signbit(left) == math.Signbit(right) { + return positiveInfinityValue() + } else { + return negativeInfinityValue() + } + } + if math.IsInf(right, 0) { + if math.Signbit(left) == math.Signbit(right) { + return positiveZeroValue() + } else { + return negativeZeroValue() + } + } + if right == 0 { + if math.Signbit(left) == math.Signbit(right) { + return positiveInfinityValue() + } else { + return negativeInfinityValue() + } + } + return toValue_float64(left / right) +} + +func (self *_runtime) evaluateModulo(left float64, right float64) Value { + // TODO 11.5.3 + return Value{} +} + +func (self *_runtime) calculateBinaryExpression(operator token.Token, left Value, right Value) Value { + + leftValue := left.resolve() + + switch operator { + + // Additive + case token.PLUS: + leftValue = toPrimitive(leftValue) + rightValue := right.resolve() + rightValue = toPrimitive(rightValue) + + if leftValue.IsString() || rightValue.IsString() { + return toValue_string(strings.Join([]string{leftValue.string(), rightValue.string()}, "")) + } else { + return toValue_float64(leftValue.float64() + rightValue.float64()) + } + case token.MINUS: + rightValue := right.resolve() + return toValue_float64(leftValue.float64() - rightValue.float64()) + + // Multiplicative + case token.MULTIPLY: + rightValue := right.resolve() + return toValue_float64(leftValue.float64() * rightValue.float64()) + case token.SLASH: + rightValue := right.resolve() + return self.evaluateDivide(leftValue.float64(), rightValue.float64()) + case token.REMAINDER: + rightValue := right.resolve() + return toValue_float64(math.Mod(leftValue.float64(), rightValue.float64())) + + // Logical + case token.LOGICAL_AND: + left := leftValue.bool() + if !left { + return falseValue + } + return toValue_bool(right.resolve().bool()) + case token.LOGICAL_OR: + left := leftValue.bool() + if left { + return trueValue + } + return toValue_bool(right.resolve().bool()) + + // Bitwise + case token.AND: + rightValue := right.resolve() + return toValue_int32(toInt32(leftValue) & toInt32(rightValue)) + case token.OR: + rightValue := right.resolve() + return toValue_int32(toInt32(leftValue) | toInt32(rightValue)) + case token.EXCLUSIVE_OR: + rightValue := right.resolve() + return toValue_int32(toInt32(leftValue) ^ toInt32(rightValue)) + + // Shift + // (Masking of 0x1f is to restrict the shift to a maximum of 31 places) + case token.SHIFT_LEFT: + rightValue := right.resolve() + return toValue_int32(toInt32(leftValue) << (toUint32(rightValue) & 0x1f)) + case token.SHIFT_RIGHT: + rightValue := right.resolve() + return toValue_int32(toInt32(leftValue) >> (toUint32(rightValue) & 0x1f)) + case token.UNSIGNED_SHIFT_RIGHT: + rightValue := right.resolve() + // Shifting an unsigned integer is a logical shift + return toValue_uint32(toUint32(leftValue) >> (toUint32(rightValue) & 0x1f)) + + case token.INSTANCEOF: + rightValue := right.resolve() + if !rightValue.IsObject() { + panic(self.panicTypeError("Expecting a function in instanceof check, but got: %v", rightValue)) + } + return toValue_bool(rightValue._object().hasInstance(leftValue)) + + case token.IN: + rightValue := right.resolve() + if !rightValue.IsObject() { + panic(self.panicTypeError()) + } + return toValue_bool(rightValue._object().hasProperty(leftValue.string())) + } + + panic(hereBeDragons(operator)) +} + +func valueKindDispatchKey(left _valueKind, right _valueKind) int { + return (int(left) << 2) + int(right) +} + +var equalDispatch map[int](func(Value, Value) bool) = makeEqualDispatch() + +func makeEqualDispatch() map[int](func(Value, Value) bool) { + key := valueKindDispatchKey + return map[int](func(Value, Value) bool){ + + key(valueNumber, valueObject): func(x Value, y Value) bool { return x.float64() == y.float64() }, + key(valueString, valueObject): func(x Value, y Value) bool { return x.float64() == y.float64() }, + key(valueObject, valueNumber): func(x Value, y Value) bool { return x.float64() == y.float64() }, + key(valueObject, valueString): func(x Value, y Value) bool { return x.float64() == y.float64() }, + } +} + +type _lessThanResult int + +const ( + lessThanFalse _lessThanResult = iota + lessThanTrue + lessThanUndefined +) + +func calculateLessThan(left Value, right Value, leftFirst bool) _lessThanResult { + + x := Value{} + y := x + + if leftFirst { + x = toNumberPrimitive(left) + y = toNumberPrimitive(right) + } else { + y = toNumberPrimitive(right) + x = toNumberPrimitive(left) + } + + result := false + if x.kind != valueString || y.kind != valueString { + x, y := x.float64(), y.float64() + if math.IsNaN(x) || math.IsNaN(y) { + return lessThanUndefined + } + result = x < y + } else { + x, y := x.string(), y.string() + result = x < y + } + + if result { + return lessThanTrue + } + + return lessThanFalse +} + +// FIXME Probably a map is not the most efficient way to do this +var lessThanTable [4](map[_lessThanResult]bool) = [4](map[_lessThanResult]bool){ + // < + map[_lessThanResult]bool{ + lessThanFalse: false, + lessThanTrue: true, + lessThanUndefined: false, + }, + + // > + map[_lessThanResult]bool{ + lessThanFalse: false, + lessThanTrue: true, + lessThanUndefined: false, + }, + + // <= + map[_lessThanResult]bool{ + lessThanFalse: true, + lessThanTrue: false, + lessThanUndefined: false, + }, + + // >= + map[_lessThanResult]bool{ + lessThanFalse: true, + lessThanTrue: false, + lessThanUndefined: false, + }, +} + +func (self *_runtime) calculateComparison(comparator token.Token, left Value, right Value) bool { + + // FIXME Use strictEqualityComparison? + // TODO This might be redundant now (with regards to evaluateComparison) + x := left.resolve() + y := right.resolve() + + kindEqualKind := false + result := true + negate := false + + switch comparator { + case token.LESS: + result = lessThanTable[0][calculateLessThan(x, y, true)] + case token.GREATER: + result = lessThanTable[1][calculateLessThan(y, x, false)] + case token.LESS_OR_EQUAL: + result = lessThanTable[2][calculateLessThan(y, x, false)] + case token.GREATER_OR_EQUAL: + result = lessThanTable[3][calculateLessThan(x, y, true)] + case token.STRICT_NOT_EQUAL: + negate = true + fallthrough + case token.STRICT_EQUAL: + if x.kind != y.kind { + result = false + } else { + kindEqualKind = true + } + case token.NOT_EQUAL: + negate = true + fallthrough + case token.EQUAL: + if x.kind == y.kind { + kindEqualKind = true + } else if x.kind <= valueNull && y.kind <= valueNull { + result = true + } else if x.kind <= valueNull || y.kind <= valueNull { + result = false + } else if x.kind <= valueString && y.kind <= valueString { + result = x.float64() == y.float64() + } else if x.kind == valueBoolean { + result = self.calculateComparison(token.EQUAL, toValue_float64(x.float64()), y) + } else if y.kind == valueBoolean { + result = self.calculateComparison(token.EQUAL, x, toValue_float64(y.float64())) + } else if x.kind == valueObject { + result = self.calculateComparison(token.EQUAL, toPrimitive(x), y) + } else if y.kind == valueObject { + result = self.calculateComparison(token.EQUAL, x, toPrimitive(y)) + } else { + panic(hereBeDragons("Unable to test for equality: %v ==? %v", x, y)) + } + default: + panic(fmt.Errorf("Unknown comparator %s", comparator.String())) + } + + if kindEqualKind { + switch x.kind { + case valueUndefined, valueNull: + result = true + case valueNumber: + x := x.float64() + y := y.float64() + if math.IsNaN(x) || math.IsNaN(y) { + result = false + } else { + result = x == y + } + case valueString: + result = x.string() == y.string() + case valueBoolean: + result = x.bool() == y.bool() + case valueObject: + result = x._object() == y._object() + default: + goto ERROR + } + } + + if negate { + result = !result + } + + return result + +ERROR: + panic(hereBeDragons("%v (%v) %s %v (%v)", x, x.kind, comparator, y, y.kind)) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/file/README.markdown b/Godeps/_workspace/src/github.com/robertkrimen/otto/file/README.markdown new file mode 100644 index 0000000000..79757baa8e --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/file/README.markdown @@ -0,0 +1,110 @@ +# file +-- + import "github.com/robertkrimen/otto/file" + +Package file encapsulates the file abstractions used by the ast & parser. + +## Usage + +#### type File + +```go +type File struct { +} +``` + + +#### func NewFile + +```go +func NewFile(filename, src string, base int) *File +``` + +#### func (*File) Base + +```go +func (fl *File) Base() int +``` + +#### func (*File) Name + +```go +func (fl *File) Name() string +``` + +#### func (*File) Source + +```go +func (fl *File) Source() string +``` + +#### type FileSet + +```go +type FileSet struct { +} +``` + +A FileSet represents a set of source files. + +#### func (*FileSet) AddFile + +```go +func (self *FileSet) AddFile(filename, src string) int +``` +AddFile adds a new file with the given filename and src. + +This an internal method, but exported for cross-package use. + +#### func (*FileSet) File + +```go +func (self *FileSet) File(idx Idx) *File +``` + +#### func (*FileSet) Position + +```go +func (self *FileSet) Position(idx Idx) *Position +``` +Position converts an Idx in the FileSet into a Position. + +#### type Idx + +```go +type Idx int +``` + +Idx is a compact encoding of a source position within a file set. It can be +converted into a Position for a more convenient, but much larger, +representation. + +#### type Position + +```go +type Position struct { + Filename string // The filename where the error occurred, if any + Offset int // The src offset + Line int // The line number, starting at 1 + Column int // The column number, starting at 1 (The character count) + +} +``` + +Position describes an arbitrary source position including the filename, line, +and column location. + +#### func (*Position) String + +```go +func (self *Position) String() string +``` +String returns a string in one of several forms: + + file:line:column A valid position with filename + line:column A valid position without filename + file An invalid position with filename + - An invalid position without filename + +-- +**godocdown** http://github.com/robertkrimen/godocdown diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/file/file.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/file/file.go new file mode 100644 index 0000000000..76524ac39e --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/file/file.go @@ -0,0 +1,135 @@ +// Package file encapsulates the file abstractions used by the ast & parser. +// +package file + +import ( + "fmt" + "strings" +) + +// Idx is a compact encoding of a source position within a file set. +// It can be converted into a Position for a more convenient, but much +// larger, representation. +type Idx int + +// Position describes an arbitrary source position +// including the filename, line, and column location. +type Position struct { + Filename string // The filename where the error occurred, if any + Offset int // The src offset + Line int // The line number, starting at 1 + Column int // The column number, starting at 1 (The character count) + +} + +// A Position is valid if the line number is > 0. + +func (self *Position) isValid() bool { + return self.Line > 0 +} + +// String returns a string in one of several forms: +// +// file:line:column A valid position with filename +// line:column A valid position without filename +// file An invalid position with filename +// - An invalid position without filename +// +func (self *Position) String() string { + str := self.Filename + if self.isValid() { + if str != "" { + str += ":" + } + str += fmt.Sprintf("%d:%d", self.Line, self.Column) + } + if str == "" { + str = "-" + } + return str +} + +// FileSet + +// A FileSet represents a set of source files. +type FileSet struct { + files []*File + last *File +} + +// AddFile adds a new file with the given filename and src. +// +// This an internal method, but exported for cross-package use. +func (self *FileSet) AddFile(filename, src string) int { + base := self.nextBase() + file := &File{ + name: filename, + src: src, + base: base, + } + self.files = append(self.files, file) + self.last = file + return base +} + +func (self *FileSet) nextBase() int { + if self.last == nil { + return 1 + } + return self.last.base + len(self.last.src) + 1 +} + +func (self *FileSet) File(idx Idx) *File { + for _, file := range self.files { + if idx <= Idx(file.base+len(file.src)) { + return file + } + } + return nil +} + +// Position converts an Idx in the FileSet into a Position. +func (self *FileSet) Position(idx Idx) *Position { + position := &Position{} + for _, file := range self.files { + if idx <= Idx(file.base+len(file.src)) { + offset := int(idx) - file.base + src := file.src[:offset] + position.Filename = file.name + position.Offset = offset + position.Line = 1 + strings.Count(src, "\n") + if index := strings.LastIndex(src, "\n"); index >= 0 { + position.Column = offset - index + } else { + position.Column = 1 + len(src) + } + } + } + return position +} + +type File struct { + name string + src string + base int // This will always be 1 or greater +} + +func NewFile(filename, src string, base int) *File { + return &File{ + name: filename, + src: src, + base: base, + } +} + +func (fl *File) Name() string { + return fl.name +} + +func (fl *File) Source() string { + return fl.src +} + +func (fl *File) Base() int { + return fl.base +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/function_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/function_test.go new file mode 100644 index 0000000000..c10bf8592a --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/function_test.go @@ -0,0 +1,280 @@ +package otto + +import ( + "testing" +) + +func TestFunction(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = Object.getOwnPropertyDescriptor(Function, "prototype"); + [ [ typeof Function.prototype, typeof Function.prototype.length, Function.prototype.length ], + [ abc.writable, abc.enumerable, abc.configurable ] ]; + `, "function,number,0,false,false,false") + }) +} + +func Test_argumentList2parameterList(t *testing.T) { + tt(t, func() { + is(argumentList2parameterList([]Value{toValue("abc, def"), toValue("ghi")}), []string{"abc", "def", "ghi"}) + }) +} + +func TestFunction_new(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: + new Function({}); + `, "SyntaxError: Unexpected identifier") + + test(` + var abc = Function("def, ghi", "jkl", "return def+ghi+jkl"); + [ typeof abc, abc instanceof Function, abc("ab", "ba", 1) ]; + `, "function,true,abba1") + + test(`raise: + var abc = { + toString: function() { throw 1; } + }; + var def = { + toString: function() { throw 2; } + }; + var ghi = new Function(abc, def); + ghi; + `, "1") + + // S15.3.2.1_A3_T10 + test(`raise: + var abc = { + toString: function() { return "z;x"; } + }; + var def = "return this"; + var ghi = new Function(abc, def); + ghi; + `, "SyntaxError: Unexpected token ;") + + test(`raise: + var abc; + var def = "return true"; + var ghi = new Function(null, def); + ghi; + `, "SyntaxError: Unexpected token null") + }) +} + +func TestFunction_apply(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Function.prototype.apply.length`, 2) + test(`String.prototype.substring.apply("abc", [1, 11])`, "bc") + }) +} + +func TestFunction_call(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Function.prototype.call.length`, 1) + test(`String.prototype.substring.call("abc", 1, 11)`, "bc") + }) +} + +func TestFunctionArguments(t *testing.T) { + tt(t, func() { + test, _ := test() + + // Should not be able to delete arguments + test(` + function abc(def, arguments){ + delete def; + return def; + } + abc(1); + `, 1) + + // Again, should not be able to delete arguments + test(` + function abc(def){ + delete def; + return def; + } + abc(1); + `, 1) + + // Test typeof of a function argument + test(` + function abc(def, ghi, jkl){ + return typeof jkl + } + abc("1st", "2nd", "3rd", "4th", "5th"); + `, "string") + + test(` + function abc(def, ghi, jkl){ + arguments[0] = 3.14; + arguments[1] = 'Nothing happens'; + arguments[2] = 42; + if (3.14 === def && 'Nothing happens' === ghi && 42 === jkl) + return true; + } + abc(-1, 4.2, 314); + `, true) + }) +} + +func TestFunctionDeclarationInFunction(t *testing.T) { + tt(t, func() { + test, _ := test() + + // Function declarations happen AFTER parameter/argument declarations + // That is, a function declared within a function will shadow/overwrite + // declared parameters + + test(` + function abc(def){ + return def; + function def(){ + return 1; + } + } + typeof abc(); + `, "function") + }) +} + +func TestArguments_defineOwnProperty(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc; + var def = true; + var ghi = {}; + (function (a, b, c) { + Object.defineProperty(arguments, "0", { + value: 42, + writable: false, + enumerable: false, + configurable: false + }); + Object.defineProperty(arguments, "1", { + value: 3.14, + configurable: true, + enumerable: true + }); + abc = Object.getOwnPropertyDescriptor(arguments, "0"); + for (var name in arguments) { + ghi[name] = (ghi[name] || 0) + 1; + if (name === "0") { + def = false; + } + } + }(0, 1, 2)); + [ abc.value, abc.writable, abc.enumerable, abc.configurable, def, ghi["1"] ]; + `, "42,false,false,false,true,1") + }) +} + +func TestFunction_bind(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + abc = function(){ + return "abc"; + }; + def = abc.bind(); + [ typeof def.prototype, typeof def.hasOwnProperty, def.hasOwnProperty("caller"), def.hasOwnProperty("arguments"), def() ]; + `, "object,function,true,true,abc") + + test(` + abc = function(){ + return arguments[1]; + }; + def = abc.bind(undefined, "abc"); + ghi = abc.bind(undefined, "abc", "ghi"); + [ def(), def("def"), ghi("def") ]; + `, ",def,ghi") + + test(` + var abc = function () {}; + var ghi; + try { + Object.defineProperty(Function.prototype, "xyzzy", { + value: 1001, + writable: true, + enumerable: true, + configurable: true + }); + var def = abc.bind({}); + ghi = !def.hasOwnProperty("xyzzy") && ghi.xyzzy === 1001; + } finally { + delete Function.prototype.xyzzy; + } + [ ghi ]; + `, "true") + + test(` + var abc = function (def, ghi) {}; + var jkl = abc.bind({}); + var mno = abc.bind({}, 1, 2); + [ jkl.length, mno.length ]; + `, "2,0") + + test(`raise: + Math.bind(); + `, "TypeError: 'bind' is not a function") + + test(` + function construct(fn, arguments) { + var bound = Function.prototype.bind.apply(fn, [null].concat(arguments)); + return new bound(); + } + var abc = construct(Date, [1957, 4, 27]); + Object.prototype.toString.call(abc); + `, "[object Date]") + + test(` + var fn = function (x, y, z) { + var result = {}; + result.abc = x + y + z; + result.def = arguments[0] === "a" && arguments.length === 3; + return result; + }; + var newFn = Function.prototype.bind.call(fn, {}, "a", "b", "c"); + var result = new newFn(); + [ result.hasOwnProperty("abc"), result.hasOwnProperty("def"), result.abc, result.def ]; + `, "true,true,abc,true") + + test(` + abc = function(){ + return "abc"; + }; + def = abc.bind(); + def.toString(); + `, "function () { [native code] }") + }) +} + +func TestFunction_toString(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: + Function.prototype.toString.call(undefined); + `, "TypeError") + + test(` + abc = function() { return -1 ; +} + 1; + abc.toString(); + `, "function() { return -1 ;\n}") + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/global.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/global.go new file mode 100644 index 0000000000..4f035314a1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/global.go @@ -0,0 +1,221 @@ +package otto + +import ( + "strconv" + "time" +) + +var ( + prototypeValueObject = interface{}(nil) + prototypeValueFunction = _nativeFunctionObject{ + call: func(_ FunctionCall) Value { + return Value{} + }, + } + prototypeValueString = _stringASCII("") + // TODO Make this just false? + prototypeValueBoolean = Value{ + kind: valueBoolean, + value: false, + } + prototypeValueNumber = Value{ + kind: valueNumber, + value: 0, + } + prototypeValueDate = _dateObject{ + epoch: 0, + isNaN: false, + time: time.Unix(0, 0).UTC(), + value: Value{ + kind: valueNumber, + value: 0, + }, + } + prototypeValueRegExp = _regExpObject{ + regularExpression: nil, + global: false, + ignoreCase: false, + multiline: false, + source: "", + flags: "", + } +) + +func newContext() *_runtime { + + self := &_runtime{} + + self.globalStash = self.newObjectStash(nil, nil) + self.globalObject = self.globalStash.object + + _newContext(self) + + self.eval = self.globalObject.property["eval"].value.(Value).value.(*_object) + self.globalObject.prototype = self.global.ObjectPrototype + + return self +} + +func (runtime *_runtime) newBaseObject() *_object { + self := newObject(runtime, "") + return self +} + +func (runtime *_runtime) newClassObject(class string) *_object { + return newObject(runtime, class) +} + +func (runtime *_runtime) newPrimitiveObject(class string, value Value) *_object { + self := runtime.newClassObject(class) + self.value = value + return self +} + +func (self *_object) primitiveValue() Value { + switch value := self.value.(type) { + case Value: + return value + case _stringObject: + return toValue_string(value.String()) + } + return Value{} +} + +func (self *_object) hasPrimitive() bool { + switch self.value.(type) { + case Value, _stringObject: + return true + } + return false +} + +func (runtime *_runtime) newObject() *_object { + self := runtime.newClassObject("Object") + self.prototype = runtime.global.ObjectPrototype + return self +} + +func (runtime *_runtime) newArray(length uint32) *_object { + self := runtime.newArrayObject(length) + self.prototype = runtime.global.ArrayPrototype + return self +} + +func (runtime *_runtime) newArrayOf(valueArray []Value) *_object { + self := runtime.newArray(uint32(len(valueArray))) + for index, value := range valueArray { + if value.isEmpty() { + continue + } + self.defineProperty(strconv.FormatInt(int64(index), 10), value, 0111, false) + } + return self +} + +func (runtime *_runtime) newString(value Value) *_object { + self := runtime.newStringObject(value) + self.prototype = runtime.global.StringPrototype + return self +} + +func (runtime *_runtime) newBoolean(value Value) *_object { + self := runtime.newBooleanObject(value) + self.prototype = runtime.global.BooleanPrototype + return self +} + +func (runtime *_runtime) newNumber(value Value) *_object { + self := runtime.newNumberObject(value) + self.prototype = runtime.global.NumberPrototype + return self +} + +func (runtime *_runtime) newRegExp(patternValue Value, flagsValue Value) *_object { + + pattern := "" + flags := "" + if object := patternValue._object(); object != nil && object.class == "RegExp" { + if flagsValue.IsDefined() { + panic(runtime.panicTypeError("Cannot supply flags when constructing one RegExp from another")) + } + regExp := object.regExpValue() + pattern = regExp.source + flags = regExp.flags + } else { + if patternValue.IsDefined() { + pattern = patternValue.string() + } + if flagsValue.IsDefined() { + flags = flagsValue.string() + } + } + + return runtime._newRegExp(pattern, flags) +} + +func (runtime *_runtime) _newRegExp(pattern string, flags string) *_object { + self := runtime.newRegExpObject(pattern, flags) + self.prototype = runtime.global.RegExpPrototype + return self +} + +// TODO Should (probably) be one argument, right? This is redundant +func (runtime *_runtime) newDate(epoch float64) *_object { + self := runtime.newDateObject(epoch) + self.prototype = runtime.global.DatePrototype + return self +} + +func (runtime *_runtime) newError(name string, message Value) *_object { + var self *_object + switch name { + case "EvalError": + return runtime.newEvalError(message) + case "TypeError": + return runtime.newTypeError(message) + case "RangeError": + return runtime.newRangeError(message) + case "ReferenceError": + return runtime.newReferenceError(message) + case "SyntaxError": + return runtime.newSyntaxError(message) + case "URIError": + return runtime.newURIError(message) + } + + self = runtime.newErrorObject(name, message) + self.prototype = runtime.global.ErrorPrototype + if name != "" { + self.defineProperty("name", toValue_string(name), 0111, false) + } + return self +} + +func (runtime *_runtime) newNativeFunction(name string, _nativeFunction _nativeFunction) *_object { + self := runtime.newNativeFunctionObject(name, _nativeFunction, 0) + self.prototype = runtime.global.FunctionPrototype + prototype := runtime.newObject() + self.defineProperty("prototype", toValue_object(prototype), 0100, false) + prototype.defineProperty("constructor", toValue_object(self), 0100, false) + return self +} + +func (runtime *_runtime) newNodeFunction(node *_nodeFunctionLiteral, scopeEnvironment _stash) *_object { + // TODO Implement 13.2 fully + self := runtime.newNodeFunctionObject(node, scopeEnvironment) + self.prototype = runtime.global.FunctionPrototype + prototype := runtime.newObject() + self.defineProperty("prototype", toValue_object(prototype), 0100, false) + prototype.defineProperty("constructor", toValue_object(self), 0101, false) + return self +} + +// FIXME Only in one place... +func (runtime *_runtime) newBoundFunction(target *_object, this Value, argumentList []Value) *_object { + self := runtime.newBoundFunctionObject(target, this, argumentList) + self.prototype = runtime.global.FunctionPrototype + prototype := runtime.newObject() + self.defineProperty("prototype", toValue_object(prototype), 0100, false) + prototype.defineProperty("constructor", toValue_object(self), 0100, false) + return self +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/global_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/global_test.go new file mode 100644 index 0000000000..9257b58c37 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/global_test.go @@ -0,0 +1,355 @@ +package otto + +import ( + "fmt" + "math" + "strings" + "testing" +) + +func TestGlobal(t *testing.T) { + tt(t, func() { + test, vm := test() + + runtime := vm.vm.runtime + + { + call := func(object interface{}, src string, argumentList ...interface{}) Value { + var tgt *Object + switch object := object.(type) { + case Value: + tgt = object.Object() + case *Object: + tgt = object + case *_object: + tgt = toValue_object(object).Object() + default: + panic("Here be dragons.") + } + value, err := tgt.Call(src, argumentList...) + is(err, nil) + return value + } + + // FIXME enterGlobalScope + if false { + value := runtime.scope.lexical.getBinding("Object", false)._object().call(UndefinedValue(), []Value{toValue(runtime.newObject())}, false, nativeFrame) + is(value.IsObject(), true) + is(value, "[object Object]") + is(value._object().prototype == runtime.global.ObjectPrototype, true) + is(value._object().prototype == runtime.global.Object.get("prototype")._object(), true) + is(value._object().get("toString"), "function toString() { [native code] }") + is(call(value.Object(), "hasOwnProperty", "hasOwnProperty"), false) + + is(call(value._object().get("toString")._object().prototype, "toString"), "function () { [native code] }") // TODO Is this right? + is(value._object().get("toString")._object().get("toString"), "function toString() { [native code] }") + is(value._object().get("toString")._object().get("toString")._object(), "function toString() { [native code] }") + + is(call(value._object(), "propertyIsEnumerable", "isPrototypeOf"), false) + value._object().put("xyzzy", toValue_string("Nothing happens."), false) + is(call(value, "propertyIsEnumerable", "isPrototypeOf"), false) + is(call(value, "propertyIsEnumerable", "xyzzy"), true) + is(value._object().get("xyzzy"), "Nothing happens.") + + is(call(runtime.scope.lexical.getBinding("Object", false), "isPrototypeOf", value), false) + is(call(runtime.scope.lexical.getBinding("Object", false)._object().get("prototype"), "isPrototypeOf", value), true) + is(call(runtime.scope.lexical.getBinding("Function", false), "isPrototypeOf", value), false) + + is(runtime.newObject().prototype == runtime.global.Object.get("prototype")._object(), true) + + abc := runtime.newBoolean(toValue_bool(true)) + is(toValue_object(abc), "true") // TODO Call primitive? + + //def := runtime.localGet("Boolean")._object().Construct(UndefinedValue(), []Value{}) + //is(def, "false") // TODO Call primitive? + } + } + + test(`new Number().constructor == Number`, true) + + test(`this.hasOwnProperty`, "function hasOwnProperty() { [native code] }") + + test(`eval.length === 1`, true) + test(`eval.prototype === undefined`, true) + test(`raise: new eval()`, "TypeError: function eval() { [native code] } is not a constructor") + + test(` + [ + [ delete undefined, undefined ], + [ delete NaN, NaN ], + [ delete Infinity, Infinity ], + ]; + `, "false,,false,NaN,false,Infinity") + + test(` + Object.getOwnPropertyNames(Function('return this')()).sort(); + `, "Array,Boolean,Date,Error,EvalError,Function,Infinity,JSON,Math,NaN,Number,Object,RangeError,ReferenceError,RegExp,String,SyntaxError,TypeError,URIError,console,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,escape,eval,isFinite,isNaN,parseFloat,parseInt,undefined,unescape") + + // __defineGetter__,__defineSetter__,__lookupGetter__,__lookupSetter__,constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf + test(` + Object.getOwnPropertyNames(Object.prototype).sort(); + `, "constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf") + + // arguments,caller,length,name,prototype + test(` + Object.getOwnPropertyNames(EvalError).sort(); + `, "length,prototype") + + test(` + var abc = []; + var def = [EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError]; + for (constructor in def) { + abc.push(def[constructor] === def[constructor].prototype.constructor); + } + def = [Array, Boolean, Date, Function, Number, Object, RegExp, String, SyntaxError]; + for (constructor in def) { + abc.push(def[constructor] === def[constructor].prototype.constructor); + } + abc; + `, "true,true,true,true,true,true,true,true,true,true,true,true,true,true,true") + + test(` + [ Array.prototype.constructor === Array, Array.constructor === Function ]; + `, "true,true") + + test(` + [ Number.prototype.constructor === Number, Number.constructor === Function ]; + `, "true,true") + + test(` + [ Function.prototype.constructor === Function, Function.constructor === Function ]; + `, "true,true") + }) +} + +func TestGlobalLength(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ Object.length, Function.length, RegExp.length, Math.length ]; + `, "1,1,2,") + }) +} + +func TestGlobalError(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ TypeError.length, TypeError(), TypeError("Nothing happens.") ]; + `, "1,TypeError,TypeError: Nothing happens.") + + test(` + [ URIError.length, URIError(), URIError("Nothing happens.") ]; + `, "1,URIError,URIError: Nothing happens.") + }) +} + +func TestGlobalReadOnly(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Number.POSITIVE_INFINITY`, math.Inf(1)) + + test(` + Number.POSITIVE_INFINITY = 1; + `, 1) + + test(`Number.POSITIVE_INFINITY`, math.Inf(1)) + + test(` + Number.POSITIVE_INFINITY = 1; + Number.POSITIVE_INFINITY; + `, math.Inf(1)) + }) +} + +func Test_isNaN(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`isNaN(0)`, false) + test(`isNaN("Xyzzy")`, true) + test(`isNaN()`, true) + test(`isNaN(NaN)`, true) + test(`isNaN(Infinity)`, false) + + test(`isNaN.length === 1`, true) + test(`isNaN.prototype === undefined`, true) + }) +} + +func Test_isFinite(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`isFinite(0)`, true) + test(`isFinite("Xyzzy")`, false) + test(`isFinite()`, false) + test(`isFinite(NaN)`, false) + test(`isFinite(Infinity)`, false) + test(`isFinite(new Number(451));`, true) + + test(`isFinite.length === 1`, true) + test(`isFinite.prototype === undefined`, true) + }) +} + +func Test_parseInt(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`parseInt("0")`, 0) + test(`parseInt("11")`, 11) + test(`parseInt(" 11")`, 11) + test(`parseInt("11 ")`, 11) + test(`parseInt(" 11 ")`, 11) + test(`parseInt(" 11\n")`, 11) + test(`parseInt(" 11\n", 16)`, 17) + + test(`parseInt("Xyzzy")`, _NaN) + + test(`parseInt(" 0x11\n", 16)`, 17) + test(`parseInt("0x0aXyzzy", 16)`, 10) + test(`parseInt("0x1", 0)`, 1) + test(`parseInt("0x10000000000000000000", 16)`, float64(75557863725914323419136)) + + test(`parseInt.length === 2`, true) + test(`parseInt.prototype === undefined`, true) + }) +} + +func Test_parseFloat(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`parseFloat("0")`, 0) + test(`parseFloat("11")`, 11) + test(`parseFloat(" 11")`, 11) + test(`parseFloat("11 ")`, 11) + test(`parseFloat(" 11 ")`, 11) + test(`parseFloat(" 11\n")`, 11) + test(`parseFloat(" 11\n", 16)`, 11) + test(`parseFloat("11.1")`, 11.1) + + test(`parseFloat("Xyzzy")`, _NaN) + + test(`parseFloat(" 0x11\n", 16)`, 0) + test(`parseFloat("0x0a")`, 0) + test(`parseFloat("0x0aXyzzy")`, 0) + test(`parseFloat("Infinity")`, _Infinity) + test(`parseFloat("infinity")`, _NaN) + test(`parseFloat("0x")`, 0) + test(`parseFloat("11x")`, 11) + test(`parseFloat("Infinity1")`, _Infinity) + + test(`parseFloat.length === 1`, true) + test(`parseFloat.prototype === undefined`, true) + }) +} + +func Test_encodeURI(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`encodeURI("http://example.com/ Nothing happens.")`, "http://example.com/%20Nothing%20happens.") + test(`encodeURI("http://example.com/ _^#")`, "http://example.com/%20_%5E#") + test(`encodeURI(String.fromCharCode("0xE000"))`, "%EE%80%80") + test(`encodeURI(String.fromCharCode("0xFFFD"))`, "%EF%BF%BD") + test(`raise: encodeURI(String.fromCharCode("0xDC00"))`, "URIError: URI malformed") + + test(`encodeURI.length === 1`, true) + test(`encodeURI.prototype === undefined`, true) + }) +} + +func Test_encodeURIComponent(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`encodeURIComponent("http://example.com/ Nothing happens.")`, "http%3A%2F%2Fexample.com%2F%20Nothing%20happens.") + test(`encodeURIComponent("http://example.com/ _^#")`, "http%3A%2F%2Fexample.com%2F%20_%5E%23") + }) +} + +func Test_decodeURI(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`decodeURI(encodeURI("http://example.com/ Nothing happens."))`, "http://example.com/ Nothing happens.") + test(`decodeURI(encodeURI("http://example.com/ _^#"))`, "http://example.com/ _^#") + test(`raise: decodeURI("http://example.com/ _^#%")`, "URIError: URI malformed") + test(`raise: decodeURI("%DF%7F")`, "URIError: URI malformed") + for _, check := range strings.Fields("+ %3B %2F %3F %3A %40 %26 %3D %2B %24 %2C %23") { + test(fmt.Sprintf(`decodeURI("%s")`, check), check) + } + + test(`decodeURI.length === 1`, true) + test(`decodeURI.prototype === undefined`, true) + }) +} + +func Test_decodeURIComponent(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`decodeURIComponent(encodeURI("http://example.com/ Nothing happens."))`, "http://example.com/ Nothing happens.") + test(`decodeURIComponent(encodeURI("http://example.com/ _^#"))`, "http://example.com/ _^#") + + test(`decodeURIComponent.length === 1`, true) + test(`decodeURIComponent.prototype === undefined`, true) + + test(` + var global = Function('return this')(); + var abc = Object.getOwnPropertyDescriptor(global, "decodeURIComponent"); + [ abc.value === global.decodeURIComponent, abc.writable, abc.enumerable, abc.configurable ]; + `, "true,true,false,true") + }) +} + +func TestGlobal_skipEnumeration(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var found = []; + for (var test in this) { + if (false || + test === 'NaN' || + test === 'undefined' || + test === 'Infinity' || + false) { + found.push(test) + } + } + found.length; + `, 0) + + test(` + var found = []; + for (var test in this) { + if (false || + test === 'Object' || + test === 'Function' || + test === 'String' || + test === 'Number' || + test === 'Array' || + test === 'Boolean' || + test === 'Date' || + test === 'RegExp' || + test === 'Error' || + test === 'EvalError' || + test === 'RangeError' || + test === 'ReferenceError' || + test === 'SyntaxError' || + test === 'TypeError' || + test === 'URIError' || + false) { + found.push(test) + } + } + found.length; + `, 0) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/inline b/Godeps/_workspace/src/github.com/robertkrimen/otto/inline new file mode 100644 index 0000000000..c3620b4a2b --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/inline @@ -0,0 +1,1086 @@ +#!/usr/bin/env perl + +my $_fmt; +$_fmt = "gofmt"; +$_fmt = "cat -n" if "cat" eq ($ARGV[0] || ""); + +use strict; +use warnings; +use IO::File; + +my $self = __PACKAGE__; + +sub functionLabel ($) { + return "$_[0]_function"; +} + +sub trim ($) { + local $_ = shift; + s/^\s*//, s/\s*$// for $_; + return $_; +} + +open my $fmt, "|-", "$_fmt" or die $!; + +$fmt->print(<<_END_); +package otto + +import ( + "math" +) + +func _newContext(runtime *_runtime) { +@{[ join "\n", $self->newContext() ]} +} + +func newConsoleObject(runtime *_runtime) *_object { +@{[ join "\n", $self->newConsoleObject() ]} +} +_END_ + +for (qw/int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 float32 float64/) { + $fmt->print(<<_END_); + +func toValue_$_(value $_) Value { + return Value{ + kind: valueNumber, + value: value, + } +} +_END_ +} + +$fmt->print(<<_END_); + +func toValue_string(value string) Value { + return Value{ + kind: valueString, + value: value, + } +} + +func toValue_string16(value []uint16) Value { + return Value{ + kind: valueString, + value: value, + } +} + +func toValue_bool(value bool) Value { + return Value{ + kind: valueBoolean, + value: value, + } +} + +func toValue_object(value *_object) Value { + return Value{ + kind: valueObject, + value: value, + } +} +_END_ + +close $fmt; + +sub newConsoleObject { + my $self = shift; + + return + $self->block(sub { + my $class = "Console"; + my @got = $self->functionDeclare( + $class, + "log", 0, + "debug:log", 0, + "info:log", 0, + "error", 0, + "warn:error", 0, + "dir", 0, + "time", 0, + "timeEnd", 0, + "trace", 0, + "assert", 0, + ); + return + "return @{[ $self->newObject(@got) ]}" + }), + ; +} + +sub newContext { + my $self = shift; + return + # ObjectPrototype + $self->block(sub { + my $class = "Object"; + return + ".${class}Prototype =", + $self->globalPrototype( + $class, + "_classObject", + undef, + "prototypeValueObject", + ), + }), + + # FunctionPrototype + $self->block(sub { + my $class = "Function"; + return + ".${class}Prototype =", + $self->globalPrototype( + $class, + "_classObject", + ".ObjectPrototype", + "prototypeValueFunction", + ), + }), + + # ObjectPrototype + $self->block(sub { + my $class = "Object"; + my @got = $self->functionDeclare( + $class, + "valueOf", 0, + "toString", 0, + "toLocaleString", 0, + "hasOwnProperty", 1, + "isPrototypeOf", 1, + "propertyIsEnumerable", 1, + ); + my @propertyMap = $self->propertyMap( + @got, + $self->property("constructor", undef), + ); + my $propertyOrder = $self->propertyOrder(@propertyMap); + $propertyOrder =~ s/^propertyOrder: //; + return + ".${class}Prototype.property =", @propertyMap, + ".${class}Prototype.propertyOrder =", $propertyOrder, + }), + + # FunctionPrototype + $self->block(sub { + my $class = "Function"; + my @got = $self->functionDeclare( + $class, + "toString", 0, + "apply", 2, + "call", 1, + "bind", 1, + ); + my @propertyMap = $self->propertyMap( + @got, + $self->property("constructor", undef), + $self->property("length", $self->numberValue(0), "0"), + ); + my $propertyOrder = $self->propertyOrder(@propertyMap); + $propertyOrder =~ s/^propertyOrder: //; + return + ".${class}Prototype.property =", @propertyMap, + ".${class}Prototype.propertyOrder =", $propertyOrder, + }), + + # Object + $self->block(sub { + my $class = "Object"; + return + ".$class =", + $self->globalFunction( + $class, + 1, + $self->functionDeclare( + $class, + "getPrototypeOf", 1, + "getOwnPropertyDescriptor", 2, + "defineProperty", 3, + "defineProperties", 2, + "create", 2, + "isExtensible", 1, + "preventExtensions", 1, + "isSealed", 1, + "seal", 1, + "isFrozen", 1, + "freeze", 1, + "keys", 1, + "getOwnPropertyNames", 1, + ), + ), + }), + + # Function + $self->block(sub { + my $class = "Function"; + return + "Function :=", + $self->globalFunction( + $class, + 1, + ), + ".$class = Function", + }), + + # Array + $self->block(sub { + my $class = "Array"; + my @got = $self->functionDeclare( + $class, + "toString", 0, + "toLocaleString", 0, + "concat", 1, + "join", 1, + "splice", 2, + "shift", 0, + "pop", 0, + "push", 1, + "slice", 2, + "unshift", 1, + "reverse", 0, + "sort", 1, + "indexOf", 1, + "lastIndexOf", 1, + "every", 1, + "some", 1, + "forEach", 1, + "map", 1, + "filter", 1, + "reduce", 1, + "reduceRight", 1, + ); + return + ".${class}Prototype =", + $self->globalPrototype( + $class, + "_classArray", + ".ObjectPrototype", + undef, + $self->property("length", $self->numberValue("uint32(0)"), "0100"), + @got, + ), + ".$class =", + $self->globalFunction( + $class, + 1, + $self->functionDeclare( + $class, + "isArray", 1, + ), + ), + }), + + # String + $self->block(sub { + my $class = "String"; + my @got = $self->functionDeclare( + $class, + "toString", 0, + "valueOf", 0, + "charAt", 1, + "charCodeAt", 1, + "concat", 1, + "indexOf", 1, + "lastIndexOf", 1, + "match", 1, + "replace", 2, + "search", 1, + "split", 2, + "slice", 2, + "substring", 2, + "toLowerCase", 0, + "toUpperCase", 0, + "substr", 2, + "trim", 0, + "trimLeft", 0, + "trimRight", 0, + "localeCompare", 1, + "toLocaleLowerCase", 0, + "toLocaleUpperCase", 0, + ); + return + ".${class}Prototype =", + $self->globalPrototype( + $class, + "_classString", + ".ObjectPrototype", + "prototypeValueString", + $self->property("length", $self->numberValue("int(0)"), "0"), + @got, + ), + ".$class =", + $self->globalFunction( + $class, + 1, + $self->functionDeclare( + $class, + "fromCharCode", 1, + ), + ), + }), + + # Boolean + $self->block(sub { + my $class = "Boolean"; + my @got = $self->functionDeclare( + $class, + "toString", 0, + "valueOf", 0, + ); + return + ".${class}Prototype =", + $self->globalPrototype( + $class, + "_classObject", + ".ObjectPrototype", + "prototypeValueBoolean", + @got, + ), + ".$class =", + $self->globalFunction( + $class, + 1, + $self->functionDeclare( + $class, + ), + ), + }), + + # Number + $self->block(sub { + my $class = "Number"; + my @got = $self->functionDeclare( + $class, + "toString", 0, + "valueOf", 0, + "toFixed", 1, + "toExponential", 1, + "toPrecision", 1, + "toLocaleString", 1, + ); + return + ".${class}Prototype =", + $self->globalPrototype( + $class, + "_classObject", + ".ObjectPrototype", + "prototypeValueNumber", + @got, + ), + ".$class =", + $self->globalFunction( + $class, + 1, + $self->functionDeclare( + $class, + ), + $self->numberConstantDeclare( + "MAX_VALUE", "math.MaxFloat64", + "MIN_VALUE", "math.SmallestNonzeroFloat64", + "NaN", "math.NaN()", + "NEGATIVE_INFINITY", "math.Inf(-1)", + "POSITIVE_INFINITY", "math.Inf(+1)", + ), + ), + }), + + # Math + $self->block(sub { + my $class = "Math"; + return + ".$class =", + $self->globalObject( + $class, + $self->functionDeclare( + $class, + "abs", 1, + "acos", 1, + "asin", 1, + "atan", 1, + "atan2", 1, + "ceil", 1, + "cos", 1, + "exp", 1, + "floor", 1, + "log", 1, + "max", 2, + "min", 2, + "pow", 2, + "random", 0, + "round", 1, + "sin", 1, + "sqrt", 1, + "tan", 1, + ), + $self->numberConstantDeclare( + "E", "math.E", + "LN10", "math.Ln10", + "LN2", "math.Ln2", + "LOG2E", "math.Log2E", + "LOG10E", "math.Log10E", + "PI", "math.Pi", + "SQRT1_2", "sqrt1_2", + "SQRT2", "math.Sqrt2", + ) + ), + }), + + # Date + $self->block(sub { + my $class = "Date"; + my @got = $self->functionDeclare( + $class, + "toString", 0, + "toDateString", 0, + "toTimeString", 0, + "toUTCString", 0, + "toISOString", 0, + "toJSON", 1, + "toGMTString", 0, + "toLocaleString", 0, + "toLocaleDateString", 0, + "toLocaleTimeString", 0, + "valueOf", 0, + "getTime", 0, + "getYear", 0, + "getFullYear", 0, + "getUTCFullYear", 0, + "getMonth", 0, + "getUTCMonth", 0, + "getDate", 0, + "getUTCDate", 0, + "getDay", 0, + "getUTCDay", 0, + "getHours", 0, + "getUTCHours", 0, + "getMinutes", 0, + "getUTCMinutes", 0, + "getSeconds", 0, + "getUTCSeconds", 0, + "getMilliseconds", 0, + "getUTCMilliseconds", 0, + "getTimezoneOffset", 0, + "setTime", 1, + "setMilliseconds", 1, + "setUTCMilliseconds", 1, + "setSeconds", 2, + "setUTCSeconds", 2, + "setMinutes", 3, + "setUTCMinutes", 3, + "setHours", 4, + "setUTCHours", 4, + "setDate", 1, + "setUTCDate", 1, + "setMonth", 2, + "setUTCMonth", 2, + "setYear", 1, + "setFullYear", 3, + "setUTCFullYear", 3, + ); + return + ".${class}Prototype =", + $self->globalPrototype( + $class, + "_classObject", + ".ObjectPrototype", + "prototypeValueDate", + @got, + ), + ".$class =", + $self->globalFunction( + $class, + 7, + $self->functionDeclare( + $class, + "parse", 1, + "UTC", 7, + "now", 0, + ), + ), + }), + + # RegExp + $self->block(sub { + my $class = "RegExp"; + my @got = $self->functionDeclare( + $class, + "toString", 0, + "exec", 1, + "test", 1, + "compile", 1, + ); + return + ".${class}Prototype =", + $self->globalPrototype( + $class, + "_classObject", + ".ObjectPrototype", + "prototypeValueRegExp", + @got, + ), + ".$class =", + $self->globalFunction( + $class, + 2, + $self->functionDeclare( + $class, + ), + ), + }), + + # Error + $self->block(sub { + my $class = "Error"; + my @got = $self->functionDeclare( + $class, + "toString", 0, + ); + return + ".${class}Prototype =", + $self->globalPrototype( + $class, + "_classObject", + ".ObjectPrototype", + undef, + @got, + $self->property("name", $self->stringValue("Error")), + $self->property("message", $self->stringValue("")), + ), + ".$class =", + $self->globalFunction( + $class, + 1, + $self->functionDeclare( + $class, + ), + ), + }), + + (map { + my $class = "${_}Error"; + $self->block(sub { + my @got = $self->functionDeclare( + $class, + ); + return + ".${class}Prototype =", + $self->globalPrototype( + $class, + "_classObject", + ".ErrorPrototype", + undef, + @got, + $self->property("name", $self->stringValue($class)), + ), + ".$class =", + $self->globalFunction( + $class, + 1, + $self->functionDeclare( + $class, + ), + ), + }); + } qw/Eval Type Range Reference Syntax URI/), + + # JSON + $self->block(sub { + my $class = "JSON"; + return + ".$class =", + $self->globalObject( + $class, + $self->functionDeclare( + $class, + "parse", 2, + "stringify", 3, + ), + ), + }), + + # Global + $self->block(sub { + my $class = "Global"; + my @got = $self->functionDeclare( + $class, + "eval", 1, + "parseInt", 2, + "parseFloat", 1, + "isNaN", 1, + "isFinite", 1, + "decodeURI", 1, + "decodeURIComponent", 1, + "encodeURI", 1, + "encodeURIComponent", 1, + "escape", 1, + "unescape", 1, + ); + my @propertyMap = $self->propertyMap( + @got, + $self->globalDeclare( + "Object", + "Function", + "Array", + "String", + "Boolean", + "Number", + "Math", + "Date", + "RegExp", + "Error", + "EvalError", + "TypeError", + "RangeError", + "ReferenceError", + "SyntaxError", + "URIError", + "JSON", + ), + $self->property("undefined", $self->undefinedValue(), "0"), + $self->property("NaN", $self->numberValue("math.NaN()"), "0"), + $self->property("Infinity", $self->numberValue("math.Inf(+1)"), "0"), + ); + my $propertyOrder = $self->propertyOrder(@propertyMap); + $propertyOrder =~ s/^propertyOrder: //; + return + "runtime.globalObject.property =", + @propertyMap, + "runtime.globalObject.propertyOrder =", + $propertyOrder, + ; + }), + ; +} + +sub propertyMap { + my $self = shift; + return "map[string]_property{", (join ",\n", @_, ""), "}", +} + +our (@preblock, @postblock); +sub block { + my $self = shift; + local @preblock = (); + local @postblock = (); + my @input = $_[0]->(); + my @output; + while (@input) { + local $_ = shift @input; + if (m/^\./) { + $_ = "runtime.global$_"; + } + if (m/ :?=$/) { + $_ .= shift @input; + } + push @output, $_; + } + return + "{", + @preblock, + @output, + @postblock, + "}", + ; +} + +sub numberConstantDeclare { + my $self = shift; + my @got; + while (@_) { + my $name = shift; + my $value = shift; + push @got, $self->property($name, $self->numberValue($value), "0"), + } + return @got; +} + +sub functionDeclare { + my $self = shift; + my $class = shift; + my $builtin = "builtin${class}"; + my @got; + while (@_) { + my $name = shift; + my $length = shift; + $name = $self->newFunction($name, "${builtin}_", $length); + push @got, $self->functionProperty($name), + } + return @got; +} + +sub globalDeclare { + my $self = shift; + my @got; + while (@_) { + my $name = shift; + push @got, $self->property($name, $self->objectValue("runtime.global.$name"), "0101"), + } + return @got; +} + +sub propertyOrder { + my $self = shift; + my $propertyMap = join "", @_; + + my (@keys) = $propertyMap =~ m/("\w+"):/g; + my $propertyOrder = + join "\n", "propertyOrder: []string{", (join ",\n", @keys, ""), "}"; + return $propertyOrder; +} + +sub globalObject { + my $self = shift; + my $name = shift; + + my $propertyMap = ""; + if (@_) { + $propertyMap = join "\n", $self->propertyMap(@_); + my $propertyOrder = $self->propertyOrder($propertyMap); + $propertyMap = "property: $propertyMap,\n$propertyOrder,"; + } + + return trim <<_END_; +&_object{ + runtime: runtime, + class: "$name", + objectClass: _classObject, + prototype: runtime.global.ObjectPrototype, + extensible: true, + $propertyMap +} +_END_ +} + +sub globalFunction { + my $self = shift; + my $name = shift; + my $length = shift; + + my $builtin = "builtin${name}"; + my $builtinNew = "builtinNew${name}"; + my $prototype = "runtime.global.${name}Prototype"; + my $propertyMap = ""; + unshift @_, + $self->property("length", $self->numberValue($length), "0"), + $self->property("prototype", $self->objectValue($prototype), "0"), + ; + + if (@_) { + $propertyMap = join "\n", $self->propertyMap(@_); + my $propertyOrder = $self->propertyOrder($propertyMap); + $propertyMap = "property: $propertyMap,\n$propertyOrder,"; + } + + push @postblock, $self->statement( + "$prototype.property[\"constructor\"] =", + $self->property(undef, $self->objectValue("runtime.global.${name}"), "0101"), + ); + + return trim <<_END_; +&_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: @{[ $self->nativeFunctionOf($name, $builtin, $builtinNew) ]}, + $propertyMap +} +_END_ +} + +sub nativeCallFunction { + my $self = shift; + my $name = shift; + my $func = shift; + return trim <<_END_; +_nativeCallFunction{ "$name", $func } +_END_ +} + +sub globalPrototype { + my $self = shift; + my $class = shift; + my $classObject = shift; + my $prototype = shift; + my $value = shift; + + if (!defined $prototype) { + $prototype = "nil"; + } + + if (!defined $value) { + $value = "nil"; + } + + if ($prototype =~ m/^\./) { + $prototype = "runtime.global$prototype"; + } + + my $propertyMap = ""; + if (@_) { + $propertyMap = join "\n", $self->propertyMap(@_); + my $propertyOrder = $self->propertyOrder($propertyMap); + $propertyMap = "property: $propertyMap,\n$propertyOrder,"; + } + + return trim <<_END_; +&_object{ + runtime: runtime, + class: "$class", + objectClass: $classObject, + prototype: $prototype, + extensible: true, + value: $value, + $propertyMap +} +_END_ +} + +sub newFunction { + my $self = shift; + my $name = shift; + my $func = shift; + my $length = shift; + + my @name = ($name, $name); + if ($name =~ m/^(\w+):(\w+)$/) { + @name = ($1, $2); + $name = $name[0]; + } + + if ($func =~ m/^builtin\w+_$/) { + $func = "$func$name[1]"; + } + + my $propertyOrder = ""; + my @propertyMap = ( + $self->property("length", $self->numberValue($length), "0"), + ); + + if (@propertyMap) { + $propertyOrder = $self->propertyOrder(@propertyMap); + $propertyOrder = "$propertyOrder,"; + } + + my $label = functionLabel($name); + push @preblock, $self->statement( + "$label := @{[ trim <<_END_ ]}", +&_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: @{[ join "\n", $self->propertyMap(@propertyMap) ]}, + $propertyOrder + value: @{[ $self->nativeFunctionOf($name, $func) ]}, +} +_END_ + ); + + return $name; +} + +sub newObject { + my $self = shift; + + my $propertyMap = join "\n", $self->propertyMap(@_); + my $propertyOrder = $self->propertyOrder($propertyMap); + + return trim <<_END_; +&_object{ + runtime: runtime, + class: "Object", + objectClass: _classObject, + prototype: runtime.global.ObjectPrototype, + extensible: true, + property: $propertyMap, + $propertyOrder, +} +_END_ +} + +sub newPrototypeObject { + my $self = shift; + my $class = shift; + my $objectClass = shift; + my $value = shift; + if (defined $value) { + $value = "value: $value,"; + } + + my $propertyMap = join "\n", $self->propertyMap(@_); + my $propertyOrder = $self->propertyOrder($propertyMap); + + return trim <<_END_; +&_object{ + runtime: runtime, + class: "$class", + objectClass: $objectClass, + prototype: runtime.global.ObjectPrototype, + extensible: true, + property: $propertyMap, + $propertyOrder, + $value +} +_END_ +} + +sub functionProperty { + my $self = shift; + my $name = shift; + + return $self->property( + $name, + $self->objectValue(functionLabel($name)) + ); +} + +sub statement { + my $self = shift; + return join "\n", @_; +} + +sub functionOf { + my $self = shift; + my $call = shift; + my $construct = shift; + if ($construct) { + $construct = "construct: $construct,"; + } else { + $construct = ""; + } + + return trim <<_END_ +_functionObject{ + call: $call, + $construct +} +_END_ +} + +sub nativeFunctionOf { + my $self = shift; + my $name = shift; + my $call = shift; + my $construct = shift; + if ($construct) { + $construct = "construct: $construct,"; + } else { + $construct = ""; + } + + return trim <<_END_ +_nativeFunctionObject{ + name: "$name", + call: $call, + $construct +} +_END_ +} + +sub nameProperty { + my $self = shift; + my $name = shift; + my $value = shift; + + return trim <<_END_; +"$name": _property{ + mode: 0101, + value: $value, +} +_END_ +} + +sub numberValue { + my $self = shift; + my $value = shift; + return trim <<_END_; +Value{ + kind: valueNumber, + value: $value, +} +_END_ +} + +sub property { + my $self = shift; + my $name = shift; + my $value = shift; + my $mode = shift; + $mode = "0101" unless defined $mode; + if (! defined $value) { + $value = "Value{}"; + } + if (defined $name) { + return trim <<_END_; +"$name": _property{ + mode: $mode, + value: $value, +} +_END_ + } else { + return trim <<_END_; +_property{ + mode: $mode, + value: $value, +} +_END_ + } + +} + +sub objectProperty { + my $self = shift; + my $name = shift; + my $value = shift; + + return trim <<_END_; +"$name": _property{ + mode: 0101, + value: @{[ $self->objectValue($value)]}, +} +_END_ +} + +sub objectValue { + my $self = shift; + my $value = shift; + return trim <<_END_ +Value{ + kind: valueObject, + value: $value, +} +_END_ +} + +sub stringValue { + my $self = shift; + my $value = shift; + return trim <<_END_ +Value{ + kind: valueString, + value: "$value", +} +_END_ +} + +sub booleanValue { + my $self = shift; + my $value = shift; + return trim <<_END_ +Value{ + kind: valueBoolean, + value: $value, +} +_END_ +} + +sub undefinedValue { + my $self = shift; + return trim <<_END_ +Value{ + kind: valueUndefined, +} +_END_ +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/inline.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/inline.go new file mode 100644 index 0000000000..6e5df8393e --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/inline.go @@ -0,0 +1,6649 @@ +package otto + +import ( + "math" +) + +func _newContext(runtime *_runtime) { + { + runtime.global.ObjectPrototype = &_object{ + runtime: runtime, + class: "Object", + objectClass: _classObject, + prototype: nil, + extensible: true, + value: prototypeValueObject, + } + } + { + runtime.global.FunctionPrototype = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.ObjectPrototype, + extensible: true, + value: prototypeValueFunction, + } + } + { + valueOf_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "valueOf", + call: builtinObject_valueOf, + }, + } + toString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toString", + call: builtinObject_toString, + }, + } + toLocaleString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toLocaleString", + call: builtinObject_toLocaleString, + }, + } + hasOwnProperty_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "hasOwnProperty", + call: builtinObject_hasOwnProperty, + }, + } + isPrototypeOf_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "isPrototypeOf", + call: builtinObject_isPrototypeOf, + }, + } + propertyIsEnumerable_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "propertyIsEnumerable", + call: builtinObject_propertyIsEnumerable, + }, + } + runtime.global.ObjectPrototype.property = map[string]_property{ + "valueOf": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: valueOf_function, + }, + }, + "toString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toString_function, + }, + }, + "toLocaleString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toLocaleString_function, + }, + }, + "hasOwnProperty": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: hasOwnProperty_function, + }, + }, + "isPrototypeOf": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: isPrototypeOf_function, + }, + }, + "propertyIsEnumerable": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: propertyIsEnumerable_function, + }, + }, + "constructor": _property{ + mode: 0101, + value: Value{}, + }, + } + runtime.global.ObjectPrototype.propertyOrder = []string{ + "valueOf", + "toString", + "toLocaleString", + "hasOwnProperty", + "isPrototypeOf", + "propertyIsEnumerable", + "constructor", + } + } + { + toString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toString", + call: builtinFunction_toString, + }, + } + apply_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "apply", + call: builtinFunction_apply, + }, + } + call_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "call", + call: builtinFunction_call, + }, + } + bind_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "bind", + call: builtinFunction_bind, + }, + } + runtime.global.FunctionPrototype.property = map[string]_property{ + "toString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toString_function, + }, + }, + "apply": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: apply_function, + }, + }, + "call": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: call_function, + }, + }, + "bind": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: bind_function, + }, + }, + "constructor": _property{ + mode: 0101, + value: Value{}, + }, + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + } + runtime.global.FunctionPrototype.propertyOrder = []string{ + "toString", + "apply", + "call", + "bind", + "constructor", + "length", + } + } + { + getPrototypeOf_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getPrototypeOf", + call: builtinObject_getPrototypeOf, + }, + } + getOwnPropertyDescriptor_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getOwnPropertyDescriptor", + call: builtinObject_getOwnPropertyDescriptor, + }, + } + defineProperty_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 3, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "defineProperty", + call: builtinObject_defineProperty, + }, + } + defineProperties_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "defineProperties", + call: builtinObject_defineProperties, + }, + } + create_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "create", + call: builtinObject_create, + }, + } + isExtensible_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "isExtensible", + call: builtinObject_isExtensible, + }, + } + preventExtensions_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "preventExtensions", + call: builtinObject_preventExtensions, + }, + } + isSealed_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "isSealed", + call: builtinObject_isSealed, + }, + } + seal_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "seal", + call: builtinObject_seal, + }, + } + isFrozen_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "isFrozen", + call: builtinObject_isFrozen, + }, + } + freeze_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "freeze", + call: builtinObject_freeze, + }, + } + keys_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "keys", + call: builtinObject_keys, + }, + } + getOwnPropertyNames_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getOwnPropertyNames", + call: builtinObject_getOwnPropertyNames, + }, + } + runtime.global.Object = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "Object", + call: builtinObject, + construct: builtinNewObject, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.ObjectPrototype, + }, + }, + "getPrototypeOf": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getPrototypeOf_function, + }, + }, + "getOwnPropertyDescriptor": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getOwnPropertyDescriptor_function, + }, + }, + "defineProperty": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: defineProperty_function, + }, + }, + "defineProperties": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: defineProperties_function, + }, + }, + "create": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: create_function, + }, + }, + "isExtensible": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: isExtensible_function, + }, + }, + "preventExtensions": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: preventExtensions_function, + }, + }, + "isSealed": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: isSealed_function, + }, + }, + "seal": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: seal_function, + }, + }, + "isFrozen": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: isFrozen_function, + }, + }, + "freeze": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: freeze_function, + }, + }, + "keys": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: keys_function, + }, + }, + "getOwnPropertyNames": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getOwnPropertyNames_function, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + "getPrototypeOf", + "getOwnPropertyDescriptor", + "defineProperty", + "defineProperties", + "create", + "isExtensible", + "preventExtensions", + "isSealed", + "seal", + "isFrozen", + "freeze", + "keys", + "getOwnPropertyNames", + }, + } + runtime.global.ObjectPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Object, + }, + } + } + { + Function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "Function", + call: builtinFunction, + construct: builtinNewFunction, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.FunctionPrototype, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + }, + } + runtime.global.Function = Function + runtime.global.FunctionPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Function, + }, + } + } + { + toString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toString", + call: builtinArray_toString, + }, + } + toLocaleString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toLocaleString", + call: builtinArray_toLocaleString, + }, + } + concat_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "concat", + call: builtinArray_concat, + }, + } + join_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "join", + call: builtinArray_join, + }, + } + splice_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "splice", + call: builtinArray_splice, + }, + } + shift_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "shift", + call: builtinArray_shift, + }, + } + pop_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "pop", + call: builtinArray_pop, + }, + } + push_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "push", + call: builtinArray_push, + }, + } + slice_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "slice", + call: builtinArray_slice, + }, + } + unshift_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "unshift", + call: builtinArray_unshift, + }, + } + reverse_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "reverse", + call: builtinArray_reverse, + }, + } + sort_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "sort", + call: builtinArray_sort, + }, + } + indexOf_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "indexOf", + call: builtinArray_indexOf, + }, + } + lastIndexOf_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "lastIndexOf", + call: builtinArray_lastIndexOf, + }, + } + every_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "every", + call: builtinArray_every, + }, + } + some_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "some", + call: builtinArray_some, + }, + } + forEach_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "forEach", + call: builtinArray_forEach, + }, + } + map_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "map", + call: builtinArray_map, + }, + } + filter_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "filter", + call: builtinArray_filter, + }, + } + reduce_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "reduce", + call: builtinArray_reduce, + }, + } + reduceRight_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "reduceRight", + call: builtinArray_reduceRight, + }, + } + isArray_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "isArray", + call: builtinArray_isArray, + }, + } + runtime.global.ArrayPrototype = &_object{ + runtime: runtime, + class: "Array", + objectClass: _classArray, + prototype: runtime.global.ObjectPrototype, + extensible: true, + value: nil, + property: map[string]_property{ + "length": _property{ + mode: 0100, + value: Value{ + kind: valueNumber, + value: uint32(0), + }, + }, + "toString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toString_function, + }, + }, + "toLocaleString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toLocaleString_function, + }, + }, + "concat": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: concat_function, + }, + }, + "join": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: join_function, + }, + }, + "splice": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: splice_function, + }, + }, + "shift": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: shift_function, + }, + }, + "pop": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: pop_function, + }, + }, + "push": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: push_function, + }, + }, + "slice": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: slice_function, + }, + }, + "unshift": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: unshift_function, + }, + }, + "reverse": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: reverse_function, + }, + }, + "sort": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: sort_function, + }, + }, + "indexOf": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: indexOf_function, + }, + }, + "lastIndexOf": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: lastIndexOf_function, + }, + }, + "every": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: every_function, + }, + }, + "some": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: some_function, + }, + }, + "forEach": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: forEach_function, + }, + }, + "map": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: map_function, + }, + }, + "filter": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: filter_function, + }, + }, + "reduce": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: reduce_function, + }, + }, + "reduceRight": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: reduceRight_function, + }, + }, + }, + propertyOrder: []string{ + "length", + "toString", + "toLocaleString", + "concat", + "join", + "splice", + "shift", + "pop", + "push", + "slice", + "unshift", + "reverse", + "sort", + "indexOf", + "lastIndexOf", + "every", + "some", + "forEach", + "map", + "filter", + "reduce", + "reduceRight", + }, + } + runtime.global.Array = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "Array", + call: builtinArray, + construct: builtinNewArray, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.ArrayPrototype, + }, + }, + "isArray": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: isArray_function, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + "isArray", + }, + } + runtime.global.ArrayPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Array, + }, + } + } + { + toString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toString", + call: builtinString_toString, + }, + } + valueOf_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "valueOf", + call: builtinString_valueOf, + }, + } + charAt_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "charAt", + call: builtinString_charAt, + }, + } + charCodeAt_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "charCodeAt", + call: builtinString_charCodeAt, + }, + } + concat_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "concat", + call: builtinString_concat, + }, + } + indexOf_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "indexOf", + call: builtinString_indexOf, + }, + } + lastIndexOf_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "lastIndexOf", + call: builtinString_lastIndexOf, + }, + } + match_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "match", + call: builtinString_match, + }, + } + replace_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "replace", + call: builtinString_replace, + }, + } + search_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "search", + call: builtinString_search, + }, + } + split_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "split", + call: builtinString_split, + }, + } + slice_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "slice", + call: builtinString_slice, + }, + } + substring_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "substring", + call: builtinString_substring, + }, + } + toLowerCase_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toLowerCase", + call: builtinString_toLowerCase, + }, + } + toUpperCase_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toUpperCase", + call: builtinString_toUpperCase, + }, + } + substr_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "substr", + call: builtinString_substr, + }, + } + trim_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "trim", + call: builtinString_trim, + }, + } + trimLeft_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "trimLeft", + call: builtinString_trimLeft, + }, + } + trimRight_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "trimRight", + call: builtinString_trimRight, + }, + } + localeCompare_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "localeCompare", + call: builtinString_localeCompare, + }, + } + toLocaleLowerCase_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toLocaleLowerCase", + call: builtinString_toLocaleLowerCase, + }, + } + toLocaleUpperCase_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toLocaleUpperCase", + call: builtinString_toLocaleUpperCase, + }, + } + fromCharCode_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "fromCharCode", + call: builtinString_fromCharCode, + }, + } + runtime.global.StringPrototype = &_object{ + runtime: runtime, + class: "String", + objectClass: _classString, + prototype: runtime.global.ObjectPrototype, + extensible: true, + value: prototypeValueString, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: int(0), + }, + }, + "toString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toString_function, + }, + }, + "valueOf": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: valueOf_function, + }, + }, + "charAt": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: charAt_function, + }, + }, + "charCodeAt": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: charCodeAt_function, + }, + }, + "concat": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: concat_function, + }, + }, + "indexOf": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: indexOf_function, + }, + }, + "lastIndexOf": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: lastIndexOf_function, + }, + }, + "match": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: match_function, + }, + }, + "replace": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: replace_function, + }, + }, + "search": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: search_function, + }, + }, + "split": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: split_function, + }, + }, + "slice": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: slice_function, + }, + }, + "substring": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: substring_function, + }, + }, + "toLowerCase": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toLowerCase_function, + }, + }, + "toUpperCase": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toUpperCase_function, + }, + }, + "substr": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: substr_function, + }, + }, + "trim": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: trim_function, + }, + }, + "trimLeft": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: trimLeft_function, + }, + }, + "trimRight": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: trimRight_function, + }, + }, + "localeCompare": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: localeCompare_function, + }, + }, + "toLocaleLowerCase": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toLocaleLowerCase_function, + }, + }, + "toLocaleUpperCase": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toLocaleUpperCase_function, + }, + }, + }, + propertyOrder: []string{ + "length", + "toString", + "valueOf", + "charAt", + "charCodeAt", + "concat", + "indexOf", + "lastIndexOf", + "match", + "replace", + "search", + "split", + "slice", + "substring", + "toLowerCase", + "toUpperCase", + "substr", + "trim", + "trimLeft", + "trimRight", + "localeCompare", + "toLocaleLowerCase", + "toLocaleUpperCase", + }, + } + runtime.global.String = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "String", + call: builtinString, + construct: builtinNewString, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.StringPrototype, + }, + }, + "fromCharCode": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: fromCharCode_function, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + "fromCharCode", + }, + } + runtime.global.StringPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.String, + }, + } + } + { + toString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toString", + call: builtinBoolean_toString, + }, + } + valueOf_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "valueOf", + call: builtinBoolean_valueOf, + }, + } + runtime.global.BooleanPrototype = &_object{ + runtime: runtime, + class: "Boolean", + objectClass: _classObject, + prototype: runtime.global.ObjectPrototype, + extensible: true, + value: prototypeValueBoolean, + property: map[string]_property{ + "toString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toString_function, + }, + }, + "valueOf": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: valueOf_function, + }, + }, + }, + propertyOrder: []string{ + "toString", + "valueOf", + }, + } + runtime.global.Boolean = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "Boolean", + call: builtinBoolean, + construct: builtinNewBoolean, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.BooleanPrototype, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + }, + } + runtime.global.BooleanPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Boolean, + }, + } + } + { + toString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toString", + call: builtinNumber_toString, + }, + } + valueOf_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "valueOf", + call: builtinNumber_valueOf, + }, + } + toFixed_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toFixed", + call: builtinNumber_toFixed, + }, + } + toExponential_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toExponential", + call: builtinNumber_toExponential, + }, + } + toPrecision_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toPrecision", + call: builtinNumber_toPrecision, + }, + } + toLocaleString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toLocaleString", + call: builtinNumber_toLocaleString, + }, + } + runtime.global.NumberPrototype = &_object{ + runtime: runtime, + class: "Number", + objectClass: _classObject, + prototype: runtime.global.ObjectPrototype, + extensible: true, + value: prototypeValueNumber, + property: map[string]_property{ + "toString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toString_function, + }, + }, + "valueOf": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: valueOf_function, + }, + }, + "toFixed": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toFixed_function, + }, + }, + "toExponential": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toExponential_function, + }, + }, + "toPrecision": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toPrecision_function, + }, + }, + "toLocaleString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toLocaleString_function, + }, + }, + }, + propertyOrder: []string{ + "toString", + "valueOf", + "toFixed", + "toExponential", + "toPrecision", + "toLocaleString", + }, + } + runtime.global.Number = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "Number", + call: builtinNumber, + construct: builtinNewNumber, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.NumberPrototype, + }, + }, + "MAX_VALUE": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.MaxFloat64, + }, + }, + "MIN_VALUE": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.SmallestNonzeroFloat64, + }, + }, + "NaN": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.NaN(), + }, + }, + "NEGATIVE_INFINITY": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.Inf(-1), + }, + }, + "POSITIVE_INFINITY": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.Inf(+1), + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + "MAX_VALUE", + "MIN_VALUE", + "NaN", + "NEGATIVE_INFINITY", + "POSITIVE_INFINITY", + }, + } + runtime.global.NumberPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Number, + }, + } + } + { + abs_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "abs", + call: builtinMath_abs, + }, + } + acos_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "acos", + call: builtinMath_acos, + }, + } + asin_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "asin", + call: builtinMath_asin, + }, + } + atan_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "atan", + call: builtinMath_atan, + }, + } + atan2_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "atan2", + call: builtinMath_atan2, + }, + } + ceil_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "ceil", + call: builtinMath_ceil, + }, + } + cos_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "cos", + call: builtinMath_cos, + }, + } + exp_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "exp", + call: builtinMath_exp, + }, + } + floor_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "floor", + call: builtinMath_floor, + }, + } + log_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "log", + call: builtinMath_log, + }, + } + max_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "max", + call: builtinMath_max, + }, + } + min_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "min", + call: builtinMath_min, + }, + } + pow_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "pow", + call: builtinMath_pow, + }, + } + random_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "random", + call: builtinMath_random, + }, + } + round_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "round", + call: builtinMath_round, + }, + } + sin_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "sin", + call: builtinMath_sin, + }, + } + sqrt_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "sqrt", + call: builtinMath_sqrt, + }, + } + tan_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "tan", + call: builtinMath_tan, + }, + } + runtime.global.Math = &_object{ + runtime: runtime, + class: "Math", + objectClass: _classObject, + prototype: runtime.global.ObjectPrototype, + extensible: true, + property: map[string]_property{ + "abs": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: abs_function, + }, + }, + "acos": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: acos_function, + }, + }, + "asin": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: asin_function, + }, + }, + "atan": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: atan_function, + }, + }, + "atan2": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: atan2_function, + }, + }, + "ceil": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: ceil_function, + }, + }, + "cos": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: cos_function, + }, + }, + "exp": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: exp_function, + }, + }, + "floor": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: floor_function, + }, + }, + "log": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: log_function, + }, + }, + "max": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: max_function, + }, + }, + "min": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: min_function, + }, + }, + "pow": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: pow_function, + }, + }, + "random": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: random_function, + }, + }, + "round": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: round_function, + }, + }, + "sin": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: sin_function, + }, + }, + "sqrt": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: sqrt_function, + }, + }, + "tan": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: tan_function, + }, + }, + "E": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.E, + }, + }, + "LN10": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.Ln10, + }, + }, + "LN2": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.Ln2, + }, + }, + "LOG2E": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.Log2E, + }, + }, + "LOG10E": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.Log10E, + }, + }, + "PI": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.Pi, + }, + }, + "SQRT1_2": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: sqrt1_2, + }, + }, + "SQRT2": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.Sqrt2, + }, + }, + }, + propertyOrder: []string{ + "abs", + "acos", + "asin", + "atan", + "atan2", + "ceil", + "cos", + "exp", + "floor", + "log", + "max", + "min", + "pow", + "random", + "round", + "sin", + "sqrt", + "tan", + "E", + "LN10", + "LN2", + "LOG2E", + "LOG10E", + "PI", + "SQRT1_2", + "SQRT2", + }, + } + } + { + toString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toString", + call: builtinDate_toString, + }, + } + toDateString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toDateString", + call: builtinDate_toDateString, + }, + } + toTimeString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toTimeString", + call: builtinDate_toTimeString, + }, + } + toUTCString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toUTCString", + call: builtinDate_toUTCString, + }, + } + toISOString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toISOString", + call: builtinDate_toISOString, + }, + } + toJSON_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toJSON", + call: builtinDate_toJSON, + }, + } + toGMTString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toGMTString", + call: builtinDate_toGMTString, + }, + } + toLocaleString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toLocaleString", + call: builtinDate_toLocaleString, + }, + } + toLocaleDateString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toLocaleDateString", + call: builtinDate_toLocaleDateString, + }, + } + toLocaleTimeString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toLocaleTimeString", + call: builtinDate_toLocaleTimeString, + }, + } + valueOf_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "valueOf", + call: builtinDate_valueOf, + }, + } + getTime_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getTime", + call: builtinDate_getTime, + }, + } + getYear_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getYear", + call: builtinDate_getYear, + }, + } + getFullYear_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getFullYear", + call: builtinDate_getFullYear, + }, + } + getUTCFullYear_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getUTCFullYear", + call: builtinDate_getUTCFullYear, + }, + } + getMonth_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getMonth", + call: builtinDate_getMonth, + }, + } + getUTCMonth_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getUTCMonth", + call: builtinDate_getUTCMonth, + }, + } + getDate_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getDate", + call: builtinDate_getDate, + }, + } + getUTCDate_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getUTCDate", + call: builtinDate_getUTCDate, + }, + } + getDay_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getDay", + call: builtinDate_getDay, + }, + } + getUTCDay_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getUTCDay", + call: builtinDate_getUTCDay, + }, + } + getHours_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getHours", + call: builtinDate_getHours, + }, + } + getUTCHours_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getUTCHours", + call: builtinDate_getUTCHours, + }, + } + getMinutes_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getMinutes", + call: builtinDate_getMinutes, + }, + } + getUTCMinutes_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getUTCMinutes", + call: builtinDate_getUTCMinutes, + }, + } + getSeconds_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getSeconds", + call: builtinDate_getSeconds, + }, + } + getUTCSeconds_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getUTCSeconds", + call: builtinDate_getUTCSeconds, + }, + } + getMilliseconds_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getMilliseconds", + call: builtinDate_getMilliseconds, + }, + } + getUTCMilliseconds_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getUTCMilliseconds", + call: builtinDate_getUTCMilliseconds, + }, + } + getTimezoneOffset_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "getTimezoneOffset", + call: builtinDate_getTimezoneOffset, + }, + } + setTime_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setTime", + call: builtinDate_setTime, + }, + } + setMilliseconds_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setMilliseconds", + call: builtinDate_setMilliseconds, + }, + } + setUTCMilliseconds_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setUTCMilliseconds", + call: builtinDate_setUTCMilliseconds, + }, + } + setSeconds_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setSeconds", + call: builtinDate_setSeconds, + }, + } + setUTCSeconds_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setUTCSeconds", + call: builtinDate_setUTCSeconds, + }, + } + setMinutes_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 3, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setMinutes", + call: builtinDate_setMinutes, + }, + } + setUTCMinutes_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 3, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setUTCMinutes", + call: builtinDate_setUTCMinutes, + }, + } + setHours_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 4, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setHours", + call: builtinDate_setHours, + }, + } + setUTCHours_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 4, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setUTCHours", + call: builtinDate_setUTCHours, + }, + } + setDate_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setDate", + call: builtinDate_setDate, + }, + } + setUTCDate_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setUTCDate", + call: builtinDate_setUTCDate, + }, + } + setMonth_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setMonth", + call: builtinDate_setMonth, + }, + } + setUTCMonth_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setUTCMonth", + call: builtinDate_setUTCMonth, + }, + } + setYear_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setYear", + call: builtinDate_setYear, + }, + } + setFullYear_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 3, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setFullYear", + call: builtinDate_setFullYear, + }, + } + setUTCFullYear_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 3, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "setUTCFullYear", + call: builtinDate_setUTCFullYear, + }, + } + parse_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "parse", + call: builtinDate_parse, + }, + } + UTC_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 7, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "UTC", + call: builtinDate_UTC, + }, + } + now_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "now", + call: builtinDate_now, + }, + } + runtime.global.DatePrototype = &_object{ + runtime: runtime, + class: "Date", + objectClass: _classObject, + prototype: runtime.global.ObjectPrototype, + extensible: true, + value: prototypeValueDate, + property: map[string]_property{ + "toString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toString_function, + }, + }, + "toDateString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toDateString_function, + }, + }, + "toTimeString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toTimeString_function, + }, + }, + "toUTCString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toUTCString_function, + }, + }, + "toISOString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toISOString_function, + }, + }, + "toJSON": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toJSON_function, + }, + }, + "toGMTString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toGMTString_function, + }, + }, + "toLocaleString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toLocaleString_function, + }, + }, + "toLocaleDateString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toLocaleDateString_function, + }, + }, + "toLocaleTimeString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toLocaleTimeString_function, + }, + }, + "valueOf": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: valueOf_function, + }, + }, + "getTime": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getTime_function, + }, + }, + "getYear": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getYear_function, + }, + }, + "getFullYear": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getFullYear_function, + }, + }, + "getUTCFullYear": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getUTCFullYear_function, + }, + }, + "getMonth": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getMonth_function, + }, + }, + "getUTCMonth": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getUTCMonth_function, + }, + }, + "getDate": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getDate_function, + }, + }, + "getUTCDate": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getUTCDate_function, + }, + }, + "getDay": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getDay_function, + }, + }, + "getUTCDay": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getUTCDay_function, + }, + }, + "getHours": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getHours_function, + }, + }, + "getUTCHours": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getUTCHours_function, + }, + }, + "getMinutes": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getMinutes_function, + }, + }, + "getUTCMinutes": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getUTCMinutes_function, + }, + }, + "getSeconds": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getSeconds_function, + }, + }, + "getUTCSeconds": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getUTCSeconds_function, + }, + }, + "getMilliseconds": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getMilliseconds_function, + }, + }, + "getUTCMilliseconds": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getUTCMilliseconds_function, + }, + }, + "getTimezoneOffset": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: getTimezoneOffset_function, + }, + }, + "setTime": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setTime_function, + }, + }, + "setMilliseconds": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setMilliseconds_function, + }, + }, + "setUTCMilliseconds": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setUTCMilliseconds_function, + }, + }, + "setSeconds": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setSeconds_function, + }, + }, + "setUTCSeconds": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setUTCSeconds_function, + }, + }, + "setMinutes": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setMinutes_function, + }, + }, + "setUTCMinutes": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setUTCMinutes_function, + }, + }, + "setHours": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setHours_function, + }, + }, + "setUTCHours": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setUTCHours_function, + }, + }, + "setDate": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setDate_function, + }, + }, + "setUTCDate": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setUTCDate_function, + }, + }, + "setMonth": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setMonth_function, + }, + }, + "setUTCMonth": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setUTCMonth_function, + }, + }, + "setYear": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setYear_function, + }, + }, + "setFullYear": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setFullYear_function, + }, + }, + "setUTCFullYear": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: setUTCFullYear_function, + }, + }, + }, + propertyOrder: []string{ + "toString", + "toDateString", + "toTimeString", + "toUTCString", + "toISOString", + "toJSON", + "toGMTString", + "toLocaleString", + "toLocaleDateString", + "toLocaleTimeString", + "valueOf", + "getTime", + "getYear", + "getFullYear", + "getUTCFullYear", + "getMonth", + "getUTCMonth", + "getDate", + "getUTCDate", + "getDay", + "getUTCDay", + "getHours", + "getUTCHours", + "getMinutes", + "getUTCMinutes", + "getSeconds", + "getUTCSeconds", + "getMilliseconds", + "getUTCMilliseconds", + "getTimezoneOffset", + "setTime", + "setMilliseconds", + "setUTCMilliseconds", + "setSeconds", + "setUTCSeconds", + "setMinutes", + "setUTCMinutes", + "setHours", + "setUTCHours", + "setDate", + "setUTCDate", + "setMonth", + "setUTCMonth", + "setYear", + "setFullYear", + "setUTCFullYear", + }, + } + runtime.global.Date = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "Date", + call: builtinDate, + construct: builtinNewDate, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 7, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.DatePrototype, + }, + }, + "parse": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: parse_function, + }, + }, + "UTC": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: UTC_function, + }, + }, + "now": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: now_function, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + "parse", + "UTC", + "now", + }, + } + runtime.global.DatePrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Date, + }, + } + } + { + toString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toString", + call: builtinRegExp_toString, + }, + } + exec_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "exec", + call: builtinRegExp_exec, + }, + } + test_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "test", + call: builtinRegExp_test, + }, + } + compile_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "compile", + call: builtinRegExp_compile, + }, + } + runtime.global.RegExpPrototype = &_object{ + runtime: runtime, + class: "RegExp", + objectClass: _classObject, + prototype: runtime.global.ObjectPrototype, + extensible: true, + value: prototypeValueRegExp, + property: map[string]_property{ + "toString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toString_function, + }, + }, + "exec": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: exec_function, + }, + }, + "test": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: test_function, + }, + }, + "compile": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: compile_function, + }, + }, + }, + propertyOrder: []string{ + "toString", + "exec", + "test", + "compile", + }, + } + runtime.global.RegExp = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "RegExp", + call: builtinRegExp, + construct: builtinNewRegExp, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.RegExpPrototype, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + }, + } + runtime.global.RegExpPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.RegExp, + }, + } + } + { + toString_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "toString", + call: builtinError_toString, + }, + } + runtime.global.ErrorPrototype = &_object{ + runtime: runtime, + class: "Error", + objectClass: _classObject, + prototype: runtime.global.ObjectPrototype, + extensible: true, + value: nil, + property: map[string]_property{ + "toString": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: toString_function, + }, + }, + "name": _property{ + mode: 0101, + value: Value{ + kind: valueString, + value: "Error", + }, + }, + "message": _property{ + mode: 0101, + value: Value{ + kind: valueString, + value: "", + }, + }, + }, + propertyOrder: []string{ + "toString", + "name", + "message", + }, + } + runtime.global.Error = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "Error", + call: builtinError, + construct: builtinNewError, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.ErrorPrototype, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + }, + } + runtime.global.ErrorPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Error, + }, + } + } + { + runtime.global.EvalErrorPrototype = &_object{ + runtime: runtime, + class: "EvalError", + objectClass: _classObject, + prototype: runtime.global.ErrorPrototype, + extensible: true, + value: nil, + property: map[string]_property{ + "name": _property{ + mode: 0101, + value: Value{ + kind: valueString, + value: "EvalError", + }, + }, + }, + propertyOrder: []string{ + "name", + }, + } + runtime.global.EvalError = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "EvalError", + call: builtinEvalError, + construct: builtinNewEvalError, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.EvalErrorPrototype, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + }, + } + runtime.global.EvalErrorPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.EvalError, + }, + } + } + { + runtime.global.TypeErrorPrototype = &_object{ + runtime: runtime, + class: "TypeError", + objectClass: _classObject, + prototype: runtime.global.ErrorPrototype, + extensible: true, + value: nil, + property: map[string]_property{ + "name": _property{ + mode: 0101, + value: Value{ + kind: valueString, + value: "TypeError", + }, + }, + }, + propertyOrder: []string{ + "name", + }, + } + runtime.global.TypeError = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "TypeError", + call: builtinTypeError, + construct: builtinNewTypeError, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.TypeErrorPrototype, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + }, + } + runtime.global.TypeErrorPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.TypeError, + }, + } + } + { + runtime.global.RangeErrorPrototype = &_object{ + runtime: runtime, + class: "RangeError", + objectClass: _classObject, + prototype: runtime.global.ErrorPrototype, + extensible: true, + value: nil, + property: map[string]_property{ + "name": _property{ + mode: 0101, + value: Value{ + kind: valueString, + value: "RangeError", + }, + }, + }, + propertyOrder: []string{ + "name", + }, + } + runtime.global.RangeError = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "RangeError", + call: builtinRangeError, + construct: builtinNewRangeError, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.RangeErrorPrototype, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + }, + } + runtime.global.RangeErrorPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.RangeError, + }, + } + } + { + runtime.global.ReferenceErrorPrototype = &_object{ + runtime: runtime, + class: "ReferenceError", + objectClass: _classObject, + prototype: runtime.global.ErrorPrototype, + extensible: true, + value: nil, + property: map[string]_property{ + "name": _property{ + mode: 0101, + value: Value{ + kind: valueString, + value: "ReferenceError", + }, + }, + }, + propertyOrder: []string{ + "name", + }, + } + runtime.global.ReferenceError = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "ReferenceError", + call: builtinReferenceError, + construct: builtinNewReferenceError, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.ReferenceErrorPrototype, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + }, + } + runtime.global.ReferenceErrorPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.ReferenceError, + }, + } + } + { + runtime.global.SyntaxErrorPrototype = &_object{ + runtime: runtime, + class: "SyntaxError", + objectClass: _classObject, + prototype: runtime.global.ErrorPrototype, + extensible: true, + value: nil, + property: map[string]_property{ + "name": _property{ + mode: 0101, + value: Value{ + kind: valueString, + value: "SyntaxError", + }, + }, + }, + propertyOrder: []string{ + "name", + }, + } + runtime.global.SyntaxError = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "SyntaxError", + call: builtinSyntaxError, + construct: builtinNewSyntaxError, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.SyntaxErrorPrototype, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + }, + } + runtime.global.SyntaxErrorPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.SyntaxError, + }, + } + } + { + runtime.global.URIErrorPrototype = &_object{ + runtime: runtime, + class: "URIError", + objectClass: _classObject, + prototype: runtime.global.ErrorPrototype, + extensible: true, + value: nil, + property: map[string]_property{ + "name": _property{ + mode: 0101, + value: Value{ + kind: valueString, + value: "URIError", + }, + }, + }, + propertyOrder: []string{ + "name", + }, + } + runtime.global.URIError = &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + value: _nativeFunctionObject{ + name: "URIError", + call: builtinURIError, + construct: builtinNewURIError, + }, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + "prototype": _property{ + mode: 0, + value: Value{ + kind: valueObject, + value: runtime.global.URIErrorPrototype, + }, + }, + }, + propertyOrder: []string{ + "length", + "prototype", + }, + } + runtime.global.URIErrorPrototype.property["constructor"] = + _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.URIError, + }, + } + } + { + parse_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "parse", + call: builtinJSON_parse, + }, + } + stringify_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 3, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "stringify", + call: builtinJSON_stringify, + }, + } + runtime.global.JSON = &_object{ + runtime: runtime, + class: "JSON", + objectClass: _classObject, + prototype: runtime.global.ObjectPrototype, + extensible: true, + property: map[string]_property{ + "parse": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: parse_function, + }, + }, + "stringify": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: stringify_function, + }, + }, + }, + propertyOrder: []string{ + "parse", + "stringify", + }, + } + } + { + eval_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "eval", + call: builtinGlobal_eval, + }, + } + parseInt_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 2, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "parseInt", + call: builtinGlobal_parseInt, + }, + } + parseFloat_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "parseFloat", + call: builtinGlobal_parseFloat, + }, + } + isNaN_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "isNaN", + call: builtinGlobal_isNaN, + }, + } + isFinite_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "isFinite", + call: builtinGlobal_isFinite, + }, + } + decodeURI_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "decodeURI", + call: builtinGlobal_decodeURI, + }, + } + decodeURIComponent_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "decodeURIComponent", + call: builtinGlobal_decodeURIComponent, + }, + } + encodeURI_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "encodeURI", + call: builtinGlobal_encodeURI, + }, + } + encodeURIComponent_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "encodeURIComponent", + call: builtinGlobal_encodeURIComponent, + }, + } + escape_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "escape", + call: builtinGlobal_escape, + }, + } + unescape_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 1, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "unescape", + call: builtinGlobal_unescape, + }, + } + runtime.globalObject.property = map[string]_property{ + "eval": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: eval_function, + }, + }, + "parseInt": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: parseInt_function, + }, + }, + "parseFloat": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: parseFloat_function, + }, + }, + "isNaN": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: isNaN_function, + }, + }, + "isFinite": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: isFinite_function, + }, + }, + "decodeURI": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: decodeURI_function, + }, + }, + "decodeURIComponent": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: decodeURIComponent_function, + }, + }, + "encodeURI": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: encodeURI_function, + }, + }, + "encodeURIComponent": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: encodeURIComponent_function, + }, + }, + "escape": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: escape_function, + }, + }, + "unescape": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: unescape_function, + }, + }, + "Object": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Object, + }, + }, + "Function": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Function, + }, + }, + "Array": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Array, + }, + }, + "String": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.String, + }, + }, + "Boolean": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Boolean, + }, + }, + "Number": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Number, + }, + }, + "Math": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Math, + }, + }, + "Date": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Date, + }, + }, + "RegExp": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.RegExp, + }, + }, + "Error": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.Error, + }, + }, + "EvalError": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.EvalError, + }, + }, + "TypeError": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.TypeError, + }, + }, + "RangeError": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.RangeError, + }, + }, + "ReferenceError": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.ReferenceError, + }, + }, + "SyntaxError": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.SyntaxError, + }, + }, + "URIError": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.URIError, + }, + }, + "JSON": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: runtime.global.JSON, + }, + }, + "undefined": _property{ + mode: 0, + value: Value{ + kind: valueUndefined, + }, + }, + "NaN": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.NaN(), + }, + }, + "Infinity": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: math.Inf(+1), + }, + }, + } + runtime.globalObject.propertyOrder = []string{ + "eval", + "parseInt", + "parseFloat", + "isNaN", + "isFinite", + "decodeURI", + "decodeURIComponent", + "encodeURI", + "encodeURIComponent", + "escape", + "unescape", + "Object", + "Function", + "Array", + "String", + "Boolean", + "Number", + "Math", + "Date", + "RegExp", + "Error", + "EvalError", + "TypeError", + "RangeError", + "ReferenceError", + "SyntaxError", + "URIError", + "JSON", + "undefined", + "NaN", + "Infinity", + } + } +} + +func newConsoleObject(runtime *_runtime) *_object { + { + log_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "log", + call: builtinConsole_log, + }, + } + debug_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "debug", + call: builtinConsole_log, + }, + } + info_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "info", + call: builtinConsole_log, + }, + } + error_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "error", + call: builtinConsole_error, + }, + } + warn_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "warn", + call: builtinConsole_error, + }, + } + dir_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "dir", + call: builtinConsole_dir, + }, + } + time_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "time", + call: builtinConsole_time, + }, + } + timeEnd_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "timeEnd", + call: builtinConsole_timeEnd, + }, + } + trace_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "trace", + call: builtinConsole_trace, + }, + } + assert_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + kind: valueNumber, + value: 0, + }, + }, + }, + propertyOrder: []string{ + "length", + }, + value: _nativeFunctionObject{ + name: "assert", + call: builtinConsole_assert, + }, + } + return &_object{ + runtime: runtime, + class: "Object", + objectClass: _classObject, + prototype: runtime.global.ObjectPrototype, + extensible: true, + property: map[string]_property{ + "log": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: log_function, + }, + }, + "debug": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: debug_function, + }, + }, + "info": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: info_function, + }, + }, + "error": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: error_function, + }, + }, + "warn": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: warn_function, + }, + }, + "dir": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: dir_function, + }, + }, + "time": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: time_function, + }, + }, + "timeEnd": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: timeEnd_function, + }, + }, + "trace": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: trace_function, + }, + }, + "assert": _property{ + mode: 0101, + value: Value{ + kind: valueObject, + value: assert_function, + }, + }, + }, + propertyOrder: []string{ + "log", + "debug", + "info", + "error", + "warn", + "dir", + "time", + "timeEnd", + "trace", + "assert", + }, + } + } +} + +func toValue_int(value int) Value { + return Value{ + kind: valueNumber, + value: value, + } +} + +func toValue_int8(value int8) Value { + return Value{ + kind: valueNumber, + value: value, + } +} + +func toValue_int16(value int16) Value { + return Value{ + kind: valueNumber, + value: value, + } +} + +func toValue_int32(value int32) Value { + return Value{ + kind: valueNumber, + value: value, + } +} + +func toValue_int64(value int64) Value { + return Value{ + kind: valueNumber, + value: value, + } +} + +func toValue_uint(value uint) Value { + return Value{ + kind: valueNumber, + value: value, + } +} + +func toValue_uint8(value uint8) Value { + return Value{ + kind: valueNumber, + value: value, + } +} + +func toValue_uint16(value uint16) Value { + return Value{ + kind: valueNumber, + value: value, + } +} + +func toValue_uint32(value uint32) Value { + return Value{ + kind: valueNumber, + value: value, + } +} + +func toValue_uint64(value uint64) Value { + return Value{ + kind: valueNumber, + value: value, + } +} + +func toValue_float32(value float32) Value { + return Value{ + kind: valueNumber, + value: value, + } +} + +func toValue_float64(value float64) Value { + return Value{ + kind: valueNumber, + value: value, + } +} + +func toValue_string(value string) Value { + return Value{ + kind: valueString, + value: value, + } +} + +func toValue_string16(value []uint16) Value { + return Value{ + kind: valueString, + value: value, + } +} + +func toValue_bool(value bool) Value { + return Value{ + kind: valueBoolean, + value: value, + } +} + +func toValue_object(value *_object) Value { + return Value{ + kind: valueObject, + value: value, + } +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/json_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/json_test.go new file mode 100644 index 0000000000..4dd2ed7bf6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/json_test.go @@ -0,0 +1,183 @@ +package otto + +import ( + "testing" +) + +func BenchmarkJSON_parse(b *testing.B) { + vm := New() + for i := 0; i < b.N; i++ { + vm.Run(`JSON.parse("1")`) + vm.Run(`JSON.parse("[1,2,3]")`) + vm.Run(`JSON.parse('{"a":{"x":100,"y":110},"b":[10,20,30],"c":"zazazaza"}')`) + vm.Run(`JSON.parse("[1,2,3]", function(k, v) { return undefined })`) + } +} + +func TestJSON_parse(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + JSON.parse("1"); + `, 1) + + test(` + JSON.parse("null"); + `, "null") // TODO Can we make this nil? + + test(` + var abc = JSON.parse('"a\uFFFFbc"'); + [ abc[0], abc[2], abc[3], abc.length ]; + `, "a,b,c,4") + + test(` + JSON.parse("[1, 2, 3]"); + `, "1,2,3") + + test(` + JSON.parse('{ "abc": 1, "def":2 }').abc; + `, 1) + + test(` + JSON.parse('{ "abc": { "x": 100, "y": 110 }, "def": [ 10, 20 ,30 ], "ghi": "zazazaza" }').def; + `, "10,20,30") + + test(`raise: + JSON.parse("12\t\r\n 34"); + `, "SyntaxError: invalid character '3' after top-level value") + + test(` + JSON.parse("[1, 2, 3]", function() { return undefined }); + `, "undefined") + + test(`raise: + JSON.parse(""); + `, "SyntaxError: unexpected end of JSON input") + + test(`raise: + JSON.parse("[1, 2, 3"); + `, "SyntaxError: unexpected end of JSON input") + + test(`raise: + JSON.parse("[1, 2, ; abc=10"); + `, "SyntaxError: invalid character ';' looking for beginning of value") + + test(`raise: + JSON.parse("[1, 2, function(){}]"); + `, "SyntaxError: invalid character 'u' in literal false (expecting 'a')") + }) +} + +func TestJSON_stringify(t *testing.T) { + tt(t, func() { + test, _ := test() + + defer mockUTC()() + + test(` + JSON.stringify(function(){}); + `, "undefined") + + test(` + JSON.stringify(new Boolean(false)); + `, "false") + + test(` + JSON.stringify({a1: {b1: [1,2,3,4], b2: {c1: 1, c2: 2}}, a2: 'a2'}, null, -5); + `, `{"a1":{"b1":[1,2,3,4],"b2":{"c1":1,"c2":2}},"a2":"a2"}`) + + test(` + JSON.stringify(undefined); + `, "undefined") + + test(` + JSON.stringify(1); + `, "1") + + test(` + JSON.stringify("abc def"); + `, "\"abc def\"") + + test(` + JSON.stringify(3.14159); + `, "3.14159") + + test(` + JSON.stringify([]); + `, "[]") + + test(` + JSON.stringify([1, 2, 3]); + `, "[1,2,3]") + + test(` + JSON.stringify([true, false, null]); + `, "[true,false,null]") + + test(` + JSON.stringify({ + abc: { x: 100, y: 110 }, + def: [ 10, 20, 30 ], + ghi: "zazazaza" + }); + `, `{"abc":{"x":100,"y":110},"def":[10,20,30],"ghi":"zazazaza"}`) + + test(` + JSON.stringify([ + 'e', + {pluribus: 'unum'} + ], null, '\t'); + `, "[\n\t\"e\",\n\t{\n\t\t\"pluribus\": \"unum\"\n\t}\n]") + + test(` + JSON.stringify(new Date(0)); + `, `"1970-01-01T00:00:00.000Z"`) + + test(` + JSON.stringify([ new Date(0) ], function(key, value){ + return this[key] instanceof Date ? 'Date(' + this[key] + ')' : value + }); + `, `["Date(Thu, 01 Jan 1970 00:00:00 UTC)"]`) + + test(` + JSON.stringify({ + abc: 1, + def: 2, + ghi: 3 + }, ['abc','def']); + `, `{"abc":1,"def":2}`) + + test(`raise: + var abc = { + def: null + }; + abc.def = abc; + JSON.stringify(abc) + `, "TypeError: Converting circular structure to JSON") + + test(`raise: + var abc= [ null ]; + abc[0] = abc; + JSON.stringify(abc); + `, "TypeError: Converting circular structure to JSON") + + test(`raise: + var abc = { + def: {} + }; + abc.def.ghi = abc; + JSON.stringify(abc) + `, "TypeError: Converting circular structure to JSON") + + test(` + var ghi = { "pi": 3.14159 }; + var abc = { + def: {} + }; + abc.ghi = ghi; + abc.def.ghi = ghi; + JSON.stringify(abc); + `, `{"def":{"ghi":{"pi":3.14159}},"ghi":{"pi":3.14159}}`) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/math_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/math_test.go new file mode 100644 index 0000000000..499998b14e --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/math_test.go @@ -0,0 +1,303 @@ +package otto + +import ( + "math" + "testing" +) + +var _NaN = math.NaN() +var _Infinity = math.Inf(1) + +func TestMath_toString(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.toString()`, "[object Math]") + }) +} + +func TestMath_abs(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.abs(NaN)`, _NaN) + test(`Math.abs(2)`, 2) + test(`Math.abs(-2)`, 2) + test(`Math.abs(-Infinity)`, _Infinity) + + test(`Math.acos(0.5)`, 1.0471975511965976) + + test(`Math.abs('-1')`, 1) + test(`Math.abs(-2)`, 2) + test(`Math.abs(null)`, 0) + test(`Math.abs("string")`, _NaN) + test(`Math.abs()`, _NaN) + }) +} + +func TestMath_acos(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.acos(NaN)`, _NaN) + test(`Math.acos(2)`, _NaN) + test(`Math.acos(-2)`, _NaN) + test(`1/Math.acos(1)`, _Infinity) + + test(`Math.acos(0.5)`, 1.0471975511965976) + }) +} + +func TestMath_asin(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.asin(NaN)`, _NaN) + test(`Math.asin(2)`, _NaN) + test(`Math.asin(-2)`, _NaN) + test(`1/Math.asin(0)`, _Infinity) + test(`1/Math.asin(-0)`, -_Infinity) + + test(`Math.asin(0.5)`, 0.5235987755982989) + }) +} + +func TestMath_atan(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.atan(NaN)`, _NaN) + test(`1/Math.atan(0)`, _Infinity) + test(`1/Math.atan(-0)`, -_Infinity) + test(`Math.atan(Infinity)`, 1.5707963267948966) + test(`Math.atan(-Infinity)`, -1.5707963267948966) + + // freebsd/386 1.03 => 0.4636476090008061 + // darwin 1.03 => 0.46364760900080604 + test(`Math.atan(0.5).toPrecision(10)`, "0.463647609") + }) +} + +func TestMath_atan2(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.atan2()`, _NaN) + test(`Math.atan2(NaN)`, _NaN) + test(`Math.atan2(0, NaN)`, _NaN) + + test(`Math.atan2(1, 0)`, 1.5707963267948966) + test(`Math.atan2(1, -0)`, 1.5707963267948966) + + test(`1/Math.atan2(0, 1)`, _Infinity) + test(`1/Math.atan2(0, 0)`, _Infinity) + test(`Math.atan2(0, -0)`, 3.141592653589793) + test(`Math.atan2(0, -1)`, 3.141592653589793) + + test(`1/Math.atan2(-0, 1)`, -_Infinity) + test(`1/Math.atan2(-0, 0)`, -_Infinity) + test(`Math.atan2(-0, -0)`, -3.141592653589793) + test(`Math.atan2(-0, -1)`, -3.141592653589793) + + test(`Math.atan2(-1, 0)`, -1.5707963267948966) + test(`Math.atan2(-1, -0)`, -1.5707963267948966) + + test(`1/Math.atan2(1, Infinity)`, _Infinity) + test(`Math.atan2(1, -Infinity)`, 3.141592653589793) + test(`1/Math.atan2(-1, Infinity)`, -_Infinity) + test(`Math.atan2(-1, -Infinity)`, -3.141592653589793) + + test(`Math.atan2(Infinity, 1)`, 1.5707963267948966) + test(`Math.atan2(-Infinity, 1)`, -1.5707963267948966) + + test(`Math.atan2(Infinity, Infinity)`, 0.7853981633974483) + test(`Math.atan2(Infinity, -Infinity)`, 2.356194490192345) + test(`Math.atan2(-Infinity, Infinity)`, -0.7853981633974483) + test(`Math.atan2(-Infinity, -Infinity)`, -2.356194490192345) + }) +} + +func TestMath_ceil(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.ceil(NaN)`, _NaN) + test(`Math.ceil(+0)`, 0) + test(`1/Math.ceil(-0)`, -_Infinity) + test(`Math.ceil(Infinity)`, _Infinity) + test(`Math.ceil(-Infinity)`, -_Infinity) + test(`1/Math.ceil(-0.5)`, -_Infinity) + + test(`Math.ceil(-11)`, -11) + test(`Math.ceil(-0.5)`, 0) + test(`Math.ceil(1.5)`, 2) + }) +} + +func TestMath_cos(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.cos(NaN)`, _NaN) + test(`Math.cos(+0)`, 1) + test(`Math.cos(-0)`, 1) + test(`Math.cos(Infinity)`, _NaN) + test(`Math.cos(-Infinity)`, _NaN) + + test(`Math.cos(0.5)`, 0.8775825618903728) + }) +} + +func TestMath_exp(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.exp(NaN)`, _NaN) + test(`Math.exp(+0)`, 1) + test(`Math.exp(-0)`, 1) + test(`Math.exp(Infinity)`, _Infinity) + test(`Math.exp(-Infinity)`, 0) + }) +} + +func TestMath_floor(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.floor(NaN)`, _NaN) + test(`Math.floor(+0)`, 0) + test(`1/Math.floor(-0)`, -_Infinity) + test(`Math.floor(Infinity)`, _Infinity) + test(`Math.floor(-Infinity)`, -_Infinity) + + test(`Math.floor(-11)`, -11) + test(`Math.floor(-0.5)`, -1) + test(`Math.floor(1.5)`, 1) + }) +} + +func TestMath_log(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.log(NaN)`, _NaN) + test(`Math.log(-1)`, _NaN) + test(`Math.log(+0)`, -_Infinity) + test(`Math.log(-0)`, -_Infinity) + test(`1/Math.log(1)`, _Infinity) + test(`Math.log(Infinity)`, _Infinity) + + test(`Math.log(0.5)`, -0.6931471805599453) + }) +} + +func TestMath_max(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.max(-11, -1, 0, 1, 2, 3, 11)`, 11) + }) +} + +func TestMath_min(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.min(-11, -1, 0, 1, 2, 3, 11)`, -11) + }) +} + +func TestMath_pow(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.pow(0, NaN)`, _NaN) + test(`Math.pow(0, 0)`, 1) + test(`Math.pow(NaN, 0)`, 1) + test(`Math.pow(0, -0)`, 1) + test(`Math.pow(NaN, -0)`, 1) + test(`Math.pow(NaN, 1)`, _NaN) + test(`Math.pow(2, Infinity)`, _Infinity) + test(`1/Math.pow(2, -Infinity)`, _Infinity) + test(`Math.pow(1, Infinity)`, _NaN) + test(`Math.pow(1, -Infinity)`, _NaN) + test(`1/Math.pow(0.1, Infinity)`, _Infinity) + test(`Math.pow(0.1, -Infinity)`, _Infinity) + test(`Math.pow(Infinity, 1)`, _Infinity) + test(`1/Math.pow(Infinity, -1)`, _Infinity) + test(`Math.pow(-Infinity, 1)`, -_Infinity) + test(`Math.pow(-Infinity, 2)`, _Infinity) + test(`1/Math.pow(-Infinity, -1)`, -_Infinity) + test(`1/Math.pow(-Infinity, -2)`, _Infinity) + test(`1/Math.pow(0, 1)`, _Infinity) + test(`Math.pow(0, -1)`, _Infinity) + test(`1/Math.pow(-0, 1)`, -_Infinity) + test(`1/Math.pow(-0, 2)`, _Infinity) + test(`Math.pow(-0, -1)`, -_Infinity) + test(`Math.pow(-0, -2)`, _Infinity) + test(`Math.pow(-1, 0.1)`, _NaN) + + test(` + [ Math.pow(-1, +Infinity), Math.pow(1, Infinity) ]; + `, "NaN,NaN") + }) +} + +func TestMath_round(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.round(NaN)`, _NaN) + test(`1/Math.round(0)`, _Infinity) + test(`1/Math.round(-0)`, -_Infinity) + test(`Math.round(Infinity)`, _Infinity) + test(`Math.round(-Infinity)`, -_Infinity) + test(`1/Math.round(0.1)`, _Infinity) + test(`1/Math.round(-0.1)`, -_Infinity) + + test(`Math.round(3.5)`, 4) + test(`Math.round(-3.5)`, -3) + }) +} + +func TestMath_sin(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.sin(NaN)`, _NaN) + test(`1/Math.sin(+0)`, _Infinity) + test(`1/Math.sin(-0)`, -_Infinity) + test(`Math.sin(Infinity)`, _NaN) + test(`Math.sin(-Infinity)`, _NaN) + + test(`Math.sin(0.5)`, 0.479425538604203) + }) +} + +func TestMath_sqrt(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.sqrt(NaN)`, _NaN) + test(`Math.sqrt(-1)`, _NaN) + test(`1/Math.sqrt(+0)`, _Infinity) + test(`1/Math.sqrt(-0)`, -_Infinity) + test(`Math.sqrt(Infinity)`, _Infinity) + + test(`Math.sqrt(2)`, 1.4142135623730951) + }) +} + +func TestMath_tan(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Math.tan(NaN)`, _NaN) + test(`1/Math.tan(+0)`, _Infinity) + test(`1/Math.tan(-0)`, -_Infinity) + test(`Math.tan(Infinity)`, _NaN) + test(`Math.tan(-Infinity)`, _NaN) + + test(`Math.tan(0.5)`, 0.5463024898437905) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/number_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/number_test.go new file mode 100644 index 0000000000..8db01cfc7c --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/number_test.go @@ -0,0 +1,165 @@ +package otto + +import ( + "testing" +) + +func TestNumber(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = Object.getOwnPropertyDescriptor(Number, "prototype"); + [ [ typeof Number.prototype ], + [ abc.writable, abc.enumerable, abc.configurable ] ]; + `, "object,false,false,false") + }) +} + +func TestNumber_toString(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + new Number(451).toString(); + `, "451") + + test(` + new Number(451).toString(10); + `, "451") + + test(` + new Number(451).toString(8); + `, "703") + + test(`raise: + new Number(451).toString(1); + `, "RangeError: RangeError: toString() radix must be between 2 and 36") + + test(`raise: + new Number(451).toString(Infinity); + `, "RangeError: RangeError: toString() radix must be between 2 and 36") + + test(` + new Number(NaN).toString() + `, "NaN") + + test(` + new Number(Infinity).toString() + `, "Infinity") + + test(` + new Number(Infinity).toString(16) + `, "Infinity") + + test(` + [ + Number.prototype.toString(undefined), + new Number().toString(undefined), + new Number(0).toString(undefined), + new Number(-1).toString(undefined), + new Number(1).toString(undefined), + new Number(Number.NaN).toString(undefined), + new Number(Number.POSITIVE_INFINITY).toString(undefined), + new Number(Number.NEGATIVE_INFINITY).toString(undefined) + ] + `, "0,0,0,-1,1,NaN,Infinity,-Infinity") + }) +} + +func TestNumber_toFixed(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`new Number(451).toFixed(2)`, "451.00") + test(`12345.6789.toFixed()`, "12346") + test(`12345.6789.toFixed(1)`, "12345.7") + test(`12345.6789.toFixed(6)`, "12345.678900") + test(`(1.23e-20).toFixed(2)`, "0.00") + test(`2.34.toFixed(1)`, "2.3") // FIXME Wtf? "2.3" + test(`-2.34.toFixed(1)`, -2.3) // FIXME Wtf? -2.3 + test(`(-2.34).toFixed(1)`, "-2.3") + + test(`raise: + new Number("a").toFixed(Number.POSITIVE_INFINITY); + `, "RangeError: toFixed() precision must be between 0 and 20") + + test(` + [ + new Number(1e21).toFixed(), + new Number(1e21).toFixed(0), + new Number(1e21).toFixed(1), + new Number(1e21).toFixed(1.1), + new Number(1e21).toFixed(0.9), + new Number(1e21).toFixed("1"), + new Number(1e21).toFixed("1.1"), + new Number(1e21).toFixed("0.9"), + new Number(1e21).toFixed(Number.NaN), + new Number(1e21).toFixed("some string") + ]; + `, "1e+21,1e+21,1e+21,1e+21,1e+21,1e+21,1e+21,1e+21,1e+21,1e+21") + + test(`raise: + new Number(1e21).toFixed(Number.POSITIVE_INFINITY); + `, "RangeError: toFixed() precision must be between 0 and 20") + }) +} + +func TestNumber_toExponential(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`new Number(451).toExponential(2)`, "4.51e+02") + test(`77.1234.toExponential()`, "7.71234e+01") + test(`77.1234.toExponential(4)`, "7.7123e+01") + test(`77.1234.toExponential(2)`, "7.71e+01") + test(`77 .toExponential()`, "7.7e+01") + }) +} + +func TestNumber_toPrecision(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`new Number(451).toPrecision()`, "451") + test(`new Number(451).toPrecision(1)`, "5e+02") + test(`5.123456.toPrecision()`, "5.123456") + test(`5.123456.toPrecision(5)`, "5.1235") + test(`5.123456.toPrecision(2)`, "5.1") + test(`5.123456.toPrecision(1)`, "5") + }) +} + +func TestNumber_toLocaleString(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ + new Number(451).toLocaleString(), + new Number(451).toLocaleString(10), + new Number(451).toLocaleString(8) + ]; + `, "451,451,703") + }) +} + +func TestValue_number(t *testing.T) { + tt(t, func() { + nm := toValue(0.0).number() + is(nm.kind, numberInteger) + + nm = toValue(3.14159).number() + is(nm.kind, numberFloat) + }) +} + +func Test_NaN(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ NaN === NaN, NaN == NaN ]; + `, "false,false") + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/object.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/object.go new file mode 100644 index 0000000000..849812c914 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/object.go @@ -0,0 +1,156 @@ +package otto + +type _object struct { + runtime *_runtime + + class string + objectClass *_objectClass + value interface{} + + prototype *_object + extensible bool + + property map[string]_property + propertyOrder []string +} + +func newObject(runtime *_runtime, class string) *_object { + self := &_object{ + runtime: runtime, + class: class, + objectClass: _classObject, + property: make(map[string]_property), + extensible: true, + } + return self +} + +// 8.12 + +// 8.12.1 +func (self *_object) getOwnProperty(name string) *_property { + return self.objectClass.getOwnProperty(self, name) +} + +// 8.12.2 +func (self *_object) getProperty(name string) *_property { + return self.objectClass.getProperty(self, name) +} + +// 8.12.3 +func (self *_object) get(name string) Value { + return self.objectClass.get(self, name) +} + +// 8.12.4 +func (self *_object) canPut(name string) bool { + return self.objectClass.canPut(self, name) +} + +// 8.12.5 +func (self *_object) put(name string, value Value, throw bool) { + self.objectClass.put(self, name, value, throw) +} + +// 8.12.6 +func (self *_object) hasProperty(name string) bool { + return self.objectClass.hasProperty(self, name) +} + +func (self *_object) hasOwnProperty(name string) bool { + return self.objectClass.hasOwnProperty(self, name) +} + +type _defaultValueHint int + +const ( + defaultValueNoHint _defaultValueHint = iota + defaultValueHintString + defaultValueHintNumber +) + +// 8.12.8 +func (self *_object) DefaultValue(hint _defaultValueHint) Value { + if hint == defaultValueNoHint { + if self.class == "Date" { + // Date exception + hint = defaultValueHintString + } else { + hint = defaultValueHintNumber + } + } + methodSequence := []string{"valueOf", "toString"} + if hint == defaultValueHintString { + methodSequence = []string{"toString", "valueOf"} + } + for _, methodName := range methodSequence { + method := self.get(methodName) + // FIXME This is redundant... + if method.isCallable() { + result := method._object().call(toValue_object(self), nil, false, nativeFrame) + if result.IsPrimitive() { + return result + } + } + } + + panic(self.runtime.panicTypeError()) +} + +func (self *_object) String() string { + return self.DefaultValue(defaultValueHintString).string() +} + +func (self *_object) defineProperty(name string, value Value, mode _propertyMode, throw bool) bool { + return self.defineOwnProperty(name, _property{value, mode}, throw) +} + +// 8.12.9 +func (self *_object) defineOwnProperty(name string, descriptor _property, throw bool) bool { + return self.objectClass.defineOwnProperty(self, name, descriptor, throw) +} + +func (self *_object) delete(name string, throw bool) bool { + return self.objectClass.delete(self, name, throw) +} + +func (self *_object) enumerate(all bool, each func(string) bool) { + self.objectClass.enumerate(self, all, each) +} + +func (self *_object) _exists(name string) bool { + _, exists := self.property[name] + return exists +} + +func (self *_object) _read(name string) (_property, bool) { + property, exists := self.property[name] + return property, exists +} + +func (self *_object) _write(name string, value interface{}, mode _propertyMode) { + if value == nil { + value = Value{} + } + _, exists := self.property[name] + self.property[name] = _property{value, mode} + if !exists { + self.propertyOrder = append(self.propertyOrder, name) + } +} + +func (self *_object) _delete(name string) { + _, exists := self.property[name] + delete(self.property, name) + if exists { + for index, property := range self.propertyOrder { + if name == property { + if index == len(self.propertyOrder)-1 { + self.propertyOrder = self.propertyOrder[:index] + } else { + self.propertyOrder = append(self.propertyOrder[:index], self.propertyOrder[index+1:]...) + } + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/object_class.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/object_class.go new file mode 100644 index 0000000000..d18b9cede0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/object_class.go @@ -0,0 +1,493 @@ +package otto + +import ( + "encoding/json" +) + +type _objectClass struct { + getOwnProperty func(*_object, string) *_property + getProperty func(*_object, string) *_property + get func(*_object, string) Value + canPut func(*_object, string) bool + put func(*_object, string, Value, bool) + hasProperty func(*_object, string) bool + hasOwnProperty func(*_object, string) bool + defineOwnProperty func(*_object, string, _property, bool) bool + delete func(*_object, string, bool) bool + enumerate func(*_object, bool, func(string) bool) + clone func(*_object, *_object, *_clone) *_object + marshalJSON func(*_object) json.Marshaler +} + +func objectEnumerate(self *_object, all bool, each func(string) bool) { + for _, name := range self.propertyOrder { + if all || self.property[name].enumerable() { + if !each(name) { + return + } + } + } +} + +var ( + _classObject, + _classArray, + _classString, + _classArguments, + _classGoStruct, + _classGoMap, + _classGoArray, + _classGoSlice, + _ *_objectClass +) + +func init() { + _classObject = &_objectClass{ + objectGetOwnProperty, + objectGetProperty, + objectGet, + objectCanPut, + objectPut, + objectHasProperty, + objectHasOwnProperty, + objectDefineOwnProperty, + objectDelete, + objectEnumerate, + objectClone, + nil, + } + + _classArray = &_objectClass{ + objectGetOwnProperty, + objectGetProperty, + objectGet, + objectCanPut, + objectPut, + objectHasProperty, + objectHasOwnProperty, + arrayDefineOwnProperty, + objectDelete, + objectEnumerate, + objectClone, + nil, + } + + _classString = &_objectClass{ + stringGetOwnProperty, + objectGetProperty, + objectGet, + objectCanPut, + objectPut, + objectHasProperty, + objectHasOwnProperty, + objectDefineOwnProperty, + objectDelete, + stringEnumerate, + objectClone, + nil, + } + + _classArguments = &_objectClass{ + argumentsGetOwnProperty, + objectGetProperty, + argumentsGet, + objectCanPut, + objectPut, + objectHasProperty, + objectHasOwnProperty, + argumentsDefineOwnProperty, + argumentsDelete, + objectEnumerate, + objectClone, + nil, + } + + _classGoStruct = &_objectClass{ + goStructGetOwnProperty, + objectGetProperty, + objectGet, + goStructCanPut, + goStructPut, + objectHasProperty, + objectHasOwnProperty, + objectDefineOwnProperty, + objectDelete, + goStructEnumerate, + objectClone, + goStructMarshalJSON, + } + + _classGoMap = &_objectClass{ + goMapGetOwnProperty, + objectGetProperty, + objectGet, + objectCanPut, + objectPut, + objectHasProperty, + objectHasOwnProperty, + goMapDefineOwnProperty, + goMapDelete, + goMapEnumerate, + objectClone, + nil, + } + + _classGoArray = &_objectClass{ + goArrayGetOwnProperty, + objectGetProperty, + objectGet, + objectCanPut, + objectPut, + objectHasProperty, + objectHasOwnProperty, + goArrayDefineOwnProperty, + goArrayDelete, + goArrayEnumerate, + objectClone, + nil, + } + + _classGoSlice = &_objectClass{ + goSliceGetOwnProperty, + objectGetProperty, + objectGet, + objectCanPut, + objectPut, + objectHasProperty, + objectHasOwnProperty, + goSliceDefineOwnProperty, + goSliceDelete, + goSliceEnumerate, + objectClone, + nil, + } +} + +// Allons-y + +// 8.12.1 +func objectGetOwnProperty(self *_object, name string) *_property { + // Return a _copy_ of the property + property, exists := self._read(name) + if !exists { + return nil + } + return &property +} + +// 8.12.2 +func objectGetProperty(self *_object, name string) *_property { + property := self.getOwnProperty(name) + if property != nil { + return property + } + if self.prototype != nil { + return self.prototype.getProperty(name) + } + return nil +} + +// 8.12.3 +func objectGet(self *_object, name string) Value { + property := self.getProperty(name) + if property != nil { + return property.get(self) + } + return Value{} +} + +// 8.12.4 +func objectCanPut(self *_object, name string) bool { + canPut, _, _ := _objectCanPut(self, name) + return canPut +} + +func _objectCanPut(self *_object, name string) (canPut bool, property *_property, setter *_object) { + property = self.getOwnProperty(name) + if property != nil { + switch propertyValue := property.value.(type) { + case Value: + canPut = property.writable() + return + case _propertyGetSet: + setter = propertyValue[1] + canPut = setter != nil + return + default: + panic(self.runtime.panicTypeError()) + } + } + + if self.prototype == nil { + return self.extensible, nil, nil + } + + property = self.prototype.getProperty(name) + if property == nil { + return self.extensible, nil, nil + } + + switch propertyValue := property.value.(type) { + case Value: + if !self.extensible { + return false, nil, nil + } + return property.writable(), nil, nil + case _propertyGetSet: + setter = propertyValue[1] + canPut = setter != nil + return + default: + panic(self.runtime.panicTypeError()) + } +} + +// 8.12.5 +func objectPut(self *_object, name string, value Value, throw bool) { + + if true { + // Shortcut... + // + // So, right now, every class is using objectCanPut and every class + // is using objectPut. + // + // If that were to no longer be the case, we would have to have + // something to detect that here, so that we do not use an + // incompatible canPut routine + canPut, property, setter := _objectCanPut(self, name) + if !canPut { + self.runtime.typeErrorResult(throw) + } else if setter != nil { + setter.call(toValue(self), []Value{value}, false, nativeFrame) + } else if property != nil { + property.value = value + self.defineOwnProperty(name, *property, throw) + } else { + self.defineProperty(name, value, 0111, throw) + } + return + } + + // The long way... + // + // Right now, code should never get here, see above + if !self.canPut(name) { + self.runtime.typeErrorResult(throw) + return + } + + property := self.getOwnProperty(name) + if property == nil { + property = self.getProperty(name) + if property != nil { + if getSet, isAccessor := property.value.(_propertyGetSet); isAccessor { + getSet[1].call(toValue(self), []Value{value}, false, nativeFrame) + return + } + } + self.defineProperty(name, value, 0111, throw) + } else { + switch propertyValue := property.value.(type) { + case Value: + property.value = value + self.defineOwnProperty(name, *property, throw) + case _propertyGetSet: + if propertyValue[1] != nil { + propertyValue[1].call(toValue(self), []Value{value}, false, nativeFrame) + return + } + if throw { + panic(self.runtime.panicTypeError()) + } + default: + panic(self.runtime.panicTypeError()) + } + } +} + +// 8.12.6 +func objectHasProperty(self *_object, name string) bool { + return self.getProperty(name) != nil +} + +func objectHasOwnProperty(self *_object, name string) bool { + return self.getOwnProperty(name) != nil +} + +// 8.12.9 +func objectDefineOwnProperty(self *_object, name string, descriptor _property, throw bool) bool { + property, exists := self._read(name) + { + if !exists { + if !self.extensible { + goto Reject + } + if newGetSet, isAccessor := descriptor.value.(_propertyGetSet); isAccessor { + if newGetSet[0] == &_nilGetSetObject { + newGetSet[0] = nil + } + if newGetSet[1] == &_nilGetSetObject { + newGetSet[1] = nil + } + descriptor.value = newGetSet + } + self._write(name, descriptor.value, descriptor.mode) + return true + } + if descriptor.isEmpty() { + return true + } + + // TODO Per 8.12.9.6 - We should shortcut here (returning true) if + // the current and new (define) properties are the same + + configurable := property.configurable() + if !configurable { + if descriptor.configurable() { + goto Reject + } + // Test that, if enumerable is set on the property descriptor, then it should + // be the same as the existing property + if descriptor.enumerateSet() && descriptor.enumerable() != property.enumerable() { + goto Reject + } + } + value, isDataDescriptor := property.value.(Value) + getSet, _ := property.value.(_propertyGetSet) + if descriptor.isGenericDescriptor() { + // GenericDescriptor + } else if isDataDescriptor != descriptor.isDataDescriptor() { + // DataDescriptor <=> AccessorDescriptor + if !configurable { + goto Reject + } + } else if isDataDescriptor && descriptor.isDataDescriptor() { + // DataDescriptor <=> DataDescriptor + if !configurable { + if !property.writable() && descriptor.writable() { + goto Reject + } + if !property.writable() { + if descriptor.value != nil && !sameValue(value, descriptor.value.(Value)) { + goto Reject + } + } + } + } else { + // AccessorDescriptor <=> AccessorDescriptor + newGetSet, _ := descriptor.value.(_propertyGetSet) + presentGet, presentSet := true, true + if newGetSet[0] == &_nilGetSetObject { + // Present, but nil + newGetSet[0] = nil + } else if newGetSet[0] == nil { + // Missing, not even nil + newGetSet[0] = getSet[0] + presentGet = false + } + if newGetSet[1] == &_nilGetSetObject { + // Present, but nil + newGetSet[1] = nil + } else if newGetSet[1] == nil { + // Missing, not even nil + newGetSet[1] = getSet[1] + presentSet = false + } + if !configurable { + if (presentGet && (getSet[0] != newGetSet[0])) || (presentSet && (getSet[1] != newGetSet[1])) { + goto Reject + } + } + descriptor.value = newGetSet + } + { + // This section will preserve attributes of + // the original property, if necessary + value1 := descriptor.value + if value1 == nil { + value1 = property.value + } else if newGetSet, isAccessor := descriptor.value.(_propertyGetSet); isAccessor { + if newGetSet[0] == &_nilGetSetObject { + newGetSet[0] = nil + } + if newGetSet[1] == &_nilGetSetObject { + newGetSet[1] = nil + } + value1 = newGetSet + } + mode1 := descriptor.mode + if mode1&0222 != 0 { + // TODO Factor this out into somewhere testable + // (Maybe put into switch ...) + mode0 := property.mode + if mode1&0200 != 0 { + if descriptor.isDataDescriptor() { + mode1 &= ^0200 // Turn off "writable" missing + mode1 |= (mode0 & 0100) + } + } + if mode1&020 != 0 { + mode1 |= (mode0 & 010) + } + if mode1&02 != 0 { + mode1 |= (mode0 & 01) + } + mode1 &= 0311 // 0311 to preserve the non-setting on "writable" + } + self._write(name, value1, mode1) + } + return true + } +Reject: + if throw { + panic(self.runtime.panicTypeError()) + } + return false +} + +func objectDelete(self *_object, name string, throw bool) bool { + property_ := self.getOwnProperty(name) + if property_ == nil { + return true + } + if property_.configurable() { + self._delete(name) + return true + } + return self.runtime.typeErrorResult(throw) +} + +func objectClone(in *_object, out *_object, clone *_clone) *_object { + *out = *in + + out.runtime = clone.runtime + if out.prototype != nil { + out.prototype = clone.object(in.prototype) + } + out.property = make(map[string]_property, len(in.property)) + out.propertyOrder = make([]string, len(in.propertyOrder)) + copy(out.propertyOrder, in.propertyOrder) + for index, property := range in.property { + out.property[index] = clone.property(property) + } + + switch value := in.value.(type) { + case _nativeFunctionObject: + out.value = value + case _bindFunctionObject: + out.value = _bindFunctionObject{ + target: clone.object(value.target), + this: clone.value(value.this), + argumentList: clone.valueArray(value.argumentList), + } + case _nodeFunctionObject: + out.value = _nodeFunctionObject{ + node: value.node, + stash: clone.stash(value.stash), + } + case _argumentsObject: + out.value = value.clone(clone) + } + + return out +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/object_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/object_test.go new file mode 100644 index 0000000000..d1e90680bd --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/object_test.go @@ -0,0 +1,639 @@ +package otto + +import ( + "testing" +) + +func TestObject_(t *testing.T) { + tt(t, func() { + test, _ := test() + + object := newObject(nil, "") + is(object != nil, true) + + object.put("xyzzy", toValue("Nothing happens."), true) + is(object.get("xyzzy"), "Nothing happens.") + + test(` + var abc = Object.getOwnPropertyDescriptor(Object, "prototype"); + [ [ typeof Object.prototype, abc.writable, abc.enumerable, abc.configurable ], + ]; + `, "object,false,false,false") + }) +} + +func TestStringObject(t *testing.T) { + tt(t, func() { + object := New().runtime.newStringObject(toValue("xyzzy")) + is(object.get("1"), "y") + is(object.get("10"), "undefined") + is(object.get("2"), "z") + }) +} + +func TestObject_getPrototypeOf(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = {}; + def = Object.getPrototypeOf(abc); + ghi = Object.getPrototypeOf(def); + [abc,def,ghi,ghi+""]; + `, "[object Object],[object Object],,null") + + test(` + abc = Object.getOwnPropertyDescriptor(Object, "getPrototypeOf"); + [ abc.value === Object.getPrototypeOf, abc.writable, abc.enumerable, abc.configurable ]; + `, "true,true,false,true") + }) +} + +func TestObject_new(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ new Object("abc"), new Object(2+2) ]; + `, "abc,4") + }) +} + +func TestObject_create(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: Object.create()`, "TypeError") + + test(` + var abc = Object.create(null) + var def = Object.create({x: 10, y: 20}) + var ghi = Object.create(Object.prototype) + + var jkl = Object.create({x: 10, y: 20}, { + z: { + value: 30, + writable: true + }, + // sum: { + // get: function() { + // return this.x + this.y + this.z + // } + // } + }); + [ abc.prototype, def.x, def.y, ghi, jkl.x, jkl.y, jkl.z ] + `, ",10,20,[object Object],10,20,30") + + test(` + var properties = {}; + Object.defineProperty(properties, "abc", { + value: {}, + enumerable: false + }); + var mno = Object.create({}, properties); + mno.hasOwnProperty("abc"); + `, false) + }) +} + +func TestObject_toLocaleString(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + ({}).toLocaleString(); + `, "[object Object]") + + test(` + object = { + toString: function() { + return "Nothing happens."; + } + }; + object.toLocaleString(); + `, "Nothing happens.") + }) +} + +func TestObject_isExtensible(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: + Object.isExtensible(); + `, "TypeError") + + // FIXME terst, Why raise? + test(`raise: + Object.isExtensible({}); + `, true) + + test(`Object.isExtensible.length`, 1) + test(`Object.isExtensible.prototype`, "undefined") + }) +} + +func TestObject_preventExtensions(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: + Object.preventExtensions() + `, "TypeError") + + test(`raise: + var abc = { def: true }; + var ghi = Object.preventExtensions(abc); + [ ghi.def === true, Object.isExtensible(abc), Object.isExtensible(ghi) ]; + `, "true,false,false") + + test(` + var abc = new String(); + var def = Object.isExtensible(abc); + Object.preventExtensions(abc); + var ghi = false; + try { + Object.defineProperty(abc, "0", { value: "~" }); + } catch (err) { + ghi = err instanceof TypeError; + } + [ def, ghi, abc.hasOwnProperty("0"), typeof abc[0] ]; + `, "true,true,false,undefined") + + test(`Object.preventExtensions.length`, 1) + test(`Object.preventExtensions.prototype`, "undefined") + }) +} + +func TestObject_isSealed(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Object.isSealed.length`, 1) + test(`Object.isSealed.prototype`, "undefined") + }) +} + +func TestObject_seal(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: Object.seal()`, "TypeError") + + test(` + var abc = {a:1,b:1,c:3}; + var sealed = Object.isSealed(abc); + Object.seal(abc); + [sealed, Object.isSealed(abc)]; + `, "false,true") + + test(` + var abc = {a:1,b:1,c:3}; + var sealed = Object.isSealed(abc); + var caught = false; + Object.seal(abc); + abc.b = 5; + Object.defineProperty(abc, "a", {value:4}); + try { + Object.defineProperty(abc, "a", {value:42,enumerable:false}); + } catch (e) { + caught = e instanceof TypeError; + } + [sealed, Object.isSealed(abc), caught, abc.a, abc.b]; + `, "false,true,true,4,5") + + test(`Object.seal.length`, 1) + test(`Object.seal.prototype`, "undefined") + }) +} + +func TestObject_isFrozen(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: Object.isFrozen()`, "TypeError") + test(`Object.isFrozen(Object.preventExtensions({a:1}))`, false) + test(`Object.isFrozen({})`, false) + + test(` + var abc = {}; + Object.defineProperty(abc, "def", { + value: "def", + writable: true, + configurable: false + }); + Object.preventExtensions(abc); + !Object.isFrozen(abc); + `, true) + + test(`Object.isFrozen.length`, 1) + test(`Object.isFrozen.prototype`, "undefined") + }) +} + +func TestObject_freeze(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: Object.freeze()`, "TypeError") + + test(` + var abc = {a:1,b:2,c:3}; + var frozen = Object.isFrozen(abc); + Object.freeze(abc); + abc.b = 5; + [frozen, Object.isFrozen(abc), abc.b]; + `, "false,true,2") + + test(` + var abc = {a:1,b:2,c:3}; + var frozen = Object.isFrozen(abc); + var caught = false; + Object.freeze(abc); + abc.b = 5; + try { + Object.defineProperty(abc, "a", {value:4}); + } catch (e) { + caught = e instanceof TypeError; + } + [frozen, Object.isFrozen(abc), caught, abc.a, abc.b]; + `, "false,true,true,1,2") + + test(`Object.freeze.length`, 1) + test(`Object.freeze.prototype`, "undefined") + }) +} + +func TestObject_defineProperty(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + (function(abc, def, ghi){ + Object.defineProperty(arguments, "0", { + enumerable: false + }); + return true; + })(0, 1, 2); + `, true) + + test(` + var abc = {}; + abc.def = 3.14; // Default: writable: true, enumerable: true, configurable: true + + Object.defineProperty(abc, "def", { + value: 42 + }); + + var ghi = Object.getOwnPropertyDescriptor(abc, "def"); + [ ghi.value, ghi.writable, ghi.enumerable, ghi.configurable ]; + `, "42,true,true,true") + + // Test that we handle the case of DefineOwnProperty + // where [[Writable]] is something but [[Value]] is not + test(` + var abc = []; + Object.defineProperty(abc, "0", { writable: false }); + 0 in abc; + `, true) + + // Test that we handle the case of DefineOwnProperty + // where [[Writable]] is something but [[Value]] is not + // (and the property originally had something for [[Value]] + test(` + abc = { + def: 42 + }; + Object.defineProperty(abc, "def", { writable: false }); + abc.def; + `, 42) + }) +} + +func TestObject_keys(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Object.keys({ abc:undefined, def:undefined })`, "abc,def") + + test(` + function abc() { + this.abc = undefined; + this.def = undefined; + } + Object.keys(new abc()) + `, "abc,def") + + test(` + function def() { + this.ghi = undefined; + } + def.prototype = new abc(); + Object.keys(new def()); + `, "ghi") + + test(` + var ghi = Object.create( + { + abc: undefined, + def: undefined + }, + { + ghi: { value: undefined, enumerable: true }, + jkl: { value: undefined, enumerable: false } + } + ); + Object.keys(ghi); + `, "ghi") + + test(` + (function(abc, def, ghi){ + return Object.keys(arguments) + })(undefined, undefined); + `, "0,1") + + test(` + (function(abc, def, ghi){ + return Object.keys(arguments) + })(undefined, undefined, undefined, undefined); + `, "0,1,2,3") + }) +} + +func TestObject_getOwnPropertyNames(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`Object.getOwnPropertyNames({ abc:undefined, def:undefined })`, "abc,def") + + test(` + var ghi = Object.create( + { + abc: undefined, + def: undefined + }, + { + ghi: { value: undefined, enumerable: true }, + jkl: { value: undefined, enumerable: false } + } + ); + Object.getOwnPropertyNames(ghi) + `, "ghi,jkl") + }) +} + +func TestObjectGetterSetter(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: + Object.create({}, { + abc: { + get: function(){ + return "true"; + }, + writable: true + } + }).abc; + `, "TypeError") + + test(`raise: + Object.create({}, { + abc: { + get: function(){ + return "true"; + }, + writable: false + } + }).abc; + `, "TypeError") + + test(` + Object.create({}, { + abc: { + get: function(){ + return "true"; + } + } + }).abc; + `, "true") + + test(` + Object.create({xyz:true},{abc:{get:function(){return this.xyx}}}).abc; + Object.create({ + xyz: true + }, { + abc: { + get: function(){ + return this.xyz; + } + } + }).abc; + `, true) + + test(` + var abc = false; + var def = Object.create({}, { + xyz: { + set: function(value) { + abc = value; + } + } + }); + def.xyz = true; + [ abc ]; + `, "true") + + test(` + var abc = {}; + Object.defineProperty(abc, "def", { + value: "xyzzy", + configurable: true + }); + Object.preventExtensions(abc); + Object.defineProperty(abc, "def", { + get: function() { + return 5; + } + }); + var def = Object.getOwnPropertyDescriptor(abc, "def"); + [ abc.def, typeof def.get, typeof def.set, typeof def.value, def.configurable, def.enumerable, typeof def.writable ]; + `, "5,function,undefined,undefined,true,false,undefined") + + test(` + var abc = {}; + Object.defineProperty(abc, "def", { + get: function() { + return 5; + } + configurable: true + }); + Object.preventExtensions(abc); + Object.defineProperty(abc, "def", { + value: "xyzzy", + }); + var def = Object.getOwnPropertyDescriptor(abc, "def"); + [ abc.def, typeof def.get, typeof def.set, def.value, def.configurable, def.enumerable, def.writable ]; + `, "xyzzy,undefined,undefined,xyzzy,true,false,false") + + test(` + var abc = {}; + + function _get0() { + return 10; + } + + function _set(value) { + abc.def = value; + } + + Object.defineProperty(abc, "ghi", { + get: _get0, + set: _set, + configurable: true + }); + + function _get1() { + return 20; + } + + Object.defineProperty(abc, "ghi", { + get: _get0 + }); + + var descriptor = Object.getOwnPropertyDescriptor(abc, "ghi"); + [ typeof descriptor.set ]; + `, "function") + + test(`raise: + var abc = []; + Object.defineProperty(abc, "length", { + get: function () { + return 2; + } + }); + `, "TypeError") + + test(` + var abc = {}; + + var getter = function() { + return 1; + } + + Object.defineProperty(abc, "def", { + get: getter, + configurable: false + }); + + var jkl = undefined; + try { + Object.defineProperty(abc, "def", { + get: undefined + }); + } + catch (err) { + jkl = err; + } + var ghi = Object.getOwnPropertyDescriptor(abc, "def"); + [ jkl instanceof TypeError, ghi.get === getter, ghi.configurable, ghi.enumerable ]; + `, "true,true,false,false") + + test(` + var abc = {}; + + var getter = function() { + return 1; + }; + + Object.defineProperty(abc, "def", { + get: getter + }); + + Object.defineProperty(abc, "def", { + set: undefined + }); + + var ghi = Object.getOwnPropertyDescriptor(abc, "def"); + [ ghi.get === getter, ghi.set === undefined, ghi.configurable, ghi.enumerable ]; + `, "true,true,false,false") + + test(` + var abc = {}; + + var getter = function() { + return 1; + }; + + Object.defineProperty(abc, "def", { + get: getter + }); + + var jkl = undefined; + try { + Object.defineProperty(abc, "def", { + set: function() {} + }); + } + catch (err) { + jkl = err; + } + + var ghi = Object.getOwnPropertyDescriptor(abc, "def"); + [ jkl instanceof TypeError, ghi.get === getter, ghi.set, ghi.configurable, ghi.enumerable ]; + `, "true,true,,false,false") + + test(` + var abc = {}; + var def = "xyzzy"; + + Object.defineProperty(abc, "ghi", { + get: undefined, + set: function(value) { + def = value; + }, + enumerable: true, + configurable: true + }); + + var hasOwn = abc.hasOwnProperty("ghi"); + var descriptor = Object.getOwnPropertyDescriptor(abc, "ghi"); + + [ hasOwn, typeof descriptor.get ]; + `, "true,undefined") + + test(` + var abc = "xyzzy"; + Object.defineProperty(Array.prototype, "abc", { + get: function () { + return abc; + }, + set: function (value) { + abc = value; + }, + enumerable: true, + configurable: true + }); + var def = []; + def.abc = 3.14159; + [ def.hasOwnProperty("abc"), def.abc, abc ]; + `, "false,3.14159,3.14159") + }) +} + +func TestProperty(t *testing.T) { + tt(t, func() { + property := _property{} + property.writeOn() + is(property.writeSet(), true) + + property.writeClear() + is(property.writeSet(), false) + + property.writeOff() + is(property.writeSet(), true) + + property.writeClear() + is(property.writeSet(), false) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go new file mode 100644 index 0000000000..9de3e08c57 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go @@ -0,0 +1,578 @@ +/* +Package otto is a JavaScript parser and interpreter written natively in Go. + +http://godoc.org/github.com/robertkrimen/otto + + import ( + "github.com/robertkrimen/otto" + ) + +Run something in the VM + + vm := otto.New() + vm.Run(` + abc = 2 + 2; + console.log("The value of abc is " + abc); // 4 + `) + +Get a value out of the VM + + value, err := vm.Get("abc") + value, _ := value.ToInteger() + } + +Set a number + + vm.Set("def", 11) + vm.Run(` + console.log("The value of def is " + def); + // The value of def is 11 + `) + +Set a string + + vm.Set("xyzzy", "Nothing happens.") + vm.Run(` + console.log(xyzzy.length); // 16 + `) + +Get the value of an expression + + value, _ = vm.Run("xyzzy.length") + { + // value is an int64 with a value of 16 + value, _ := value.ToInteger() + } + +An error happens + + value, err = vm.Run("abcdefghijlmnopqrstuvwxyz.length") + if err != nil { + // err = ReferenceError: abcdefghijlmnopqrstuvwxyz is not defined + // If there is an error, then value.IsUndefined() is true + ... + } + +Set a Go function + + vm.Set("sayHello", func(call otto.FunctionCall) otto.Value { + fmt.Printf("Hello, %s.\n", call.Argument(0).String()) + return otto.Value{} + }) + +Set a Go function that returns something useful + + vm.Set("twoPlus", func(call otto.FunctionCall) otto.Value { + right, _ := call.Argument(0).ToInteger() + result, _ := vm.ToValue(2 + right) + return result + }) + +Use the functions in JavaScript + + result, _ = vm.Run(` + sayHello("Xyzzy"); // Hello, Xyzzy. + sayHello(); // Hello, undefined + + result = twoPlus(2.0); // 4 + `) + +Parser + +A separate parser is available in the parser package if you're just interested in building an AST. + +http://godoc.org/github.com/robertkrimen/otto/parser + +Parse and return an AST + + filename := "" // A filename is optional + src := ` + // Sample xyzzy example + (function(){ + if (3.14159 > 0) { + console.log("Hello, World."); + return; + } + + var xyzzy = NaN; + console.log("Nothing happens."); + return xyzzy; + })(); + ` + + // Parse some JavaScript, yielding a *ast.Program and/or an ErrorList + program, err := parser.ParseFile(nil, filename, src, 0) + +otto + +You can run (Go) JavaScript from the commandline with: http://github.com/robertkrimen/otto/tree/master/otto + + $ go get -v github.com/robertkrimen/otto/otto + +Run JavaScript by entering some source on stdin or by giving otto a filename: + + $ otto example.js + +underscore + +Optionally include the JavaScript utility-belt library, underscore, with this import: + + import ( + "github.com/robertkrimen/otto" + _ "github.com/robertkrimen/otto/underscore" + ) + + // Now every otto runtime will come loaded with underscore + +For more information: http://github.com/robertkrimen/otto/tree/master/underscore + +Caveat Emptor + +The following are some limitations with otto: + + * "use strict" will parse, but does nothing. + * The regular expression engine (re2/regexp) is not fully compatible with the ECMA5 specification. + +Regular Expression Incompatibility + +Go translates JavaScript-style regular expressions into something that is "regexp" compatible via `parser.TransformRegExp`. +Unfortunately, RegExp requires backtracking for some patterns, and backtracking is not supported by the standard Go engine: https://code.google.com/p/re2/wiki/Syntax + +Therefore, the following syntax is incompatible: + + (?=) // Lookahead (positive), currently a parsing error + (?!) // Lookahead (backhead), currently a parsing error + \1 // Backreference (\1, \2, \3, ...), currently a parsing error + +A brief discussion of these limitations: "Regexp (?!re)" https://groups.google.com/forum/?fromgroups=#%21topic/golang-nuts/7qgSDWPIh_E + +More information about re2: https://code.google.com/p/re2/ + +In addition to the above, re2 (Go) has a different definition for \s: [\t\n\f\r ]. +The JavaScript definition, on the other hand, also includes \v, Unicode "Separator, Space", etc. + +Halting Problem + +If you want to stop long running executions (like third-party code), you can use the interrupt channel to do this: + + package main + + import ( + "errors" + "fmt" + "os" + "time" + + "github.com/robertkrimen/otto" + ) + + var halt = errors.New("Stahp") + + func main() { + runUnsafe(`var abc = [];`) + runUnsafe(` + while (true) { + // Loop forever + }`) + } + + func runUnsafe(unsafe string) { + start := time.Now() + defer func() { + duration := time.Since(start) + if caught := recover(); caught != nil { + if caught == halt { + fmt.Fprintf(os.Stderr, "Some code took to long! Stopping after: %v\n", duration) + return + } + panic(caught) // Something else happened, repanic! + } + fmt.Fprintf(os.Stderr, "Ran code successfully: %v\n", duration) + }() + + vm := otto.New() + vm.Interrupt = make(chan func(), 1) // The buffer prevents blocking + + go func() { + time.Sleep(2 * time.Second) // Stop after two seconds + vm.Interrupt <- func() { + panic(halt) + } + }() + + vm.Run(unsafe) // Here be dragons (risky code) + } + +Where is setTimeout/setInterval? + +These timing functions are not actually part of the ECMA-262 specification. Typically, they belong to the `windows` object (in the browser). +It would not be difficult to provide something like these via Go, but you probably want to wrap otto in an event loop in that case. + +For an example of how this could be done in Go with otto, see natto: + +http://github.com/robertkrimen/natto + +Here is some more discussion of the issue: + +* http://book.mixu.net/node/ch2.html + +* http://en.wikipedia.org/wiki/Reentrancy_%28computing%29 + +* http://aaroncrane.co.uk/2009/02/perl_safe_signals/ + +*/ +package otto + +import ( + "fmt" + "strings" + + "github.com/robertkrimen/otto/registry" +) + +// Otto is the representation of the JavaScript runtime. Each instance of Otto has a self-contained namespace. +type Otto struct { + // Interrupt is a channel for interrupting the runtime. You can use this to halt a long running execution, for example. + // See "Halting Problem" for more information. + Interrupt chan func() + runtime *_runtime +} + +// New will allocate a new JavaScript runtime +func New() *Otto { + self := &Otto{ + runtime: newContext(), + } + self.runtime.otto = self + self.Set("console", self.runtime.newConsole()) + + registry.Apply(func(entry registry.Entry) { + self.Run(entry.Source()) + }) + + return self +} + +func (otto *Otto) clone() *Otto { + self := &Otto{ + runtime: otto.runtime.clone(), + } + self.runtime.otto = self + return self +} + +// Run will allocate a new JavaScript runtime, run the given source +// on the allocated runtime, and return the runtime, resulting value, and +// error (if any). +// +// src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST always be in UTF-8. +// +// src may also be a Script. +// +// src may also be a Program, but if the AST has been modified, then runtime behavior is undefined. +// +func Run(src interface{}) (*Otto, Value, error) { + otto := New() + value, err := otto.Run(src) // This already does safety checking + return otto, value, err +} + +// Run will run the given source (parsing it first if necessary), returning the resulting value and error (if any) +// +// src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST always be in UTF-8. +// +// If the runtime is unable to parse source, then this function will return undefined and the parse error (nothing +// will be evaluated in this case). +// +// src may also be a Script. +// +// src may also be a Program, but if the AST has been modified, then runtime behavior is undefined. +// +func (self Otto) Run(src interface{}) (Value, error) { + value, err := self.runtime.cmpl_run(src) + if !value.safe() { + value = Value{} + } + return value, err +} + +// Get the value of the top-level binding of the given name. +// +// If there is an error (like the binding does not exist), then the value +// will be undefined. +func (self Otto) Get(name string) (Value, error) { + value := Value{} + err := catchPanic(func() { + value = self.getValue(name) + }) + if !value.safe() { + value = Value{} + } + return value, err +} + +func (self Otto) getValue(name string) Value { + return self.runtime.globalStash.getBinding(name, false) +} + +// Set the top-level binding of the given name to the given value. +// +// Set will automatically apply ToValue to the given value in order +// to convert it to a JavaScript value (type Value). +// +// If there is an error (like the binding is read-only, or the ToValue conversion +// fails), then an error is returned. +// +// If the top-level binding does not exist, it will be created. +func (self Otto) Set(name string, value interface{}) error { + { + value, err := self.ToValue(value) + if err != nil { + return err + } + err = catchPanic(func() { + self.setValue(name, value) + }) + return err + } +} + +func (self Otto) setValue(name string, value Value) { + self.runtime.globalStash.setValue(name, value, false) +} + +// Call the given JavaScript with a given this and arguments. +// +// If this is nil, then some special handling takes place to determine the proper +// this value, falling back to a "standard" invocation if necessary (where this is +// undefined). +// +// If source begins with "new " (A lowercase new followed by a space), then +// Call will invoke the function constructor rather than performing a function call. +// In this case, the this argument has no effect. +// +// // value is a String object +// value, _ := vm.Call("Object", nil, "Hello, World.") +// +// // Likewise... +// value, _ := vm.Call("new Object", nil, "Hello, World.") +// +// // This will perform a concat on the given array and return the result +// // value is [ 1, 2, 3, undefined, 4, 5, 6, 7, "abc" ] +// value, _ := vm.Call(`[ 1, 2, 3, undefined, 4 ].concat`, nil, 5, 6, 7, "abc") +// +func (self Otto) Call(source string, this interface{}, argumentList ...interface{}) (Value, error) { + + thisValue := Value{} + + construct := false + if strings.HasPrefix(source, "new ") { + source = source[4:] + construct = true + } + + // FIXME enterGlobalScope + self.runtime.enterGlobalScope() + defer func() { + self.runtime.leaveScope() + }() + + if !construct && this == nil { + program, err := self.runtime.cmpl_parse("", source+"()") + if err == nil { + if node, ok := program.body[0].(*_nodeExpressionStatement); ok { + if node, ok := node.expression.(*_nodeCallExpression); ok { + var value Value + err := catchPanic(func() { + value = self.runtime.cmpl_evaluate_nodeCallExpression(node, argumentList) + }) + if err != nil { + return Value{}, err + } + return value, nil + } + } + } + } else { + value, err := self.ToValue(this) + if err != nil { + return Value{}, err + } + thisValue = value + } + + { + this := thisValue + + fn, err := self.Run(source) + if err != nil { + return Value{}, err + } + + if construct { + result, err := fn.constructSafe(self.runtime, this, argumentList...) + if err != nil { + return Value{}, err + } + return result, nil + } + + result, err := fn.Call(this, argumentList...) + if err != nil { + return Value{}, err + } + return result, nil + } +} + +// Object will run the given source and return the result as an object. +// +// For example, accessing an existing object: +// +// object, _ := vm.Object(`Number`) +// +// Or, creating a new object: +// +// object, _ := vm.Object(`({ xyzzy: "Nothing happens." })`) +// +// Or, creating and assigning an object: +// +// object, _ := vm.Object(`xyzzy = {}`) +// object.Set("volume", 11) +// +// If there is an error (like the source does not result in an object), then +// nil and an error is returned. +func (self Otto) Object(source string) (*Object, error) { + value, err := self.runtime.cmpl_run(source) + if err != nil { + return nil, err + } + if value.IsObject() { + return value.Object(), nil + } + return nil, fmt.Errorf("value is not an object") +} + +// ToValue will convert an interface{} value to a value digestible by otto/JavaScript. +func (self Otto) ToValue(value interface{}) (Value, error) { + return self.runtime.safeToValue(value) +} + +// Copy will create a copy/clone of the runtime. +// +// Copy is useful for saving some time when creating many similar runtimes. +// +// This method works by walking the original runtime and cloning each object, scope, stash, +// etc. into a new runtime. +// +// Be on the lookout for memory leaks or inadvertent sharing of resources. +func (in *Otto) Copy() *Otto { + out := &Otto{ + runtime: in.runtime.clone(), + } + out.runtime.otto = out + return out +} + +// Object{} + +// Object is the representation of a JavaScript object. +type Object struct { + object *_object + value Value +} + +func _newObject(object *_object, value Value) *Object { + // value MUST contain object! + return &Object{ + object: object, + value: value, + } +} + +// Call a method on the object. +// +// It is essentially equivalent to: +// +// var method, _ := object.Get(name) +// method.Call(object, argumentList...) +// +// An undefined value and an error will result if: +// +// 1. There is an error during conversion of the argument list +// 2. The property is not actually a function +// 3. An (uncaught) exception is thrown +// +func (self Object) Call(name string, argumentList ...interface{}) (Value, error) { + // TODO: Insert an example using JavaScript below... + // e.g., Object("JSON").Call("stringify", ...) + + function, err := self.Get(name) + if err != nil { + return Value{}, err + } + return function.Call(self.Value(), argumentList...) +} + +// Value will return self as a value. +func (self Object) Value() Value { + return self.value +} + +// Get the value of the property with the given name. +func (self Object) Get(name string) (Value, error) { + value := Value{} + err := catchPanic(func() { + value = self.object.get(name) + }) + if !value.safe() { + value = Value{} + } + return value, err +} + +// Set the property of the given name to the given value. +// +// An error will result if the setting the property triggers an exception (i.e. read-only), +// or there is an error during conversion of the given value. +func (self Object) Set(name string, value interface{}) error { + { + value, err := self.object.runtime.safeToValue(value) + if err != nil { + return err + } + err = catchPanic(func() { + self.object.put(name, value, true) + }) + return err + } +} + +// Get the keys for the object +// +// Equivalent to calling Object.keys on the object +func (self Object) Keys() []string { + var keys []string + self.object.enumerate(false, func(name string) bool { + keys = append(keys, name) + return true + }) + return keys +} + +// Class will return the class string of the object. +// +// The return value will (generally) be one of: +// +// Object +// Function +// Array +// String +// Number +// Boolean +// Date +// RegExp +// +func (self Object) Class() string { + return self.object.class +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto/Makefile b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto/Makefile new file mode 100644 index 0000000000..bac5cd4a55 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto/Makefile @@ -0,0 +1,5 @@ +.PHONY: build + +build: + go build -a + -gxc build-darwin-386 -a diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto/main.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto/main.go new file mode 100644 index 0000000000..f379e42a92 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + + "github.com/robertkrimen/otto" + "github.com/robertkrimen/otto/underscore" +) + +var flag_underscore *bool = flag.Bool("underscore", true, "Load underscore into the runtime environment") + +func readSource(filename string) ([]byte, error) { + if filename == "" || filename == "-" { + return ioutil.ReadAll(os.Stdin) + } + return ioutil.ReadFile(filename) +} + +func main() { + flag.Parse() + + if !*flag_underscore { + underscore.Disable() + } + + err := func() error { + src, err := readSource(flag.Arg(0)) + if err != nil { + return err + } + + vm := otto.New() + _, err = vm.Run(src) + return err + }() + if err != nil { + switch err := err.(type) { + case *otto.Error: + fmt.Print(err.String()) + default: + fmt.Println(err) + } + os.Exit(64) + } +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_.go new file mode 100644 index 0000000000..e053b54e29 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_.go @@ -0,0 +1,178 @@ +package otto + +import ( + "fmt" + "regexp" + runtime_ "runtime" + "strconv" + "strings" +) + +var isIdentifier_Regexp *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z\$][a-zA-Z0-9\$]*$`) + +func isIdentifier(string_ string) bool { + return isIdentifier_Regexp.MatchString(string_) +} + +func (self *_runtime) toValueArray(arguments ...interface{}) []Value { + length := len(arguments) + if length == 1 { + if valueArray, ok := arguments[0].([]Value); ok { + return valueArray + } + return []Value{toValue(arguments[0])} + } + + valueArray := make([]Value, length) + for index, value := range arguments { + valueArray[index] = toValue(value) + } + + return valueArray +} + +func stringToArrayIndex(name string) int64 { + index, err := strconv.ParseInt(name, 10, 64) + if err != nil { + return -1 + } + if index < 0 { + return -1 + } + if index >= maxUint32 { + // The value 2^32 (or above) is not a valid index because + // you cannot store a uint32 length for an index of uint32 + return -1 + } + return index +} + +func isUint32(value int64) bool { + return value >= 0 && value <= maxUint32 +} + +func arrayIndexToString(index int64) string { + return strconv.FormatInt(index, 10) +} + +func valueOfArrayIndex(array []Value, index int) Value { + value, _ := getValueOfArrayIndex(array, index) + return value +} + +func getValueOfArrayIndex(array []Value, index int) (Value, bool) { + if index >= 0 && index < len(array) { + value := array[index] + if !value.isEmpty() { + return value, true + } + } + return Value{}, false +} + +// A range index can be anything from 0 up to length. It is NOT safe to use as an index +// to an array, but is useful for slicing and in some ECMA algorithms. +func valueToRangeIndex(indexValue Value, length int64, negativeIsZero bool) int64 { + index := indexValue.number().int64 + if negativeIsZero { + if index < 0 { + index = 0 + } + // minimum(index, length) + if index >= length { + index = length + } + return index + } + + if index < 0 { + index += length + if index < 0 { + index = 0 + } + } else { + if index > length { + index = length + } + } + return index +} + +func rangeStartEnd(array []Value, size int64, negativeIsZero bool) (start, end int64) { + start = valueToRangeIndex(valueOfArrayIndex(array, 0), size, negativeIsZero) + if len(array) == 1 { + // If there is only the start argument, then end = size + end = size + return + } + + // Assuming the argument is undefined... + end = size + endValue := valueOfArrayIndex(array, 1) + if !endValue.IsUndefined() { + // Which it is not, so get the value as an array index + end = valueToRangeIndex(endValue, size, negativeIsZero) + } + return +} + +func rangeStartLength(source []Value, size int64) (start, length int64) { + start = valueToRangeIndex(valueOfArrayIndex(source, 0), size, false) + + // Assume the second argument is missing or undefined + length = int64(size) + if len(source) == 1 { + // If there is only the start argument, then length = size + return + } + + lengthValue := valueOfArrayIndex(source, 1) + if !lengthValue.IsUndefined() { + // Which it is not, so get the value as an array index + length = lengthValue.number().int64 + } + return +} + +func boolFields(input string) (result map[string]bool) { + result = map[string]bool{} + for _, word := range strings.Fields(input) { + result[word] = true + } + return result +} + +func hereBeDragons(arguments ...interface{}) string { + pc, _, _, _ := runtime_.Caller(1) + name := runtime_.FuncForPC(pc).Name() + message := fmt.Sprintf("Here be dragons -- %s", name) + if len(arguments) > 0 { + message += ": " + argument0 := fmt.Sprintf("%s", arguments[0]) + if len(arguments) == 1 { + message += argument0 + } else { + message += fmt.Sprintf(argument0, arguments[1:]...) + } + } else { + message += "." + } + return message +} + +func throwHereBeDragons(arguments ...interface{}) { + panic(hereBeDragons(arguments...)) +} + +func eachPair(list []interface{}, fn func(_0, _1 interface{})) { + for len(list) > 0 { + var _0, _1 interface{} + _0 = list[0] + list = list[1:] // Pop off first + if len(list) > 0 { + _1 = list[0] + list = list[1:] // Pop off second + } + fn(_0, _1) + } +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_error_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_error_test.go new file mode 100644 index 0000000000..5ce358819a --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_error_test.go @@ -0,0 +1,48 @@ +package otto + +import ( + "testing" +) + +func TestOttoError(t *testing.T) { + tt(t, func() { + vm := New() + + _, err := vm.Run(`throw "Xyzzy"`) + is(err, "Xyzzy") + + _, err = vm.Run(`throw new TypeError()`) + is(err, "TypeError") + + _, err = vm.Run(`throw new TypeError("Nothing happens.")`) + is(err, "TypeError: Nothing happens.") + + _, err = ToValue([]byte{}) + is(err, "TypeError: invalid value (slice): missing runtime: [] ([]uint8)") + + _, err = vm.Run(` + (function(){ + return abcdef.length + })() + `) + is(err, "ReferenceError: 'abcdef' is not defined") + + _, err = vm.Run(` + function start() { + } + + start() + + xyzzy() + `) + is(err, "ReferenceError: 'xyzzy' is not defined") + + _, err = vm.Run(` + // Just a comment + + xyzzy + `) + is(err, "ReferenceError: 'xyzzy' is not defined") + + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_test.go new file mode 100644 index 0000000000..2f1e1c35f6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_test.go @@ -0,0 +1,1379 @@ +package otto + +import ( + "bytes" + "io" + "testing" + + "github.com/robertkrimen/otto/parser" +) + +func TestOtto(t *testing.T) { + tt(t, func() { + test, _ := test() + + test("xyzzy = 2", 2) + + test("xyzzy + 2", 4) + + test("xyzzy += 16", 18) + + test("xyzzy", 18) + + test(` + (function(){ + return 1 + })() + `, 1) + + test(` + (function(){ + return 1 + }).call(this) + `, 1) + + test(` + (function(){ + var result + (function(){ + result = -1 + })() + return result + })() + `, -1) + + test(` + var abc = 1 + abc || (abc = -1) + abc + `, 1) + + test(` + var abc = (function(){ 1 === 1 })(); + abc; + `, "undefined") + }) +} + +func TestFunction__(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + function abc() { + return 1; + }; + abc(); + `, 1) + }) +} + +func TestIf(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = undefined; + def = undefined; + if (true) abc = 1 + else abc = 2; + if (false) { + def = 3; + } + else def = 4; + + [ abc, def ]; + `, "1,4") + + test(` + if (1) { + abc = 1; + } + else { + abc = 0; + } + abc; + `, 1) + + test(` + if (0) { + abc = 1; + } + else { + abc = 0; + } + abc; + `, 0) + + test(` + abc = 0; + if (0) { + abc = 1; + } + abc; + `, 0) + + test(` + abc = 0; + if (abc) { + abc = 1; + } + abc; + `, 0) + }) +} + +func TestSequence(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + 1, 2, 3; + `, 3) + }) +} + +func TestCall(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + Math.pow(3, 2); + `, 9) + }) +} + +func TestMember(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = [ 0, 1, 2 ]; + def = { + "abc": 0, + "def": 1, + "ghi": 2, + }; + [ abc[2], def.abc, abc[1], def.def ]; + `, "2,0,1,1") + }) +} + +func Test_this(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + typeof this; + `, "object") + }) +} + +func TestWhile(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + limit = 4 + abc = 0 + while (limit) { + abc = abc + 1 + limit = limit - 1 + } + abc; + `, 4) + }) +} + +func TestSwitch_break(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = true; + var ghi = "Xyzzy"; + while (abc) { + switch ('def') { + case 'def': + break; + } + ghi = "Nothing happens."; + abc = false; + } + ghi; + `, "Nothing happens.") + + test(` + var abc = true; + var ghi = "Xyzzy"; + WHILE: + while (abc) { + switch ('def') { + case 'def': + break WHILE; + } + ghi = "Nothing happens." + abc = false + } + ghi; + `, "Xyzzy") + + test(` + var ghi = "Xyzzy"; + FOR: + for (;;) { + switch ('def') { + case 'def': + break FOR; + ghi = ""; + } + ghi = "Nothing happens."; + } + ghi; + `, "Xyzzy") + + test(` + var ghi = "Xyzzy"; + FOR: + for (var jkl in {}) { + switch ('def') { + case 'def': + break FOR; + ghi = "Something happens."; + } + ghi = "Nothing happens."; + } + ghi; + `, "Xyzzy") + + test(` + var ghi = "Xyzzy"; + function jkl() { + switch ('def') { + case 'def': + break; + ghi = ""; + } + ghi = "Nothing happens."; + } + while (abc) { + jkl(); + abc = false; + ghi = "Something happens."; + } + ghi; + `, "Something happens.") + }) +} + +func TestTryFinally(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc; + try { + abc = 1; + } + finally { + abc = 2; + } + abc; + `, 2) + + test(` + var abc = false, def = 0; + do { + def += 1; + if (def > 100) { + break; + } + try { + continue; + } + finally { + abc = true; + } + } + while(!abc && def < 10) + def; + `, 1) + + test(` + var abc = false, def = 0, ghi = 0; + do { + def += 1; + if (def > 100) { + break; + } + try { + throw 0; + } + catch (jkl) { + continue; + } + finally { + abc = true; + ghi = 11; + } + ghi -= 1; + } + while(!abc && def < 10) + ghi; + `, 11) + + test(` + var abc = 0, def = 0; + do { + try { + abc += 1; + throw "ghi"; + } + finally { + def = 1; + continue; + } + def -= 1; + } + while (abc < 2) + [ abc, def ]; + `, "2,1") + }) +} + +func TestTryCatch(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = 1; + try { + throw 4; + abc = -1; + } + catch (xyzzy) { + abc += xyzzy + 1; + } + abc; + `, 6) + + test(` + abc = 1; + var def; + try { + try { + throw 4; + abc = -1; + } + catch (xyzzy) { + abc += xyzzy + 1; + throw 64; + } + } + catch (xyzzy) { + def = xyzzy; + abc = -2; + } + [ def, abc ]; + `, "64,-2") + }) +} + +func TestWith(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var def; + with({ abc: 9 }) { + def = abc; + } + def; + `, 9) + + test(` + var def; + with({ abc: function(){ + return 11; + } }) { + def = abc(); + } + def; + `, 11) + }) +} + +func TestSwitch(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = 0; + switch (0) { + default: + abc += 1; + case 1: + abc += 2; + case 2: + abc += 4; + case 3: + abc += 8; + } + abc; + `, 15) + + test(` + abc = 0; + switch (3) { + default: + abc += 1; + case 1: + abc += 2; + case 2: + abc += 4; + case 3: + abc += 8; + } + abc; + `, 8) + + test(` + abc = 0; + switch (60) { + case 1: + abc += 2; + case 2: + abc += 4; + case 3: + abc += 8; + } + abc; + `, 0) + }) +} + +func TestForIn(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc; + for (property in { a: 1 }) { + abc = property; + } + abc; + `, "a") + + test(` + var ghi; + for (property in new String("xyzzy")) { + ghi = property; + } + ghi; + `, "4") + }) +} + +func TestFor(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = 7; + for (i = 0; i < 3; i += 1) { + abc += 1; + } + abc; + `, 10) + + test(` + abc = 7; + for (i = 0; i < 3; i += 1) { + abc += 1; + if (i == 1) { + break; + } + } + abc; + `, 9) + + test(` + abc = 7; + for (i = 0; i < 3; i += 1) { + if (i == 2) { + continue; + } + abc += 1; + } + abc; + `, 9) + + test(` + abc = 0; + for (;;) { + abc += 1; + if (abc == 3) + break; + } + abc; + `, 3) + + test(` + for (abc = 0; ;) { + abc += 1; + if (abc == 3) + break; + } + abc; + `, 3) + + test(` + for (abc = 0; ; abc += 1) { + abc += 1; + if (abc == 3) + break; + } + abc; + `, 3) + }) +} + +func TestLabelled(t *testing.T) { + tt(t, func() { + test, _ := test() + + // TODO Add emergency break + + test(` + xyzzy: for (var abc = 0; abc <= 0; abc++) { + for (var def = 0; def <= 1; def++) { + if (def === 0) { + continue xyzzy; + } else { + } + } + } + `) + + test(` + abc = 0 + def: + while (true) { + while (true) { + abc = abc + 1 + if (abc > 11) { + break def; + } + } + } + abc; + `, 12) + + test(` + abc = 0 + def: + do { + do { + abc = abc + 1 + if (abc > 11) { + break def; + } + } while (true) + } while (true) + abc; + `, 12) + }) +} + +func TestConditional(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ true ? false : true, true ? 1 : 0, false ? 3.14159 : "abc" ]; + `, "false,1,abc") + }) +} + +func TestArrayLiteral(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ 1, , 3.14159 ]; + `, "1,,3.14159") + }) +} + +func TestAssignment(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = 1; + abc; + `, 1) + + test(` + abc += 2; + abc; + `, 3) + }) +} + +func TestBinaryOperation(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`0 == 1`, false) + test(`1 == "1"`, true) + test(`0 === 1`, false) + test(`1 === "1"`, false) + test(`"1" === "1"`, true) + }) +} + +func Test_typeof(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`typeof abc`, "undefined") + test(`typeof abc === 'undefined'`, true) + test(`typeof {}`, "object") + test(`typeof null`, "object") + }) +} + +func Test_PrimitiveValueObjectValue(t *testing.T) { + tt(t, func() { + test, _ := test() + + Number11 := test(`new Number(11)`) + is(Number11.float64(), 11) + }) +} + +func Test_eval(t *testing.T) { + tt(t, func() { + test, _ := test() + + // FIXME terst, Is this correct? + test(` + var abc = 1; + `, "undefined") + + test(` + eval("abc += 1"); + `, 2) + + test(` + (function(){ + var abc = 11; + eval("abc += 1"); + return abc; + })(); + `, 12) + test(`abc`, 2) + + test(` + (function(){ + try { + eval("var prop = \\u2029;"); + return false; + } catch (abc) { + return [ abc instanceof SyntaxError, abc.toString() ]; + } + })(); + `, "true,SyntaxError: Unexpected token ILLEGAL") + + test(` + function abc(){ + this.THIS = eval("this"); + } + var def = new abc(); + def === def.THIS; + `, true) + }) +} + +func Test_evalDirectIndirect(t *testing.T) { + tt(t, func() { + test, _ := test() + + // (function () {return this;}()).abc = "global"; + test(` + var abc = "global"; + (function(){ + try { + var _eval = eval; + var abc = "function"; + return [ + _eval("\'global\' === abc"), // eval (Indirect) + eval("\'function\' === abc"), // eval (Direct) + ]; + } finally { + delete this.abc; + } + })(); + `, "true,true") + }) +} + +func TestError_URIError(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`new URIError() instanceof URIError`, true) + + test(` + var abc + try { + decodeURI("http://example.com/ _^#%") + } + catch (def) { + abc = def instanceof URIError + } + abc + `, true) + }) +} + +func TestTo(t *testing.T) { + tt(t, func() { + test, _ := test() + + { + value, _ := test(`"11"`).ToFloat() + is(value, float64(11)) + } + + { + value, _ := test(`"11"`).ToInteger() + is(value, int64(11)) + + value, _ = test(`1.1`).ToInteger() + is(value, int64(1)) + } + }) +} + +func TestShouldError(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`raise: + xyzzy + throw new TypeError("Nothing happens.") + `, "ReferenceError: 'xyzzy' is not defined") + }) +} + +func TestAPI(t *testing.T) { + tt(t, func() { + test, vm := test() + + test(` + String.prototype.xyzzy = function(){ + return this.length + 11 + (arguments[0] || 0) + } + abc = new String("xyzzy") + def = "Nothing happens." + abc.xyzzy() + `, 16) + abc, _ := vm.Get("abc") + def, _ := vm.Get("def") + object := abc.Object() + result, _ := object.Call("xyzzy") + is(result, 16) + result, _ = object.Call("xyzzy", 1) + is(result, 17) + value, _ := object.Get("xyzzy") + result, _ = value.Call(def) + is(result, 27) + result, _ = value.Call(def, 3) + is(result, 30) + object = value.Object() // Object xyzzy + result, _ = object.Value().Call(def, 3) + is(result, 30) + + test(` + abc = { + 'abc': 1, + 'def': false, + 3.14159: NaN, + }; + abc['abc']; + `, 1) + abc, err := vm.Get("abc") + is(err, nil) + object = abc.Object() // Object abc + value, err = object.Get("abc") + is(err, nil) + is(value, 1) + is(object.Keys(), []string{"abc", "def", "3.14159"}) + + test(` + abc = [ 0, 1, 2, 3.14159, "abc", , ]; + abc.def = true; + `) + abc, err = vm.Get("abc") + is(err, nil) + object = abc.Object() // Object abc + is(object.Keys(), []string{"0", "1", "2", "3", "4", "def"}) + }) +} + +func TestUnicode(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`var abc = eval("\"a\uFFFFa\"");`, "undefined") + + test(`abc.length`, 3) + + test(`abc != "aa"`, true) + + test("abc[1] === \"\uFFFF\"", true) + }) +} + +func TestDotMember(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = { + ghi: 11, + } + abc.def = "Xyzzy" + abc.null = "Nothing happens." + `) + test(`abc.def`, "Xyzzy") + test(`abc.null`, "Nothing happens.") + test(`abc.ghi`, 11) + + test(` + abc = { + null: 11, + } + `) + test(`abc.def`, "undefined") + test(`abc.null`, 11) + test(`abc.ghi`, "undefined") + }) +} + +func Test_stringToFloat(t *testing.T) { + tt(t, func() { + + is(parseNumber("10e10000"), _Infinity) + is(parseNumber("10e10_."), _NaN) + }) +} + +func Test_delete(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + delete 42; + `, true) + + test(` + var abc = delete $_undefined_$; + abc = abc && delete ($_undefined_$); + abc; + `, true) + + // delete should not trigger get() + test(` + var abc = { + get def() { + throw "Test_delete: delete should not trigger get()" + } + }; + delete abc.def + `, true) + }) +} + +func TestObject_defineOwnProperty(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var object = {}; + + var descriptor = new Boolean(false); + descriptor.configurable = true; + + Object.defineProperties(object, { + property: descriptor + }); + + var abc = object.hasOwnProperty("property"); + delete object.property; + var def = object.hasOwnProperty("property"); + + [ abc, def ]; + `, "true,false") + + test(` + var object = [0, 1, 2]; + Object.defineProperty(object, "0", { + value: 42, + writable: false, + enumerable: false, + configurable: false + }); + var abc = Object.getOwnPropertyDescriptor(object, "0"); + [ abc.value, abc.writable, abc.enumerable, abc.configurable ]; + `, "42,false,false,false") + + test(` + var abc = { "xyzzy": 42 }; + var def = Object.defineProperties(abc, ""); + abc === def; + `, true) + }) +} + +func Test_assignmentEvaluationOrder(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = 0; + ((abc = 1) & abc); + `, 1) + + test(` + var abc = 0; + (abc & (abc = 1)); + `, 0) + }) +} + +func TestOttoCall(t *testing.T) { + tt(t, func() { + vm := New() + + _, err := vm.Run(` + var abc = { + ghi: 1, + def: function(def){ + var ghi = 0; + if (this.ghi) { + ghi = this.ghi; + } + return "def: " + (def + 3.14159 + ghi); + } + }; + `) + is(err, nil) + + value, err := vm.Call(`abc.def`, nil, 2) + is(err, nil) + is(value, "def: 6.14159") + + value, err = vm.Call(`abc.def`, "", 2) + is(err, nil) + is(value, "def: 5.14159") + + // Do not attempt to do a ToValue on a this of nil + value, err = vm.Call(`jkl.def`, nil, 1, 2, 3) + is(err, "!=", nil) + is(value, "undefined") + + value, err = vm.Call(`[ 1, 2, 3, undefined, 4 ].concat`, nil, 5, 6, 7, "abc") + is(err, nil) + is(value, "1,2,3,,4,5,6,7,abc") + }) +} + +func TestOttoCall_new(t *testing.T) { + tt(t, func() { + test, vm := test() + + vm.Set("abc", func(call FunctionCall) Value { + value, err := call.Otto.Call(`new Object`, nil, "Nothing happens.") + is(err, nil) + return value + }) + test(` + def = abc(); + [ def, def instanceof String ]; + `, "Nothing happens.,true") + }) +} + +func TestOttoCall_throw(t *testing.T) { + // FIXME? (Been broken for a while) + // Looks like this has been broken for a while... what + // behavior do we want here? + + if true { + return + } + + tt(t, func() { + test, vm := test() + + vm.Set("abc", func(call FunctionCall) Value { + if false { + call.Otto.Call(`throw eval`, nil, "({ def: 3.14159 })") + } + call.Otto.Call(`throw Error`, nil, "abcdef") + return Value{} + }) + // TODO try { abc(); } catch (err) { error = err } + // Possible unrelated error case: + // If error is not declared beforehand, is later referencing it a ReferenceError? + // Should the catch { } declare error in the outer scope? + test(` + var error; + try { + abc(); + } + catch (err) { + error = err; + } + [ error instanceof Error, error.message, error.def ]; + `, "true,abcdef,") + + vm.Set("def", func(call FunctionCall) Value { + call.Otto.Call(`throw new Object`, nil, 3.14159) + return UndefinedValue() + }) + test(` + try { + def(); + } + catch (err) { + error = err; + } + [ error instanceof Error, error.message, error.def, typeof error, error, error instanceof Number ]; + `, "false,,,object,3.14159,true") + }) +} + +func TestOttoCopy(t *testing.T) { + tt(t, func() { + vm0 := New() + vm0.Run(` + var abc = function() { + return "Xyzzy"; + }; + + function def() { + return abc() + (0 + {}); + } + `) + + value, err := vm0.Run(` + def(); + `) + is(err, nil) + is(value, "Xyzzy0[object Object]") + + vm1 := vm0.Copy() + value, err = vm1.Run(` + def(); + `) + is(err, nil) + is(value, "Xyzzy0[object Object]") + + vm1.Run(` + abc = function() { + return 3.14159; + }; + `) + value, err = vm1.Run(` + def(); + `) + is(err, nil) + is(value, "3.141590[object Object]") + + value, err = vm0.Run(` + def(); + `) + is(err, nil) + is(value, "Xyzzy0[object Object]") + + { + vm0 := New() + vm0.Run(` + var global = (function () {return this;}()) + var abc = 0; + var vm = "vm0"; + + var def = (function(){ + var jkl = 0; + var abc = function() { + global.abc += 1; + jkl += 1; + return 1; + }; + + return function() { + return [ vm, global.abc, jkl, abc() ]; + }; + })(); + `) + + value, err := vm0.Run(` + def(); + `) + is(err, nil) + is(value, "vm0,0,0,1") + + vm1 := vm0.Copy() + vm1.Set("vm", "vm1") + value, err = vm1.Run(` + def(); + `) + is(err, nil) + is(value, "vm1,1,1,1") + + value, err = vm0.Run(` + def(); + `) + is(err, nil) + is(value, "vm0,1,1,1") + + value, err = vm1.Run(` + def(); + `) + is(err, nil) + is(value, "vm1,2,2,1") + } + }) +} + +func TestOttoCall_clone(t *testing.T) { + tt(t, func() { + vm := New().clone() + rt := vm.runtime + + { + // FIXME terst, Check how this comparison is done + is(rt.global.Array.prototype, rt.global.FunctionPrototype) + is(rt.global.ArrayPrototype, "!=", nil) + is(rt.global.Array.runtime, rt) + is(rt.global.Array.prototype.runtime, rt) + is(rt.global.Array.get("prototype")._object().runtime, rt) + } + + { + value, err := vm.Run(`[ 1, 2, 3 ].toString()`) + is(err, nil) + is(value, "1,2,3") + } + + { + value, err := vm.Run(`[ 1, 2, 3 ]`) + is(err, nil) + is(value, "1,2,3") + object := value._object() + is(object, "!=", nil) + is(object.prototype, rt.global.ArrayPrototype) + + value, err = vm.Run(`Array.prototype`) + is(err, nil) + object = value._object() + is(object.runtime, rt) + is(object, "!=", nil) + is(object, rt.global.ArrayPrototype) + } + + { + otto1 := New() + _, err := otto1.Run(` + var abc = 1; + var def = 2; + `) + is(err, nil) + + otto2 := otto1.clone() + value, err := otto2.Run(`abc += 1; abc;`) + is(err, nil) + is(value, 2) + + value, err = otto1.Run(`abc += 4; abc;`) + is(err, nil) + is(value, 5) + } + + { + vm1 := New() + _, err := vm1.Run(` + var abc = 1; + var def = function(value) { + abc += value; + return abc; + } + `) + is(err, nil) + + vm2 := vm1.clone() + value, err := vm2.Run(`def(1)`) + is(err, nil) + is(value, 2) + + value, err = vm1.Run(`def(4)`) + is(err, nil) + is(value, 5) + } + + { + vm1 := New() + _, err := vm1.Run(` + var abc = { + ghi: 1, + jkl: function(value) { + this.ghi += value; + return this.ghi; + } + }; + var def = { + abc: abc + }; + `) + is(err, nil) + + otto2 := vm1.clone() + value, err := otto2.Run(`def.abc.jkl(1)`) + is(err, nil) + is(value, 2) + + value, err = vm1.Run(`def.abc.jkl(4)`) + is(err, nil) + is(value, 5) + } + + { + vm1 := New() + _, err := vm1.Run(` + var abc = function() { return "abc"; }; + var def = function() { return "def"; }; + `) + is(err, nil) + + vm2 := vm1.clone() + value, err := vm2.Run(` + [ abc.toString(), def.toString() ]; + `) + is(value, `function() { return "abc"; },function() { return "def"; }`) + + _, err = vm2.Run(` + var def = function() { return "ghi"; }; + `) + is(err, nil) + + value, err = vm1.Run(` + [ abc.toString(), def.toString() ]; + `) + is(value, `function() { return "abc"; },function() { return "def"; }`) + + value, err = vm2.Run(` + [ abc.toString(), def.toString() ]; + `) + is(value, `function() { return "abc"; },function() { return "ghi"; }`) + } + + }) +} + +func TestOttoRun(t *testing.T) { + tt(t, func() { + vm := New() + + program, err := parser.ParseFile(nil, "", "", 0) + is(err, nil) + value, err := vm.Run(program) + is(err, nil) + is(value, UndefinedValue()) + + program, err = parser.ParseFile(nil, "", "2 + 2", 0) + is(err, nil) + value, err = vm.Run(program) + is(err, nil) + is(value, 4) + value, err = vm.Run(program) + is(err, nil) + is(value, 4) + + program, err = parser.ParseFile(nil, "", "var abc; if (!abc) abc = 0; abc += 2; abc;", 0) + value, err = vm.Run(program) + is(err, nil) + is(value, 2) + value, err = vm.Run(program) + is(err, nil) + is(value, 4) + value, err = vm.Run(program) + is(err, nil) + is(value, 6) + + { + src := []byte("var abc; if (!abc) abc = 0; abc += 2; abc;") + value, err = vm.Run(src) + is(err, nil) + is(value, 8) + + value, err = vm.Run(bytes.NewBuffer(src)) + is(err, nil) + is(value, 10) + + value, err = vm.Run(io.Reader(bytes.NewBuffer(src))) + is(err, nil) + is(value, 12) + } + + { + script, err := vm.Compile("", `var abc; if (!abc) abc = 0; abc += 2; abc;`) + is(err, nil) + + value, err = vm.Run(script) + is(err, nil) + is(value, 14) + + value, err = vm.Run(script) + is(err, nil) + is(value, 16) + + is(script.String(), "// \nvar abc; if (!abc) abc = 0; abc += 2; abc;") + } + }) +} + +func Test_objectLength(t *testing.T) { + tt(t, func() { + _, vm := test() + + value := vm.Set("abc", []string{"jkl", "mno"}) + is(objectLength(value._object()), 2) + + value, _ = vm.Run(`[1, 2, 3]`) + is(objectLength(value._object()), 3) + + value, _ = vm.Run(`new String("abcdefghi")`) + is(objectLength(value._object()), 9) + + value, _ = vm.Run(`"abcdefghi"`) + is(objectLength(value._object()), 0) + }) +} + +func BenchmarkNew(b *testing.B) { + for i := 0; i < b.N; i++ { + New() + } +} + +func BenchmarkClone(b *testing.B) { + vm := New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + vm.clone() + } +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/panic_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/panic_test.go new file mode 100644 index 0000000000..06f0a64fc1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/panic_test.go @@ -0,0 +1,40 @@ +package otto + +import ( + "testing" +) + +func Test_panic(t *testing.T) { + tt(t, func() { + test, _ := test() + + // Test that property.value is set to something if writable is set + // to something + test(` + var abc = []; + Object.defineProperty(abc, "0", { writable: false }); + Object.defineProperty(abc, "0", { writable: false }); + "0" in abc; + `, true) + + test(`raise: + var abc = []; + Object.defineProperty(abc, "0", { writable: false }); + Object.defineProperty(abc, "0", { value: false, writable: false }); + `, "TypeError") + + // Test that a regular expression can contain \c0410 (CYRILLIC CAPITAL LETTER A) + // without panicking + test(` + var abc = 0x0410; + var def = String.fromCharCode(abc); + new RegExp("\\c" + def).exec(def); + `, "null") + + // Test transforming a transformable regular expression without a panic + test(` + new RegExp("\\u0000"); + new RegExp("\\undefined").test("undefined"); + `, true) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/Makefile b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/Makefile new file mode 100644 index 0000000000..766fd4d0b3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/Makefile @@ -0,0 +1,4 @@ +.PHONY: test + +test: + go test diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/README.markdown b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/README.markdown new file mode 100644 index 0000000000..c3cae5b603 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/README.markdown @@ -0,0 +1,190 @@ +# parser +-- + import "github.com/robertkrimen/otto/parser" + +Package parser implements a parser for JavaScript. + + import ( + "github.com/robertkrimen/otto/parser" + ) + +Parse and return an AST + + filename := "" // A filename is optional + src := ` + // Sample xyzzy example + (function(){ + if (3.14159 > 0) { + console.log("Hello, World."); + return; + } + + var xyzzy = NaN; + console.log("Nothing happens."); + return xyzzy; + })(); + ` + + // Parse some JavaScript, yielding a *ast.Program and/or an ErrorList + program, err := parser.ParseFile(nil, filename, src, 0) + + +### Warning + +The parser and AST interfaces are still works-in-progress (particularly where +node types are concerned) and may change in the future. + +## Usage + +#### func ParseFile + +```go +func ParseFile(fileSet *file.FileSet, filename string, src interface{}, mode Mode) (*ast.Program, error) +``` +ParseFile parses the source code of a single JavaScript/ECMAScript source file +and returns the corresponding ast.Program node. + +If fileSet == nil, ParseFile parses source without a FileSet. If fileSet != nil, +ParseFile first adds filename and src to fileSet. + +The filename argument is optional and is used for labelling errors, etc. + +src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST +always be in UTF-8. + + // Parse some JavaScript, yielding a *ast.Program and/or an ErrorList + program, err := parser.ParseFile(nil, "", `if (abc > 1) {}`, 0) + +#### func ParseFunction + +```go +func ParseFunction(parameterList, body string) (*ast.FunctionLiteral, error) +``` +ParseFunction parses a given parameter list and body as a function and returns +the corresponding ast.FunctionLiteral node. + +The parameter list, if any, should be a comma-separated list of identifiers. + +#### func ReadSource + +```go +func ReadSource(filename string, src interface{}) ([]byte, error) +``` + +#### func TransformRegExp + +```go +func TransformRegExp(pattern string) (string, error) +``` +TransformRegExp transforms a JavaScript pattern into a Go "regexp" pattern. + +re2 (Go) cannot do backtracking, so the presence of a lookahead (?=) (?!) or +backreference (\1, \2, ...) will cause an error. + +re2 (Go) has a different definition for \s: [\t\n\f\r ]. The JavaScript +definition, on the other hand, also includes \v, Unicode "Separator, Space", +etc. + +If the pattern is invalid (not valid even in JavaScript), then this function +returns the empty string and an error. + +If the pattern is valid, but incompatible (contains a lookahead or +backreference), then this function returns the transformation (a non-empty +string) AND an error. + +#### type Error + +```go +type Error struct { + Position file.Position + Message string +} +``` + +An Error represents a parsing error. It includes the position where the error +occurred and a message/description. + +#### func (Error) Error + +```go +func (self Error) Error() string +``` + +#### type ErrorList + +```go +type ErrorList []*Error +``` + +ErrorList is a list of *Errors. + +#### func (*ErrorList) Add + +```go +func (self *ErrorList) Add(position file.Position, msg string) +``` +Add adds an Error with given position and message to an ErrorList. + +#### func (ErrorList) Err + +```go +func (self ErrorList) Err() error +``` +Err returns an error equivalent to this ErrorList. If the list is empty, Err +returns nil. + +#### func (ErrorList) Error + +```go +func (self ErrorList) Error() string +``` +Error implements the Error interface. + +#### func (ErrorList) Len + +```go +func (self ErrorList) Len() int +``` + +#### func (ErrorList) Less + +```go +func (self ErrorList) Less(i, j int) bool +``` + +#### func (*ErrorList) Reset + +```go +func (self *ErrorList) Reset() +``` +Reset resets an ErrorList to no errors. + +#### func (ErrorList) Sort + +```go +func (self ErrorList) Sort() +``` + +#### func (ErrorList) Swap + +```go +func (self ErrorList) Swap(i, j int) +``` + +#### type Mode + +```go +type Mode uint +``` + +A Mode value is a set of flags (or 0). They control optional parser +functionality. + +```go +const ( + IgnoreRegExpErrors Mode = 1 << iota // Ignore RegExp compatibility errors (allow backtracking) +) +``` + +-- +**godocdown** http://github.com/robertkrimen/godocdown diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/dbg.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/dbg.go new file mode 100644 index 0000000000..3c5f2f698e --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/dbg.go @@ -0,0 +1,9 @@ +// This file was AUTOMATICALLY GENERATED by dbg-import (smuggol) for github.com/robertkrimen/dbg + +package parser + +import ( + Dbg "github.com/robertkrimen/otto/dbg" +) + +var dbg, dbgf = Dbg.New() diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/error.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/error.go new file mode 100644 index 0000000000..e0f74a5cfc --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/error.go @@ -0,0 +1,175 @@ +package parser + +import ( + "fmt" + "sort" + + "github.com/robertkrimen/otto/file" + "github.com/robertkrimen/otto/token" +) + +const ( + err_UnexpectedToken = "Unexpected token %v" + err_UnexpectedEndOfInput = "Unexpected end of input" + err_UnexpectedEscape = "Unexpected escape" +) + +// UnexpectedNumber: 'Unexpected number', +// UnexpectedString: 'Unexpected string', +// UnexpectedIdentifier: 'Unexpected identifier', +// UnexpectedReserved: 'Unexpected reserved word', +// NewlineAfterThrow: 'Illegal newline after throw', +// InvalidRegExp: 'Invalid regular expression', +// UnterminatedRegExp: 'Invalid regular expression: missing /', +// InvalidLHSInAssignment: 'Invalid left-hand side in assignment', +// InvalidLHSInForIn: 'Invalid left-hand side in for-in', +// MultipleDefaultsInSwitch: 'More than one default clause in switch statement', +// NoCatchOrFinally: 'Missing catch or finally after try', +// UnknownLabel: 'Undefined label \'%0\'', +// Redeclaration: '%0 \'%1\' has already been declared', +// IllegalContinue: 'Illegal continue statement', +// IllegalBreak: 'Illegal break statement', +// IllegalReturn: 'Illegal return statement', +// StrictModeWith: 'Strict mode code may not include a with statement', +// StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', +// StrictVarName: 'Variable name may not be eval or arguments in strict mode', +// StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', +// StrictParamDupe: 'Strict mode function may not have duplicate parameter names', +// StrictFunctionName: 'Function name may not be eval or arguments in strict mode', +// StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', +// StrictDelete: 'Delete of an unqualified identifier in strict mode.', +// StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', +// AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', +// AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', +// StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', +// StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', +// StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', +// StrictReservedWord: 'Use of future reserved word in strict mode' + +// A SyntaxError is a description of an ECMAScript syntax error. + +// An Error represents a parsing error. It includes the position where the error occurred and a message/description. +type Error struct { + Position file.Position + Message string +} + +// FIXME Should this be "SyntaxError"? + +func (self Error) Error() string { + filename := self.Position.Filename + if filename == "" { + filename = "(anonymous)" + } + return fmt.Sprintf("%s: Line %d:%d %s", + filename, + self.Position.Line, + self.Position.Column, + self.Message, + ) +} + +func (self *_parser) error(place interface{}, msg string, msgValues ...interface{}) *Error { + idx := file.Idx(0) + switch place := place.(type) { + case int: + idx = self.idxOf(place) + case file.Idx: + if place == 0 { + idx = self.idxOf(self.chrOffset) + } else { + idx = place + } + default: + panic(fmt.Errorf("error(%T, ...)", place)) + } + + position := self.position(idx) + msg = fmt.Sprintf(msg, msgValues...) + self.errors.Add(position, msg) + return self.errors[len(self.errors)-1] +} + +func (self *_parser) errorUnexpected(idx file.Idx, chr rune) error { + if chr == -1 { + return self.error(idx, err_UnexpectedEndOfInput) + } + return self.error(idx, err_UnexpectedToken, token.ILLEGAL) +} + +func (self *_parser) errorUnexpectedToken(tkn token.Token) error { + switch tkn { + case token.EOF: + return self.error(file.Idx(0), err_UnexpectedEndOfInput) + } + value := tkn.String() + switch tkn { + case token.BOOLEAN, token.NULL: + value = self.literal + case token.IDENTIFIER: + return self.error(self.idx, "Unexpected identifier") + case token.KEYWORD: + // TODO Might be a future reserved word + return self.error(self.idx, "Unexpected reserved word") + case token.NUMBER: + return self.error(self.idx, "Unexpected number") + case token.STRING: + return self.error(self.idx, "Unexpected string") + } + return self.error(self.idx, err_UnexpectedToken, value) +} + +// ErrorList is a list of *Errors. +// +type ErrorList []*Error + +// Add adds an Error with given position and message to an ErrorList. +func (self *ErrorList) Add(position file.Position, msg string) { + *self = append(*self, &Error{position, msg}) +} + +// Reset resets an ErrorList to no errors. +func (self *ErrorList) Reset() { *self = (*self)[0:0] } + +func (self ErrorList) Len() int { return len(self) } +func (self ErrorList) Swap(i, j int) { self[i], self[j] = self[j], self[i] } +func (self ErrorList) Less(i, j int) bool { + x := &self[i].Position + y := &self[j].Position + if x.Filename < y.Filename { + return true + } + if x.Filename == y.Filename { + if x.Line < y.Line { + return true + } + if x.Line == y.Line { + return x.Column < y.Column + } + } + return false +} + +func (self ErrorList) Sort() { + sort.Sort(self) +} + +// Error implements the Error interface. +func (self ErrorList) Error() string { + switch len(self) { + case 0: + return "no errors" + case 1: + return self[0].Error() + } + return fmt.Sprintf("%s (and %d more errors)", self[0].Error(), len(self)-1) +} + +// Err returns an error equivalent to this ErrorList. +// If the list is empty, Err returns nil. +func (self ErrorList) Err() error { + if len(self) == 0 { + return nil + } + return self +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go new file mode 100644 index 0000000000..dc397b5cba --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go @@ -0,0 +1,815 @@ +package parser + +import ( + "regexp" + + "github.com/robertkrimen/otto/ast" + "github.com/robertkrimen/otto/file" + "github.com/robertkrimen/otto/token" +) + +func (self *_parser) parseIdentifier() *ast.Identifier { + literal := self.literal + idx := self.idx + self.next() + return &ast.Identifier{ + Name: literal, + Idx: idx, + } +} + +func (self *_parser) parsePrimaryExpression() ast.Expression { + literal := self.literal + idx := self.idx + switch self.token { + case token.IDENTIFIER: + self.next() + if len(literal) > 1 { + tkn, strict := token.IsKeyword(literal) + if tkn == token.KEYWORD { + if !strict { + self.error(idx, "Unexpected reserved word") + } + } + } + return &ast.Identifier{ + Name: literal, + Idx: idx, + } + case token.NULL: + self.next() + return &ast.NullLiteral{ + Idx: idx, + Literal: literal, + } + case token.BOOLEAN: + self.next() + value := false + switch literal { + case "true": + value = true + case "false": + value = false + default: + self.error(idx, "Illegal boolean literal") + } + return &ast.BooleanLiteral{ + Idx: idx, + Literal: literal, + Value: value, + } + case token.STRING: + self.next() + value, err := parseStringLiteral(literal[1 : len(literal)-1]) + if err != nil { + self.error(idx, err.Error()) + } + return &ast.StringLiteral{ + Idx: idx, + Literal: literal, + Value: value, + } + case token.NUMBER: + self.next() + value, err := parseNumberLiteral(literal) + if err != nil { + self.error(idx, err.Error()) + value = 0 + } + return &ast.NumberLiteral{ + Idx: idx, + Literal: literal, + Value: value, + } + case token.SLASH, token.QUOTIENT_ASSIGN: + return self.parseRegExpLiteral() + case token.LEFT_BRACE: + return self.parseObjectLiteral() + case token.LEFT_BRACKET: + return self.parseArrayLiteral() + case token.LEFT_PARENTHESIS: + self.expect(token.LEFT_PARENTHESIS) + expression := self.parseExpression() + self.expect(token.RIGHT_PARENTHESIS) + return expression + case token.THIS: + self.next() + return &ast.ThisExpression{ + Idx: idx, + } + case token.FUNCTION: + return self.parseFunction(false) + } + + self.errorUnexpectedToken(self.token) + self.nextStatement() + return &ast.BadExpression{From: idx, To: self.idx} +} + +func (self *_parser) parseRegExpLiteral() *ast.RegExpLiteral { + + offset := self.chrOffset - 1 // Opening slash already gotten + if self.token == token.QUOTIENT_ASSIGN { + offset -= 1 // = + } + idx := self.idxOf(offset) + + pattern, err := self.scanString(offset) + endOffset := self.chrOffset + + self.next() + if err == nil { + pattern = pattern[1 : len(pattern)-1] + } + + flags := "" + if self.token == token.IDENTIFIER { // gim + + flags = self.literal + self.next() + endOffset = self.chrOffset - 1 + } + + var value string + // TODO 15.10 + { + // Test during parsing that this is a valid regular expression + // Sorry, (?=) and (?!) are invalid (for now) + pattern, err := TransformRegExp(pattern) + if err != nil { + if pattern == "" || self.mode&IgnoreRegExpErrors == 0 { + self.error(idx, "Invalid regular expression: %s", err.Error()) + } + } else { + _, err = regexp.Compile(pattern) + if err != nil { + // We should not get here, ParseRegExp should catch any errors + self.error(idx, "Invalid regular expression: %s", err.Error()[22:]) // Skip redundant "parse regexp error" + } else { + value = pattern + } + } + } + + literal := self.str[offset:endOffset] + + return &ast.RegExpLiteral{ + Idx: idx, + Literal: literal, + Pattern: pattern, + Flags: flags, + Value: value, + } +} + +func (self *_parser) parseVariableDeclaration(declarationList *[]*ast.VariableExpression) ast.Expression { + + if self.token != token.IDENTIFIER { + idx := self.expect(token.IDENTIFIER) + self.nextStatement() + return &ast.BadExpression{From: idx, To: self.idx} + } + + literal := self.literal + idx := self.idx + self.next() + node := &ast.VariableExpression{ + Name: literal, + Idx: idx, + } + + if declarationList != nil { + *declarationList = append(*declarationList, node) + } + + if self.token == token.ASSIGN { + self.next() + node.Initializer = self.parseAssignmentExpression() + } + + return node +} + +func (self *_parser) parseVariableDeclarationList(var_ file.Idx) []ast.Expression { + + var declarationList []*ast.VariableExpression // Avoid bad expressions + var list []ast.Expression + + for { + list = append(list, self.parseVariableDeclaration(&declarationList)) + if self.token != token.COMMA { + break + } + self.next() + } + + self.scope.declare(&ast.VariableDeclaration{ + Var: var_, + List: declarationList, + }) + + return list +} + +func (self *_parser) parseObjectPropertyKey() (string, string) { + idx, tkn, literal := self.idx, self.token, self.literal + value := "" + self.next() + switch tkn { + case token.IDENTIFIER: + value = literal + case token.NUMBER: + var err error + _, err = parseNumberLiteral(literal) + if err != nil { + self.error(idx, err.Error()) + } else { + value = literal + } + case token.STRING: + var err error + value, err = parseStringLiteral(literal[1 : len(literal)-1]) + if err != nil { + self.error(idx, err.Error()) + } + default: + // null, false, class, etc. + if matchIdentifier.MatchString(literal) { + value = literal + } + } + return literal, value +} + +func (self *_parser) parseObjectProperty() ast.Property { + + literal, value := self.parseObjectPropertyKey() + if literal == "get" && self.token != token.COLON { + idx := self.idx + _, value := self.parseObjectPropertyKey() + parameterList := self.parseFunctionParameterList() + + node := &ast.FunctionLiteral{ + Function: idx, + ParameterList: parameterList, + } + self.parseFunctionBlock(node) + return ast.Property{ + Key: value, + Kind: "get", + Value: node, + } + } else if literal == "set" && self.token != token.COLON { + idx := self.idx + _, value := self.parseObjectPropertyKey() + parameterList := self.parseFunctionParameterList() + + node := &ast.FunctionLiteral{ + Function: idx, + ParameterList: parameterList, + } + self.parseFunctionBlock(node) + return ast.Property{ + Key: value, + Kind: "set", + Value: node, + } + } + + self.expect(token.COLON) + + return ast.Property{ + Key: value, + Kind: "value", + Value: self.parseAssignmentExpression(), + } +} + +func (self *_parser) parseObjectLiteral() ast.Expression { + var value []ast.Property + idx0 := self.expect(token.LEFT_BRACE) + for self.token != token.RIGHT_BRACE && self.token != token.EOF { + property := self.parseObjectProperty() + value = append(value, property) + if self.token == token.COMMA { + self.next() + continue + } + } + idx1 := self.expect(token.RIGHT_BRACE) + + return &ast.ObjectLiteral{ + LeftBrace: idx0, + RightBrace: idx1, + Value: value, + } +} + +func (self *_parser) parseArrayLiteral() ast.Expression { + + idx0 := self.expect(token.LEFT_BRACKET) + var value []ast.Expression + for self.token != token.RIGHT_BRACKET && self.token != token.EOF { + if self.token == token.COMMA { + self.next() + value = append(value, nil) + continue + } + value = append(value, self.parseAssignmentExpression()) + if self.token != token.RIGHT_BRACKET { + self.expect(token.COMMA) + } + } + idx1 := self.expect(token.RIGHT_BRACKET) + + return &ast.ArrayLiteral{ + LeftBracket: idx0, + RightBracket: idx1, + Value: value, + } +} + +func (self *_parser) parseArgumentList() (argumentList []ast.Expression, idx0, idx1 file.Idx) { + idx0 = self.expect(token.LEFT_PARENTHESIS) + if self.token != token.RIGHT_PARENTHESIS { + for { + argumentList = append(argumentList, self.parseAssignmentExpression()) + if self.token != token.COMMA { + break + } + self.next() + } + } + idx1 = self.expect(token.RIGHT_PARENTHESIS) + return +} + +func (self *_parser) parseCallExpression(left ast.Expression) ast.Expression { + argumentList, idx0, idx1 := self.parseArgumentList() + return &ast.CallExpression{ + Callee: left, + LeftParenthesis: idx0, + ArgumentList: argumentList, + RightParenthesis: idx1, + } +} + +func (self *_parser) parseDotMember(left ast.Expression) ast.Expression { + period := self.expect(token.PERIOD) + + literal := self.literal + idx := self.idx + + if !matchIdentifier.MatchString(literal) { + self.expect(token.IDENTIFIER) + self.nextStatement() + return &ast.BadExpression{From: period, To: self.idx} + } + + self.next() + + return &ast.DotExpression{ + Left: left, + Identifier: ast.Identifier{ + Idx: idx, + Name: literal, + }, + } +} + +func (self *_parser) parseBracketMember(left ast.Expression) ast.Expression { + idx0 := self.expect(token.LEFT_BRACKET) + member := self.parseExpression() + idx1 := self.expect(token.RIGHT_BRACKET) + return &ast.BracketExpression{ + LeftBracket: idx0, + Left: left, + Member: member, + RightBracket: idx1, + } +} + +func (self *_parser) parseNewExpression() ast.Expression { + idx := self.expect(token.NEW) + callee := self.parseLeftHandSideExpression() + node := &ast.NewExpression{ + New: idx, + Callee: callee, + } + if self.token == token.LEFT_PARENTHESIS { + argumentList, idx0, idx1 := self.parseArgumentList() + node.ArgumentList = argumentList + node.LeftParenthesis = idx0 + node.RightParenthesis = idx1 + } + return node +} + +func (self *_parser) parseLeftHandSideExpression() ast.Expression { + + var left ast.Expression + if self.token == token.NEW { + left = self.parseNewExpression() + } else { + left = self.parsePrimaryExpression() + } + + for { + if self.token == token.PERIOD { + left = self.parseDotMember(left) + } else if self.token == token.LEFT_BRACE { + left = self.parseBracketMember(left) + } else { + break + } + } + + return left +} + +func (self *_parser) parseLeftHandSideExpressionAllowCall() ast.Expression { + + allowIn := self.scope.allowIn + self.scope.allowIn = true + defer func() { + self.scope.allowIn = allowIn + }() + + var left ast.Expression + if self.token == token.NEW { + left = self.parseNewExpression() + } else { + left = self.parsePrimaryExpression() + } + + for { + if self.token == token.PERIOD { + left = self.parseDotMember(left) + } else if self.token == token.LEFT_BRACKET { + left = self.parseBracketMember(left) + } else if self.token == token.LEFT_PARENTHESIS { + left = self.parseCallExpression(left) + } else { + break + } + } + + return left +} + +func (self *_parser) parsePostfixExpression() ast.Expression { + operand := self.parseLeftHandSideExpressionAllowCall() + + switch self.token { + case token.INCREMENT, token.DECREMENT: + // Make sure there is no line terminator here + if self.implicitSemicolon { + break + } + tkn := self.token + idx := self.idx + self.next() + switch operand.(type) { + case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression: + default: + self.error(idx, "Invalid left-hand side in assignment") + self.nextStatement() + return &ast.BadExpression{From: idx, To: self.idx} + } + return &ast.UnaryExpression{ + Operator: tkn, + Idx: idx, + Operand: operand, + Postfix: true, + } + } + + return operand +} + +func (self *_parser) parseUnaryExpression() ast.Expression { + + switch self.token { + case token.PLUS, token.MINUS, token.NOT, token.BITWISE_NOT: + fallthrough + case token.DELETE, token.VOID, token.TYPEOF: + tkn := self.token + idx := self.idx + self.next() + return &ast.UnaryExpression{ + Operator: tkn, + Idx: idx, + Operand: self.parseUnaryExpression(), + } + case token.INCREMENT, token.DECREMENT: + tkn := self.token + idx := self.idx + self.next() + operand := self.parseUnaryExpression() + switch operand.(type) { + case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression: + default: + self.error(idx, "Invalid left-hand side in assignment") + self.nextStatement() + return &ast.BadExpression{From: idx, To: self.idx} + } + return &ast.UnaryExpression{ + Operator: tkn, + Idx: idx, + Operand: operand, + } + } + + return self.parsePostfixExpression() +} + +func (self *_parser) parseMultiplicativeExpression() ast.Expression { + next := self.parseUnaryExpression + left := next() + + for self.token == token.MULTIPLY || self.token == token.SLASH || + self.token == token.REMAINDER { + tkn := self.token + self.next() + left = &ast.BinaryExpression{ + Operator: tkn, + Left: left, + Right: next(), + } + } + + return left +} + +func (self *_parser) parseAdditiveExpression() ast.Expression { + next := self.parseMultiplicativeExpression + left := next() + + for self.token == token.PLUS || self.token == token.MINUS { + tkn := self.token + self.next() + left = &ast.BinaryExpression{ + Operator: tkn, + Left: left, + Right: next(), + } + } + + return left +} + +func (self *_parser) parseShiftExpression() ast.Expression { + next := self.parseAdditiveExpression + left := next() + + for self.token == token.SHIFT_LEFT || self.token == token.SHIFT_RIGHT || + self.token == token.UNSIGNED_SHIFT_RIGHT { + tkn := self.token + self.next() + left = &ast.BinaryExpression{ + Operator: tkn, + Left: left, + Right: next(), + } + } + + return left +} + +func (self *_parser) parseRelationalExpression() ast.Expression { + next := self.parseShiftExpression + left := next() + + allowIn := self.scope.allowIn + self.scope.allowIn = true + defer func() { + self.scope.allowIn = allowIn + }() + + switch self.token { + case token.LESS, token.LESS_OR_EQUAL, token.GREATER, token.GREATER_OR_EQUAL: + tkn := self.token + self.next() + return &ast.BinaryExpression{ + Operator: tkn, + Left: left, + Right: self.parseRelationalExpression(), + Comparison: true, + } + case token.INSTANCEOF: + tkn := self.token + self.next() + return &ast.BinaryExpression{ + Operator: tkn, + Left: left, + Right: self.parseRelationalExpression(), + } + case token.IN: + if !allowIn { + return left + } + tkn := self.token + self.next() + return &ast.BinaryExpression{ + Operator: tkn, + Left: left, + Right: self.parseRelationalExpression(), + } + } + + return left +} + +func (self *_parser) parseEqualityExpression() ast.Expression { + next := self.parseRelationalExpression + left := next() + + for self.token == token.EQUAL || self.token == token.NOT_EQUAL || + self.token == token.STRICT_EQUAL || self.token == token.STRICT_NOT_EQUAL { + tkn := self.token + self.next() + left = &ast.BinaryExpression{ + Operator: tkn, + Left: left, + Right: next(), + Comparison: true, + } + } + + return left +} + +func (self *_parser) parseBitwiseAndExpression() ast.Expression { + next := self.parseEqualityExpression + left := next() + + for self.token == token.AND { + tkn := self.token + self.next() + left = &ast.BinaryExpression{ + Operator: tkn, + Left: left, + Right: next(), + } + } + + return left +} + +func (self *_parser) parseBitwiseExclusiveOrExpression() ast.Expression { + next := self.parseBitwiseAndExpression + left := next() + + for self.token == token.EXCLUSIVE_OR { + tkn := self.token + self.next() + left = &ast.BinaryExpression{ + Operator: tkn, + Left: left, + Right: next(), + } + } + + return left +} + +func (self *_parser) parseBitwiseOrExpression() ast.Expression { + next := self.parseBitwiseExclusiveOrExpression + left := next() + + for self.token == token.OR { + tkn := self.token + self.next() + left = &ast.BinaryExpression{ + Operator: tkn, + Left: left, + Right: next(), + } + } + + return left +} + +func (self *_parser) parseLogicalAndExpression() ast.Expression { + next := self.parseBitwiseOrExpression + left := next() + + for self.token == token.LOGICAL_AND { + tkn := self.token + self.next() + left = &ast.BinaryExpression{ + Operator: tkn, + Left: left, + Right: next(), + } + } + + return left +} + +func (self *_parser) parseLogicalOrExpression() ast.Expression { + next := self.parseLogicalAndExpression + left := next() + + for self.token == token.LOGICAL_OR { + tkn := self.token + self.next() + left = &ast.BinaryExpression{ + Operator: tkn, + Left: left, + Right: next(), + } + } + + return left +} + +func (self *_parser) parseConditionlExpression() ast.Expression { + left := self.parseLogicalOrExpression() + + if self.token == token.QUESTION_MARK { + self.next() + consequent := self.parseAssignmentExpression() + self.expect(token.COLON) + return &ast.ConditionalExpression{ + Test: left, + Consequent: consequent, + Alternate: self.parseAssignmentExpression(), + } + } + + return left +} + +func (self *_parser) parseAssignmentExpression() ast.Expression { + left := self.parseConditionlExpression() + var operator token.Token + switch self.token { + case token.ASSIGN: + operator = self.token + case token.ADD_ASSIGN: + operator = token.PLUS + case token.SUBTRACT_ASSIGN: + operator = token.MINUS + case token.MULTIPLY_ASSIGN: + operator = token.MULTIPLY + case token.QUOTIENT_ASSIGN: + operator = token.SLASH + case token.REMAINDER_ASSIGN: + operator = token.REMAINDER + case token.AND_ASSIGN: + operator = token.AND + case token.AND_NOT_ASSIGN: + operator = token.AND_NOT + case token.OR_ASSIGN: + operator = token.OR + case token.EXCLUSIVE_OR_ASSIGN: + operator = token.EXCLUSIVE_OR + case token.SHIFT_LEFT_ASSIGN: + operator = token.SHIFT_LEFT + case token.SHIFT_RIGHT_ASSIGN: + operator = token.SHIFT_RIGHT + case token.UNSIGNED_SHIFT_RIGHT_ASSIGN: + operator = token.UNSIGNED_SHIFT_RIGHT + } + + if operator != 0 { + idx := self.idx + self.next() + switch left.(type) { + case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression: + default: + self.error(left.Idx0(), "Invalid left-hand side in assignment") + self.nextStatement() + return &ast.BadExpression{From: idx, To: self.idx} + } + return &ast.AssignExpression{ + Left: left, + Operator: operator, + Right: self.parseAssignmentExpression(), + } + } + + return left +} + +func (self *_parser) parseExpression() ast.Expression { + next := self.parseAssignmentExpression + left := next() + + if self.token == token.COMMA { + sequence := []ast.Expression{left} + for { + if self.token != token.COMMA { + break + } + self.next() + sequence = append(sequence, next()) + } + return &ast.SequenceExpression{ + Sequence: sequence, + } + } + + return left +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer.go new file mode 100644 index 0000000000..bc3e74f77a --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer.go @@ -0,0 +1,819 @@ +package parser + +import ( + "bytes" + "errors" + "fmt" + "regexp" + "strconv" + "strings" + "unicode" + "unicode/utf8" + + "github.com/robertkrimen/otto/file" + "github.com/robertkrimen/otto/token" +) + +type _chr struct { + value rune + width int +} + +var matchIdentifier = regexp.MustCompile(`^[$_\p{L}][$_\p{L}\d}]*$`) + +func isDecimalDigit(chr rune) bool { + return '0' <= chr && chr <= '9' +} + +func digitValue(chr rune) int { + switch { + case '0' <= chr && chr <= '9': + return int(chr - '0') + case 'a' <= chr && chr <= 'f': + return int(chr - 'a' + 10) + case 'A' <= chr && chr <= 'F': + return int(chr - 'A' + 10) + } + return 16 // Larger than any legal digit value +} + +func isDigit(chr rune, base int) bool { + return digitValue(chr) < base +} + +func isIdentifierStart(chr rune) bool { + return chr == '$' || chr == '_' || chr == '\\' || + 'a' <= chr && chr <= 'z' || 'A' <= chr && chr <= 'Z' || + chr >= utf8.RuneSelf && unicode.IsLetter(chr) +} + +func isIdentifierPart(chr rune) bool { + return chr == '$' || chr == '_' || chr == '\\' || + 'a' <= chr && chr <= 'z' || 'A' <= chr && chr <= 'Z' || + '0' <= chr && chr <= '9' || + chr >= utf8.RuneSelf && (unicode.IsLetter(chr) || unicode.IsDigit(chr)) +} + +func (self *_parser) scanIdentifier() (string, error) { + offset := self.chrOffset + parse := false + for isIdentifierPart(self.chr) { + if self.chr == '\\' { + distance := self.chrOffset - offset + self.read() + if self.chr != 'u' { + return "", fmt.Errorf("Invalid identifier escape character: %c (%s)", self.chr, string(self.chr)) + } + parse = true + var value rune + for j := 0; j < 4; j++ { + self.read() + decimal, ok := hex2decimal(byte(self.chr)) + if !ok { + return "", fmt.Errorf("Invalid identifier escape character: %c (%s)", self.chr, string(self.chr)) + } + value = value<<4 | decimal + } + if value == '\\' { + return "", fmt.Errorf("Invalid identifier escape value: %c (%s)", value, string(value)) + } else if distance == 0 { + if !isIdentifierStart(value) { + return "", fmt.Errorf("Invalid identifier escape value: %c (%s)", value, string(value)) + } + } else if distance > 0 { + if !isIdentifierPart(value) { + return "", fmt.Errorf("Invalid identifier escape value: %c (%s)", value, string(value)) + } + } + } + self.read() + } + literal := string(self.str[offset:self.chrOffset]) + if parse { + return parseStringLiteral(literal) + } + return literal, nil +} + +// 7.2 +func isLineWhiteSpace(chr rune) bool { + switch chr { + case '\u0009', '\u000b', '\u000c', '\u0020', '\u00a0', '\ufeff': + return true + case '\u000a', '\u000d', '\u2028', '\u2029': + return false + case '\u0085': + return false + } + return unicode.IsSpace(chr) +} + +// 7.3 +func isLineTerminator(chr rune) bool { + switch chr { + case '\u000a', '\u000d', '\u2028', '\u2029': + return true + } + return false +} + +func (self *_parser) scan() (tkn token.Token, literal string, idx file.Idx) { + + self.implicitSemicolon = false + + for { + self.skipWhiteSpace() + + idx = self.idxOf(self.chrOffset) + insertSemicolon := false + + switch chr := self.chr; { + case isIdentifierStart(chr): + var err error + literal, err = self.scanIdentifier() + if err != nil { + tkn = token.ILLEGAL + break + } + if len(literal) > 1 { + // Keywords are longer than 1 character, avoid lookup otherwise + var strict bool + tkn, strict = token.IsKeyword(literal) + + switch tkn { + + case 0: // Not a keyword + if literal == "true" || literal == "false" { + self.insertSemicolon = true + tkn = token.BOOLEAN + return + } else if literal == "null" { + self.insertSemicolon = true + tkn = token.NULL + return + } + + case token.KEYWORD: + tkn = token.KEYWORD + if strict { + // TODO If strict and in strict mode, then this is not a break + break + } + return + + case + token.THIS, + token.BREAK, + token.THROW, // A newline after a throw is not allowed, but we need to detect it + token.RETURN, + token.CONTINUE, + token.DEBUGGER: + self.insertSemicolon = true + return + + default: + return + + } + } + self.insertSemicolon = true + tkn = token.IDENTIFIER + return + case '0' <= chr && chr <= '9': + self.insertSemicolon = true + tkn, literal = self.scanNumericLiteral(false) + return + default: + self.read() + switch chr { + case -1: + if self.insertSemicolon { + self.insertSemicolon = false + self.implicitSemicolon = true + } + tkn = token.EOF + case '\r', '\n', '\u2028', '\u2029': + self.insertSemicolon = false + self.implicitSemicolon = true + continue + case ':': + tkn = token.COLON + case '.': + if digitValue(self.chr) < 10 { + insertSemicolon = true + tkn, literal = self.scanNumericLiteral(true) + } else { + tkn = token.PERIOD + } + case ',': + tkn = token.COMMA + case ';': + tkn = token.SEMICOLON + case '(': + tkn = token.LEFT_PARENTHESIS + case ')': + tkn = token.RIGHT_PARENTHESIS + insertSemicolon = true + case '[': + tkn = token.LEFT_BRACKET + case ']': + tkn = token.RIGHT_BRACKET + insertSemicolon = true + case '{': + tkn = token.LEFT_BRACE + case '}': + tkn = token.RIGHT_BRACE + insertSemicolon = true + case '+': + tkn = self.switch3(token.PLUS, token.ADD_ASSIGN, '+', token.INCREMENT) + if tkn == token.INCREMENT { + insertSemicolon = true + } + case '-': + tkn = self.switch3(token.MINUS, token.SUBTRACT_ASSIGN, '-', token.DECREMENT) + if tkn == token.DECREMENT { + insertSemicolon = true + } + case '*': + tkn = self.switch2(token.MULTIPLY, token.MULTIPLY_ASSIGN) + case '/': + if self.chr == '/' { + self.skipSingleLineComment() + continue + } else if self.chr == '*' { + self.skipMultiLineComment() + continue + } else { + // Could be division, could be RegExp literal + tkn = self.switch2(token.SLASH, token.QUOTIENT_ASSIGN) + insertSemicolon = true + } + case '%': + tkn = self.switch2(token.REMAINDER, token.REMAINDER_ASSIGN) + case '^': + tkn = self.switch2(token.EXCLUSIVE_OR, token.EXCLUSIVE_OR_ASSIGN) + case '<': + tkn = self.switch4(token.LESS, token.LESS_OR_EQUAL, '<', token.SHIFT_LEFT, token.SHIFT_LEFT_ASSIGN) + case '>': + tkn = self.switch6(token.GREATER, token.GREATER_OR_EQUAL, '>', token.SHIFT_RIGHT, token.SHIFT_RIGHT_ASSIGN, '>', token.UNSIGNED_SHIFT_RIGHT, token.UNSIGNED_SHIFT_RIGHT_ASSIGN) + case '=': + tkn = self.switch2(token.ASSIGN, token.EQUAL) + if tkn == token.EQUAL && self.chr == '=' { + self.read() + tkn = token.STRICT_EQUAL + } + case '!': + tkn = self.switch2(token.NOT, token.NOT_EQUAL) + if tkn == token.NOT_EQUAL && self.chr == '=' { + self.read() + tkn = token.STRICT_NOT_EQUAL + } + case '&': + if self.chr == '^' { + self.read() + tkn = self.switch2(token.AND_NOT, token.AND_NOT_ASSIGN) + } else { + tkn = self.switch3(token.AND, token.AND_ASSIGN, '&', token.LOGICAL_AND) + } + case '|': + tkn = self.switch3(token.OR, token.OR_ASSIGN, '|', token.LOGICAL_OR) + case '~': + tkn = token.BITWISE_NOT + case '?': + tkn = token.QUESTION_MARK + case '"', '\'': + insertSemicolon = true + tkn = token.STRING + var err error + literal, err = self.scanString(self.chrOffset - 1) + if err != nil { + tkn = token.ILLEGAL + } + default: + self.errorUnexpected(idx, chr) + tkn = token.ILLEGAL + } + } + self.insertSemicolon = insertSemicolon + return + } +} + +func (self *_parser) switch2(tkn0, tkn1 token.Token) token.Token { + if self.chr == '=' { + self.read() + return tkn1 + } + return tkn0 +} + +func (self *_parser) switch3(tkn0, tkn1 token.Token, chr2 rune, tkn2 token.Token) token.Token { + if self.chr == '=' { + self.read() + return tkn1 + } + if self.chr == chr2 { + self.read() + return tkn2 + } + return tkn0 +} + +func (self *_parser) switch4(tkn0, tkn1 token.Token, chr2 rune, tkn2, tkn3 token.Token) token.Token { + if self.chr == '=' { + self.read() + return tkn1 + } + if self.chr == chr2 { + self.read() + if self.chr == '=' { + self.read() + return tkn3 + } + return tkn2 + } + return tkn0 +} + +func (self *_parser) switch6(tkn0, tkn1 token.Token, chr2 rune, tkn2, tkn3 token.Token, chr3 rune, tkn4, tkn5 token.Token) token.Token { + if self.chr == '=' { + self.read() + return tkn1 + } + if self.chr == chr2 { + self.read() + if self.chr == '=' { + self.read() + return tkn3 + } + if self.chr == chr3 { + self.read() + if self.chr == '=' { + self.read() + return tkn5 + } + return tkn4 + } + return tkn2 + } + return tkn0 +} + +func (self *_parser) chrAt(index int) _chr { + value, width := utf8.DecodeRuneInString(self.str[index:]) + return _chr{ + value: value, + width: width, + } +} + +func (self *_parser) _peek() rune { + if self.offset+1 < self.length { + return rune(self.str[self.offset+1]) + } + return -1 +} + +func (self *_parser) read() { + if self.offset < self.length { + self.chrOffset = self.offset + chr, width := rune(self.str[self.offset]), 1 + if chr >= utf8.RuneSelf { // !ASCII + chr, width = utf8.DecodeRuneInString(self.str[self.offset:]) + if chr == utf8.RuneError && width == 1 { + self.error(self.chrOffset, "Invalid UTF-8 character") + } + } + self.offset += width + self.chr = chr + } else { + self.chrOffset = self.length + self.chr = -1 // EOF + } +} + +// This is here since the functions are so similar +func (self *_RegExp_parser) read() { + if self.offset < self.length { + self.chrOffset = self.offset + chr, width := rune(self.str[self.offset]), 1 + if chr >= utf8.RuneSelf { // !ASCII + chr, width = utf8.DecodeRuneInString(self.str[self.offset:]) + if chr == utf8.RuneError && width == 1 { + self.error(self.chrOffset, "Invalid UTF-8 character") + } + } + self.offset += width + self.chr = chr + } else { + self.chrOffset = self.length + self.chr = -1 // EOF + } +} + +func (self *_parser) skipSingleLineComment() { + for self.chr != -1 { + self.read() + if isLineTerminator(self.chr) { + return + } + } +} + +func (self *_parser) skipMultiLineComment() { + self.read() + for self.chr >= 0 { + chr := self.chr + self.read() + if chr == '*' && self.chr == '/' { + self.read() + return + } + } + + self.errorUnexpected(0, self.chr) +} + +func (self *_parser) skipWhiteSpace() { + for { + switch self.chr { + case ' ', '\t', '\f', '\v', '\u00a0', '\ufeff': + self.read() + continue + case '\r': + if self._peek() == '\n' { + self.read() + } + fallthrough + case '\u2028', '\u2029', '\n': + if self.insertSemicolon { + return + } + self.read() + continue + } + if self.chr >= utf8.RuneSelf { + if unicode.IsSpace(self.chr) { + self.read() + continue + } + } + break + } +} + +func (self *_parser) skipLineWhiteSpace() { + for isLineWhiteSpace(self.chr) { + self.read() + } +} + +func (self *_parser) scanMantissa(base int) { + for digitValue(self.chr) < base { + self.read() + } +} + +func (self *_parser) scanEscape(quote rune) { + + var length, base uint32 + switch self.chr { + //case '0', '1', '2', '3', '4', '5', '6', '7': + // Octal: + // length, base, limit = 3, 8, 255 + case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"', '\'', '0': + self.read() + return + case '\r', '\n', '\u2028', '\u2029': + self.scanNewline() + return + case 'x': + self.read() + length, base = 2, 16 + case 'u': + self.read() + length, base = 4, 16 + default: + self.read() // Always make progress + return + } + + var value uint32 + for ; length > 0 && self.chr != quote && self.chr >= 0; length-- { + digit := uint32(digitValue(self.chr)) + if digit >= base { + break + } + value = value*base + digit + self.read() + } +} + +func (self *_parser) scanString(offset int) (string, error) { + // " ' / + quote := rune(self.str[offset]) + + for self.chr != quote { + chr := self.chr + if chr == '\n' || chr == '\r' || chr == '\u2028' || chr == '\u2029' || chr < 0 { + goto newline + } + self.read() + if chr == '\\' { + if quote == '/' { + if self.chr == '\n' || self.chr == '\r' || self.chr == '\u2028' || self.chr == '\u2029' || self.chr < 0 { + goto newline + } + self.read() + } else { + self.scanEscape(quote) + } + } else if chr == '[' && quote == '/' { + // Allow a slash (/) in a bracket character class ([...]) + // TODO Fix this, this is hacky... + quote = -1 + } else if chr == ']' && quote == -1 { + quote = '/' + } + } + + // " ' / + self.read() + + return string(self.str[offset:self.chrOffset]), nil + +newline: + self.scanNewline() + err := "String not terminated" + if quote == '/' { + err = "Invalid regular expression: missing /" + self.error(self.idxOf(offset), err) + } + return "", errors.New(err) +} + +func (self *_parser) scanNewline() { + if self.chr == '\r' { + self.read() + if self.chr != '\n' { + return + } + } + self.read() +} + +func hex2decimal(chr byte) (value rune, ok bool) { + { + chr := rune(chr) + switch { + case '0' <= chr && chr <= '9': + return chr - '0', true + case 'a' <= chr && chr <= 'f': + return chr - 'a' + 10, true + case 'A' <= chr && chr <= 'F': + return chr - 'A' + 10, true + } + return + } +} + +func parseNumberLiteral(literal string) (value interface{}, err error) { + // TODO Is Uint okay? What about -MAX_UINT + value, err = strconv.ParseInt(literal, 0, 64) + if err == nil { + return + } + + parseIntErr := err // Save this first error, just in case + + value, err = strconv.ParseFloat(literal, 64) + if err == nil { + return + } else if err.(*strconv.NumError).Err == strconv.ErrRange { + // Infinity, etc. + return value, nil + } + + err = parseIntErr + + if err.(*strconv.NumError).Err == strconv.ErrRange { + if len(literal) > 2 && literal[0] == '0' && (literal[1] == 'X' || literal[1] == 'x') { + // Could just be a very large number (e.g. 0x8000000000000000) + var value float64 + literal = literal[2:] + for _, chr := range literal { + digit := digitValue(chr) + if digit >= 16 { + goto error + } + value = value*16 + float64(digit) + } + return value, nil + } + } + +error: + return nil, errors.New("Illegal numeric literal") +} + +func parseStringLiteral(literal string) (string, error) { + // Best case scenario... + if literal == "" { + return "", nil + } + + // Slightly less-best case scenario... + if !strings.ContainsRune(literal, '\\') { + return literal, nil + } + + str := literal + buffer := bytes.NewBuffer(make([]byte, 0, 3*len(literal)/2)) + + for len(str) > 0 { + switch chr := str[0]; { + // We do not explicitly handle the case of the quote + // value, which can be: " ' / + // This assumes we're already passed a partially well-formed literal + case chr >= utf8.RuneSelf: + chr, size := utf8.DecodeRuneInString(str) + buffer.WriteRune(chr) + str = str[size:] + continue + case chr != '\\': + buffer.WriteByte(chr) + str = str[1:] + continue + } + + if len(str) <= 1 { + panic("len(str) <= 1") + } + chr := str[1] + var value rune + if chr >= utf8.RuneSelf { + str = str[1:] + var size int + value, size = utf8.DecodeRuneInString(str) + str = str[size:] // \ + + } else { + str = str[2:] // \ + switch chr { + case 'b': + value = '\b' + case 'f': + value = '\f' + case 'n': + value = '\n' + case 'r': + value = '\r' + case 't': + value = '\t' + case 'v': + value = '\v' + case 'x', 'u': + size := 0 + switch chr { + case 'x': + size = 2 + case 'u': + size = 4 + } + if len(str) < size { + return "", fmt.Errorf("invalid escape: \\%s: len(%q) != %d", string(chr), str, size) + } + for j := 0; j < size; j++ { + decimal, ok := hex2decimal(str[j]) + if !ok { + return "", fmt.Errorf("invalid escape: \\%s: %q", string(chr), str[:size]) + } + value = value<<4 | decimal + } + str = str[size:] + if chr == 'x' { + break + } + if value > utf8.MaxRune { + panic("value > utf8.MaxRune") + } + case '0': + if len(str) == 0 || '0' > str[0] || str[0] > '7' { + value = 0 + break + } + fallthrough + case '1', '2', '3', '4', '5', '6', '7': + // TODO strict + value = rune(chr) - '0' + j := 0 + for ; j < 2; j++ { + if len(str) < j+1 { + break + } + chr := str[j] + if '0' > chr || chr > '7' { + break + } + decimal := rune(str[j]) - '0' + value = (value << 3) | decimal + } + str = str[j:] + case '\\': + value = '\\' + case '\'', '"': + value = rune(chr) + case '\r': + if len(str) > 0 { + if str[0] == '\n' { + str = str[1:] + } + } + fallthrough + case '\n': + continue + default: + value = rune(chr) + } + } + buffer.WriteRune(value) + } + + return buffer.String(), nil +} + +func (self *_parser) scanNumericLiteral(decimalPoint bool) (token.Token, string) { + + offset := self.chrOffset + tkn := token.NUMBER + + if decimalPoint { + offset-- + self.scanMantissa(10) + goto exponent + } + + if self.chr == '0' { + offset := self.chrOffset + self.read() + if self.chr == 'x' || self.chr == 'X' { + // Hexadecimal + self.read() + if isDigit(self.chr, 16) { + self.read() + } else { + return token.ILLEGAL, self.str[offset:self.chrOffset] + } + self.scanMantissa(16) + + if self.chrOffset-offset <= 2 { + // Only "0x" or "0X" + self.error(0, "Illegal hexadecimal number") + } + + goto hexadecimal + } else if self.chr == '.' { + // Float + goto float + } else { + // Octal, Float + if self.chr == 'e' || self.chr == 'E' { + goto exponent + } + self.scanMantissa(8) + if self.chr == '8' || self.chr == '9' { + return token.ILLEGAL, self.str[offset:self.chrOffset] + } + goto octal + } + } + + self.scanMantissa(10) + +float: + if self.chr == '.' { + self.read() + self.scanMantissa(10) + } + +exponent: + if self.chr == 'e' || self.chr == 'E' { + self.read() + if self.chr == '-' || self.chr == '+' { + self.read() + } + if isDecimalDigit(self.chr) { + self.read() + self.scanMantissa(10) + } else { + return token.ILLEGAL, self.str[offset:self.chrOffset] + } + } + +hexadecimal: +octal: + if isIdentifierStart(self.chr) || isDecimalDigit(self.chr) { + return token.ILLEGAL, self.str[offset:self.chrOffset] + } + + return tkn, self.str[offset:self.chrOffset] +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer_test.go new file mode 100644 index 0000000000..37eb7a464b --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer_test.go @@ -0,0 +1,380 @@ +package parser + +import ( + "../terst" + "testing" + + "github.com/robertkrimen/otto/file" + "github.com/robertkrimen/otto/token" +) + +var tt = terst.Terst +var is = terst.Is + +func TestLexer(t *testing.T) { + tt(t, func() { + setup := func(src string) *_parser { + parser := newParser("", src) + return parser + } + + test := func(src string, test ...interface{}) { + parser := setup(src) + for len(test) > 0 { + tkn, literal, idx := parser.scan() + if len(test) > 0 { + is(tkn, test[0].(token.Token)) + test = test[1:] + } + if len(test) > 0 { + is(literal, test[0].(string)) + test = test[1:] + } + if len(test) > 0 { + // FIXME terst, Fix this so that cast to file.Idx is not necessary? + is(idx, file.Idx(test[0].(int))) + test = test[1:] + } + } + } + + test("", + token.EOF, "", 1, + ) + + test("1", + token.NUMBER, "1", 1, + token.EOF, "", 2, + ) + + test(".0", + token.NUMBER, ".0", 1, + token.EOF, "", 3, + ) + + test("abc", + token.IDENTIFIER, "abc", 1, + token.EOF, "", 4, + ) + + test("abc(1)", + token.IDENTIFIER, "abc", 1, + token.LEFT_PARENTHESIS, "", 4, + token.NUMBER, "1", 5, + token.RIGHT_PARENTHESIS, "", 6, + token.EOF, "", 7, + ) + + test(".", + token.PERIOD, "", 1, + token.EOF, "", 2, + ) + + test("===.", + token.STRICT_EQUAL, "", 1, + token.PERIOD, "", 4, + token.EOF, "", 5, + ) + + test(">>>=.0", + token.UNSIGNED_SHIFT_RIGHT_ASSIGN, "", 1, + token.NUMBER, ".0", 5, + token.EOF, "", 7, + ) + + test(">>>=0.0.", + token.UNSIGNED_SHIFT_RIGHT_ASSIGN, "", 1, + token.NUMBER, "0.0", 5, + token.PERIOD, "", 8, + token.EOF, "", 9, + ) + + test("\"abc\"", + token.STRING, "\"abc\"", 1, + token.EOF, "", 6, + ) + + test("abc = //", + token.IDENTIFIER, "abc", 1, + token.ASSIGN, "", 5, + token.EOF, "", 9, + ) + + test("abc = 1 / 2", + token.IDENTIFIER, "abc", 1, + token.ASSIGN, "", 5, + token.NUMBER, "1", 7, + token.SLASH, "", 9, + token.NUMBER, "2", 11, + token.EOF, "", 12, + ) + + test("xyzzy = 'Nothing happens.'", + token.IDENTIFIER, "xyzzy", 1, + token.ASSIGN, "", 7, + token.STRING, "'Nothing happens.'", 9, + token.EOF, "", 27, + ) + + test("abc = !false", + token.IDENTIFIER, "abc", 1, + token.ASSIGN, "", 5, + token.NOT, "", 7, + token.BOOLEAN, "false", 8, + token.EOF, "", 13, + ) + + test("abc = !!true", + token.IDENTIFIER, "abc", 1, + token.ASSIGN, "", 5, + token.NOT, "", 7, + token.NOT, "", 8, + token.BOOLEAN, "true", 9, + token.EOF, "", 13, + ) + + test("abc *= 1", + token.IDENTIFIER, "abc", 1, + token.MULTIPLY_ASSIGN, "", 5, + token.NUMBER, "1", 8, + token.EOF, "", 9, + ) + + test("if 1 else", + token.IF, "if", 1, + token.NUMBER, "1", 4, + token.ELSE, "else", 6, + token.EOF, "", 10, + ) + + test("null", + token.NULL, "null", 1, + token.EOF, "", 5, + ) + + test(`"\u007a\x79\u000a\x78"`, + token.STRING, "\"\\u007a\\x79\\u000a\\x78\"", 1, + token.EOF, "", 23, + ) + + test(`"[First line \ +Second line \ + Third line\ +. ]" + `, + token.STRING, "\"[First line \\\nSecond line \\\n Third line\\\n. ]\"", 1, + token.EOF, "", 53, + ) + + test("/", + token.SLASH, "", 1, + token.EOF, "", 2, + ) + + test("var abc = \"abc\uFFFFabc\"", + token.VAR, "var", 1, + token.IDENTIFIER, "abc", 5, + token.ASSIGN, "", 9, + token.STRING, "\"abc\uFFFFabc\"", 11, + token.EOF, "", 22, + ) + + test(`'\t' === '\r'`, + token.STRING, "'\\t'", 1, + token.STRICT_EQUAL, "", 6, + token.STRING, "'\\r'", 10, + token.EOF, "", 14, + ) + + test(`var \u0024 = 1`, + token.VAR, "var", 1, + token.IDENTIFIER, "$", 5, + token.ASSIGN, "", 12, + token.NUMBER, "1", 14, + token.EOF, "", 15, + ) + + test("10e10000", + token.NUMBER, "10e10000", 1, + token.EOF, "", 9, + ) + + test(`var if var class`, + token.VAR, "var", 1, + token.IF, "if", 5, + token.VAR, "var", 8, + token.KEYWORD, "class", 12, + token.EOF, "", 17, + ) + + test(`-0`, + token.MINUS, "", 1, + token.NUMBER, "0", 2, + token.EOF, "", 3, + ) + + test(`.01`, + token.NUMBER, ".01", 1, + token.EOF, "", 4, + ) + + test(`.01e+2`, + token.NUMBER, ".01e+2", 1, + token.EOF, "", 7, + ) + + test(";", + token.SEMICOLON, "", 1, + token.EOF, "", 2, + ) + + test(";;", + token.SEMICOLON, "", 1, + token.SEMICOLON, "", 2, + token.EOF, "", 3, + ) + + test("//", + token.EOF, "", 3, + ) + + test(";;//", + token.SEMICOLON, "", 1, + token.SEMICOLON, "", 2, + token.EOF, "", 5, + ) + + test("1", + token.NUMBER, "1", 1, + ) + + test("12 123", + token.NUMBER, "12", 1, + token.NUMBER, "123", 4, + ) + + test("1.2 12.3", + token.NUMBER, "1.2", 1, + token.NUMBER, "12.3", 5, + ) + + test("/ /=", + token.SLASH, "", 1, + token.QUOTIENT_ASSIGN, "", 3, + ) + + test(`"abc"`, + token.STRING, `"abc"`, 1, + ) + + test(`'abc'`, + token.STRING, `'abc'`, 1, + ) + + test("++", + token.INCREMENT, "", 1, + ) + + test(">", + token.GREATER, "", 1, + ) + + test(">=", + token.GREATER_OR_EQUAL, "", 1, + ) + + test(">>", + token.SHIFT_RIGHT, "", 1, + ) + + test(">>=", + token.SHIFT_RIGHT_ASSIGN, "", 1, + ) + + test(">>>", + token.UNSIGNED_SHIFT_RIGHT, "", 1, + ) + + test(">>>=", + token.UNSIGNED_SHIFT_RIGHT_ASSIGN, "", 1, + ) + + test("1 \"abc\"", + token.NUMBER, "1", 1, + token.STRING, "\"abc\"", 3, + ) + + test(",", + token.COMMA, "", 1, + ) + + test("1, \"abc\"", + token.NUMBER, "1", 1, + token.COMMA, "", 2, + token.STRING, "\"abc\"", 4, + ) + + test("new abc(1, 3.14159);", + token.NEW, "new", 1, + token.IDENTIFIER, "abc", 5, + token.LEFT_PARENTHESIS, "", 8, + token.NUMBER, "1", 9, + token.COMMA, "", 10, + token.NUMBER, "3.14159", 12, + token.RIGHT_PARENTHESIS, "", 19, + token.SEMICOLON, "", 20, + ) + + test("1 == \"1\"", + token.NUMBER, "1", 1, + token.EQUAL, "", 3, + token.STRING, "\"1\"", 6, + ) + + test("1\n[]\n", + token.NUMBER, "1", 1, + token.LEFT_BRACKET, "", 3, + token.RIGHT_BRACKET, "", 4, + ) + + test("1\ufeff[]\ufeff", + token.NUMBER, "1", 1, + token.LEFT_BRACKET, "", 5, + token.RIGHT_BRACKET, "", 6, + ) + + // ILLEGAL + + test(`3ea`, + token.ILLEGAL, "3e", 1, + token.IDENTIFIER, "a", 3, + token.EOF, "", 4, + ) + + test(`3in`, + token.ILLEGAL, "3", 1, + token.IN, "in", 2, + token.EOF, "", 4, + ) + + test("\"Hello\nWorld\"", + token.ILLEGAL, "", 1, + token.IDENTIFIER, "World", 8, + token.ILLEGAL, "", 13, + token.EOF, "", 14, + ) + + test("\u203f = 10", + token.ILLEGAL, "", 1, + token.ASSIGN, "", 5, + token.NUMBER, "10", 7, + token.EOF, "", 9, + ) + + test(`"\x0G"`, + token.STRING, "\"\\x0G\"", 1, + token.EOF, "", 7, + ) + + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/marshal_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/marshal_test.go new file mode 100644 index 0000000000..f54cd2d4fb --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/marshal_test.go @@ -0,0 +1,930 @@ +package parser + +import ( + "bytes" + "encoding/json" + "fmt" + "os" + "reflect" + "strings" + "testing" + + "github.com/robertkrimen/otto/ast" +) + +func marshal(name string, children ...interface{}) interface{} { + if len(children) == 1 { + if name == "" { + return testMarshalNode(children[0]) + } + return map[string]interface{}{ + name: children[0], + } + } + map_ := map[string]interface{}{} + length := len(children) / 2 + for i := 0; i < length; i++ { + name := children[i*2].(string) + value := children[i*2+1] + map_[name] = value + } + if name == "" { + return map_ + } + return map[string]interface{}{ + name: map_, + } +} + +func testMarshalNode(node interface{}) interface{} { + switch node := node.(type) { + + // Expression + + case *ast.ArrayLiteral: + return marshal("Array", testMarshalNode(node.Value)) + + case *ast.AssignExpression: + return marshal("Assign", + "Left", testMarshalNode(node.Left), + "Right", testMarshalNode(node.Right), + ) + + case *ast.BinaryExpression: + return marshal("BinaryExpression", + "Operator", node.Operator.String(), + "Left", testMarshalNode(node.Left), + "Right", testMarshalNode(node.Right), + ) + + case *ast.BooleanLiteral: + return marshal("Literal", node.Value) + + case *ast.CallExpression: + return marshal("Call", + "Callee", testMarshalNode(node.Callee), + "ArgumentList", testMarshalNode(node.ArgumentList), + ) + + case *ast.ConditionalExpression: + return marshal("Conditional", + "Test", testMarshalNode(node.Test), + "Consequent", testMarshalNode(node.Consequent), + "Alternate", testMarshalNode(node.Alternate), + ) + + case *ast.DotExpression: + return marshal("Dot", + "Left", testMarshalNode(node.Left), + "Member", node.Identifier.Name, + ) + + case *ast.NewExpression: + return marshal("New", + "Callee", testMarshalNode(node.Callee), + "ArgumentList", testMarshalNode(node.ArgumentList), + ) + + case *ast.NullLiteral: + return marshal("Literal", nil) + + case *ast.NumberLiteral: + return marshal("Literal", node.Value) + + case *ast.ObjectLiteral: + return marshal("Object", testMarshalNode(node.Value)) + + case *ast.RegExpLiteral: + return marshal("Literal", node.Literal) + + case *ast.StringLiteral: + return marshal("Literal", node.Literal) + + case *ast.VariableExpression: + return []interface{}{node.Name, testMarshalNode(node.Initializer)} + + // Statement + + case *ast.Program: + return testMarshalNode(node.Body) + + case *ast.BlockStatement: + return marshal("BlockStatement", testMarshalNode(node.List)) + + case *ast.EmptyStatement: + return "EmptyStatement" + + case *ast.ExpressionStatement: + return testMarshalNode(node.Expression) + + case *ast.ForInStatement: + return marshal("ForIn", + "Into", marshal("", node.Into), + "Source", marshal("", node.Source), + "Body", marshal("", node.Body), + ) + + case *ast.FunctionLiteral: + return marshal("Function", testMarshalNode(node.Body)) + + case *ast.Identifier: + return marshal("Identifier", node.Name) + + case *ast.IfStatement: + if_ := marshal("", + "Test", testMarshalNode(node.Test), + "Consequent", testMarshalNode(node.Consequent), + ).(map[string]interface{}) + if node.Alternate != nil { + if_["Alternate"] = testMarshalNode(node.Alternate) + } + return marshal("If", if_) + + case *ast.LabelledStatement: + return marshal("Label", + "Name", node.Label.Name, + "Statement", testMarshalNode(node.Statement), + ) + case ast.Property: + return marshal("", + "Key", node.Key, + "Value", testMarshalNode(node.Value), + ) + + case *ast.ReturnStatement: + return marshal("Return", testMarshalNode(node.Argument)) + + case *ast.SequenceExpression: + return marshal("Sequence", testMarshalNode(node.Sequence)) + + case *ast.ThrowStatement: + return marshal("Throw", testMarshalNode(node.Argument)) + + case *ast.VariableStatement: + return marshal("Var", testMarshalNode(node.List)) + + } + + { + value := reflect.ValueOf(node) + if value.Kind() == reflect.Slice { + tmp0 := []interface{}{} + for index := 0; index < value.Len(); index++ { + tmp0 = append(tmp0, testMarshalNode(value.Index(index).Interface())) + } + return tmp0 + } + } + + if node != nil { + fmt.Fprintf(os.Stderr, "testMarshalNode(%T)\n", node) + } + + return nil +} + +func testMarshal(node interface{}) string { + value, err := json.Marshal(testMarshalNode(node)) + if err != nil { + panic(err) + } + return string(value) +} + +func TestParserAST(t *testing.T) { + tt(t, func() { + + test := func(inputOutput string) { + match := matchBeforeAfterSeparator.FindStringIndex(inputOutput) + input := strings.TrimSpace(inputOutput[0:match[0]]) + wantOutput := strings.TrimSpace(inputOutput[match[1]:]) + _, program, err := testParse(input) + is(err, nil) + haveOutput := testMarshal(program) + tmp0, tmp1 := bytes.Buffer{}, bytes.Buffer{} + json.Indent(&tmp0, []byte(haveOutput), "\t\t", " ") + json.Indent(&tmp1, []byte(wantOutput), "\t\t", " ") + is("\n\t\t"+tmp0.String(), "\n\t\t"+tmp1.String()) + } + + test(` + --- +[] + `) + + test(` + ; + --- +[ + "EmptyStatement" +] + `) + + test(` + ;;; + --- +[ + "EmptyStatement", + "EmptyStatement", + "EmptyStatement" +] + `) + + test(` + 1; true; abc; "abc"; null; + --- +[ + { + "Literal": 1 + }, + { + "Literal": true + }, + { + "Identifier": "abc" + }, + { + "Literal": "\"abc\"" + }, + { + "Literal": null + } +] + `) + + test(` + { 1; null; 3.14159; ; } + --- +[ + { + "BlockStatement": [ + { + "Literal": 1 + }, + { + "Literal": null + }, + { + "Literal": 3.14159 + }, + "EmptyStatement" + ] + } +] + `) + + test(` + new abc(); + --- +[ + { + "New": { + "ArgumentList": [], + "Callee": { + "Identifier": "abc" + } + } + } +] + `) + + test(` + new abc(1, 3.14159) + --- +[ + { + "New": { + "ArgumentList": [ + { + "Literal": 1 + }, + { + "Literal": 3.14159 + } + ], + "Callee": { + "Identifier": "abc" + } + } + } +] + `) + + test(` + true ? false : true + --- +[ + { + "Conditional": { + "Alternate": { + "Literal": true + }, + "Consequent": { + "Literal": false + }, + "Test": { + "Literal": true + } + } + } +] + `) + + test(` + true || false + --- +[ + { + "BinaryExpression": { + "Left": { + "Literal": true + }, + "Operator": "||", + "Right": { + "Literal": false + } + } + } +] + `) + + test(` + 0 + { abc: true } + --- +[ + { + "BinaryExpression": { + "Left": { + "Literal": 0 + }, + "Operator": "+", + "Right": { + "Object": [ + { + "Key": "abc", + "Value": { + "Literal": true + } + } + ] + } + } + } +] + `) + + test(` + 1 == "1" + --- +[ + { + "BinaryExpression": { + "Left": { + "Literal": 1 + }, + "Operator": "==", + "Right": { + "Literal": "\"1\"" + } + } + } +] + `) + + test(` + abc(1) + --- +[ + { + "Call": { + "ArgumentList": [ + { + "Literal": 1 + } + ], + "Callee": { + "Identifier": "abc" + } + } + } +] + `) + + test(` + Math.pow(3, 2) + --- +[ + { + "Call": { + "ArgumentList": [ + { + "Literal": 3 + }, + { + "Literal": 2 + } + ], + "Callee": { + "Dot": { + "Left": { + "Identifier": "Math" + }, + "Member": "pow" + } + } + } + } +] + `) + + test(` + 1, 2, 3 + --- +[ + { + "Sequence": [ + { + "Literal": 1 + }, + { + "Literal": 2 + }, + { + "Literal": 3 + } + ] + } +] + `) + + test(` + / abc / gim; + --- +[ + { + "Literal": "/ abc / gim" + } +] + `) + + test(` + if (0) + 1; + --- +[ + { + "If": { + "Consequent": { + "Literal": 1 + }, + "Test": { + "Literal": 0 + } + } + } +] + `) + + test(` + 0+function(){ + return; + } + --- +[ + { + "BinaryExpression": { + "Left": { + "Literal": 0 + }, + "Operator": "+", + "Right": { + "Function": { + "BlockStatement": [ + { + "Return": null + } + ] + } + } + } + } +] + `) + + test(` + xyzzy // Ignore it + // Ignore this + // And this + /* And all.. + + + + ... of this! + */ + "Nothing happens." + // And finally this + --- +[ + { + "Identifier": "xyzzy" + }, + { + "Literal": "\"Nothing happens.\"" + } +] + `) + + test(` + ((x & (x = 1)) !== 0) + --- +[ + { + "BinaryExpression": { + "Left": { + "BinaryExpression": { + "Left": { + "Identifier": "x" + }, + "Operator": "\u0026", + "Right": { + "Assign": { + "Left": { + "Identifier": "x" + }, + "Right": { + "Literal": 1 + } + } + } + } + }, + "Operator": "!==", + "Right": { + "Literal": 0 + } + } + } +] + `) + + test(` + { abc: 'def' } + --- +[ + { + "BlockStatement": [ + { + "Label": { + "Name": "abc", + "Statement": { + "Literal": "'def'" + } + } + } + ] + } +] + `) + + test(` + // This is not an object, this is a string literal with a label! + ({ abc: 'def' }) + --- +[ + { + "Object": [ + { + "Key": "abc", + "Value": { + "Literal": "'def'" + } + } + ] + } +] + `) + + test(` + [,] + --- +[ + { + "Array": [ + null + ] + } +] + `) + + test(` + [,,] + --- +[ + { + "Array": [ + null, + null + ] + } +] + `) + + test(` + ({ get abc() {} }) + --- +[ + { + "Object": [ + { + "Key": "abc", + "Value": { + "Function": { + "BlockStatement": [] + } + } + } + ] + } +] + `) + + test(` + /abc/.source + --- +[ + { + "Dot": { + "Left": { + "Literal": "/abc/" + }, + "Member": "source" + } + } +] + `) + + test(` + xyzzy + + throw new TypeError("Nothing happens.") + --- +[ + { + "Identifier": "xyzzy" + }, + { + "Throw": { + "New": { + "ArgumentList": [ + { + "Literal": "\"Nothing happens.\"" + } + ], + "Callee": { + "Identifier": "TypeError" + } + } + } + } +] + `) + + // When run, this will call a type error to be thrown + // This is essentially the same as: + // + // var abc = 1(function(){})() + // + test(` + var abc = 1 + (function(){ + })() + --- +[ + { + "Var": [ + [ + "abc", + { + "Call": { + "ArgumentList": [], + "Callee": { + "Call": { + "ArgumentList": [ + { + "Function": { + "BlockStatement": [] + } + } + ], + "Callee": { + "Literal": 1 + } + } + } + } + } + ] + ] + } +] + `) + + test(` + "use strict" + --- +[ + { + "Literal": "\"use strict\"" + } +] + `) + + test(` + "use strict" + abc = 1 + 2 + 11 + --- +[ + { + "Literal": "\"use strict\"" + }, + { + "Assign": { + "Left": { + "Identifier": "abc" + }, + "Right": { + "BinaryExpression": { + "Left": { + "BinaryExpression": { + "Left": { + "Literal": 1 + }, + "Operator": "+", + "Right": { + "Literal": 2 + } + } + }, + "Operator": "+", + "Right": { + "Literal": 11 + } + } + } + } + } +] + `) + + test(` + abc = function() { 'use strict' } + --- +[ + { + "Assign": { + "Left": { + "Identifier": "abc" + }, + "Right": { + "Function": { + "BlockStatement": [ + { + "Literal": "'use strict'" + } + ] + } + } + } + } +] + `) + + test(` + for (var abc in def) { + } + --- +[ + { + "ForIn": { + "Body": { + "BlockStatement": [] + }, + "Into": [ + "abc", + null + ], + "Source": { + "Identifier": "def" + } + } + } +] + `) + + test(` + abc = { + '"': "'", + "'": '"', + } + --- +[ + { + "Assign": { + "Left": { + "Identifier": "abc" + }, + "Right": { + "Object": [ + { + "Key": "\"", + "Value": { + "Literal": "\"'\"" + } + }, + { + "Key": "'", + "Value": { + "Literal": "'\"'" + } + } + ] + } + } + } +] + `) + + return + + test(` + if (!abc && abc.jkl(def) && abc[0] === +abc[0] && abc.length < ghi) { + } + --- +[ + { + "If": { + "Consequent": { + "BlockStatement": [] + }, + "Test": { + "BinaryExpression": { + "Left": { + "BinaryExpression": { + "Left": { + "BinaryExpression": { + "Left": null, + "Operator": "\u0026\u0026", + "Right": { + "Call": { + "ArgumentList": [ + { + "Identifier": "def" + } + ], + "Callee": { + "Dot": { + "Left": { + "Identifier": "abc" + }, + "Member": "jkl" + } + } + } + } + } + }, + "Operator": "\u0026\u0026", + "Right": { + "BinaryExpression": { + "Left": null, + "Operator": "===", + "Right": null + } + } + } + }, + "Operator": "\u0026\u0026", + "Right": { + "BinaryExpression": { + "Left": { + "Dot": { + "Left": { + "Identifier": "abc" + }, + "Member": "length" + } + }, + "Operator": "\u003c", + "Right": { + "Identifier": "ghi" + } + } + } + } + } + } + } +] + `) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go new file mode 100644 index 0000000000..1536344d7d --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go @@ -0,0 +1,273 @@ +/* +Package parser implements a parser for JavaScript. + + import ( + "github.com/robertkrimen/otto/parser" + ) + +Parse and return an AST + + filename := "" // A filename is optional + src := ` + // Sample xyzzy example + (function(){ + if (3.14159 > 0) { + console.log("Hello, World."); + return; + } + + var xyzzy = NaN; + console.log("Nothing happens."); + return xyzzy; + })(); + ` + + // Parse some JavaScript, yielding a *ast.Program and/or an ErrorList + program, err := parser.ParseFile(nil, filename, src, 0) + +Warning + +The parser and AST interfaces are still works-in-progress (particularly where +node types are concerned) and may change in the future. + +*/ +package parser + +import ( + "bytes" + "errors" + "io" + "io/ioutil" + + "github.com/robertkrimen/otto/ast" + "github.com/robertkrimen/otto/file" + "github.com/robertkrimen/otto/token" +) + +// A Mode value is a set of flags (or 0). They control optional parser functionality. +type Mode uint + +const ( + IgnoreRegExpErrors Mode = 1 << iota // Ignore RegExp compatibility errors (allow backtracking) +) + +type _parser struct { + filename string + str string + length int + base int + + chr rune // The current character + chrOffset int // The offset of current character + offset int // The offset after current character (may be greater than 1) + + idx file.Idx // The index of token + token token.Token // The token + literal string // The literal of the token, if any + + scope *_scope + insertSemicolon bool // If we see a newline, then insert an implicit semicolon + implicitSemicolon bool // An implicit semicolon exists + + errors ErrorList + + recover struct { + // Scratch when trying to seek to the next statement, etc. + idx file.Idx + count int + } + + mode Mode + + file *file.File +} + +func _newParser(filename, src string, base int) *_parser { + return &_parser{ + chr: ' ', // This is set so we can start scanning by skipping whitespace + str: src, + length: len(src), + base: base, + file: file.NewFile(filename, src, base), + } +} + +func newParser(filename, src string) *_parser { + return _newParser(filename, src, 1) +} + +func ReadSource(filename string, src interface{}) ([]byte, error) { + if src != nil { + switch src := src.(type) { + case string: + return []byte(src), nil + case []byte: + return src, nil + case *bytes.Buffer: + if src != nil { + return src.Bytes(), nil + } + case io.Reader: + var bfr bytes.Buffer + if _, err := io.Copy(&bfr, src); err != nil { + return nil, err + } + return bfr.Bytes(), nil + } + return nil, errors.New("invalid source") + } + return ioutil.ReadFile(filename) +} + +// ParseFile parses the source code of a single JavaScript/ECMAScript source file and returns +// the corresponding ast.Program node. +// +// If fileSet == nil, ParseFile parses source without a FileSet. +// If fileSet != nil, ParseFile first adds filename and src to fileSet. +// +// The filename argument is optional and is used for labelling errors, etc. +// +// src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST always be in UTF-8. +// +// // Parse some JavaScript, yielding a *ast.Program and/or an ErrorList +// program, err := parser.ParseFile(nil, "", `if (abc > 1) {}`, 0) +// +func ParseFile(fileSet *file.FileSet, filename string, src interface{}, mode Mode) (*ast.Program, error) { + str, err := ReadSource(filename, src) + if err != nil { + return nil, err + } + { + str := string(str) + + base := 1 + if fileSet != nil { + base = fileSet.AddFile(filename, str) + } + + parser := _newParser(filename, str, base) + parser.mode = mode + return parser.parse() + } +} + +// ParseFunction parses a given parameter list and body as a function and returns the +// corresponding ast.FunctionLiteral node. +// +// The parameter list, if any, should be a comma-separated list of identifiers. +// +func ParseFunction(parameterList, body string) (*ast.FunctionLiteral, error) { + + src := "(function(" + parameterList + ") {\n" + body + "\n})" + + parser := _newParser("", src, 1) + program, err := parser.parse() + if err != nil { + return nil, err + } + + return program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral), nil +} + +func (self *_parser) slice(idx0, idx1 file.Idx) string { + from := int(idx0) - self.base + to := int(idx1) - self.base + if from >= 0 && to <= len(self.str) { + return self.str[from:to] + } + + return "" +} + +func (self *_parser) parse() (*ast.Program, error) { + self.next() + program := self.parseProgram() + if false { + self.errors.Sort() + } + return program, self.errors.Err() +} + +func (self *_parser) next() { + self.token, self.literal, self.idx = self.scan() +} + +func (self *_parser) optionalSemicolon() { + if self.token == token.SEMICOLON { + self.next() + return + } + + if self.implicitSemicolon { + self.implicitSemicolon = false + return + } + + if self.token != token.EOF && self.token != token.RIGHT_BRACE { + self.expect(token.SEMICOLON) + } +} + +func (self *_parser) semicolon() { + if self.token != token.RIGHT_PARENTHESIS && self.token != token.RIGHT_BRACE { + if self.implicitSemicolon { + self.implicitSemicolon = false + return + } + + self.expect(token.SEMICOLON) + } +} + +func (self *_parser) idxOf(offset int) file.Idx { + return file.Idx(self.base + offset) +} + +func (self *_parser) expect(value token.Token) file.Idx { + idx := self.idx + if self.token != value { + self.errorUnexpectedToken(self.token) + } + self.next() + return idx +} + +func lineCount(str string) (int, int) { + line, last := 0, -1 + pair := false + for index, chr := range str { + switch chr { + case '\r': + line += 1 + last = index + pair = true + continue + case '\n': + if !pair { + line += 1 + } + last = index + case '\u2028', '\u2029': + line += 1 + last = index + 2 + } + pair = false + } + return line, last +} + +func (self *_parser) position(idx file.Idx) file.Position { + position := file.Position{} + offset := int(idx) - self.base + str := self.str[:offset] + position.Filename = self.filename + line, last := lineCount(str) + position.Line = 1 + line + if last >= 0 { + position.Column = offset - last + } else { + position.Column = 1 + len(str) + } + + return position +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser_test.go new file mode 100644 index 0000000000..8f94577455 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser_test.go @@ -0,0 +1,1004 @@ +package parser + +import ( + "errors" + "regexp" + "strings" + "testing" + + "github.com/robertkrimen/otto/ast" + "github.com/robertkrimen/otto/file" +) + +func firstErr(err error) error { + switch err := err.(type) { + case ErrorList: + return err[0] + } + return err +} + +var matchBeforeAfterSeparator = regexp.MustCompile(`(?m)^[ \t]*---$`) + +func testParse(src string) (parser *_parser, program *ast.Program, err error) { + defer func() { + if tmp := recover(); tmp != nil { + switch tmp := tmp.(type) { + case string: + if strings.HasPrefix(tmp, "SyntaxError:") { + parser = nil + program = nil + err = errors.New(tmp) + return + } + } + panic(tmp) + } + }() + parser = newParser("", src) + program, err = parser.parse() + return +} + +func TestParseFile(t *testing.T) { + tt(t, func() { + _, err := ParseFile(nil, "", `/abc/`, 0) + is(err, nil) + + _, err = ParseFile(nil, "", `/(?!def)abc/`, IgnoreRegExpErrors) + is(err, nil) + + _, err = ParseFile(nil, "", `/(?!def)abc/`, 0) + is(err, "(anonymous): Line 1:1 Invalid regular expression: re2: Invalid (?!) ") + + _, err = ParseFile(nil, "", `/(?!def)abc/; return`, IgnoreRegExpErrors) + is(err, "(anonymous): Line 1:15 Illegal return statement") + }) +} + +func TestParseFunction(t *testing.T) { + tt(t, func() { + test := func(prm, bdy string, expect interface{}) *ast.FunctionLiteral { + function, err := ParseFunction(prm, bdy) + is(firstErr(err), expect) + return function + } + + test("a, b,c,d", "", nil) + + test("a, b;,c,d", "", "(anonymous): Line 1:15 Unexpected token ;") + + test("this", "", "(anonymous): Line 1:11 Unexpected token this") + + test("a, b, c, null", "", "(anonymous): Line 1:20 Unexpected token null") + + test("a, b,c,d", "return;", nil) + + test("a, b,c,d", "break;", "(anonymous): Line 2:1 Illegal break statement") + + test("a, b,c,d", "{}", nil) + }) +} + +func TestParserErr(t *testing.T) { + tt(t, func() { + test := func(input string, expect interface{}) (*ast.Program, *_parser) { + parser := newParser("", input) + program, err := parser.parse() + is(firstErr(err), expect) + return program, parser + } + + program, parser := test("", nil) + + program, parser = test(` + var abc; + break; do { + } while(true); + `, "(anonymous): Line 3:9 Illegal break statement") + { + stmt := program.Body[1].(*ast.BadStatement) + is(parser.position(stmt.From).Column, 9) + is(parser.position(stmt.To).Column, 16) + is(parser.slice(stmt.From, stmt.To), "break; ") + } + + test("{", "(anonymous): Line 1:2 Unexpected end of input") + + test("}", "(anonymous): Line 1:1 Unexpected token }") + + test("3ea", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("3in", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("3in []", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("3e", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("3e+", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("3e-", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("3x", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("3x0", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("0x", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("09", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("018", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("01.0", "(anonymous): Line 1:3 Unexpected number") + + test("01a", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("0x3in[]", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("\"Hello\nWorld\"", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("\u203f = 10", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("x\\", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("x\\\\", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("x\\u005c", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("x\\u002a", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("x\\\\u002a", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("/\n", "(anonymous): Line 1:1 Invalid regular expression: missing /") + + test("var x = /(s/g", "(anonymous): Line 1:9 Invalid regular expression: Unterminated group") + + test("0 = 1", "(anonymous): Line 1:1 Invalid left-hand side in assignment") + + test("func() = 1", "(anonymous): Line 1:1 Invalid left-hand side in assignment") + + test("(1 + 1) = 2", "(anonymous): Line 1:2 Invalid left-hand side in assignment") + + test("1++", "(anonymous): Line 1:2 Invalid left-hand side in assignment") + + test("1--", "(anonymous): Line 1:2 Invalid left-hand side in assignment") + + test("--1", "(anonymous): Line 1:1 Invalid left-hand side in assignment") + + test("for((1 + 1) in abc) def();", "(anonymous): Line 1:1 Invalid left-hand side in for-in") + + test("[", "(anonymous): Line 1:2 Unexpected end of input") + + test("[,", "(anonymous): Line 1:3 Unexpected end of input") + + test("1 + {", "(anonymous): Line 1:6 Unexpected end of input") + + test("1 + { abc:abc", "(anonymous): Line 1:14 Unexpected end of input") + + test("1 + { abc:abc,", "(anonymous): Line 1:15 Unexpected end of input") + + test("var abc = /\n/", "(anonymous): Line 1:11 Invalid regular expression: missing /") + + test("var abc = \"\n", "(anonymous): Line 1:11 Unexpected token ILLEGAL") + + test("var if = 0", "(anonymous): Line 1:5 Unexpected token if") + + test("abc + 0 = 1", "(anonymous): Line 1:1 Invalid left-hand side in assignment") + + test("+abc = 1", "(anonymous): Line 1:1 Invalid left-hand side in assignment") + + test("1 + (", "(anonymous): Line 1:6 Unexpected end of input") + + test("\n\n\n{", "(anonymous): Line 4:2 Unexpected end of input") + + test("\n/* Some multiline\ncomment */\n)", "(anonymous): Line 4:1 Unexpected token )") + + // TODO + //{ set 1 } + //{ get 2 } + //({ set: s(if) { } }) + //({ set s(.) { } }) + //({ set: s() { } }) + //({ set: s(a, b) { } }) + //({ get: g(d) { } }) + //({ get i() { }, i: 42 }) + //({ i: 42, get i() { } }) + //({ set i(x) { }, i: 42 }) + //({ i: 42, set i(x) { } }) + //({ get i() { }, get i() { } }) + //({ set i(x) { }, set i(x) { } }) + + test("function abc(if) {}", "(anonymous): Line 1:14 Unexpected token if") + + test("function abc(true) {}", "(anonymous): Line 1:14 Unexpected token true") + + test("function abc(false) {}", "(anonymous): Line 1:14 Unexpected token false") + + test("function abc(null) {}", "(anonymous): Line 1:14 Unexpected token null") + + test("function null() {}", "(anonymous): Line 1:10 Unexpected token null") + + test("function true() {}", "(anonymous): Line 1:10 Unexpected token true") + + test("function false() {}", "(anonymous): Line 1:10 Unexpected token false") + + test("function if() {}", "(anonymous): Line 1:10 Unexpected token if") + + test("a b;", "(anonymous): Line 1:3 Unexpected identifier") + + test("if.a", "(anonymous): Line 1:3 Unexpected token .") + + test("a if", "(anonymous): Line 1:3 Unexpected token if") + + test("a class", "(anonymous): Line 1:3 Unexpected reserved word") + + test("break\n", "(anonymous): Line 1:1 Illegal break statement") + + test("break 1;", "(anonymous): Line 1:7 Unexpected number") + + test("for (;;) { break 1; }", "(anonymous): Line 1:18 Unexpected number") + + test("continue\n", "(anonymous): Line 1:1 Illegal continue statement") + + test("continue 1;", "(anonymous): Line 1:10 Unexpected number") + + test("for (;;) { continue 1; }", "(anonymous): Line 1:21 Unexpected number") + + test("throw", "(anonymous): Line 1:1 Unexpected end of input") + + test("throw;", "(anonymous): Line 1:6 Unexpected token ;") + + test("throw \n", "(anonymous): Line 1:1 Unexpected end of input") + + test("for (var abc, def in {});", "(anonymous): Line 1:19 Unexpected token in") + + test("for ((abc in {});;);", nil) + + test("for ((abc in {}));", "(anonymous): Line 1:17 Unexpected token )") + + test("for (+abc in {});", "(anonymous): Line 1:1 Invalid left-hand side in for-in") + + test("if (false)", "(anonymous): Line 1:11 Unexpected end of input") + + test("if (false) abc(); else", "(anonymous): Line 1:23 Unexpected end of input") + + test("do", "(anonymous): Line 1:3 Unexpected end of input") + + test("while (false)", "(anonymous): Line 1:14 Unexpected end of input") + + test("for (;;)", "(anonymous): Line 1:9 Unexpected end of input") + + test("with (abc)", "(anonymous): Line 1:11 Unexpected end of input") + + test("try {}", "(anonymous): Line 1:1 Missing catch or finally after try") + + test("try {} catch {}", "(anonymous): Line 1:14 Unexpected token {") + + test("try {} catch () {}", "(anonymous): Line 1:15 Unexpected token )") + + test("\u203f = 1", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + // TODO + // const x = 12, y; + // const x, y = 12; + // const x; + // if(true) let a = 1; + // if(true) const a = 1; + + test(`new abc()."def"`, "(anonymous): Line 1:11 Unexpected string") + + test("/*", "(anonymous): Line 1:3 Unexpected end of input") + + test("/**", "(anonymous): Line 1:4 Unexpected end of input") + + test("/*\n\n\n", "(anonymous): Line 4:1 Unexpected end of input") + + test("/*\n\n\n*", "(anonymous): Line 4:2 Unexpected end of input") + + test("/*abc", "(anonymous): Line 1:6 Unexpected end of input") + + test("/*abc *", "(anonymous): Line 1:9 Unexpected end of input") + + test("\n]", "(anonymous): Line 2:1 Unexpected token ]") + + test("\r\n]", "(anonymous): Line 2:1 Unexpected token ]") + + test("\n\r]", "(anonymous): Line 3:1 Unexpected token ]") + + test("//\r\n]", "(anonymous): Line 2:1 Unexpected token ]") + + test("//\n\r]", "(anonymous): Line 3:1 Unexpected token ]") + + test("/abc\\\n/", "(anonymous): Line 1:1 Invalid regular expression: missing /") + + test("//\r \n]", "(anonymous): Line 3:1 Unexpected token ]") + + test("/*\r\n*/]", "(anonymous): Line 2:3 Unexpected token ]") + + test("/*\r \n*/]", "(anonymous): Line 3:3 Unexpected token ]") + + test("\\\\", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("\\u005c", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("\\abc", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("\\u0000", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("\\u200c = []", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("\\u200D = []", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test(`"\`, "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test(`"\u`, "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("return", "(anonymous): Line 1:1 Illegal return statement") + + test("continue", "(anonymous): Line 1:1 Illegal continue statement") + + test("break", "(anonymous): Line 1:1 Illegal break statement") + + test("switch (abc) { default: continue; }", "(anonymous): Line 1:25 Illegal continue statement") + + test("do { abc } *", "(anonymous): Line 1:12 Unexpected token *") + + test("while (true) { break abc; }", "(anonymous): Line 1:16 Undefined label 'abc'") + + test("while (true) { continue abc; }", "(anonymous): Line 1:16 Undefined label 'abc'") + + test("abc: while (true) { (function(){ break abc; }); }", "(anonymous): Line 1:34 Undefined label 'abc'") + + test("abc: while (true) { (function(){ abc: break abc; }); }", nil) + + test("abc: while (true) { (function(){ continue abc; }); }", "(anonymous): Line 1:34 Undefined label 'abc'") + + test(`abc: if (0) break abc; else {}`, nil) + + test(`abc: if (0) { break abc; } else {}`, nil) + + test(`abc: if (0) { break abc } else {}`, nil) + + test("abc: while (true) { abc: while (true) {} }", "(anonymous): Line 1:21 Label 'abc' already exists") + + if false { + // TODO When strict mode is implemented + test("(function () { 'use strict'; delete abc; }())", "") + } + + test("_: _: while (true) {]", "(anonymous): Line 1:4 Label '_' already exists") + + test("_:\n_:\nwhile (true) {]", "(anonymous): Line 2:1 Label '_' already exists") + + test("_:\n _:\nwhile (true) {]", "(anonymous): Line 2:4 Label '_' already exists") + + test("/Xyzzy(?!Nothing happens)/", + "(anonymous): Line 1:1 Invalid regular expression: re2: Invalid (?!) ") + + test("function(){}", "(anonymous): Line 1:9 Unexpected token (") + + test("\n/*/", "(anonymous): Line 2:4 Unexpected end of input") + + test("/*/.source", "(anonymous): Line 1:11 Unexpected end of input") + + test("/\\1/.source", "(anonymous): Line 1:1 Invalid regular expression: re2: Invalid \\1 ") + + test("var class", "(anonymous): Line 1:5 Unexpected reserved word") + + test("var if", "(anonymous): Line 1:5 Unexpected token if") + + test("object Object", "(anonymous): Line 1:8 Unexpected identifier") + + test("[object Object]", "(anonymous): Line 1:9 Unexpected identifier") + + test("\\u0xyz", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test(`for (var abc, def in {}) {}`, "(anonymous): Line 1:19 Unexpected token in") + + test(`for (abc, def in {}) {}`, "(anonymous): Line 1:1 Invalid left-hand side in for-in") + + test(`for (var abc=def, ghi=("abc" in {}); true;) {}`, nil) + + { + // Semicolon insertion + + test("this\nif (1);", nil) + + test("while (1) { break\nif (1); }", nil) + + test("throw\nif (1);", "(anonymous): Line 1:1 Illegal newline after throw") + + test("(function(){ return\nif (1); })", nil) + + test("while (1) { continue\nif (1); }", nil) + + test("debugger\nif (1);", nil) + } + + { // Reserved words + + test("class", "(anonymous): Line 1:1 Unexpected reserved word") + test("abc.class = 1", nil) + test("var class;", "(anonymous): Line 1:5 Unexpected reserved word") + + test("const", "(anonymous): Line 1:1 Unexpected reserved word") + test("abc.const = 1", nil) + test("var const;", "(anonymous): Line 1:5 Unexpected reserved word") + + test("enum", "(anonymous): Line 1:1 Unexpected reserved word") + test("abc.enum = 1", nil) + test("var enum;", "(anonymous): Line 1:5 Unexpected reserved word") + + test("export", "(anonymous): Line 1:1 Unexpected reserved word") + test("abc.export = 1", nil) + test("var export;", "(anonymous): Line 1:5 Unexpected reserved word") + + test("extends", "(anonymous): Line 1:1 Unexpected reserved word") + test("abc.extends = 1", nil) + test("var extends;", "(anonymous): Line 1:5 Unexpected reserved word") + + test("import", "(anonymous): Line 1:1 Unexpected reserved word") + test("abc.import = 1", nil) + test("var import;", "(anonymous): Line 1:5 Unexpected reserved word") + + test("super", "(anonymous): Line 1:1 Unexpected reserved word") + test("abc.super = 1", nil) + test("var super;", "(anonymous): Line 1:5 Unexpected reserved word") + } + + { // Reserved words (strict) + + test(`implements`, nil) + test(`abc.implements = 1`, nil) + test(`var implements;`, nil) + + test(`interface`, nil) + test(`abc.interface = 1`, nil) + test(`var interface;`, nil) + + test(`let`, nil) + test(`abc.let = 1`, nil) + test(`var let;`, nil) + + test(`package`, nil) + test(`abc.package = 1`, nil) + test(`var package;`, nil) + + test(`private`, nil) + test(`abc.private = 1`, nil) + test(`var private;`, nil) + + test(`protected`, nil) + test(`abc.protected = 1`, nil) + test(`var protected;`, nil) + + test(`public`, nil) + test(`abc.public = 1`, nil) + test(`var public;`, nil) + + test(`static`, nil) + test(`abc.static = 1`, nil) + test(`var static;`, nil) + + test(`yield`, nil) + test(`abc.yield = 1`, nil) + test(`var yield;`, nil) + } + }) +} + +func TestParser(t *testing.T) { + tt(t, func() { + test := func(source string, chk interface{}) *ast.Program { + _, program, err := testParse(source) + is(firstErr(err), chk) + return program + } + + test(` + abc + -- + [] + `, "(anonymous): Line 3:13 Invalid left-hand side in assignment") + + test(` + abc-- + [] + `, nil) + + test("1\n[]\n", "(anonymous): Line 2:2 Unexpected token ]") + + test(` + function abc() { + } + abc() + `, nil) + + program := test("", nil) + + test("//", nil) + + test("/* */", nil) + + test("/** **/", nil) + + test("/*****/", nil) + + test("/*", "(anonymous): Line 1:3 Unexpected end of input") + + test("#", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("/**/#", "(anonymous): Line 1:5 Unexpected token ILLEGAL") + + test("new +", "(anonymous): Line 1:5 Unexpected token +") + + program = test(";", nil) + is(len(program.Body), 1) + is(program.Body[0].(*ast.EmptyStatement).Semicolon, file.Idx(1)) + + program = test(";;", nil) + is(len(program.Body), 2) + is(program.Body[0].(*ast.EmptyStatement).Semicolon, file.Idx(1)) + is(program.Body[1].(*ast.EmptyStatement).Semicolon, file.Idx(2)) + + program = test("1.2", nil) + is(len(program.Body), 1) + is(program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.NumberLiteral).Literal, "1.2") + + program = test("/* */1.2", nil) + is(len(program.Body), 1) + is(program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.NumberLiteral).Literal, "1.2") + + program = test("\n", nil) + is(len(program.Body), 0) + + test(` + if (0) { + abc = 0 + } + else abc = 0 + `, nil) + + test("if (0) abc = 0 else abc = 0", "(anonymous): Line 1:16 Unexpected token else") + + test(` + if (0) { + abc = 0 + } else abc = 0 + `, nil) + + test(` + if (0) { + abc = 1 + } else { + } + `, nil) + + test(` + do { + } while (true) + `, nil) + + test(` + try { + } finally { + } + `, nil) + + test(` + try { + } catch (abc) { + } finally { + } + `, nil) + + test(` + try { + } + catch (abc) { + } + finally { + } + `, nil) + + test(`try {} catch (abc) {} finally {}`, nil) + + test(` + do { + do { + } while (0) + } while (0) + `, nil) + + test(` + (function(){ + try { + if ( + 1 + ) { + return 1 + } + return 0 + } finally { + } + })() + `, nil) + + test("abc = ''\ndef", nil) + + test("abc = 1\ndef", nil) + + test("abc = Math\ndef", nil) + + test(`"\'"`, nil) + + test(` + abc = function(){ + } + abc = 0 + `, nil) + + test("abc.null = 0", nil) + + test("0x41", nil) + + test(`"\d"`, nil) + + test(`(function(){return this})`, nil) + + test(` + Object.defineProperty(Array.prototype, "0", { + value: 100, + writable: false, + configurable: true + }); + abc = [101]; + abc.hasOwnProperty("0") && abc[0] === 101; + `, nil) + + test(`new abc()`, nil) + test(`new {}`, nil) + + test(` + limit = 4 + result = 0 + while (limit) { + limit = limit - 1 + if (limit) { + } + else { + break + } + result = result + 1 + } + `, nil) + + test(` + while (0) { + if (0) { + continue + } + } + `, nil) + + test("var \u0061\u0062\u0063 = 0", nil) + + // 7_3_1 + test("var test7_3_1\nabc = 66;", nil) + test("var test7_3_1\u2028abc = 66;", nil) + + // 7_3_3 + test("//\u2028 =;", "(anonymous): Line 2:2 Unexpected token =") + + // 7_3_10 + test("var abc = \u2029;", "(anonymous): Line 2:1 Unexpected token ;") + test("var abc = \\u2029;", "(anonymous): Line 1:11 Unexpected token ILLEGAL") + test("var \\u0061\\u0062\\u0063 = 0;", nil) + + test("'", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + test("'\nstr\ning\n'", "(anonymous): Line 1:1 Unexpected token ILLEGAL") + + // S7.6_A4.3_T1 + test(`var $\u0030 = 0;`, nil) + + // S7.6.1.1_A1.1 + test(`switch = 1`, "(anonymous): Line 1:8 Unexpected token =") + + // S7.8.3_A2.1_T1 + test(`.0 === 0.0`, nil) + + // 7.8.5-1 + test("var regExp = /\\\rn/;", "(anonymous): Line 1:14 Invalid regular expression: missing /") + + // S7.8.5_A1.1_T2 + test("var regExp = /=/;", nil) + + // S7.8.5_A1.2_T1 + test("/*/", "(anonymous): Line 1:4 Unexpected end of input") + + // Sbp_7.9_A9_T3 + test(` + do { + ; + } while (false) true + `, nil) + + // S7.9_A10_T10 + test(` + {a:1 + } 3 + `, nil) + + test(` + abc + ++def + `, nil) + + // S7.9_A5.2_T1 + test(` + for(false;false + ) { + break; + } + `, "(anonymous): Line 3:13 Unexpected token )") + + // S7.9_A9_T8 + test(` + do {}; + while (false) + `, "(anonymous): Line 2:18 Unexpected token ;") + + // S8.4_A5 + test(` + "x\0y" + `, nil) + + // S9.3.1_A6_T1 + test(` + 10e10000 + `, nil) + + // 10.4.2-1-5 + test(` + "abc\ + def" + `, nil) + + test("'\\\n'", nil) + + test("'\\\r\n'", nil) + + //// 11.13.1-1-1 + test("42 = 42;", "(anonymous): Line 1:1 Invalid left-hand side in assignment") + + // S11.13.2_A4.2_T1.3 + test(` + abc /= "1" + `, nil) + + // 12.1-1 + test(` + try{};catch(){} + `, "(anonymous): Line 2:13 Missing catch or finally after try") + + // 12.1-3 + test(` + try{};finally{} + `, "(anonymous): Line 2:13 Missing catch or finally after try") + + // S12.6.3_A11.1_T3 + test(` + while (true) { + break abc; + } + `, "(anonymous): Line 3:17 Undefined label 'abc'") + + // S15.3_A2_T1 + test(`var x / = 1;`, "(anonymous): Line 1:7 Unexpected token /") + + test(` + function abc() { + if (0) + return; + else { + } + } + `, nil) + + test("//\u2028 var =;", "(anonymous): Line 2:6 Unexpected token =") + + test(` + throw + {} + `, "(anonymous): Line 2:13 Illegal newline after throw") + + // S7.6.1.1_A1.11 + test(` + function = 1 + `, "(anonymous): Line 2:22 Unexpected token =") + + // S7.8.3_A1.2_T1 + test(`0e1`, nil) + + test("abc = 1; abc\n++", "(anonymous): Line 2:3 Unexpected end of input") + + // --- + + test("({ get abc() {} })", nil) + + test(`for (abc.def in {}) {}`, nil) + + test(`while (true) { break }`, nil) + + test(`while (true) { continue }`, nil) + + test(`abc=/^(?:(\w+:)\/{2}(\w+(?:\.\w+)*\/?)|(.{0,2}\/{1}))?([/.]*?(?:[^?]+)?\/)?((?:[^/?]+)\.(\w+))(?:\?(\S+)?)?$/,def=/^(?:(\w+:)\/{2})|(.{0,2}\/{1})?([/.]*?(?:[^?]+)?\/?)?$/`, nil) + + test(`(function() { try {} catch (err) {} finally {} return })`, nil) + + test(`0xde0b6b3a7640080.toFixed(0)`, nil) + + test(`/[^-._0-9A-Za-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u37f-\u1fff\u200c-\u200d\u203f\u2040\u2070-\u218f]/`, nil) + + test(`/[\u0000-\u0008\u000B-\u000C\u000E-\u001F\uD800-\uDFFF\uFFFE-\uFFFF]/`, nil) + + test("var abc = 1;\ufeff", nil) + + test("\ufeff/* var abc = 1; */", nil) + + test(`if (-0x8000000000000000<=abc&&abc<=0x8000000000000000) {}`, nil) + + test(`(function(){debugger;return this;})`, nil) + + test(` + + `, nil) + + test(` + var abc = "" + debugger + `, nil) + + test(` + var abc = /\[\]$/ + debugger + `, nil) + + test(` + var abc = 1 / + 2 + debugger + `, nil) + }) +} + +func Test_parseStringLiteral(t *testing.T) { + tt(t, func() { + test := func(have, want string) { + have, err := parseStringLiteral(have) + is(err, nil) + is(have, want) + } + + test("", "") + + test("1(\\\\d+)", "1(\\d+)") + + test("\\u2029", "\u2029") + + test("abc\\uFFFFabc", "abc\uFFFFabc") + + test("[First line \\\nSecond line \\\n Third line\\\n. ]", + "[First line Second line Third line. ]") + + test("\\u007a\\x79\\u000a\\x78", "zy\nx") + + // S7.8.4_A4.2_T3 + test("\\a", "a") + test("\u0410", "\u0410") + + // S7.8.4_A5.1_T1 + test("\\0", "\u0000") + + // S8.4_A5 + test("\u0000", "\u0000") + + // 15.5.4.20 + test("'abc'\\\n'def'", "'abc''def'") + + // 15.5.4.20-4-1 + test("'abc'\\\r\n'def'", "'abc''def'") + + // Octal + test("\\0", "\000") + test("\\00", "\000") + test("\\000", "\000") + test("\\09", "\0009") + test("\\009", "\0009") + test("\\0009", "\0009") + test("\\1", "\001") + test("\\01", "\001") + test("\\001", "\001") + test("\\0011", "\0011") + test("\\1abc", "\001abc") + + test("\\\u4e16", "\u4e16") + + // err + test = func(have, want string) { + have, err := parseStringLiteral(have) + is(err.Error(), want) + is(have, "") + } + + test(`\u`, `invalid escape: \u: len("") != 4`) + test(`\u0`, `invalid escape: \u: len("0") != 4`) + test(`\u00`, `invalid escape: \u: len("00") != 4`) + test(`\u000`, `invalid escape: \u: len("000") != 4`) + + test(`\x`, `invalid escape: \x: len("") != 2`) + test(`\x0`, `invalid escape: \x: len("0") != 2`) + test(`\x0`, `invalid escape: \x: len("0") != 2`) + }) +} + +func Test_parseNumberLiteral(t *testing.T) { + tt(t, func() { + test := func(input string, expect interface{}) { + result, err := parseNumberLiteral(input) + is(err, nil) + is(result, expect) + } + + test("0", 0) + + test("0x8000000000000000", float64(9.223372036854776e+18)) + }) +} + +func TestPosition(t *testing.T) { + tt(t, func() { + parser := newParser("", "// Lorem ipsum") + + // Out of range, idx0 (error condition) + is(parser.slice(0, 1), "") + is(parser.slice(0, 10), "") + + // Out of range, idx1 (error condition) + is(parser.slice(1, 128), "") + + is(parser.str[0:0], "") + is(parser.slice(1, 1), "") + + is(parser.str[0:1], "/") + is(parser.slice(1, 2), "/") + + is(parser.str[0:14], "// Lorem ipsum") + is(parser.slice(1, 15), "// Lorem ipsum") + + parser = newParser("", "(function(){ return 0; })") + program, err := parser.parse() + is(err, nil) + + var node ast.Node + node = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral) + is(node.Idx0(), file.Idx(2)) + is(node.Idx1(), file.Idx(25)) + is(parser.slice(node.Idx0(), node.Idx1()), "function(){ return 0; }") + is(parser.slice(node.Idx0(), node.Idx1()+1), "function(){ return 0; })") + is(parser.slice(node.Idx0(), node.Idx1()+2), "") + is(node.(*ast.FunctionLiteral).Source, "function(){ return 0; }") + + node = program + is(node.Idx0(), file.Idx(2)) + is(node.Idx1(), file.Idx(25)) + is(parser.slice(node.Idx0(), node.Idx1()), "function(){ return 0; }") + + parser = newParser("", "(function(){ return abc; })") + program, err = parser.parse() + is(err, nil) + node = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral) + is(node.(*ast.FunctionLiteral).Source, "function(){ return abc; }") + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/regexp.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/regexp.go new file mode 100644 index 0000000000..f614dae745 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/regexp.go @@ -0,0 +1,358 @@ +package parser + +import ( + "bytes" + "fmt" + "strconv" +) + +type _RegExp_parser struct { + str string + length int + + chr rune // The current character + chrOffset int // The offset of current character + offset int // The offset after current character (may be greater than 1) + + errors []error + invalid bool // The input is an invalid JavaScript RegExp + + goRegexp *bytes.Buffer +} + +// TransformRegExp transforms a JavaScript pattern into a Go "regexp" pattern. +// +// re2 (Go) cannot do backtracking, so the presence of a lookahead (?=) (?!) or +// backreference (\1, \2, ...) will cause an error. +// +// re2 (Go) has a different definition for \s: [\t\n\f\r ]. +// The JavaScript definition, on the other hand, also includes \v, Unicode "Separator, Space", etc. +// +// If the pattern is invalid (not valid even in JavaScript), then this function +// returns the empty string and an error. +// +// If the pattern is valid, but incompatible (contains a lookahead or backreference), +// then this function returns the transformation (a non-empty string) AND an error. +func TransformRegExp(pattern string) (string, error) { + + if pattern == "" { + return "", nil + } + + // TODO If without \, if without (?=, (?!, then another shortcut + + parser := _RegExp_parser{ + str: pattern, + length: len(pattern), + goRegexp: bytes.NewBuffer(make([]byte, 0, 3*len(pattern)/2)), + } + parser.read() // Pull in the first character + parser.scan() + var err error + if len(parser.errors) > 0 { + err = parser.errors[0] + } + if parser.invalid { + return "", err + } + + // Might not be re2 compatible, but is still a valid JavaScript RegExp + return parser.goRegexp.String(), err +} + +func (self *_RegExp_parser) scan() { + for self.chr != -1 { + switch self.chr { + case '\\': + self.read() + self.scanEscape(false) + case '(': + self.pass() + self.scanGroup() + case '[': + self.pass() + self.scanBracket() + case ')': + self.error(-1, "Unmatched ')'") + self.invalid = true + self.pass() + default: + self.pass() + } + } +} + +// (...) +func (self *_RegExp_parser) scanGroup() { + str := self.str[self.chrOffset:] + if len(str) > 1 { // A possibility of (?= or (?! + if str[0] == '?' { + if str[1] == '=' || str[1] == '!' { + self.error(-1, "re2: Invalid (%s) ", self.str[self.chrOffset:self.chrOffset+2]) + } + } + } + for self.chr != -1 && self.chr != ')' { + switch self.chr { + case '\\': + self.read() + self.scanEscape(false) + case '(': + self.pass() + self.scanGroup() + case '[': + self.pass() + self.scanBracket() + default: + self.pass() + continue + } + } + if self.chr != ')' { + self.error(-1, "Unterminated group") + self.invalid = true + return + } + self.pass() +} + +// [...] +func (self *_RegExp_parser) scanBracket() { + for self.chr != -1 { + if self.chr == ']' { + break + } else if self.chr == '\\' { + self.read() + self.scanEscape(true) + continue + } + self.pass() + } + if self.chr != ']' { + self.error(-1, "Unterminated character class") + self.invalid = true + return + } + self.pass() +} + +// \... +func (self *_RegExp_parser) scanEscape(inClass bool) { + offset := self.chrOffset + + var length, base uint32 + switch self.chr { + + case '0', '1', '2', '3', '4', '5', '6', '7': + var value int64 + size := 0 + for { + digit := int64(digitValue(self.chr)) + if digit >= 8 { + // Not a valid digit + break + } + value = value*8 + digit + self.read() + size += 1 + } + if size == 1 { // The number of characters read + _, err := self.goRegexp.Write([]byte{'\\', byte(value) + '0'}) + if err != nil { + self.errors = append(self.errors, err) + } + if value != 0 { + // An invalid backreference + self.error(-1, "re2: Invalid \\%d ", value) + } + return + } + tmp := []byte{'\\', 'x', '0', 0} + if value >= 16 { + tmp = tmp[0:2] + } else { + tmp = tmp[0:3] + } + tmp = strconv.AppendInt(tmp, value, 16) + _, err := self.goRegexp.Write(tmp) + if err != nil { + self.errors = append(self.errors, err) + } + return + + case '8', '9': + size := 0 + for { + digit := digitValue(self.chr) + if digit >= 10 { + // Not a valid digit + break + } + self.read() + size += 1 + } + err := self.goRegexp.WriteByte('\\') + if err != nil { + self.errors = append(self.errors, err) + } + _, err = self.goRegexp.WriteString(self.str[offset:self.chrOffset]) + if err != nil { + self.errors = append(self.errors, err) + } + self.error(-1, "re2: Invalid \\%s ", self.str[offset:self.chrOffset]) + return + + case 'x': + self.read() + length, base = 2, 16 + + case 'u': + self.read() + length, base = 4, 16 + + case 'b': + if inClass { + _, err := self.goRegexp.Write([]byte{'\\', 'x', '0', '8'}) + if err != nil { + self.errors = append(self.errors, err) + } + self.read() + return + } + fallthrough + + case 'B': + fallthrough + + case 'd', 'D', 's', 'S', 'w', 'W': + // This is slightly broken, because ECMAScript + // includes \v in \s, \S, while re2 does not + fallthrough + + case '\\': + fallthrough + + case 'f', 'n', 'r', 't', 'v': + err := self.goRegexp.WriteByte('\\') + if err != nil { + self.errors = append(self.errors, err) + } + self.pass() + return + + case 'c': + self.read() + var value int64 + if 'a' <= self.chr && self.chr <= 'z' { + value = int64(self.chr) - 'a' + 1 + } else if 'A' <= self.chr && self.chr <= 'Z' { + value = int64(self.chr) - 'A' + 1 + } else { + err := self.goRegexp.WriteByte('c') + if err != nil { + self.errors = append(self.errors, err) + } + return + } + tmp := []byte{'\\', 'x', '0', 0} + if value >= 16 { + tmp = tmp[0:2] + } else { + tmp = tmp[0:3] + } + tmp = strconv.AppendInt(tmp, value, 16) + _, err := self.goRegexp.Write(tmp) + if err != nil { + self.errors = append(self.errors, err) + } + self.read() + return + + default: + // $ is an identifier character, so we have to have + // a special case for it here + if self.chr == '$' || !isIdentifierPart(self.chr) { + // A non-identifier character needs escaping + err := self.goRegexp.WriteByte('\\') + if err != nil { + self.errors = append(self.errors, err) + } + } else { + // Unescape the character for re2 + } + self.pass() + return + } + + // Otherwise, we're a \u.... or \x... + valueOffset := self.chrOffset + + var value uint32 + { + length := length + for ; length > 0; length-- { + digit := uint32(digitValue(self.chr)) + if digit >= base { + // Not a valid digit + goto skip + } + value = value*base + digit + self.read() + } + } + + if length == 4 { + _, err := self.goRegexp.Write([]byte{ + '\\', + 'x', + '{', + self.str[valueOffset+0], + self.str[valueOffset+1], + self.str[valueOffset+2], + self.str[valueOffset+3], + '}', + }) + if err != nil { + self.errors = append(self.errors, err) + } + } else if length == 2 { + _, err := self.goRegexp.Write([]byte{ + '\\', + 'x', + self.str[valueOffset+0], + self.str[valueOffset+1], + }) + if err != nil { + self.errors = append(self.errors, err) + } + } else { + // Should never, ever get here... + self.error(-1, "re2: Illegal branch in scanEscape") + goto skip + } + + return + +skip: + _, err := self.goRegexp.WriteString(self.str[offset:self.chrOffset]) + if err != nil { + self.errors = append(self.errors, err) + } +} + +func (self *_RegExp_parser) pass() { + if self.chr != -1 { + _, err := self.goRegexp.WriteRune(self.chr) + if err != nil { + self.errors = append(self.errors, err) + } + } + self.read() +} + +// TODO Better error reporting, use the offset, etc. +func (self *_RegExp_parser) error(offset int, msg string, msgValues ...interface{}) error { + err := fmt.Errorf(msg, msgValues...) + self.errors = append(self.errors, err) + return err +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/regexp_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/regexp_test.go new file mode 100644 index 0000000000..3222db1a7b --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/regexp_test.go @@ -0,0 +1,149 @@ +package parser + +import ( + "regexp" + "testing" +) + +func TestRegExp(t *testing.T) { + tt(t, func() { + { + // err + test := func(input string, expect interface{}) { + _, err := TransformRegExp(input) + is(err, expect) + } + + test("[", "Unterminated character class") + + test("(", "Unterminated group") + + test("(?=)", "re2: Invalid (?=) ") + + test("(?=)", "re2: Invalid (?=) ") + + test("(?!)", "re2: Invalid (?!) ") + + // An error anyway + test("(?=", "re2: Invalid (?=) ") + + test("\\1", "re2: Invalid \\1 ") + + test("\\90", "re2: Invalid \\90 ") + + test("\\9123456789", "re2: Invalid \\9123456789 ") + + test("\\(?=)", "Unmatched ')'") + + test(")", "Unmatched ')'") + } + + { + // err + test := func(input, expect string, expectErr interface{}) { + output, err := TransformRegExp(input) + is(output, expect) + is(err, expectErr) + } + + test("(?!)", "(?!)", "re2: Invalid (?!) ") + + test(")", "", "Unmatched ')'") + + test("(?!))", "", "re2: Invalid (?!) ") + + test("\\0", "\\0", nil) + + test("\\1", "\\1", "re2: Invalid \\1 ") + + test("\\9123456789", "\\9123456789", "re2: Invalid \\9123456789 ") + } + + { + // err + test := func(input string, expect string) { + result, err := TransformRegExp(input) + is(err, nil) + if is(result, expect) { + _, err := regexp.Compile(result) + if !is(err, nil) { + t.Log(result) + } + } + } + + test("", "") + + test("abc", "abc") + + test(`\abc`, `abc`) + + test(`\a\b\c`, `a\bc`) + + test(`\x`, `x`) + + test(`\c`, `c`) + + test(`\cA`, `\x01`) + + test(`\cz`, `\x1a`) + + test(`\ca`, `\x01`) + + test(`\cj`, `\x0a`) + + test(`\ck`, `\x0b`) + + test(`\+`, `\+`) + + test(`[\b]`, `[\x08]`) + + test(`\u0z01\x\undefined`, `u0z01xundefined`) + + test(`\\|'|\r|\n|\t|\u2028|\u2029`, `\\|'|\r|\n|\t|\x{2028}|\x{2029}`) + + test("]", "]") + + test("}", "}") + + test("%", "%") + + test("(%)", "(%)") + + test("(?:[%\\s])", "(?:[%\\s])") + + test("[[]", "[[]") + + test("\\101", "\\x41") + + test("\\51", "\\x29") + + test("\\051", "\\x29") + + test("\\175", "\\x7d") + + test("\\04", "\\x04") + + test(`<%([\s\S]+?)%>`, `<%([\s\S]+?)%>`) + + test(`(.)^`, "(.)^") + + test(`<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|<%([\s\S]+?)%>|$`, `<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|<%([\s\S]+?)%>|$`) + + test(`\$`, `\$`) + + test(`[G-b]`, `[G-b]`) + + test(`[G-b\0]`, `[G-b\0]`) + } + }) +} + +func TestTransformRegExp(t *testing.T) { + tt(t, func() { + pattern, err := TransformRegExp(`\s+abc\s+`) + is(err, nil) + is(pattern, `\s+abc\s+`) + is(regexp.MustCompile(pattern).MatchString("\t abc def"), true) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/scope.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/scope.go new file mode 100644 index 0000000000..e1dbdda132 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/scope.go @@ -0,0 +1,44 @@ +package parser + +import ( + "github.com/robertkrimen/otto/ast" +) + +type _scope struct { + outer *_scope + allowIn bool + inIteration bool + inSwitch bool + inFunction bool + declarationList []ast.Declaration + + labels []string +} + +func (self *_parser) openScope() { + self.scope = &_scope{ + outer: self.scope, + allowIn: true, + } +} + +func (self *_parser) closeScope() { + self.scope = self.scope.outer +} + +func (self *_scope) declare(declaration ast.Declaration) { + self.declarationList = append(self.declarationList, declaration) +} + +func (self *_scope) hasLabel(name string) bool { + for _, label := range self.labels { + if label == name { + return true + } + } + if self.outer != nil && !self.inFunction { + // Crossing a function boundary to look for a label is verboten + return self.outer.hasLabel(name) + } + return false +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/statement.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/statement.go new file mode 100644 index 0000000000..2059d38563 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/statement.go @@ -0,0 +1,663 @@ +package parser + +import ( + "github.com/robertkrimen/otto/ast" + "github.com/robertkrimen/otto/token" +) + +func (self *_parser) parseBlockStatement() *ast.BlockStatement { + node := &ast.BlockStatement{} + node.LeftBrace = self.expect(token.LEFT_BRACE) + node.List = self.parseStatementList() + node.RightBrace = self.expect(token.RIGHT_BRACE) + + return node +} + +func (self *_parser) parseEmptyStatement() ast.Statement { + idx := self.expect(token.SEMICOLON) + return &ast.EmptyStatement{Semicolon: idx} +} + +func (self *_parser) parseStatementList() (list []ast.Statement) { + for self.token != token.RIGHT_BRACE && self.token != token.EOF { + list = append(list, self.parseStatement()) + } + + return +} + +func (self *_parser) parseStatement() ast.Statement { + + if self.token == token.EOF { + self.errorUnexpectedToken(self.token) + return &ast.BadStatement{From: self.idx, To: self.idx + 1} + } + + switch self.token { + case token.SEMICOLON: + return self.parseEmptyStatement() + case token.LEFT_BRACE: + return self.parseBlockStatement() + case token.IF: + return self.parseIfStatement() + case token.DO: + return self.parseDoWhileStatement() + case token.WHILE: + return self.parseWhileStatement() + case token.FOR: + return self.parseForOrForInStatement() + case token.BREAK: + return self.parseBreakStatement() + case token.CONTINUE: + return self.parseContinueStatement() + case token.DEBUGGER: + return self.parseDebuggerStatement() + case token.WITH: + return self.parseWithStatement() + case token.VAR: + return self.parseVariableStatement() + case token.FUNCTION: + self.parseFunction(true) + // FIXME + return &ast.EmptyStatement{} + case token.SWITCH: + return self.parseSwitchStatement() + case token.RETURN: + return self.parseReturnStatement() + case token.THROW: + return self.parseThrowStatement() + case token.TRY: + return self.parseTryStatement() + } + + expression := self.parseExpression() + + if identifier, isIdentifier := expression.(*ast.Identifier); isIdentifier && self.token == token.COLON { + // LabelledStatement + colon := self.idx + self.next() // : + label := identifier.Name + for _, value := range self.scope.labels { + if label == value { + self.error(identifier.Idx0(), "Label '%s' already exists", label) + } + } + self.scope.labels = append(self.scope.labels, label) // Push the label + statement := self.parseStatement() + self.scope.labels = self.scope.labels[:len(self.scope.labels)-1] // Pop the label + return &ast.LabelledStatement{ + Label: identifier, + Colon: colon, + Statement: statement, + } + } + + self.optionalSemicolon() + + return &ast.ExpressionStatement{ + Expression: expression, + } +} + +func (self *_parser) parseTryStatement() ast.Statement { + + node := &ast.TryStatement{ + Try: self.expect(token.TRY), + Body: self.parseBlockStatement(), + } + + if self.token == token.CATCH { + catch := self.idx + self.next() + self.expect(token.LEFT_PARENTHESIS) + if self.token != token.IDENTIFIER { + self.expect(token.IDENTIFIER) + self.nextStatement() + return &ast.BadStatement{From: catch, To: self.idx} + } else { + identifier := self.parseIdentifier() + self.expect(token.RIGHT_PARENTHESIS) + node.Catch = &ast.CatchStatement{ + Catch: catch, + Parameter: identifier, + Body: self.parseBlockStatement(), + } + } + } + + if self.token == token.FINALLY { + self.next() + node.Finally = self.parseBlockStatement() + } + + if node.Catch == nil && node.Finally == nil { + self.error(node.Try, "Missing catch or finally after try") + return &ast.BadStatement{From: node.Try, To: node.Body.Idx1()} + } + + return node +} + +func (self *_parser) parseFunctionParameterList() *ast.ParameterList { + opening := self.expect(token.LEFT_PARENTHESIS) + var list []*ast.Identifier + for self.token != token.RIGHT_PARENTHESIS && self.token != token.EOF { + if self.token != token.IDENTIFIER { + self.expect(token.IDENTIFIER) + } else { + list = append(list, self.parseIdentifier()) + } + if self.token != token.RIGHT_PARENTHESIS { + self.expect(token.COMMA) + } + } + closing := self.expect(token.RIGHT_PARENTHESIS) + + return &ast.ParameterList{ + Opening: opening, + List: list, + Closing: closing, + } +} + +func (self *_parser) parseParameterList() (list []string) { + for self.token != token.EOF { + if self.token != token.IDENTIFIER { + self.expect(token.IDENTIFIER) + } + list = append(list, self.literal) + self.next() + if self.token != token.EOF { + self.expect(token.COMMA) + } + } + return +} + +func (self *_parser) parseFunction(declaration bool) *ast.FunctionLiteral { + + node := &ast.FunctionLiteral{ + Function: self.expect(token.FUNCTION), + } + + var name *ast.Identifier + if self.token == token.IDENTIFIER { + name = self.parseIdentifier() + if declaration { + self.scope.declare(&ast.FunctionDeclaration{ + Function: node, + }) + } + } else if declaration { + // Use expect error handling + self.expect(token.IDENTIFIER) + } + node.Name = name + node.ParameterList = self.parseFunctionParameterList() + self.parseFunctionBlock(node) + node.Source = self.slice(node.Idx0(), node.Idx1()) + + return node +} + +func (self *_parser) parseFunctionBlock(node *ast.FunctionLiteral) { + { + self.openScope() + inFunction := self.scope.inFunction + self.scope.inFunction = true + defer func() { + self.scope.inFunction = inFunction + self.closeScope() + }() + node.Body = self.parseBlockStatement() + node.DeclarationList = self.scope.declarationList + } +} + +func (self *_parser) parseDebuggerStatement() ast.Statement { + idx := self.expect(token.DEBUGGER) + + node := &ast.DebuggerStatement{ + Debugger: idx, + } + + self.semicolon() + + return node +} + +func (self *_parser) parseReturnStatement() ast.Statement { + idx := self.expect(token.RETURN) + + if !self.scope.inFunction { + self.error(idx, "Illegal return statement") + self.nextStatement() + return &ast.BadStatement{From: idx, To: self.idx} + } + + node := &ast.ReturnStatement{ + Return: idx, + } + + if !self.implicitSemicolon && self.token != token.SEMICOLON && self.token != token.RIGHT_BRACE && self.token != token.EOF { + node.Argument = self.parseExpression() + } + + self.semicolon() + + return node +} + +func (self *_parser) parseThrowStatement() ast.Statement { + idx := self.expect(token.THROW) + + if self.implicitSemicolon { + if self.chr == -1 { // Hackish + self.error(idx, "Unexpected end of input") + } else { + self.error(idx, "Illegal newline after throw") + } + self.nextStatement() + return &ast.BadStatement{From: idx, To: self.idx} + } + + node := &ast.ThrowStatement{ + Argument: self.parseExpression(), + } + + self.semicolon() + + return node +} + +func (self *_parser) parseSwitchStatement() ast.Statement { + self.expect(token.SWITCH) + self.expect(token.LEFT_PARENTHESIS) + node := &ast.SwitchStatement{ + Discriminant: self.parseExpression(), + Default: -1, + } + self.expect(token.RIGHT_PARENTHESIS) + + self.expect(token.LEFT_BRACE) + + inSwitch := self.scope.inSwitch + self.scope.inSwitch = true + defer func() { + self.scope.inSwitch = inSwitch + }() + + for index := 0; self.token != token.EOF; index++ { + if self.token == token.RIGHT_BRACE { + self.next() + break + } + + clause := self.parseCaseStatement() + if clause.Test == nil { + if node.Default != -1 { + self.error(clause.Case, "Already saw a default in switch") + } + node.Default = index + } + node.Body = append(node.Body, clause) + } + + return node +} + +func (self *_parser) parseWithStatement() ast.Statement { + self.expect(token.WITH) + self.expect(token.LEFT_PARENTHESIS) + node := &ast.WithStatement{ + Object: self.parseExpression(), + } + self.expect(token.RIGHT_PARENTHESIS) + + node.Body = self.parseStatement() + + return node +} + +func (self *_parser) parseCaseStatement() *ast.CaseStatement { + + node := &ast.CaseStatement{ + Case: self.idx, + } + if self.token == token.DEFAULT { + self.next() + } else { + self.expect(token.CASE) + node.Test = self.parseExpression() + } + self.expect(token.COLON) + + for { + if self.token == token.EOF || + self.token == token.RIGHT_BRACE || + self.token == token.CASE || + self.token == token.DEFAULT { + break + } + node.Consequent = append(node.Consequent, self.parseStatement()) + + } + + return node +} + +func (self *_parser) parseIterationStatement() ast.Statement { + inIteration := self.scope.inIteration + self.scope.inIteration = true + defer func() { + self.scope.inIteration = inIteration + }() + return self.parseStatement() +} + +func (self *_parser) parseForIn(into ast.Expression) *ast.ForInStatement { + + // Already have consumed " in" + + source := self.parseExpression() + self.expect(token.RIGHT_PARENTHESIS) + + return &ast.ForInStatement{ + Into: into, + Source: source, + Body: self.parseIterationStatement(), + } +} + +func (self *_parser) parseFor(initializer ast.Expression) *ast.ForStatement { + + // Already have consumed " ;" + + var test, update ast.Expression + + if self.token != token.SEMICOLON { + test = self.parseExpression() + } + self.expect(token.SEMICOLON) + + if self.token != token.RIGHT_PARENTHESIS { + update = self.parseExpression() + } + self.expect(token.RIGHT_PARENTHESIS) + + return &ast.ForStatement{ + Initializer: initializer, + Test: test, + Update: update, + Body: self.parseIterationStatement(), + } +} + +func (self *_parser) parseForOrForInStatement() ast.Statement { + idx := self.expect(token.FOR) + self.expect(token.LEFT_PARENTHESIS) + + var left []ast.Expression + + forIn := false + if self.token != token.SEMICOLON { + + allowIn := self.scope.allowIn + self.scope.allowIn = false + if self.token == token.VAR { + var_ := self.idx + self.next() + list := self.parseVariableDeclarationList(var_) + if len(list) == 1 && self.token == token.IN { + self.next() // in + forIn = true + left = []ast.Expression{list[0]} // There is only one declaration + } else { + left = list + } + } else { + left = append(left, self.parseExpression()) + if self.token == token.IN { + self.next() + forIn = true + } + } + self.scope.allowIn = allowIn + } + + if forIn { + switch left[0].(type) { + case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression, *ast.VariableExpression: + // These are all acceptable + default: + self.error(idx, "Invalid left-hand side in for-in") + self.nextStatement() + return &ast.BadStatement{From: idx, To: self.idx} + } + return self.parseForIn(left[0]) + } + + self.expect(token.SEMICOLON) + return self.parseFor(&ast.SequenceExpression{Sequence: left}) +} + +func (self *_parser) parseVariableStatement() *ast.VariableStatement { + + idx := self.expect(token.VAR) + + list := self.parseVariableDeclarationList(idx) + self.semicolon() + + return &ast.VariableStatement{ + Var: idx, + List: list, + } +} + +func (self *_parser) parseDoWhileStatement() ast.Statement { + inIteration := self.scope.inIteration + self.scope.inIteration = true + defer func() { + self.scope.inIteration = inIteration + }() + + self.expect(token.DO) + node := &ast.DoWhileStatement{} + if self.token == token.LEFT_BRACE { + node.Body = self.parseBlockStatement() + } else { + node.Body = self.parseStatement() + } + + self.expect(token.WHILE) + self.expect(token.LEFT_PARENTHESIS) + node.Test = self.parseExpression() + self.expect(token.RIGHT_PARENTHESIS) + + return node +} + +func (self *_parser) parseWhileStatement() ast.Statement { + self.expect(token.WHILE) + self.expect(token.LEFT_PARENTHESIS) + node := &ast.WhileStatement{ + Test: self.parseExpression(), + } + self.expect(token.RIGHT_PARENTHESIS) + node.Body = self.parseIterationStatement() + + return node +} + +func (self *_parser) parseIfStatement() ast.Statement { + self.expect(token.IF) + self.expect(token.LEFT_PARENTHESIS) + node := &ast.IfStatement{ + Test: self.parseExpression(), + } + self.expect(token.RIGHT_PARENTHESIS) + + if self.token == token.LEFT_BRACE { + node.Consequent = self.parseBlockStatement() + } else { + node.Consequent = self.parseStatement() + } + + if self.token == token.ELSE { + self.next() + node.Alternate = self.parseStatement() + } + + return node +} + +func (self *_parser) parseSourceElement() ast.Statement { + return self.parseStatement() +} + +func (self *_parser) parseSourceElements() []ast.Statement { + body := []ast.Statement(nil) + + for { + if self.token != token.STRING { + break + } + + body = append(body, self.parseSourceElement()) + } + + for self.token != token.EOF { + body = append(body, self.parseSourceElement()) + } + + return body +} + +func (self *_parser) parseProgram() *ast.Program { + self.openScope() + defer self.closeScope() + return &ast.Program{ + Body: self.parseSourceElements(), + DeclarationList: self.scope.declarationList, + File: self.file, + } +} + +func (self *_parser) parseBreakStatement() ast.Statement { + idx := self.expect(token.BREAK) + semicolon := self.implicitSemicolon + if self.token == token.SEMICOLON { + semicolon = true + self.next() + } + + if semicolon || self.token == token.RIGHT_BRACE { + self.implicitSemicolon = false + if !self.scope.inIteration && !self.scope.inSwitch { + goto illegal + } + return &ast.BranchStatement{ + Idx: idx, + Token: token.BREAK, + } + } + + if self.token == token.IDENTIFIER { + identifier := self.parseIdentifier() + if !self.scope.hasLabel(identifier.Name) { + self.error(idx, "Undefined label '%s'", identifier.Name) + return &ast.BadStatement{From: idx, To: identifier.Idx1()} + } + self.semicolon() + return &ast.BranchStatement{ + Idx: idx, + Token: token.BREAK, + Label: identifier, + } + } + + self.expect(token.IDENTIFIER) + +illegal: + self.error(idx, "Illegal break statement") + self.nextStatement() + return &ast.BadStatement{From: idx, To: self.idx} +} + +func (self *_parser) parseContinueStatement() ast.Statement { + idx := self.expect(token.CONTINUE) + semicolon := self.implicitSemicolon + if self.token == token.SEMICOLON { + semicolon = true + self.next() + } + + if semicolon || self.token == token.RIGHT_BRACE { + self.implicitSemicolon = false + if !self.scope.inIteration { + goto illegal + } + return &ast.BranchStatement{ + Idx: idx, + Token: token.CONTINUE, + } + } + + if self.token == token.IDENTIFIER { + identifier := self.parseIdentifier() + if !self.scope.hasLabel(identifier.Name) { + self.error(idx, "Undefined label '%s'", identifier.Name) + return &ast.BadStatement{From: idx, To: identifier.Idx1()} + } + if !self.scope.inIteration { + goto illegal + } + self.semicolon() + return &ast.BranchStatement{ + Idx: idx, + Token: token.CONTINUE, + Label: identifier, + } + } + + self.expect(token.IDENTIFIER) + +illegal: + self.error(idx, "Illegal continue statement") + self.nextStatement() + return &ast.BadStatement{From: idx, To: self.idx} +} + +// Find the next statement after an error (recover) +func (self *_parser) nextStatement() { + for { + switch self.token { + case token.BREAK, token.CONTINUE, + token.FOR, token.IF, token.RETURN, token.SWITCH, + token.VAR, token.DO, token.TRY, token.WITH, + token.WHILE, token.THROW, token.CATCH, token.FINALLY: + // Return only if parser made some progress since last + // sync or if it has not reached 10 next calls without + // progress. Otherwise consume at least one token to + // avoid an endless parser loop + if self.idx == self.recover.idx && self.recover.count < 10 { + self.recover.count++ + return + } + if self.idx > self.recover.idx { + self.recover.idx = self.idx + self.recover.count = 0 + return + } + // Reaching here indicates a parser bug, likely an + // incorrect token list in this function, but it only + // leads to skipping of possibly correct code if a + // previous error is present, and thus is preferred + // over a non-terminating parse. + case token.EOF: + return + } + self.next() + } +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser_test.go new file mode 100644 index 0000000000..7db43d239d --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser_test.go @@ -0,0 +1,42 @@ +package otto + +import ( + "testing" +) + +func TestPersistence(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + function abc() { return 1; } + abc.toString(); + `, "function abc() { return 1; }") + + test(` + function def() { return 3.14159; } + [ abc.toString(), def.toString() ]; + `, "function abc() { return 1; },function def() { return 3.14159; }") + + test(` + eval("function ghi() { return 'ghi' }"); + [ abc.toString(), def.toString(), ghi.toString() ]; + `, "function abc() { return 1; },function def() { return 3.14159; },function ghi() { return 'ghi' }") + + test(` + [ abc.toString(), def.toString(), ghi.toString() ]; + `, "function abc() { return 1; },function def() { return 3.14159; },function ghi() { return 'ghi' }") + + test(`/* + + + + + + + + + + */`, UndefinedValue()) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/property.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/property.go new file mode 100644 index 0000000000..5445eccdeb --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/property.go @@ -0,0 +1,220 @@ +package otto + +// property + +type _propertyMode int + +const ( + modeWriteMask _propertyMode = 0700 + modeEnumerateMask = 0070 + modeConfigureMask = 0007 + modeOnMask = 0111 + modeOffMask = 0000 + modeSetMask = 0222 // If value is 2, then mode is neither "On" nor "Off" +) + +type _propertyGetSet [2]*_object + +var _nilGetSetObject _object = _object{} + +type _property struct { + value interface{} + mode _propertyMode +} + +func (self _property) writable() bool { + return self.mode&modeWriteMask == modeWriteMask&modeOnMask +} + +func (self *_property) writeOn() { + self.mode = (self.mode & ^modeWriteMask) | (modeWriteMask & modeOnMask) +} + +func (self *_property) writeOff() { + self.mode &= ^modeWriteMask +} + +func (self *_property) writeClear() { + self.mode = (self.mode & ^modeWriteMask) | (modeWriteMask & modeSetMask) +} + +func (self _property) writeSet() bool { + return 0 == self.mode&modeWriteMask&modeSetMask +} + +func (self _property) enumerable() bool { + return self.mode&modeEnumerateMask == modeEnumerateMask&modeOnMask +} + +func (self *_property) enumerateOn() { + self.mode = (self.mode & ^modeEnumerateMask) | (modeEnumerateMask & modeOnMask) +} + +func (self *_property) enumerateOff() { + self.mode &= ^modeEnumerateMask +} + +func (self _property) enumerateSet() bool { + return 0 == self.mode&modeEnumerateMask&modeSetMask +} + +func (self _property) configurable() bool { + return self.mode&modeConfigureMask == modeConfigureMask&modeOnMask +} + +func (self *_property) configureOn() { + self.mode = (self.mode & ^modeConfigureMask) | (modeConfigureMask & modeOnMask) +} + +func (self *_property) configureOff() { + self.mode &= ^modeConfigureMask +} + +func (self _property) configureSet() bool { + return 0 == self.mode&modeConfigureMask&modeSetMask +} + +func (self _property) copy() *_property { + property := self + return &property +} + +func (self _property) get(this *_object) Value { + switch value := self.value.(type) { + case Value: + return value + case _propertyGetSet: + if value[0] != nil { + return value[0].call(toValue(this), nil, false, nativeFrame) + } + } + return Value{} +} + +func (self _property) isAccessorDescriptor() bool { + setGet, test := self.value.(_propertyGetSet) + return test && (setGet[0] != nil || setGet[1] != nil) +} + +func (self _property) isDataDescriptor() bool { + if self.writeSet() { // Either "On" or "Off" + return true + } + value, valid := self.value.(Value) + return valid && !value.isEmpty() +} + +func (self _property) isGenericDescriptor() bool { + return !(self.isDataDescriptor() || self.isAccessorDescriptor()) +} + +func (self _property) isEmpty() bool { + return self.mode == 0222 && self.isGenericDescriptor() +} + +// _enumerableValue, _enumerableTrue, _enumerableFalse? +// .enumerableValue() .enumerableExists() + +func toPropertyDescriptor(rt *_runtime, value Value) (descriptor _property) { + objectDescriptor := value._object() + if objectDescriptor == nil { + panic(rt.panicTypeError()) + } + + { + descriptor.mode = modeSetMask // Initially nothing is set + if objectDescriptor.hasProperty("enumerable") { + if objectDescriptor.get("enumerable").bool() { + descriptor.enumerateOn() + } else { + descriptor.enumerateOff() + } + } + + if objectDescriptor.hasProperty("configurable") { + if objectDescriptor.get("configurable").bool() { + descriptor.configureOn() + } else { + descriptor.configureOff() + } + } + + if objectDescriptor.hasProperty("writable") { + if objectDescriptor.get("writable").bool() { + descriptor.writeOn() + } else { + descriptor.writeOff() + } + } + } + + var getter, setter *_object + getterSetter := false + + if objectDescriptor.hasProperty("get") { + value := objectDescriptor.get("get") + if value.IsDefined() { + if !value.isCallable() { + panic(rt.panicTypeError()) + } + getter = value._object() + getterSetter = true + } else { + getter = &_nilGetSetObject + getterSetter = true + } + } + + if objectDescriptor.hasProperty("set") { + value := objectDescriptor.get("set") + if value.IsDefined() { + if !value.isCallable() { + panic(rt.panicTypeError()) + } + setter = value._object() + getterSetter = true + } else { + setter = &_nilGetSetObject + getterSetter = true + } + } + + if getterSetter { + if descriptor.writeSet() { + panic(rt.panicTypeError()) + } + descriptor.value = _propertyGetSet{getter, setter} + } + + if objectDescriptor.hasProperty("value") { + if getterSetter { + panic(rt.panicTypeError()) + } + descriptor.value = objectDescriptor.get("value") + } + + return +} + +func (self *_runtime) fromPropertyDescriptor(descriptor _property) *_object { + object := self.newObject() + if descriptor.isDataDescriptor() { + object.defineProperty("value", descriptor.value.(Value), 0111, false) + object.defineProperty("writable", toValue_bool(descriptor.writable()), 0111, false) + } else if descriptor.isAccessorDescriptor() { + getSet := descriptor.value.(_propertyGetSet) + get := Value{} + if getSet[0] != nil { + get = toValue_object(getSet[0]) + } + set := Value{} + if getSet[1] != nil { + set = toValue_object(getSet[1]) + } + object.defineProperty("get", get, 0111, false) + object.defineProperty("set", set, 0111, false) + } + object.defineProperty("enumerable", toValue_bool(descriptor.enumerable()), 0111, false) + object.defineProperty("configurable", toValue_bool(descriptor.configurable()), 0111, false) + return object +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/reflect_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/reflect_test.go new file mode 100644 index 0000000000..e4e83adeb8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/reflect_test.go @@ -0,0 +1,483 @@ +package otto + +import ( + "math" + "reflect" + "testing" +) + +type _abcStruct struct { + Abc bool + Def int + Ghi string + Jkl interface{} + Mno _mnoStruct + Pqr map[string]int8 +} + +func (abc _abcStruct) String() string { + return abc.Ghi +} + +func (abc *_abcStruct) FuncPointer() string { + return "abc" +} + +func (abc _abcStruct) Func() { + return +} + +func (abc _abcStruct) FuncReturn1() string { + return "abc" +} + +func (abc _abcStruct) FuncReturn2() (string, error) { + return "def", nil +} + +func (abc _abcStruct) Func1Return1(a string) string { + return a +} + +func (abc _abcStruct) Func2Return1(x, y string) string { + return x + y +} + +func (abc _abcStruct) FuncEllipsis(xyz ...string) int { + return len(xyz) +} + +func (abc _abcStruct) FuncReturnStruct() _mnoStruct { + return _mnoStruct{} +} + +type _mnoStruct struct { + Ghi string +} + +func (mno _mnoStruct) Func() string { + return "mno" +} + +func TestReflect(t *testing.T) { + if true { + return + } + tt(t, func() { + // Testing dbgf + // These should panic + toValue("Xyzzy").toReflectValue(reflect.Ptr) + stringToReflectValue("Xyzzy", reflect.Ptr) + }) +} + +func Test_reflectStruct(t *testing.T) { + tt(t, func() { + test, vm := test() + + // _abcStruct + { + abc := &_abcStruct{} + vm.Set("abc", abc) + + test(` + [ abc.Abc, abc.Ghi ]; + `, "false,") + + abc.Abc = true + abc.Ghi = "Nothing happens." + + test(` + [ abc.Abc, abc.Ghi ]; + `, "true,Nothing happens.") + + *abc = _abcStruct{} + + test(` + [ abc.Abc, abc.Ghi ]; + `, "false,") + + abc.Abc = true + abc.Ghi = "Xyzzy" + vm.Set("abc", abc) + + test(` + [ abc.Abc, abc.Ghi ]; + `, "true,Xyzzy") + + is(abc.Abc, true) + test(` + abc.Abc = false; + abc.Def = 451; + abc.Ghi = "Nothing happens."; + abc.abc = "Something happens."; + [ abc.Def, abc.abc ]; + `, "451,Something happens.") + is(abc.Abc, false) + is(abc.Def, 451) + is(abc.Ghi, "Nothing happens.") + + test(` + delete abc.Def; + delete abc.abc; + [ abc.Def, abc.abc ]; + `, "451,") + is(abc.Def, 451) + + test(` + abc.FuncPointer(); + `, "abc") + + test(` + abc.Func(); + `, "undefined") + + test(` + abc.FuncReturn1(); + `, "abc") + + test(` + abc.Func1Return1("abc"); + `, "abc") + + test(` + abc.Func2Return1("abc", "def"); + `, "abcdef") + + test(` + abc.FuncEllipsis("abc", "def", "ghi"); + `, 3) + + test(`raise: + abc.FuncReturn2(); + `, "TypeError") + + test(` + abc.FuncReturnStruct(); + `, "[object Object]") + + test(` + abc.FuncReturnStruct().Func(); + `, "mno") + } + }) +} + +func Test_reflectMap(t *testing.T) { + tt(t, func() { + test, vm := test() + + // map[string]string + { + abc := map[string]string{ + "Xyzzy": "Nothing happens.", + "def": "1", + } + vm.Set("abc", abc) + + test(` + abc.xyz = "pqr"; + [ abc.Xyzzy, abc.def, abc.ghi ]; + `, "Nothing happens.,1,") + + is(abc["xyz"], "pqr") + } + + // map[string]float64 + { + abc := map[string]float64{ + "Xyzzy": math.Pi, + "def": 1, + } + vm.Set("abc", abc) + + test(` + abc.xyz = "pqr"; + abc.jkl = 10; + [ abc.Xyzzy, abc.def, abc.ghi ]; + `, "3.141592653589793,1,") + + is(abc["xyz"], math.NaN()) + is(abc["jkl"], float64(10)) + } + + // map[string]int32 + { + abc := map[string]int32{ + "Xyzzy": 3, + "def": 1, + } + vm.Set("abc", abc) + + test(` + abc.xyz = "pqr"; + abc.jkl = 10; + [ abc.Xyzzy, abc.def, abc.ghi ]; + `, "3,1,") + + is(abc["xyz"], 0) + is(abc["jkl"], int32(10)) + + test(` + delete abc["Xyzzy"]; + `) + + _, exists := abc["Xyzzy"] + is(exists, false) + is(abc["Xyzzy"], 0) + } + + // map[int32]string + { + abc := map[int32]string{ + 0: "abc", + 1: "def", + } + vm.Set("abc", abc) + + test(` + abc[2] = "pqr"; + //abc.jkl = 10; + abc[3] = 10; + [ abc[0], abc[1], abc[2], abc[3] ] + `, "abc,def,pqr,10") + + is(abc[2], "pqr") + is(abc[3], "10") + + test(` + delete abc[2]; + `) + + _, exists := abc[2] + is(exists, false) + } + + }) +} + +func Test_reflectSlice(t *testing.T) { + tt(t, func() { + test, vm := test() + + // []bool + { + abc := []bool{ + false, + true, + true, + false, + } + vm.Set("abc", abc) + + test(` + abc; + `, "false,true,true,false") + + test(` + abc[0] = true; + abc[abc.length-1] = true; + delete abc[2]; + abc; + `, "true,true,false,true") + + is(abc, []bool{true, true, false, true}) + is(abc[len(abc)-1], true) + } + + // []int32 + { + abc := make([]int32, 4) + vm.Set("abc", abc) + + test(` + abc; + `, "0,0,0,0") + + test(` + abc[0] = 4.2; + abc[1] = "42"; + abc[2] = 3.14; + abc; + `, "4,42,3,0") + + is(abc, []int32{4, 42, 3, 0}) + + test(` + delete abc[1]; + delete abc[2]; + `) + is(abc[1], 0) + is(abc[2], 0) + } + }) +} + +func Test_reflectArray(t *testing.T) { + tt(t, func() { + test, vm := test() + + // []bool + { + abc := [4]bool{ + false, + true, + true, + false, + } + vm.Set("abc", abc) + + test(` + abc; + `, "false,true,true,false") + // Unaddressable array + + test(` + abc[0] = true; + abc[abc.length-1] = true; + abc; + `, "false,true,true,false") + // Again, unaddressable array + + is(abc, [4]bool{false, true, true, false}) + is(abc[len(abc)-1], false) + // ... + } + + // []int32 + { + abc := make([]int32, 4) + vm.Set("abc", abc) + + test(` + abc; + `, "0,0,0,0") + + test(` + abc[0] = 4.2; + abc[1] = "42"; + abc[2] = 3.14; + abc; + `, "4,42,3,0") + + is(abc, []int32{4, 42, 3, 0}) + } + + // []bool + { + abc := [4]bool{ + false, + true, + true, + false, + } + vm.Set("abc", &abc) + + test(` + abc; + `, "false,true,true,false") + + test(` + abc[0] = true; + abc[abc.length-1] = true; + delete abc[2]; + abc; + `, "true,true,false,true") + + is(abc, [4]bool{true, true, false, true}) + is(abc[len(abc)-1], true) + } + + }) +} + +func Test_reflectArray_concat(t *testing.T) { + tt(t, func() { + test, vm := test() + + vm.Set("ghi", []string{"jkl", "mno"}) + vm.Set("pqr", []interface{}{"jkl", 42, 3.14159, true}) + test(` + var def = { + "abc": ["abc"], + "xyz": ["xyz"] + }; + xyz = pqr.concat(ghi, def.abc, def, def.xyz); + [ xyz, xyz.length ]; + `, "jkl,42,3.14159,true,jkl,mno,abc,[object Object],xyz,9") + }) +} + +func Test_reflectMapInterface(t *testing.T) { + tt(t, func() { + test, vm := test() + + { + abc := map[string]interface{}{ + "Xyzzy": "Nothing happens.", + "def": "1", + "jkl": "jkl", + } + vm.Set("abc", abc) + vm.Set("mno", &_abcStruct{}) + + test(` + abc.xyz = "pqr"; + abc.ghi = {}; + abc.jkl = 3.14159; + abc.mno = mno; + mno.Abc = true; + mno.Ghi = "Something happens."; + [ abc.Xyzzy, abc.def, abc.ghi, abc.mno ]; + `, "Nothing happens.,1,[object Object],[object Object]") + + is(abc["xyz"], "pqr") + is(abc["ghi"], "[object Object]") + is(abc["jkl"], float64(3.14159)) + mno, valid := abc["mno"].(*_abcStruct) + is(valid, true) + is(mno.Abc, true) + is(mno.Ghi, "Something happens.") + } + }) +} + +func TestPassthrough(t *testing.T) { + tt(t, func() { + test, vm := test() + + { + abc := &_abcStruct{ + Mno: _mnoStruct{ + Ghi: "", + }, + } + vm.Set("abc", abc) + + test(` + abc.Mno.Ghi; + `, "") + + vm.Set("pqr", map[string]int8{ + "xyzzy": 0, + "Nothing happens.": 1, + }) + + test(` + abc.Ghi = "abc"; + abc.Pqr = pqr; + abc.Pqr["Nothing happens."]; + `, 1) + + mno := _mnoStruct{ + Ghi: "", + } + vm.Set("mno", mno) + + test(` + abc.Mno = mno; + abc.Mno.Ghi; + `, "") + } + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/regexp_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/regexp_test.go new file mode 100644 index 0000000000..8e65ee46a4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/regexp_test.go @@ -0,0 +1,290 @@ +package otto + +import ( + "fmt" + "testing" +) + +func TestRegExp(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ + /abc/.toString(), + /abc/gim.toString(), + ""+/abc/gi.toString(), + new RegExp("1(\\d+)").toString(), + ]; + `, "/abc/,/abc/gim,/abc/gi,/1(\\d+)/") + + test(` + [ + new RegExp("abc").exec("123abc456"), + null === new RegExp("xyzzy").exec("123abc456"), + new RegExp("1(\\d+)").exec("123abc456"), + new RegExp("xyzzy").test("123abc456"), + new RegExp("1(\\d+)").test("123abc456"), + new RegExp("abc").exec("123abc456"), + ]; + `, "abc,true,123,23,false,true,abc") + + test(`new RegExp("abc").toString()`, "/abc/") + test(`new RegExp("abc", "g").toString()`, "/abc/g") + test(`new RegExp("abc", "mig").toString()`, "/abc/gim") + + result := test(`/(a)?/.exec('b')`, ",") + is(result._object().get("0"), "") + is(result._object().get("1"), "undefined") + is(result._object().get("length"), 2) + + result = test(`/(a)?(b)?/.exec('b')`, "b,,b") + is(result._object().get("0"), "b") + is(result._object().get("1"), "undefined") + is(result._object().get("2"), "b") + is(result._object().get("length"), 3) + + test(`/\u0041/.source`, "\\u0041") + test(`/\a/.source`, "\\a") + test(`/\;/.source`, "\\;") + + test(`/a\a/.source`, "a\\a") + test(`/,\;/.source`, ",\\;") + test(`/ \ /.source`, " \\ ") + + // Start sanity check... + test("eval(\"/abc/\").source", "abc") + test("eval(\"/\u0023/\").source", "#") + test("eval(\"/\u0058/\").source", "X") + test("eval(\"/\\\u0023/\").source == \"\\\u0023\"", true) + test("'0x' + '0058'", "0x0058") + test("'\\\\' + '0x' + '0058'", "\\0x0058") + // ...stop sanity check + + test(`abc = '\\' + String.fromCharCode('0x' + '0058'); eval('/' + abc + '/').source`, "\\X") + test(`abc = '\\' + String.fromCharCode('0x0058'); eval('/' + abc + '/').source == "\\\u0058"`, true) + test(`abc = '\\' + String.fromCharCode('0x0023'); eval('/' + abc + '/').source == "\\\u0023"`, true) + test(`abc = '\\' + String.fromCharCode('0x0078'); eval('/' + abc + '/').source == "\\\u0078"`, true) + + test(` + var abc = Object.getOwnPropertyDescriptor(RegExp, "prototype"); + [ [ typeof RegExp.prototype ], + [ abc.writable, abc.enumerable, abc.configurable ] ]; + `, "object,false,false,false") + }) +} + +func TestRegExp_global(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = /(?:ab|cd)\d?/g; + var found = []; + do { + match = abc.exec("ab cd2 ab34 cd"); + if (match !== null) { + found.push(match[0]); + } else { + break; + } + } while (true); + found; + `, "ab,cd2,ab3,cd") + }) +} + +func TestRegExp_exec(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = /./g; + def = '123456'; + ghi = 0; + while (ghi < 100 && abc.exec(def) !== null) { + ghi += 1; + } + [ ghi, def.length, ghi == def.length ]; + `, "6,6,true") + + test(` + abc = /[abc](\d)?/g; + def = 'a0 b c1 d3'; + ghi = 0; + lastIndex = 0; + while (ghi < 100 && abc.exec(def) !== null) { + lastIndex = abc.lastIndex; + ghi += 1; + + } + [ ghi, lastIndex ]; + `, "3,7") + + test(` + var abc = /[abc](\d)?/.exec("a0 b c1 d3"); + [ abc.length, abc.input, abc.index, abc ]; + `, "2,a0 b c1 d3,0,a0,0") + + test(`raise: + var exec = RegExp.prototype.exec; + exec("Xyzzy"); + `, "TypeError: Calling RegExp.exec on a non-RegExp object") + + test(` + var abc = /\w{3}\d?/.exec("CE\uFFFFL\uFFDDbox127"); + [ abc.input.length, abc.length, abc.input, abc.index, abc ]; + `, "11,1,CE\uFFFFL\uFFDDbox127,5,box1") + + test(`RegExp.prototype.exec.length`, 1) + test(`RegExp.prototype.exec.prototype`, "undefined") + }) +} + +func TestRegExp_test(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`RegExp.prototype.test.length`, 1) + test(`RegExp.prototype.test.prototype`, "undefined") + }) +} + +func TestRegExp_toString(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`RegExp.prototype.toString.length`, 0) + test(`RegExp.prototype.toString.prototype`, "undefined") + }) +} + +func TestRegExp_zaacbbbcac(t *testing.T) { + if true { + return + } + + tt(t, func() { + test, _ := test() + + // FIXME? TODO /(z)((a+)?(b+)?(c))*/.exec("zaacbbbcac") + test(` + var abc = /(z)((a+)?(b+)?(c))*/.exec("zaacbbbcac"); + [ abc.length, abc.index, abc ]; + `, "6,0,zaacbbbcac,z,ac,a,,c") + }) +} + +func TestRegExpCopying(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = /xyzzy/i; + def = RegExp(abc); + abc.indicator = 1; + [ abc.indicator, def.indicator ]; + `, "1,1") + + test(`raise: + RegExp(new RegExp("\\d"), "1"); + `, "TypeError: Cannot supply flags when constructing one RegExp from another") + }) +} + +func TestRegExp_multiline(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = /s$/m.exec("pairs\nmakes\tdouble"); + [ abc.length, abc.index, abc ]; + `, "1,4,s") + }) +} + +func TestRegExp_source(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [ /xyzzy/i.source, /./i.source ]; + `, "xyzzy,.") + + test(` + var abc = /./i; + var def = new RegExp(abc); + [ abc.source, def.source, abc.source === def.source ]; + `, ".,.,true") + + test(` + var abc = /./i; + var def = abc.hasOwnProperty("source"); + var ghi = abc.source; + abc.source = "xyzzy"; + [ def, abc.source ]; + `, "true,.") + }) +} + +func TestRegExp_newRegExp(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + Math.toString(); + var abc = new RegExp(Math,eval("\"g\"")); + [ abc, abc.global ]; + `, "/[object Math]/g,true") + }) +} + +func TestRegExp_flags(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = /./i; + var def = new RegExp(abc); + [ abc.multiline == def.multiline, abc.global == def.global, abc.ignoreCase == def.ignoreCase ]; + `, "true,true,true") + }) +} + +func TestRegExp_controlCharacter(t *testing.T) { + tt(t, func() { + test, _ := test() + + for code := 0x41; code < 0x5a; code++ { + string_ := string(code - 64) + test(fmt.Sprintf(` + var code = 0x%x; + var string = String.fromCharCode(code %% 32); + var result = (new RegExp("\\c" + String.fromCharCode(code))).exec(string); + [ code, string, result ]; + `, code), fmt.Sprintf("%d,%s,%s", code, string_, string_)) + } + }) +} + +func TestRegExp_notNotEmptyCharacterClass(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = /[\s\S]a/m.exec("a\naba"); + [ abc.length, abc.input, abc ]; + `, "1,a\naba,\na") + }) +} + +func TestRegExp_compile(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = /[\s\S]a/; + abc.compile('^\w+'); + `, "undefined") + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/registry/README.markdown b/Godeps/_workspace/src/github.com/robertkrimen/otto/registry/README.markdown new file mode 100644 index 0000000000..ba2d389090 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/registry/README.markdown @@ -0,0 +1,51 @@ +# registry +-- + import "github.com/robertkrimen/otto/registry" + +Package registry is an expirmental package to facillitate altering the otto +runtime via import. + +This interface can change at any time. + +## Usage + +#### func Apply + +```go +func Apply(callback func(Entry)) +``` + +#### type Entry + +```go +type Entry struct { +} +``` + + +#### func Register + +```go +func Register(source func() string) *Entry +``` + +#### func (*Entry) Disable + +```go +func (self *Entry) Disable() +``` + +#### func (*Entry) Enable + +```go +func (self *Entry) Enable() +``` + +#### func (Entry) Source + +```go +func (self Entry) Source() string +``` + +-- +**godocdown** http://github.com/robertkrimen/godocdown diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/registry/registry.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/registry/registry.go new file mode 100644 index 0000000000..966638ac4c --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/registry/registry.go @@ -0,0 +1,47 @@ +/* +Package registry is an expirmental package to facillitate altering the otto runtime via import. + +This interface can change at any time. +*/ +package registry + +var registry []*Entry = make([]*Entry, 0) + +type Entry struct { + active bool + source func() string +} + +func newEntry(source func() string) *Entry { + return &Entry{ + active: true, + source: source, + } +} + +func (self *Entry) Enable() { + self.active = true +} + +func (self *Entry) Disable() { + self.active = false +} + +func (self Entry) Source() string { + return self.source() +} + +func Apply(callback func(Entry)) { + for _, entry := range registry { + if !entry.active { + continue + } + callback(*entry) + } +} + +func Register(source func() string) *Entry { + entry := newEntry(source) + registry = append(registry, entry) + return entry +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/result.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/result.go new file mode 100644 index 0000000000..63642e7d03 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/result.go @@ -0,0 +1,30 @@ +package otto + +import () + +type _resultKind int + +const ( + resultNormal _resultKind = iota + resultReturn + resultBreak + resultContinue +) + +type _result struct { + kind _resultKind + value Value + target string +} + +func newReturnResult(value Value) _result { + return _result{resultReturn, value, ""} +} + +func newContinueResult(target string) _result { + return _result{resultContinue, emptyValue, target} +} + +func newBreakResult(target string) _result { + return _result{resultBreak, emptyValue, target} +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go new file mode 100644 index 0000000000..1ac1b435ec --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go @@ -0,0 +1,331 @@ +package otto + +import ( + "errors" + "reflect" + "sync" + + "github.com/robertkrimen/otto/ast" + "github.com/robertkrimen/otto/parser" +) + +type _global struct { + Object *_object // Object( ... ), new Object( ... ) - 1 (length) + Function *_object // Function( ... ), new Function( ... ) - 1 + Array *_object // Array( ... ), new Array( ... ) - 1 + String *_object // String( ... ), new String( ... ) - 1 + Boolean *_object // Boolean( ... ), new Boolean( ... ) - 1 + Number *_object // Number( ... ), new Number( ... ) - 1 + Math *_object + Date *_object // Date( ... ), new Date( ... ) - 7 + RegExp *_object // RegExp( ... ), new RegExp( ... ) - 2 + Error *_object // Error( ... ), new Error( ... ) - 1 + EvalError *_object + TypeError *_object + RangeError *_object + ReferenceError *_object + SyntaxError *_object + URIError *_object + JSON *_object + + ObjectPrototype *_object // Object.prototype + FunctionPrototype *_object // Function.prototype + ArrayPrototype *_object // Array.prototype + StringPrototype *_object // String.prototype + BooleanPrototype *_object // Boolean.prototype + NumberPrototype *_object // Number.prototype + DatePrototype *_object // Date.prototype + RegExpPrototype *_object // RegExp.prototype + ErrorPrototype *_object // Error.prototype + EvalErrorPrototype *_object + TypeErrorPrototype *_object + RangeErrorPrototype *_object + ReferenceErrorPrototype *_object + SyntaxErrorPrototype *_object + URIErrorPrototype *_object +} + +type _runtime struct { + global _global + globalObject *_object + globalStash *_objectStash + scope *_scope + otto *Otto + eval *_object // The builtin eval, for determine indirect versus direct invocation + + labels []string // FIXME + lck sync.Mutex +} + +func (self *_runtime) enterScope(scope *_scope) { + scope.outer = self.scope + self.scope = scope +} + +func (self *_runtime) leaveScope() { + self.scope = self.scope.outer +} + +// FIXME This is used in two places (cloning) +func (self *_runtime) enterGlobalScope() { + self.enterScope(newScope(self.globalStash, self.globalStash, self.globalObject)) +} + +func (self *_runtime) enterFunctionScope(outer _stash, this Value) *_fnStash { + if outer == nil { + outer = self.globalStash + } + stash := self.newFunctionStash(outer) + var thisObject *_object + switch this.kind { + case valueUndefined, valueNull: + thisObject = self.globalObject + default: + thisObject = self.toObject(this) + } + self.enterScope(newScope(stash, stash, thisObject)) + return stash +} + +func (self *_runtime) putValue(reference _reference, value Value) { + name := reference.putValue(value) + if name != "" { + // Why? -- If reference.base == nil + // strict = false + self.globalObject.defineProperty(name, value, 0111, false) + } +} + +func (self *_runtime) tryCatchEvaluate(inner func() Value) (tryValue Value, exception bool) { + // resultValue = The value of the block (e.g. the last statement) + // throw = Something was thrown + // throwValue = The value of what was thrown + // other = Something that changes flow (return, break, continue) that is not a throw + // Otherwise, some sort of unknown panic happened, we'll just propagate it + defer func() { + if caught := recover(); caught != nil { + if exception, ok := caught.(*_exception); ok { + caught = exception.eject() + } + switch caught := caught.(type) { + case _error: + exception = true + tryValue = toValue_object(self.newError(caught.name, caught.messageValue())) + case Value: + exception = true + tryValue = caught + default: + panic(caught) + } + } + }() + + tryValue = inner() + return +} + +// toObject + +func (self *_runtime) toObject(value Value) *_object { + switch value.kind { + case valueEmpty, valueUndefined, valueNull: + panic(self.panicTypeError()) + case valueBoolean: + return self.newBoolean(value) + case valueString: + return self.newString(value) + case valueNumber: + return self.newNumber(value) + case valueObject: + return value._object() + } + panic(self.panicTypeError()) +} + +func (self *_runtime) objectCoerce(value Value) (*_object, error) { + switch value.kind { + case valueUndefined: + return nil, errors.New("undefined") + case valueNull: + return nil, errors.New("null") + case valueBoolean: + return self.newBoolean(value), nil + case valueString: + return self.newString(value), nil + case valueNumber: + return self.newNumber(value), nil + case valueObject: + return value._object(), nil + } + panic(self.panicTypeError()) +} + +func checkObjectCoercible(rt *_runtime, value Value) { + isObject, mustCoerce := testObjectCoercible(value) + if !isObject && !mustCoerce { + panic(rt.panicTypeError()) + } +} + +// testObjectCoercible + +func testObjectCoercible(value Value) (isObject bool, mustCoerce bool) { + switch value.kind { + case valueReference, valueEmpty, valueNull, valueUndefined: + return false, false + case valueNumber, valueString, valueBoolean: + isObject = false + mustCoerce = true + case valueObject: + isObject = true + mustCoerce = false + } + return +} + +func (self *_runtime) safeToValue(value interface{}) (Value, error) { + result := Value{} + err := catchPanic(func() { + result = self.toValue(value) + }) + return result, err +} + +func (self *_runtime) toValue(value interface{}) Value { + switch value := value.(type) { + case Value: + return value + case func(FunctionCall) Value: + return toValue_object(self.newNativeFunction("", value)) + case _nativeFunction: + return toValue_object(self.newNativeFunction("", value)) + case Object, *Object, _object, *_object: + // Nothing happens. + // FIXME We should really figure out what can come here. + // This catch-all is ugly. + default: + { + value := reflect.ValueOf(value) + switch value.Kind() { + case reflect.Ptr: + switch reflect.Indirect(value).Kind() { + case reflect.Struct: + return toValue_object(self.newGoStructObject(value)) + case reflect.Array: + return toValue_object(self.newGoArray(value)) + } + case reflect.Func: + // TODO Maybe cache this? + return toValue_object(self.newNativeFunction("", func(call FunctionCall) Value { + in := make([]reflect.Value, len(call.ArgumentList)) + for i, value := range call.ArgumentList { + in[i] = reflect.ValueOf(value.export()) + } + + out := value.Call(in) + if len(out) == 1 { + return self.toValue(out[0].Interface()) + } else if len(out) == 0 { + return Value{} + } + + panic(call.runtime.panicTypeError()) + })) + case reflect.Struct: + return toValue_object(self.newGoStructObject(value)) + case reflect.Map: + return toValue_object(self.newGoMapObject(value)) + case reflect.Slice: + return toValue_object(self.newGoSlice(value)) + case reflect.Array: + return toValue_object(self.newGoArray(value)) + } + } + } + return toValue(value) +} + +func (runtime *_runtime) newGoSlice(value reflect.Value) *_object { + self := runtime.newGoSliceObject(value) + self.prototype = runtime.global.ArrayPrototype + return self +} + +func (runtime *_runtime) newGoArray(value reflect.Value) *_object { + self := runtime.newGoArrayObject(value) + self.prototype = runtime.global.ArrayPrototype + return self +} + +func (runtime *_runtime) parse(filename string, src interface{}) (*ast.Program, error) { + return parser.ParseFile(nil, filename, src, 0) +} + +func (runtime *_runtime) cmpl_parse(filename string, src interface{}) (*_nodeProgram, error) { + program, err := parser.ParseFile(nil, filename, src, 0) + if err != nil { + return nil, err + } + return cmpl_parse(program), nil +} + +func (self *_runtime) parseSource(src interface{}) (*_nodeProgram, *ast.Program, error) { + switch src := src.(type) { + case *ast.Program: + return nil, src, nil + case *Script: + return src.program, nil, nil + } + program, err := self.parse("", src) + return nil, program, err +} + +func (self *_runtime) cmpl_run(src interface{}) (Value, error) { + result := Value{} + cmpl_program, program, err := self.parseSource(src) + if err != nil { + return result, err + } + if cmpl_program == nil { + cmpl_program = cmpl_parse(program) + } + err = catchPanic(func() { + result = self.cmpl_evaluate_nodeProgram(cmpl_program, false) + }) + switch result.kind { + case valueEmpty: + result = Value{} + case valueReference: + result = result.resolve() + } + return result, err +} + +func (self *_runtime) parseThrow(err error) { + if err == nil { + return + } + switch err := err.(type) { + case parser.ErrorList: + { + err := err[0] + if err.Message == "Invalid left-hand side in assignment" { + panic(self.panicReferenceError(err.Message)) + } + panic(self.panicSyntaxError(err.Message)) + } + } + panic(self.panicSyntaxError(err.Error())) +} + +func (self *_runtime) parseOrThrow(source string) *ast.Program { + program, err := self.parse("", source) + self.parseThrow(err) // Will panic/throw appropriately + return program +} + +func (self *_runtime) cmpl_parseOrThrow(source string) *_nodeProgram { + program, err := self.cmpl_parse("", source) + self.parseThrow(err) // Will panic/throw appropriately + return program +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime_test.go new file mode 100644 index 0000000000..2510a0b3fa --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime_test.go @@ -0,0 +1,778 @@ +package otto + +import ( + "math" + "testing" +) + +// FIXME terst, Review tests + +func TestOperator(t *testing.T) { + tt(t, func() { + test, vm := test() + + test("xyzzy = 1") + test("xyzzy", 1) + + if true { + vm.Set("twoPlusTwo", func(FunctionCall) Value { + return toValue(5) + }) + test("twoPlusTwo( 1 )", 5) + + test("1 + twoPlusTwo( 1 )", 6) + + test("-1 + twoPlusTwo( 1 )", 4) + } + + test("result = 4") + test("result", 4) + + test("result += 1") + test("result", 5) + + test("result *= 2") + test("result", 10) + + test("result /= 2") + test("result", 5) + + test("result = 112.51 % 3.1") + test("result", 0.9100000000000019) + + test("result = 'Xyzzy'") + test("result", "Xyzzy") + + test("result = 'Xyz' + 'zy'") + test("result", "Xyzzy") + + test("result = \"Xyzzy\"") + test("result", "Xyzzy") + + test("result = 1; result = result") + test("result", 1) + + test(` + var result64 + = + 64 + , result10 = + 10 + `) + test("result64", 64) + test("result10", 10) + + test(` + result = 1; + result += 1; + `) + test("result", 2) + }) +} + +func TestFunction_(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + result = 2 + xyzzy = function() { + result += 1 + } + xyzzy() + result; + `, 3) + + test(` + xyzzy = function() { + return 1 + } + result = xyzzy() + `, 1) + + test(` + xyzzy = function() {} + result = xyzzy() + `, "undefined") + + test(` + xyzzy = function() { + return 64 + return 1 + } + result = xyzzy() + `, 64) + + test(` + result = 4 + xyzzy = function() { + result = 2 + } + xyzzy(); + result; + `, 2) + + test(` + result = 4 + xyzzy = function() { + var result + result = 2 + } + xyzzy(); + result; + `, 4) + + test(` + xyzzy = function() { + var result = 4 + return result + } + result = xyzzy() + `, 4) + + test(` + xyzzy = function() { + function test() { + var result = 1 + return result + } + return test() + 1 + } + result = xyzzy() + 1 + `, 3) + + test(` + xyzzy = function() { + function test() { + var result = 1 + return result + } + _xyzzy = 2 + var result = _xyzzy + test() + 1 + return result + } + result = xyzzy() + 1; + [ result, _xyzzy ]; + `, "5,2") + + test(` + xyzzy = function(apple) { + return 1 + } + result = xyzzy(1) + `, 1) + + test(` + xyzzy = function(apple) { + return apple + 1 + } + result = xyzzy(2) + `, 3) + + test(` + { + result = 1 + result += 1; + } + `, 2) + + test(` + var global = 1 + outer = function() { + var global = 2 + var inner = function(){ + return global + } + return inner() + } + result = outer() + `, 2) + + test(` + var apple = 1 + var banana = function() { + return apple + } + var cherry = function() { + var apple = 2 + return banana() + } + result = cherry() + `, 1) + + test(` + function xyz() { + }; + delete xyz; + `, false) + + test(` + var abc = function __factorial(def){ + if (def === 1) { + return def; + } else { + return __factorial(def-1)*def; + } + }; + abc(3); + `, 6) + }) +} + +func TestDoWhile(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + limit = 4; + result = 0; + do { + result = result + 1; + limit = limit - 1; + } while (limit); + result; + `, 4) + + test(` + result = eval("do {abc=1; break; abc=2;} while (0);"); + [ result, abc ]; + `, "1,1") + }) +} + +func TestContinueBreak(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + limit = 4 + result = 0 + while (limit) { + limit = limit - 1 + if (limit) { + } + else { + break + } + result = result + 1 + } + [ result, limit ]; + `, "3,0") + + test(` + limit = 4 + result = 0 + while (limit) { + limit = limit - 1 + if (limit) { + continue + } + else { + break + } + result = result + 1 + } + result; + `, 0) + + test(` + limit = 4 + result = 0 + do { + limit = limit - 1 + if (limit) { + continue + } + else { + break + } + result = result + 1 + } while (limit) + result; + `, 0) + }) +} + +func TestTryCatchError(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc + try { + 1() + } + catch (def) { + abc = def + } + abc; + `, "TypeError: 1 is not a function") + + }) +} + +func TestPositiveNegativeZero(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`1/0`, _Infinity) + test(`1/-0`, -_Infinity) + test(` + abc = -0 + 1/abc + `, -_Infinity) + }) +} + +func TestComparison(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + undefined = 1; undefined; + `, "undefined") + + test("undefined == undefined", true) + + test("undefined != undefined", false) + + test("null == null", true) + + test("null != null", false) + + test("0 == 1", false) + + is(negativeZero(), -0) + is(positiveZero(), 0) + is(math.Signbit(negativeZero()), true) + is(positiveZero() == negativeZero(), true) + + test("1 == 1", true) + + test("'Hello, World.' == 'Goodbye, World.'", false) + + test("'Hello, World.' == true", false) + + test("'Hello, World.' == false", false) + + test("'Hello, World.' == 1", false) + + test("1 == 'Hello, World.'", false) + + is(parseNumber("-1"), -1) + + test("0+Object", "0function Object() { [native code] }") + }) +} + +func TestComparisonRelational(t *testing.T) { + tt(t, func() { + test, _ := test() + + test("0 < 0", false) + + test("0 > 0", false) + + test("0 <= 0", true) + + test("0 >= 0", true) + + test("' 0' >= 0", true) + + test("'_ 0' >= 0", false) + }) +} + +func TestArguments(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + xyzzy = function() { + return arguments[0] + } + result = xyzzy("xyzzy"); + `, "xyzzy") + + test(` + xyzzy = function() { + arguments[0] = "abcdef" + return arguments[0] + } + result = xyzzy("xyzzy"); + `, "abcdef") + + test(` + xyzzy = function(apple) { + apple = "abcdef" + return arguments[0] + } + result = xyzzy("xyzzy"); + `, "abcdef") + + test(` + (function(){ + return arguments + })() + `, "[object Arguments]") + + test(` + (function(){ + return arguments.length + })() + `, 0) + + test(` + (function(){ + return arguments.length + })(1, 2, 4, 8, 10) + `, 5) + }) +} + +func TestObjectLiteral(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + ({}); + `, "[object Object]") + + test(` + var abc = { + xyzzy: "Nothing happens.", + get 1e2() { + return 3.14159; + }, + get null() { + return true; + }, + get "[\n]"() { + return "<>"; + } + }; + [ abc["1e2"], abc.null, abc["[\n]"] ]; + `, "3.14159,true,<>") + + test(` + var abc = { + xyzzy: "Nothing happens.", + set 1e2() { + this[3.14159] = 100; + return Math.random(); + }, + set null(def) { + this.def = def; + return Math.random(); + }, + }; + [ abc["1e2"] = Infinity, abc[3.14159], abc.null = "xyz", abc.def ]; + `, "Infinity,100,xyz,xyz") + }) +} + +func TestUnaryPrefix(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var result = 0; + [++result, result]; + `, "1,1") + + test(` + result = 0; + [--result, result]; + `, "-1,-1") + + test(` + var object = { valueOf: function() { return 1; } }; + result = ++object; + [ result, typeof result ]; + `, "2,number") + + test(` + var object = { valueOf: function() { return 1; } }; + result = --object; + [ result, typeof result ]; + `, "0,number") + }) +} + +func TestUnaryPostfix(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var result = 0; + result++; + [ result++, result ]; + `, "1,2") + + test(` + result = 0; + result--; + [ result--, result ]; + `, "-1,-2") + + test(` + var object = { valueOf: function() { return 1; } }; + result = object++; + [ result, typeof result ]; + `, "1,number") + + test(` + var object = { valueOf: function() { return 1; } }; + result = object-- + [ result, typeof result ]; + `, "1,number") + }) +} + +func TestBinaryLogicalOperation(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = true + def = false + ghi = false + jkl = false + result = abc && def || ghi && jkl + `, false) + + test(` + abc = true + def = true + ghi = false + jkl = false + result = abc && def || ghi && jkl + `, true) + + }) +} + +func TestBinaryBitwiseOperation(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = 1 & 2; + def = 1 & 3; + ghi = 1 | 3; + jkl = 1 ^ 2; + mno = 1 ^ 3; + [ abc, def, ghi, jkl, mno ]; + `, "0,1,3,3,2") + }) +} + +func TestBinaryShiftOperation(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + high = (1 << 30) - 1 + (1 << 30) + low = -high - 1 + abc = 23 << 1 + def = -105 >> 1 + ghi = 23 << 2 + jkl = 1 >>> 31 + mno = 1 << 64 + pqr = 1 >> 2 + stu = -2 >> 4 + vwx = low >> 1 + yz = low >>> 1 + `) + test("abc", 46) + test("def", -53) + test("ghi", 92) + test("jkl", 0) + test("mno", 1) + test("pqr", 0) + test("stu", -1) + test("vwx", -1073741824) + test("yz", 1073741824) + }) +} + +func TestParenthesizing(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = 1 + 2 * 3 + def = (1 + 2) * 3 + ghi = !(false || true) + jkl = !false || true + `) + test("abc", 7) + test("def", 9) + test("ghi", false) + test("jkl", true) + }) +} + +func Test_instanceof(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = {} instanceof Object; + `, true) + + test(` + abc = "abc" instanceof Object; + `, false) + + test(`raise: + abc = {} instanceof "abc"; + `, "TypeError: Expecting a function in instanceof check, but got: abc") + + test(`raise: + "xyzzy" instanceof Math; + `, "TypeError") + }) +} + +func TestIn(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = "prototype" in Object; + def = "xyzzy" in Object; + [ abc, def ]; + `, "true,false") + }) +} + +func Test_new(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = new Boolean; + def = new Boolean(1); + [ abc, def ]; + `, "false,true") + }) +} + +func TestNewFunction(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + new Function("return 11")() + `, 11) + + test(` + abc = 10 + new Function("abc += 1")() + abc + `, 11) + + test(` + new Function("a", "b", "c", "return b + 2")(10, 11, 12) + `, 13) + + test(`raise: + new 1 + `, "TypeError: 1 is not a function") + + // TODO Better error reporting: new this + test(`raise: + new this + `, "TypeError: [object environment] is not a function") + + test(`raise: + new {} + `, "TypeError: [object Object] is not a function") + }) +} + +func TestNewPrototype(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = { 'xyzzy': 'Nothing happens.' } + function Xyzzy(){} + Xyzzy.prototype = abc; + (new Xyzzy()).xyzzy + `, "Nothing happens.") + }) +} + +func TestBlock(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc=0; + var ghi; + def: { + do { + abc++; + if (!(abc < 10)) { + break def; + ghi = "ghi"; + } + } while (true); + } + [ abc,ghi ]; + `, "10,") + }) +} + +func Test_toString(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + [undefined+""] + `, "undefined") + }) +} + +func TestEvaluationOrder(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + var abc = 0; + abc < (abc = 1) === true; + `, true) + }) +} + +func TestClone(t *testing.T) { + tt(t, func() { + vm1 := New() + vm1.Run(` + var abc = 1; + `) + + vm2 := vm1.clone() + vm1.Run(` + abc += 2; + `) + vm2.Run(` + abc += 4; + `) + + is(vm1.getValue("abc"), 3) + is(vm2.getValue("abc"), 5) + }) +} + +func Test_debugger(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + debugger; + `, "undefined") + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/scope.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/scope.go new file mode 100644 index 0000000000..b80808434f --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/scope.go @@ -0,0 +1,34 @@ +package otto + +// _scope: +// entryFile +// entryIdx +// top? +// outer => nil + +// _stash: +// lexical +// variable +// +// _thisStash (ObjectEnvironment) +// _fnStash +// _dclStash + +// An ECMA-262 ExecutionContext +type _scope struct { + lexical _stash + variable _stash + this *_object + eval bool // Replace this with kind? + outer *_scope + + frame _frame +} + +func newScope(lexical _stash, variable _stash, this *_object) *_scope { + return &_scope{ + lexical: lexical, + variable: variable, + this: this, + } +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/script.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/script.go new file mode 100644 index 0000000000..ed8aebbf49 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/script.go @@ -0,0 +1,122 @@ +package otto + +import ( + "bytes" + "encoding/gob" + "errors" + + "github.com/robertkrimen/otto/parser" +) + +var ErrVersion = errors.New("version mismatch") + +var scriptVersion = "2014-04-13/1" + +// Script is a handle for some (reusable) JavaScript. +// Passing a Script value to a run method will evaluate the JavaScript. +// +type Script struct { + version string + program *_nodeProgram + filename string + src string +} + +// Compile will parse the given source and return a Script value or nil and +// an error if there was a problem during compilation. +// +// script, err := vm.Compile("", `var abc; if (!abc) abc = 0; abc += 2; abc;`) +// vm.Run(script) +// +func (self *Otto) Compile(filename string, src interface{}) (*Script, error) { + { + src, err := parser.ReadSource(filename, src) + if err != nil { + return nil, err + } + + program, err := self.runtime.parse(filename, src) + if err != nil { + return nil, err + } + + cmpl_program := cmpl_parse(program) + + script := &Script{ + version: scriptVersion, + program: cmpl_program, + filename: filename, + src: string(src), + } + + return script, nil + } +} + +func (self *Script) String() string { + return "// " + self.filename + "\n" + self.src +} + +// MarshalBinary will marshal a script into a binary form. A marshalled script +// that is later unmarshalled can be executed on the same version of the otto runtime. +// +// The binary format can change at any time and should be considered unspecified and opaque. +// +func (self *Script) marshalBinary() ([]byte, error) { + var bfr bytes.Buffer + encoder := gob.NewEncoder(&bfr) + err := encoder.Encode(self.version) + if err != nil { + return nil, err + } + err = encoder.Encode(self.program) + if err != nil { + return nil, err + } + err = encoder.Encode(self.filename) + if err != nil { + return nil, err + } + err = encoder.Encode(self.src) + if err != nil { + return nil, err + } + return bfr.Bytes(), nil +} + +// UnmarshalBinary will vivify a marshalled script into something usable. If the script was +// originally marshalled on a different version of the otto runtime, then this method +// will return an error. +// +// The binary format can change at any time and should be considered unspecified and opaque. +// +func (self *Script) unmarshalBinary(data []byte) error { + decoder := gob.NewDecoder(bytes.NewReader(data)) + err := decoder.Decode(&self.version) + if err != nil { + goto error + } + if self.version != scriptVersion { + err = ErrVersion + goto error + } + err = decoder.Decode(&self.program) + if err != nil { + goto error + } + err = decoder.Decode(&self.filename) + if err != nil { + goto error + } + err = decoder.Decode(&self.src) + if err != nil { + goto error + } + return nil +error: + self.version = "" + self.program = nil + self.filename = "" + self.src = "" + return err +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/script_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/script_test.go new file mode 100644 index 0000000000..4c35c646eb --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/script_test.go @@ -0,0 +1,78 @@ +package otto + +import ( + "testing" +) + +func TestScript(t *testing.T) { + tt(t, func() { + vm := New() + + script, err := vm.Compile("xyzzy", `var abc; if (!abc) abc = 0; abc += 2; abc;`) + is(err, nil) + + str := script.String() + is(str, "// xyzzy\nvar abc; if (!abc) abc = 0; abc += 2; abc;") + + value, err := vm.Run(script) + is(err, nil) + is(value, 2) + + if true { + return + } + + tmp, err := script.marshalBinary() + is(err, nil) + is(len(tmp), 1228) + + { + script := &Script{} + err = script.unmarshalBinary(tmp) + is(err, nil) + + is(script.String(), str) + + value, err = vm.Run(script) + is(err, nil) + is(value, 4) + + tmp, err = script.marshalBinary() + is(err, nil) + is(len(tmp), 1228) + } + + { + script := &Script{} + err = script.unmarshalBinary(tmp) + is(err, nil) + + is(script.String(), str) + + value, err := vm.Run(script) + is(err, nil) + is(value, 6) + + tmp, err = script.marshalBinary() + is(err, nil) + is(len(tmp), 1228) + } + + { + version := scriptVersion + scriptVersion = "bogus" + + script := &Script{} + err = script.unmarshalBinary(tmp) + is(err, "version mismatch") + + is(script.String(), "// \n") + is(script.version, "") + is(script.program == nil, true) + is(script.filename, "") + is(script.src, "") + + scriptVersion = version + } + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/stash.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/stash.go new file mode 100644 index 0000000000..578708d3ff --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/stash.go @@ -0,0 +1,275 @@ +package otto + +import ( + "fmt" +) + +// ====== +// _stash +// ====== + +type _stash interface { + hasBinding(string) bool // + createBinding(string, bool, Value) // CreateMutableBinding + setBinding(string, Value, bool) // SetMutableBinding + getBinding(string, bool) Value // GetBindingValue + deleteBinding(string) bool // + setValue(string, Value, bool) // createBinding + setBinding + + outer() _stash + runtime() *_runtime + + newReference(string, bool, _at) _reference + + clone(clone *_clone) _stash +} + +// ========== +// _objectStash +// ========== + +type _objectStash struct { + _runtime *_runtime + _outer _stash + object *_object +} + +func (self *_objectStash) runtime() *_runtime { + return self._runtime +} + +func (runtime *_runtime) newObjectStash(object *_object, outer _stash) *_objectStash { + if object == nil { + object = runtime.newBaseObject() + object.class = "environment" + } + return &_objectStash{ + _runtime: runtime, + _outer: outer, + object: object, + } +} + +func (in *_objectStash) clone(clone *_clone) _stash { + out, exists := clone.objectStash(in) + if exists { + return out + } + *out = _objectStash{ + clone.runtime, + clone.stash(in._outer), + clone.object(in.object), + } + return out +} + +func (self *_objectStash) hasBinding(name string) bool { + return self.object.hasProperty(name) +} + +func (self *_objectStash) createBinding(name string, deletable bool, value Value) { + if self.object.hasProperty(name) { + panic(hereBeDragons()) + } + mode := _propertyMode(0111) + if !deletable { + mode = _propertyMode(0110) + } + // TODO False? + self.object.defineProperty(name, value, mode, false) +} + +func (self *_objectStash) setBinding(name string, value Value, strict bool) { + self.object.put(name, value, strict) +} + +func (self *_objectStash) setValue(name string, value Value, throw bool) { + if !self.hasBinding(name) { + self.createBinding(name, true, value) // Configurable by default + } else { + self.setBinding(name, value, throw) + } +} + +func (self *_objectStash) getBinding(name string, throw bool) Value { + if self.object.hasProperty(name) { + return self.object.get(name) + } + if throw { // strict? + panic(self._runtime.panicReferenceError("Not Defined", name)) + } + return Value{} +} + +func (self *_objectStash) deleteBinding(name string) bool { + return self.object.delete(name, false) +} + +func (self *_objectStash) outer() _stash { + return self._outer +} + +func (self *_objectStash) newReference(name string, strict bool, at _at) _reference { + return newPropertyReference(self._runtime, self.object, name, strict, at) +} + +// ========= +// _dclStash +// ========= + +type _dclStash struct { + _runtime *_runtime + _outer _stash + property map[string]_dclProperty +} + +type _dclProperty struct { + value Value + mutable bool + deletable bool + readable bool +} + +func (runtime *_runtime) newDeclarationStash(outer _stash) *_dclStash { + return &_dclStash{ + _runtime: runtime, + _outer: outer, + property: map[string]_dclProperty{}, + } +} + +func (in *_dclStash) clone(clone *_clone) _stash { + out, exists := clone.dclStash(in) + if exists { + return out + } + property := make(map[string]_dclProperty, len(in.property)) + for index, value := range in.property { + property[index] = clone.dclProperty(value) + } + *out = _dclStash{ + clone.runtime, + clone.stash(in._outer), + property, + } + return out +} + +func (self *_dclStash) hasBinding(name string) bool { + _, exists := self.property[name] + return exists +} + +func (self *_dclStash) runtime() *_runtime { + return self._runtime +} + +func (self *_dclStash) createBinding(name string, deletable bool, value Value) { + _, exists := self.property[name] + if exists { + panic(fmt.Errorf("createBinding: %s: already exists", name)) + } + self.property[name] = _dclProperty{ + value: value, + mutable: true, + deletable: deletable, + readable: false, + } +} + +func (self *_dclStash) setBinding(name string, value Value, strict bool) { + property, exists := self.property[name] + if !exists { + panic(fmt.Errorf("setBinding: %s: missing", name)) + } + if property.mutable { + property.value = value + self.property[name] = property + } else { + self._runtime.typeErrorResult(strict) + } +} + +func (self *_dclStash) setValue(name string, value Value, throw bool) { + if !self.hasBinding(name) { + self.createBinding(name, false, value) // NOT deletable by default + } else { + self.setBinding(name, value, throw) + } +} + +// FIXME This is called a __lot__ +func (self *_dclStash) getBinding(name string, throw bool) Value { + property, exists := self.property[name] + if !exists { + panic(fmt.Errorf("getBinding: %s: missing", name)) + } + if !property.mutable && !property.readable { + if throw { // strict? + panic(self._runtime.panicTypeError()) + } + return Value{} + } + return property.value +} + +func (self *_dclStash) deleteBinding(name string) bool { + property, exists := self.property[name] + if !exists { + return true + } + if !property.deletable { + return false + } + delete(self.property, name) + return true +} + +func (self *_dclStash) outer() _stash { + return self._outer +} + +func (self *_dclStash) newReference(name string, strict bool, _ _at) _reference { + return &_stashReference{ + name: name, + base: self, + } +} + +// ======== +// _fnStash +// ======== + +type _fnStash struct { + _dclStash + arguments *_object + indexOfArgumentName map[string]string +} + +func (runtime *_runtime) newFunctionStash(outer _stash) *_fnStash { + return &_fnStash{ + _dclStash: _dclStash{ + _runtime: runtime, + _outer: outer, + property: map[string]_dclProperty{}, + }, + } +} + +func (in *_fnStash) clone(clone *_clone) _stash { + out, exists := clone.fnStash(in) + if exists { + return out + } + dclStash := in._dclStash.clone(clone).(*_dclStash) + index := make(map[string]string, len(in.indexOfArgumentName)) + for name, value := range in.indexOfArgumentName { + index[name] = value + } + *out = _fnStash{ + _dclStash: *dclStash, + arguments: clone.object(in.arguments), + indexOfArgumentName: index, + } + return out +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/string_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/string_test.go new file mode 100644 index 0000000000..b7b06324b7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/string_test.go @@ -0,0 +1,365 @@ +package otto + +import ( + "testing" +) + +func TestString(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = (new String("xyzzy")).length; + def = new String().length; + ghi = new String("Nothing happens.").length; + `) + test("abc", 5) + test("def", 0) + test("ghi", 16) + test(`"".length`, 0) + test(`"a\uFFFFbc".length`, 4) + test(`String(+0)`, "0") + test(`String(-0)`, "0") + test(`""+-0`, "0") + test(` + var abc = Object.getOwnPropertyDescriptor(String, "prototype"); + [ [ typeof String.prototype ], + [ abc.writable, abc.enumerable, abc.configurable ] ]; + `, "object,false,false,false") + }) +} + +func TestString_charAt(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = "xyzzy".charAt(0) + def = "xyzzy".charAt(11) + `) + test("abc", "x") + test("def", "") + }) +} + +func TestString_charCodeAt(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(` + abc = "xyzzy".charCodeAt(0) + def = "xyzzy".charCodeAt(11) + `) + test("abc", 120) + test("def", _NaN) + }) +} + +func TestString_fromCharCode(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`String.fromCharCode()`, []uint16{}) + test(`String.fromCharCode(88, 121, 122, 122, 121)`, []uint16{88, 121, 122, 122, 121}) // FIXME terst, Double-check these... + test(`String.fromCharCode("88", 121, 122, 122.05, 121)`, []uint16{88, 121, 122, 122, 121}) + test(`String.fromCharCode("88", 121, 122, NaN, 121)`, []uint16{88, 121, 122, 0, 121}) + test(`String.fromCharCode("0x21")`, []uint16{33}) + test(`String.fromCharCode(-1).charCodeAt(0)`, 65535) + test(`String.fromCharCode(65535).charCodeAt(0)`, 65535) + test(`String.fromCharCode(65534).charCodeAt(0)`, 65534) + test(`String.fromCharCode(4294967295).charCodeAt(0)`, 65535) + test(`String.fromCharCode(4294967294).charCodeAt(0)`, 65534) + test(`String.fromCharCode(0x0024) === "$"`, true) + }) +} + +func TestString_concat(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`"".concat()`, "") + test(`"".concat("abc", "def")`, "abcdef") + test(`"".concat("abc", undefined, "def")`, "abcundefineddef") + }) +} + +func TestString_indexOf(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`"".indexOf("")`, 0) + test(`"".indexOf("", 11)`, 0) + test(`"abc".indexOf("")`, 0) + test(`"abc".indexOf("", 11)`, 3) + test(`"abc".indexOf("a")`, 0) + test(`"abc".indexOf("bc")`, 1) + test(`"abc".indexOf("bc", 11)`, -1) + test(`"$$abcdabcd".indexOf("ab", function(){return -Infinity;}())`, 2) + test(`"$$abcdabcd".indexOf("ab", function(){return NaN;}())`, 2) + + test(` + var abc = {toString:function(){return "\u0041B";}} + var def = {valueOf:function(){return true;}} + var ghi = "ABB\u0041BABAB"; + var jkl; + with(ghi) { + jkl = indexOf(abc, def); + } + jkl; + `, 3) + }) +} + +func TestString_lastIndexOf(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`"".lastIndexOf("")`, 0) + test(`"".lastIndexOf("", 11)`, 0) + test(`"abc".lastIndexOf("")`, 3) + test(`"abc".lastIndexOf("", 11)`, 3) + test(`"abc".lastIndexOf("a")`, 0) + test(`"abc".lastIndexOf("bc")`, 1) + test(`"abc".lastIndexOf("bc", 11)`, 1) + test(`"abc".lastIndexOf("bc", 0)`, -1) + test(`"abc".lastIndexOf("abcabcabc", 2)`, -1) + test(`"abc".lastIndexOf("abc", 0)`, 0) + test(`"abc".lastIndexOf("abc", 1)`, 0) + test(`"abc".lastIndexOf("abc", 2)`, 0) + test(`"abc".lastIndexOf("abc", 3)`, 0) + + test(` + abc = new Object(true); + abc.lastIndexOf = String.prototype.lastIndexOf; + abc.lastIndexOf(true, false); + `, 0) + }) +} + +func TestString_match(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`"abc____abc_abc___".match(/__abc/)`, "__abc") + test(`"abc___abc_abc__abc__abc".match(/abc/g)`, "abc,abc,abc,abc,abc") + test(`"abc____abc_abc___".match(/__abc/g)`, "__abc") + test(` + abc = /abc/g + "abc___abc_abc__abc__abc".match(abc) + `, "abc,abc,abc,abc,abc") + test(`abc.lastIndex`, 23) + }) +} + +func TestString_replace(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`"abc_abc".replace(/abc/, "$&123")`, "abc123_abc") + test(`"abc_abc".replace(/abc/g, "$&123")`, "abc123_abc123") + test(`"abc_abc_".replace(/abc/g, "$&123")`, "abc123_abc123_") + test(`"_abc_abc_".replace(/abc/g, "$&123")`, "_abc123_abc123_") + test(`"abc".replace(/abc/, "$&123")`, "abc123") + test(`"abc_".replace(/abc/, "$&123")`, "abc123_") + test("\"^abc$\".replace(/abc/, \"$`def\")", "^^def$") + test("\"^abc$\".replace(/abc/, \"def$`\")", "^def^$") + test(`"_abc_abd_".replace(/ab(c|d)/g, "$1")`, "_c_d_") + test(` + "_abc_abd_".replace(/ab(c|d)/g, function(){ + }) + `, "_undefined_undefined_") + + test(`"b".replace(/(a)?(b)?/, "_$1_")`, "__") + test(` + "b".replace(/(a)?(b)?/, function(a, b, c, d, e, f){ + return [a, b, c, d, e, f] + }) + `, "b,,b,0,b,") + + test(` + var abc = 'She sells seashells by the seashore.'; + var def = /sh/; + [ abc.replace(def, "$'" + 'sch') ]; + `, "She sells seaells by the seashore.schells by the seashore.") + }) +} + +func TestString_search(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`"abc".search(/abc/)`, 0) + test(`"abc".search(/def/)`, -1) + test(`"abc".search(/c$/)`, 2) + test(`"abc".search(/$/)`, 3) + }) +} + +func TestString_split(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`"abc".split("", 1)`, "a") + test(`"abc".split("", 2)`, "a,b") + test(`"abc".split("", 3)`, "a,b,c") + test(`"abc".split("", 4)`, "a,b,c") + test(`"abc".split("", 11)`, "a,b,c") + test(`"abc".split("", 0)`, "") + test(`"abc".split("")`, "a,b,c") + + test(`"abc".split(undefined)`, "abc") + + test(`"__1__3_1__2__".split("_")`, ",,1,,3,1,,2,,") + + test(`"__1__3_1__2__".split(/_/)`, ",,1,,3,1,,2,,") + + test(`"ab".split(/a*/)`, ",b") + + test(`_ = "Aboldandcoded".split(/<(\/)?([^<>]+)>/)`, "A,,B,bold,/,B,and,,CODE,coded,/,CODE,") + test(`_.length`, 13) + test(`_[1] === undefined`, true) + test(`_[12] === ""`, true) + + test(` + var abc = new String("one-1 two-2 three-3"); + var def = abc.split(new RegExp); + + [ def.constructor === Array, abc.length, def.length, def.join('') ]; + `, "true,19,19,one-1 two-2 three-3") + }) +} + +func TestString_slice(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`"abc".slice()`, "abc") + test(`"abc".slice(0)`, "abc") + test(`"abc".slice(0,11)`, "abc") + test(`"abc".slice(0,-1)`, "ab") + test(`"abc".slice(-1,11)`, "c") + test(`abc = "abc"; abc.slice(abc.length+1, 0)`, "") + }) +} + +func TestString_substring(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`"abc".substring()`, "abc") + test(`"abc".substring(0)`, "abc") + test(`"abc".substring(0,11)`, "abc") + test(`"abc".substring(11,0)`, "abc") + test(`"abc".substring(0,-1)`, "") + test(`"abc".substring(-1,11)`, "abc") + test(`"abc".substring(11,1)`, "bc") + test(`"abc".substring(1)`, "bc") + test(`"abc".substring(Infinity, Infinity)`, "") + }) +} + +func TestString_toCase(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`"abc".toLowerCase()`, "abc") + test(`"ABC".toLowerCase()`, "abc") + test(`"abc".toLocaleLowerCase()`, "abc") + test(`"ABC".toLocaleLowerCase()`, "abc") + test(`"abc".toUpperCase()`, "ABC") + test(`"ABC".toUpperCase()`, "ABC") + test(`"abc".toLocaleUpperCase()`, "ABC") + test(`"ABC".toLocaleUpperCase()`, "ABC") + }) +} + +func Test_floatToString(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`String(-1234567890)`, "-1234567890") + test(`-+String(-(-1234567890))`, -1234567890) + test(`String(-1e128)`, "-1e+128") + test(`String(0.12345)`, "0.12345") + test(`String(-0.00000012345)`, "-1.2345e-7") + test(`String(0.0000012345)`, "0.0000012345") + test(`String(1000000000000000000000)`, "1e+21") + test(`String(1e21)`, "1e+21") + test(`String(1E21)`, "1e+21") + test(`String(-1000000000000000000000)`, "-1e+21") + test(`String(-1e21)`, "-1e+21") + test(`String(-1E21)`, "-1e+21") + test(`String(0.0000001)`, "1e-7") + test(`String(1e-7)`, "1e-7") + test(`String(1E-7)`, "1e-7") + test(`String(-0.0000001)`, "-1e-7") + test(`String(-1e-7)`, "-1e-7") + test(`String(-1E-7)`, "-1e-7") + }) +} + +func TestString_indexing(t *testing.T) { + tt(t, func() { + test, _ := test() + + // Actually a test of stringToArrayIndex, under the hood. + test(` + abc = new String("abc"); + index = Math.pow(2, 32); + [ abc.length, abc[index], abc[index+1], abc[index+2], abc[index+3] ]; + `, "3,,,,") + }) +} + +func TestString_trim(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`' \n abc \t \n'.trim();`, "abc") + test(`" abc\u000B".trim()`, "abc") + test(`"abc ".trim()`, "abc") + test(` + var a = "\u180Eabc \u000B " + var b = a.trim() + a.length + b.length + `, 10) + }) +} + +func TestString_trimLeft(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`" abc\u000B".trimLeft()`, "abc\u000B") + test(`"abc ".trimLeft()`, "abc ") + test(` + var a = "\u180Eabc \u000B " + var b = a.trimLeft() + a.length + b.length + `, 13) + }) +} + +func TestString_trimRight(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`" abc\u000B".trimRight()`, " abc") + test(`" abc ".trimRight()`, " abc") + test(` + var a = "\u180Eabc \u000B " + var b = a.trimRight() + a.length + b.length + `, 11) + }) +} + +func TestString_localeCompare(t *testing.T) { + tt(t, func() { + test, _ := test() + + test(`'a'.localeCompare('c');`, -1) + test(`'c'.localeCompare('a');`, 1) + test(`'a'.localeCompare('a');`, 0) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/terst/terst.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/terst/terst.go new file mode 100644 index 0000000000..a25ca8b9c8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/terst/terst.go @@ -0,0 +1,669 @@ +// This file was AUTOMATICALLY GENERATED by terst-import (smuggol) from github.com/robertkrimen/terst + +/* +Package terst is a terse (terst = test + terse), easy-to-use testing library for Go. + +terst is compatible with (and works via) the standard testing package: http://golang.org/pkg/testing + + var is = terst.Is + + func Test(t *testing.T) { + terst.Terst(t, func() { + is("abc", "abc") + + is(1, ">", 0) + + var abc []int + is(abc, nil) + } + } + +Do not import terst directly, instead use `terst-import` to copy it into your testing environment: + +https://github.com/robertkrimen/terst/tree/master/terst-import + + $ go get github.com/robertkrimen/terst/terst-import + + $ terst-import + +*/ +package terst + +import ( + "bytes" + "errors" + "fmt" + "math/big" + "reflect" + "regexp" + "runtime" + "strings" + "sync" + "testing" + "time" +) + +// Is compares two values (got & expect) and returns true if the comparison is true, +// false otherwise. In addition, if the comparison is false, Is will report the error +// in a manner similar to testing.T.Error(...). Is also takes an optional argument, +// a comparator, that changes how the comparison is made. The following +// comparators are available: +// +// == # got == expect (default) +// != # got != expect +// +// > # got > expect (float32, uint, uint16, int, int64, ...) +// >= # got >= expect +// < # got < expect +// <= # got <= expect +// +// =~ # regexp.MustCompile(expect).Match{String}(got) +// !~ # !regexp.MustCompile(expect).Match{String}(got) +// +// Basic usage with the default comparator (==): +// +// Is(, ) +// +// Specifying a different comparator: +// +// Is(, , ) +// +// A simple comparison: +// +// Is(2 + 2, 4) +// +// A bit trickier: +// +// Is(1, ">", 0) +// Is(2 + 2, "!=", 5) +// Is("Nothing happens.", "=~", `ing(\s+)happens\.$`) +// +// Is should only be called under a Terst(t, ...) call. For a standalone version, +// use IsErr. If no scope is found and the comparison is false, then Is will panic the error. +// +func Is(arguments ...interface{}) bool { + err := IsErr(arguments...) + if err != nil { + call := Caller() + if call == nil { + panic(err) + } + call.Error(err) + return false + } + return true +} + +type ( + // ErrFail indicates a comparison failure (e.g. 0 > 1). + ErrFail error + + // ErrInvalid indicates an invalid comparison (e.g. bool == string). + ErrInvalid error +) + +var errInvalid = errors.New("invalid") + +var registry = struct { + table map[uintptr]*_scope + lock sync.RWMutex +}{ + table: map[uintptr]*_scope{}, +} + +func registerScope(pc uintptr, scope *_scope) { + registry.lock.Lock() + defer registry.lock.Unlock() + registry.table[pc] = scope +} + +func scope() *_scope { + scope, _ := findScope() + return scope +} + +func floatCompare(a float64, b float64) int { + if a > b { + return 1 + } else if a < b { + return -1 + } + // NaN == NaN + return 0 +} + +func bigIntCompare(a *big.Int, b *big.Int) int { + return a.Cmp(b) +} + +func bigInt(value int64) *big.Int { + return big.NewInt(value) +} + +func bigUint(value uint64) *big.Int { + return big.NewInt(0).SetUint64(value) +} + +type _toString interface { + String() string +} + +func toString(value interface{}) (string, error) { + switch value := value.(type) { + case string: + return value, nil + case _toString: + return value.String(), nil + case error: + return value.Error(), nil + } + return "", errInvalid +} + +func matchString(got string, expect *regexp.Regexp) (int, error) { + if expect.MatchString(got) { + return 0, nil + } + return -1, nil +} + +func match(got []byte, expect *regexp.Regexp) (int, error) { + if expect.Match(got) { + return 0, nil + } + return -1, nil +} + +func compareMatch(got, expect interface{}) (int, error) { + switch got := got.(type) { + case []byte: + switch expect := expect.(type) { + case string: + matcher, err := regexp.Compile(expect) + if err != nil { + return 0, err + } + return match(got, matcher) + case *regexp.Regexp: + return match(got, expect) + } + default: + if got, err := toString(got); err == nil { + switch expect := expect.(type) { + case string: + matcher, err := regexp.Compile(expect) + if err != nil { + return 0, err + } + return matchString(got, matcher) + case *regexp.Regexp: + return matchString(got, expect) + } + } else { + return 0, err + } + } + return 0, errInvalid +} + +func floatPromote(value reflect.Value) (float64, error) { + kind := value.Kind() + if reflect.Int <= kind && kind <= reflect.Int64 { + return float64(value.Int()), nil + } + if reflect.Uint <= kind && kind <= reflect.Uint64 { + return float64(value.Uint()), nil + } + if reflect.Float32 <= kind && kind <= reflect.Float64 { + return value.Float(), nil + } + return 0, errInvalid +} + +func bigIntPromote(value reflect.Value) (*big.Int, error) { + kind := value.Kind() + if reflect.Int <= kind && kind <= reflect.Int64 { + return bigInt(value.Int()), nil + } + if reflect.Uint <= kind && kind <= reflect.Uint64 { + return bigUint(value.Uint()), nil + } + return nil, errInvalid +} + +func compareOther(got, expect interface{}) (int, error) { + { + switch expect.(type) { + case float32, float64: + return compareNumber(got, expect) + case uint, uint8, uint16, uint32, uint64: + return compareNumber(got, expect) + case int, int8, int16, int32, int64: + return compareNumber(got, expect) + case string: + var err error + got, err = toString(got) + if err != nil { + return 0, err + } + case nil: + got := reflect.ValueOf(got) + switch got.Kind() { + case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface: + if got.IsNil() { + return 0, nil + } + return -1, nil + case reflect.Invalid: // reflect.Invalid: var abc interface{} = nil + return 0, nil + } + return 0, errInvalid + } + } + + if reflect.ValueOf(got).Type() != reflect.ValueOf(expect).Type() { + return 0, errInvalid + } + + if reflect.DeepEqual(got, expect) { + return 0, nil + } + return -1, nil +} + +func compareNumber(got, expect interface{}) (int, error) { + { + got := reflect.ValueOf(got) + k0 := got.Kind() + expect := reflect.ValueOf(expect) + k1 := expect.Kind() + if reflect.Float32 <= k0 && k0 <= reflect.Float64 || + reflect.Float32 <= k1 && k1 <= reflect.Float64 { + got, err := floatPromote(got) + if err != nil { + return 0, err + } + expect, err := floatPromote(expect) + if err != nil { + return 0, err + } + return floatCompare(got, expect), nil + } else { + got, err := bigIntPromote(got) + if err != nil { + return 0, err + } + expect, err := bigIntPromote(expect) + if err != nil { + return 0, err + } + return got.Cmp(expect), nil + } + } + + return 0, errInvalid +} + +// IsErr compares two values (got & expect) and returns nil if the comparison is true, an ErrFail if +// the comparison is false, or an ErrInvalid if the comparison is invalid. IsErr also +// takes an optional argument, a comparator, that changes how the comparison is made. +// +// Is & IsErr are similar but different: +// +// Is(...) // Should only be called within a Terst(...) call +// IsErr(...) // A standalone comparator, the same as Is, just without the automatic reporting +// +func IsErr(arguments ...interface{}) error { + var got, expect interface{} + comparator := "==" + switch len(arguments) { + case 0, 1: + return fmt.Errorf("invalid number of arguments to IsErr: %d", len(arguments)) + case 2: + got, expect = arguments[0], arguments[1] + default: + if value, ok := arguments[1].(string); ok { + comparator = value + } else { + return fmt.Errorf("invalid comparator: %v", arguments[1]) + } + got, expect = arguments[0], arguments[2] + } + + var result int + var err error + + switch comparator { + case "<", "<=", ">", ">=": + result, err = compareNumber(got, expect) + case "=~", "!~": + result, err = compareMatch(got, expect) + case "==", "!=": + result, err = compareOther(got, expect) + default: + return fmt.Errorf("invalid comparator: %s", comparator) + } + + if err == errInvalid { + return ErrInvalid(fmt.Errorf( + "\nINVALID (%s):\n got: %v (%T)\n expected: %v (%T)", + comparator, + got, got, + expect, expect, + )) + } else if err != nil { + return err + } + + equality, pass := false, false + + switch comparator { + case "==", "=~": + equality = true + pass = result == 0 + case "!=", "!~": + equality = true + pass = result != 0 + case "<": + pass = result < 0 + case "<=": + pass = result <= 0 + case ">": + pass = result > 0 + case ">=": + pass = result >= 0 + } + + if !pass { + if equality { + if comparator[1] == '~' { + if value, ok := got.([]byte); ok { + return ErrFail(fmt.Errorf( + "\nFAIL (%s)\n got: %s %v%s\nexpected: %v%s", + comparator, + value, got, typeKindString(got), + expect, typeKindString(expect), + )) + } + } + return ErrFail(fmt.Errorf( + "\nFAIL (%s)\n got: %v%s\nexpected: %v%s", + comparator, + got, typeKindString(got), + expect, typeKindString(expect), + )) + } + return ErrFail(fmt.Errorf( + "\nFAIL (%s)\n got: %v%s\nexpected: %s %v%s", + comparator, + got, typeKindString(got), + comparator, expect, typeKindString(expect), + )) + } + + return nil +} + +func typeKindString(value interface{}) string { + reflectValue := reflect.ValueOf(value) + kind := reflectValue.Kind().String() + result := fmt.Sprintf("%T", value) + if kind == result { + if kind == "string" { + return "" + } + return fmt.Sprintf(" (%T)", value) + } + return fmt.Sprintf(" (%T=%s)", value, kind) +} + +func (scope *_scope) reset() { + scope.name = "" + scope.output = scope.output[:] + scope.start = time.Time{} + scope.duration = 0 +} + +// Terst creates a testing scope, where Is can be called and errors will be reported +// according to the top-level location of the comparison, and not where the Is call +// actually takes place. For example: +// +// func test(value int) { +// Is(value, 5) // <--- This failure is reported below. +// } +// +// Terst(t, func(){ +// +// Is(2, ">", 3) // <--- An error is reported here. +// +// test(5) // <--- An error is reported here. +// +// }) +// +func Terst(t *testing.T, arguments ...func()) { + scope := &_scope{ + t: t, + } + + pc, _, _, ok := runtime.Caller(1) // TODO Associate with the Test... func + if !ok { + panic("Here be dragons.") + } + + _, scope.testFunc = findTestFunc() + + registerScope(pc, scope) + + for _, fn := range arguments { + func() { + scope.reset() + name := scope.testFunc.Name() + index := strings.LastIndex(scope.testFunc.Name(), ".") + if index >= 0 { + name = name[index+1:] + "(Terst)" + } else { + name = "(Terst)" + } + name = "(Terst)" + scope.name = name + scope.start = time.Now() + defer func() { + scope.duration = time.Now().Sub(scope.start) + if err := recover(); err != nil { + scope.t.Fail() + scope.report() + panic(err) + } + scope.report() + }() + fn() + }() + } +} + +// From "testing" +func (scope *_scope) report() { + format := "~~~ %s: (Terst)\n%s" + if scope.t.Failed() { + fmt.Printf(format, "FAIL", scope.output) + } else if testing.Verbose() && len(scope.output) > 0 { + fmt.Printf(format, "PASS", scope.output) + } +} + +func (scope *_scope) log(call _entry, str string) { + scope.mu.Lock() + defer scope.mu.Unlock() + scope.output = append(scope.output, decorate(call, str)...) +} + +// decorate prefixes the string with the file and line of the call site +// and inserts the final newline if needed and indentation tabs for formascing. +func decorate(call _entry, s string) string { + + file, line := call.File, call.Line + if call.PC > 0 { + // Truncate file name at last file name separator. + if index := strings.LastIndex(file, "/"); index >= 0 { + file = file[index+1:] + } else if index = strings.LastIndex(file, "\\"); index >= 0 { + file = file[index+1:] + } + } else { + file = "???" + line = 1 + } + buf := new(bytes.Buffer) + // Every line is indented at least one tab. + buf.WriteByte('\t') + fmt.Fprintf(buf, "%s:%d: ", file, line) + lines := strings.Split(s, "\n") + if l := len(lines); l > 1 && lines[l-1] == "" { + lines = lines[:l-1] + } + for i, line := range lines { + if i > 0 { + // Second and subsequent lines are indented an extra tab. + buf.WriteString("\n\t\t") + } + buf.WriteString(line) + } + buf.WriteByte('\n') + return buf.String() +} + +func findScope() (*_scope, _entry) { + registry.lock.RLock() + defer registry.lock.RUnlock() + table := registry.table + depth := 2 // Starting depth + call := _entry{} + for { + pc, _, _, ok := runtime.Caller(depth) + if !ok { + break + } + if scope, exists := table[pc]; exists { + pc, file, line, _ := runtime.Caller(depth - 3) // Terst(...) + func(){}() + fn() => ???() + call.PC = pc + call.File = file + call.Line = line + return scope, call + } + depth++ + } + return nil, _entry{} +} + +// Call is a reference to a line immediately under a Terst testing scope. +type Call struct { + scope *_scope + entry _entry +} + +// Caller will search the stack, looking for a Terst testing scope. If a scope +// is found, then Caller returns a Call for logging errors, accessing testing.T, etc. +// If no scope is found, Caller returns nil. +func Caller() *Call { + scope, entry := findScope() + if scope == nil { + return nil + } + return &Call{ + scope: scope, + entry: entry, + } +} + +// TestFunc returns the *runtime.Func entry for the top-level Test...(t testing.T) +// function. +func (cl *Call) TestFunc() *runtime.Func { + return cl.scope.testFunc +} + +// T returns the original testing.T passed to Terst(...) +func (cl *Call) T() *testing.T { + return cl.scope.t +} + +// Log is the terst version of `testing.T.Log` +func (cl *Call) Log(arguments ...interface{}) { + cl.scope.log(cl.entry, fmt.Sprintln(arguments...)) +} + +// Logf is the terst version of `testing.T.Logf` +func (cl *Call) Logf(format string, arguments ...interface{}) { + cl.scope.log(cl.entry, fmt.Sprintf(format, arguments...)) +} + +// Error is the terst version of `testing.T.Error` +func (cl *Call) Error(arguments ...interface{}) { + cl.scope.log(cl.entry, fmt.Sprintln(arguments...)) + cl.scope.t.Fail() +} + +// Errorf is the terst version of `testing.T.Errorf` +func (cl *Call) Errorf(format string, arguments ...interface{}) { + cl.scope.log(cl.entry, fmt.Sprintf(format, arguments...)) + cl.scope.t.Fail() +} + +// Skip is the terst version of `testing.T.Skip` +func (cl *Call) Skip(arguments ...interface{}) { + cl.scope.log(cl.entry, fmt.Sprintln(arguments...)) + cl.scope.t.SkipNow() +} + +// Skipf is the terst version of `testing.T.Skipf` +func (cl *Call) Skipf(format string, arguments ...interface{}) { + cl.scope.log(cl.entry, fmt.Sprintf(format, arguments...)) + cl.scope.t.SkipNow() +} + +type _scope struct { + t *testing.T + testFunc *runtime.Func + name string + mu sync.RWMutex + output []byte + start time.Time + duration time.Duration +} + +type _entry struct { + PC uintptr + File string + Line int + Func *runtime.Func +} + +func _findFunc(match string) (_entry, *runtime.Func) { + depth := 2 // Starting depth + for { + pc, file, line, ok := runtime.Caller(depth) + if !ok { + break + } + fn := runtime.FuncForPC(pc) + name := fn.Name() + if index := strings.LastIndex(name, match); index >= 0 { + // Assume we have an instance of TestXyzzy in a _test file + return _entry{ + PC: pc, + File: file, + Line: line, + Func: fn, + }, fn + } + depth++ + } + return _entry{}, nil +} + +func findTestFunc() (_entry, *runtime.Func) { + return _findFunc(".Test") +} + +func findTerstFunc() (_entry, *runtime.Func) { + return _findFunc(".Terst") +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/test/Makefile b/Godeps/_workspace/src/github.com/robertkrimen/otto/test/Makefile new file mode 100644 index 0000000000..ac76fdeacf --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/test/Makefile @@ -0,0 +1,26 @@ +.PHONY: test fetch clean build err report + +TESTER := tester + +test: $(TESTER) + for test in test-*.js; do ./$^ -test=true $$test 1>/dev/null || exit 1; done + @echo PASS + +report: $(TESTER) + ./$^ -report | grep -v "MT READY" + +fetch: $(TESTER) + ./$^ fetch + +build: + go build -a -o $(TESTER) + +$(TESTER): tester.go + $(MAKE) build + +clean: + rm -f test-*.js + rm -f $(TESTER) + +err: $(TESTER) + for test in test-*.js; do ./$^ $$test; done 2>$@ diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/test/tester.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/test/tester.go new file mode 100644 index 0000000000..ea694fd8de --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/test/tester.go @@ -0,0 +1,196 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "net/http" + "os" + "regexp" + "strings" + "sync" + "text/tabwriter" + + "github.com/robertkrimen/otto" + "github.com/robertkrimen/otto/parser" +) + +var flag_test *bool = flag.Bool("test", false, "") +var flag_report *bool = flag.Bool("report", false, "") + +var match_ReferenceError_not_defined = regexp.MustCompile(`^ReferenceError: \S+ is not defined$`) +var match_lookahead = regexp.MustCompile(`Invalid regular expression: re2: Invalid \(\?[=!]\) `) +var match_backreference = regexp.MustCompile(`Invalid regular expression: re2: Invalid \\\d `) +var match_TypeError_undefined = regexp.MustCompile(`^TypeError: Cannot access member '[^']+' of undefined$`) + +var target = map[string]string{ + "test-angular-bindonce.js": "fail", // (anonymous): Line 1:944 Unexpected token ( (and 40 more errors) + "test-jsforce.js": "fail", // (anonymous): Line 9:28329 RuneError (and 5 more errors) + "test-chaplin.js": "parse", // Error: Chaplin requires Common.js or AMD modules + "test-dropbox.js.js": "parse", // Error: dropbox.js loaded in an unsupported JavaScript environment. + "test-epitome.js": "parse", // TypeError: undefined is not a function + "test-portal.js": "parse", // TypeError + "test-reactive-coffee.js": "parse", // Dependencies are not met for reactive: _ and $ not found + "test-scriptaculous.js": "parse", // script.aculo.us requires the Prototype JavaScript framework >= 1.6.0.3 + "test-waypoints.js": "parse", // TypeError: undefined is not a function + "test-webuploader.js": "parse", // Error: `jQuery` is undefined + "test-xuijs.js": "parse", // TypeError: undefined is not a function +} + +// http://cdnjs.com/ +// http://api.cdnjs.com/libraries + +func fetch(name, location string) error { + response, err := http.Get(location) + if err != nil { + return err + } + defer response.Body.Close() + body, err := ioutil.ReadAll(response.Body) + if err != nil { + return err + } + + if !strings.HasSuffix(location, ".js") { + return nil + } + + filename := "test-" + name + ".js" + fmt.Println(filename, len(body)) + return ioutil.WriteFile(filename, body, 0644) +} + +func test(filename string) error { + script, err := ioutil.ReadFile(filename) + if err != nil { + return err + } + + if !*flag_report { + fmt.Fprintln(os.Stdout, filename, len(script)) + } + + parse := false + option := target[filename] + + if option != "parse" { + vm := otto.New() + _, err = vm.Run(string(script)) + if err != nil { + value := err.Error() + switch { + case match_ReferenceError_not_defined.MatchString(value): + case match_TypeError_undefined.MatchString(value): + case match_lookahead.MatchString(value): + case match_backreference.MatchString(value): + default: + return err + } + parse = true + } + } + + if parse { + _, err = parser.ParseFile(nil, filename, string(script), parser.IgnoreRegExpErrors) + if err != nil { + return err + } + target[filename] = "parse" + } + + return nil +} + +func main() { + flag.Parse() + + filename := "" + + err := func() error { + + if flag.Arg(0) == "fetch" { + response, err := http.Get("http://api.cdnjs.com/libraries") + if err != nil { + return err + } + defer response.Body.Close() + body, err := ioutil.ReadAll(response.Body) + if err != nil { + return err + } + + var tmp map[string]interface{} + + err = json.Unmarshal(body, &tmp) + if err != nil { + return err + } + + var wg sync.WaitGroup + + for _, value := range tmp["results"].([]interface{}) { + wg.Add(1) + library := value.(map[string]interface{}) + go func() { + defer wg.Done() + fetch(library["name"].(string), library["latest"].(string)) + }() + } + + wg.Wait() + + return nil + } + + if *flag_report { + files, err := ioutil.ReadDir(".") + if err != nil { + return err + } + writer := tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0) + fmt.Fprintln(writer, "", "\t| Status") + fmt.Fprintln(writer, "---", "\t| ---") + for _, file := range files { + filename := file.Name() + if !strings.HasPrefix(filename, "test-") { + continue + } + err := test(filename) + option := target[filename] + name := strings.TrimPrefix(strings.TrimSuffix(filename, ".js"), "test-") + if err == nil { + switch option { + case "": + fmt.Fprintln(writer, name, "\t| pass") + case "parse": + fmt.Fprintln(writer, name, "\t| pass (parse)") + case "re2": + continue + fmt.Fprintln(writer, name, "\t| unknown (re2)") + } + } else { + fmt.Fprintln(writer, name, "\t| fail") + } + } + writer.Flush() + return nil + } + + filename = flag.Arg(0) + return test(filename) + + }() + if err != nil { + if filename != "" { + if *flag_test && target[filename] == "fail" { + goto exit + } + fmt.Fprintf(os.Stderr, "%s: %s\n", filename, err.Error()) + } else { + fmt.Fprintln(os.Stderr, err) + } + os.Exit(64) + } +exit: +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/testing_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/testing_test.go new file mode 100644 index 0000000000..bf820bc0c9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/testing_test.go @@ -0,0 +1,135 @@ +package otto + +import ( + "./terst" + "errors" + "strings" + "testing" + "time" +) + +func tt(t *testing.T, arguments ...func()) { + halt := errors.New("A test was taking too long") + timer := time.AfterFunc(2*time.Second, func() { + panic(halt) + }) + defer func() { + timer.Stop() + }() + terst.Terst(t, arguments...) +} + +func is(arguments ...interface{}) bool { + var got, expect interface{} + + switch len(arguments) { + case 0, 1: + return terst.Is(arguments...) + case 2: + got, expect = arguments[0], arguments[1] + default: + got, expect = arguments[0], arguments[2] + } + + switch value := got.(type) { + case Value: + if value.value != nil { + got = value.value + } + case *Error: + if value != nil { + got = value.Error() + } + if expect == nil { + // FIXME This is weird + expect = "" + } + } + + if len(arguments) == 2 { + arguments[0] = got + arguments[1] = expect + } else { + arguments[0] = got + arguments[2] = expect + } + + return terst.Is(arguments...) +} + +func test(arguments ...interface{}) (func(string, ...interface{}) Value, *_tester) { + tester := newTester() + if len(arguments) > 0 { + tester.test(arguments[0].(string)) + } + return tester.test, tester +} + +type _tester struct { + vm *Otto +} + +func newTester() *_tester { + return &_tester{ + vm: New(), + } +} + +func (self *_tester) Get(name string) (Value, error) { + return self.vm.Get(name) +} + +func (self *_tester) Set(name string, value interface{}) Value { + err := self.vm.Set(name, value) + is(err, nil) + if err != nil { + terst.Caller().T().FailNow() + } + return self.vm.getValue(name) +} + +func (self *_tester) Run(src interface{}) (Value, error) { + return self.vm.Run(src) +} + +func (self *_tester) test(name string, expect ...interface{}) Value { + vm := self.vm + raise := false + defer func() { + if caught := recover(); caught != nil { + if exception, ok := caught.(*_exception); ok { + caught = exception.eject() + } + if raise { + if len(expect) > 0 { + is(caught, expect[0]) + } + } else { + dbg("Panic, caught:", caught) + panic(caught) + } + } + }() + var value Value + var err error + if isIdentifier(name) { + value = vm.getValue(name) + } else { + source := name + index := strings.Index(source, "raise:") + if index == 0 { + raise = true + source = source[6:] + source = strings.TrimLeft(source, " ") + } + value, err = vm.runtime.cmpl_run(source) + if err != nil { + panic(err) + } + } + value = value.resolve() + if len(expect) > 0 { + is(value, expect[0]) + } + return value +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/token/Makefile b/Godeps/_workspace/src/github.com/robertkrimen/otto/token/Makefile new file mode 100644 index 0000000000..1e85c73488 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/token/Makefile @@ -0,0 +1,2 @@ +token_const.go: tokenfmt + ./$^ | gofmt > $@ diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/token/README.markdown b/Godeps/_workspace/src/github.com/robertkrimen/otto/token/README.markdown new file mode 100644 index 0000000000..ff3b161040 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/token/README.markdown @@ -0,0 +1,171 @@ +# token +-- + import "github.com/robertkrimen/otto/token" + +Package token defines constants representing the lexical tokens of JavaScript +(ECMA5). + +## Usage + +```go +const ( + ILLEGAL + EOF + COMMENT + KEYWORD + + STRING + BOOLEAN + NULL + NUMBER + IDENTIFIER + + PLUS // + + MINUS // - + MULTIPLY // * + SLASH // / + REMAINDER // % + + AND // & + OR // | + EXCLUSIVE_OR // ^ + SHIFT_LEFT // << + SHIFT_RIGHT // >> + UNSIGNED_SHIFT_RIGHT // >>> + AND_NOT // &^ + + ADD_ASSIGN // += + SUBTRACT_ASSIGN // -= + MULTIPLY_ASSIGN // *= + QUOTIENT_ASSIGN // /= + REMAINDER_ASSIGN // %= + + AND_ASSIGN // &= + OR_ASSIGN // |= + EXCLUSIVE_OR_ASSIGN // ^= + SHIFT_LEFT_ASSIGN // <<= + SHIFT_RIGHT_ASSIGN // >>= + UNSIGNED_SHIFT_RIGHT_ASSIGN // >>>= + AND_NOT_ASSIGN // &^= + + LOGICAL_AND // && + LOGICAL_OR // || + INCREMENT // ++ + DECREMENT // -- + + EQUAL // == + STRICT_EQUAL // === + LESS // < + GREATER // > + ASSIGN // = + NOT // ! + + BITWISE_NOT // ~ + + NOT_EQUAL // != + STRICT_NOT_EQUAL // !== + LESS_OR_EQUAL // <= + GREATER_OR_EQUAL // >= + + LEFT_PARENTHESIS // ( + LEFT_BRACKET // [ + LEFT_BRACE // { + COMMA // , + PERIOD // . + + RIGHT_PARENTHESIS // ) + RIGHT_BRACKET // ] + RIGHT_BRACE // } + SEMICOLON // ; + COLON // : + QUESTION_MARK // ? + + IF + IN + DO + + VAR + FOR + NEW + TRY + + THIS + ELSE + CASE + VOID + WITH + + WHILE + BREAK + CATCH + THROW + + RETURN + TYPEOF + DELETE + SWITCH + + DEFAULT + FINALLY + + FUNCTION + CONTINUE + DEBUGGER + + INSTANCEOF +) +``` + +#### type Token + +```go +type Token int +``` + +Token is the set of lexical tokens in JavaScript (ECMA5). + +#### func IsKeyword + +```go +func IsKeyword(literal string) (Token, bool) +``` +IsKeyword returns the keyword token if literal is a keyword, a KEYWORD token if +the literal is a future keyword (const, let, class, super, ...), or 0 if the +literal is not a keyword. + +If the literal is a keyword, IsKeyword returns a second value indicating if the +literal is considered a future keyword in strict-mode only. + +7.6.1.2 Future Reserved Words: + + const + class + enum + export + extends + import + super + +7.6.1.2 Future Reserved Words (strict): + + implements + interface + let + package + private + protected + public + static + +#### func (Token) String + +```go +func (tkn Token) String() string +``` +String returns the string corresponding to the token. For operators, delimiters, +and keywords the string is the actual token string (e.g., for the token PLUS, +the String() is "+"). For all other tokens the string corresponds to the token +name (e.g. for the token IDENTIFIER, the string is "IDENTIFIER"). + +-- +**godocdown** http://github.com/robertkrimen/godocdown diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/token/token.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/token/token.go new file mode 100644 index 0000000000..0e941ac96d --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/token/token.go @@ -0,0 +1,116 @@ +// Package token defines constants representing the lexical tokens of JavaScript (ECMA5). +package token + +import ( + "strconv" +) + +// Token is the set of lexical tokens in JavaScript (ECMA5). +type Token int + +// String returns the string corresponding to the token. +// For operators, delimiters, and keywords the string is the actual +// token string (e.g., for the token PLUS, the String() is +// "+"). For all other tokens the string corresponds to the token +// name (e.g. for the token IDENTIFIER, the string is "IDENTIFIER"). +// +func (tkn Token) String() string { + if 0 == tkn { + return "UNKNOWN" + } + if tkn < Token(len(token2string)) { + return token2string[tkn] + } + return "token(" + strconv.Itoa(int(tkn)) + ")" +} + +// This is not used for anything +func (tkn Token) precedence(in bool) int { + + switch tkn { + case LOGICAL_OR: + return 1 + + case LOGICAL_AND: + return 2 + + case OR, OR_ASSIGN: + return 3 + + case EXCLUSIVE_OR: + return 4 + + case AND, AND_ASSIGN, AND_NOT, AND_NOT_ASSIGN: + return 5 + + case EQUAL, + NOT_EQUAL, + STRICT_EQUAL, + STRICT_NOT_EQUAL: + return 6 + + case LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL, INSTANCEOF: + return 7 + + case IN: + if in { + return 7 + } + return 0 + + case SHIFT_LEFT, SHIFT_RIGHT, UNSIGNED_SHIFT_RIGHT: + fallthrough + case SHIFT_LEFT_ASSIGN, SHIFT_RIGHT_ASSIGN, UNSIGNED_SHIFT_RIGHT_ASSIGN: + return 8 + + case PLUS, MINUS, ADD_ASSIGN, SUBTRACT_ASSIGN: + return 9 + + case MULTIPLY, SLASH, REMAINDER, MULTIPLY_ASSIGN, QUOTIENT_ASSIGN, REMAINDER_ASSIGN: + return 11 + } + return 0 +} + +type _keyword struct { + token Token + futureKeyword bool + strict bool +} + +// IsKeyword returns the keyword token if literal is a keyword, a KEYWORD token +// if the literal is a future keyword (const, let, class, super, ...), or 0 if the literal is not a keyword. +// +// If the literal is a keyword, IsKeyword returns a second value indicating if the literal +// is considered a future keyword in strict-mode only. +// +// 7.6.1.2 Future Reserved Words: +// +// const +// class +// enum +// export +// extends +// import +// super +// +// 7.6.1.2 Future Reserved Words (strict): +// +// implements +// interface +// let +// package +// private +// protected +// public +// static +// +func IsKeyword(literal string) (Token, bool) { + if keyword, exists := keywordTable[literal]; exists { + if keyword.futureKeyword { + return KEYWORD, keyword.strict + } + return keyword.token, false + } + return 0, false +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/token/token_const.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/token/token_const.go new file mode 100644 index 0000000000..b1d83c6de9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/token/token_const.go @@ -0,0 +1,349 @@ +package token + +const ( + _ Token = iota + + ILLEGAL + EOF + COMMENT + KEYWORD + + STRING + BOOLEAN + NULL + NUMBER + IDENTIFIER + + PLUS // + + MINUS // - + MULTIPLY // * + SLASH // / + REMAINDER // % + + AND // & + OR // | + EXCLUSIVE_OR // ^ + SHIFT_LEFT // << + SHIFT_RIGHT // >> + UNSIGNED_SHIFT_RIGHT // >>> + AND_NOT // &^ + + ADD_ASSIGN // += + SUBTRACT_ASSIGN // -= + MULTIPLY_ASSIGN // *= + QUOTIENT_ASSIGN // /= + REMAINDER_ASSIGN // %= + + AND_ASSIGN // &= + OR_ASSIGN // |= + EXCLUSIVE_OR_ASSIGN // ^= + SHIFT_LEFT_ASSIGN // <<= + SHIFT_RIGHT_ASSIGN // >>= + UNSIGNED_SHIFT_RIGHT_ASSIGN // >>>= + AND_NOT_ASSIGN // &^= + + LOGICAL_AND // && + LOGICAL_OR // || + INCREMENT // ++ + DECREMENT // -- + + EQUAL // == + STRICT_EQUAL // === + LESS // < + GREATER // > + ASSIGN // = + NOT // ! + + BITWISE_NOT // ~ + + NOT_EQUAL // != + STRICT_NOT_EQUAL // !== + LESS_OR_EQUAL // <= + GREATER_OR_EQUAL // >= + + LEFT_PARENTHESIS // ( + LEFT_BRACKET // [ + LEFT_BRACE // { + COMMA // , + PERIOD // . + + RIGHT_PARENTHESIS // ) + RIGHT_BRACKET // ] + RIGHT_BRACE // } + SEMICOLON // ; + COLON // : + QUESTION_MARK // ? + + firstKeyword + IF + IN + DO + + VAR + FOR + NEW + TRY + + THIS + ELSE + CASE + VOID + WITH + + WHILE + BREAK + CATCH + THROW + + RETURN + TYPEOF + DELETE + SWITCH + + DEFAULT + FINALLY + + FUNCTION + CONTINUE + DEBUGGER + + INSTANCEOF + lastKeyword +) + +var token2string = [...]string{ + ILLEGAL: "ILLEGAL", + EOF: "EOF", + COMMENT: "COMMENT", + KEYWORD: "KEYWORD", + STRING: "STRING", + BOOLEAN: "BOOLEAN", + NULL: "NULL", + NUMBER: "NUMBER", + IDENTIFIER: "IDENTIFIER", + PLUS: "+", + MINUS: "-", + MULTIPLY: "*", + SLASH: "/", + REMAINDER: "%", + AND: "&", + OR: "|", + EXCLUSIVE_OR: "^", + SHIFT_LEFT: "<<", + SHIFT_RIGHT: ">>", + UNSIGNED_SHIFT_RIGHT: ">>>", + AND_NOT: "&^", + ADD_ASSIGN: "+=", + SUBTRACT_ASSIGN: "-=", + MULTIPLY_ASSIGN: "*=", + QUOTIENT_ASSIGN: "/=", + REMAINDER_ASSIGN: "%=", + AND_ASSIGN: "&=", + OR_ASSIGN: "|=", + EXCLUSIVE_OR_ASSIGN: "^=", + SHIFT_LEFT_ASSIGN: "<<=", + SHIFT_RIGHT_ASSIGN: ">>=", + UNSIGNED_SHIFT_RIGHT_ASSIGN: ">>>=", + AND_NOT_ASSIGN: "&^=", + LOGICAL_AND: "&&", + LOGICAL_OR: "||", + INCREMENT: "++", + DECREMENT: "--", + EQUAL: "==", + STRICT_EQUAL: "===", + LESS: "<", + GREATER: ">", + ASSIGN: "=", + NOT: "!", + BITWISE_NOT: "~", + NOT_EQUAL: "!=", + STRICT_NOT_EQUAL: "!==", + LESS_OR_EQUAL: "<=", + GREATER_OR_EQUAL: ">=", + LEFT_PARENTHESIS: "(", + LEFT_BRACKET: "[", + LEFT_BRACE: "{", + COMMA: ",", + PERIOD: ".", + RIGHT_PARENTHESIS: ")", + RIGHT_BRACKET: "]", + RIGHT_BRACE: "}", + SEMICOLON: ";", + COLON: ":", + QUESTION_MARK: "?", + IF: "if", + IN: "in", + DO: "do", + VAR: "var", + FOR: "for", + NEW: "new", + TRY: "try", + THIS: "this", + ELSE: "else", + CASE: "case", + VOID: "void", + WITH: "with", + WHILE: "while", + BREAK: "break", + CATCH: "catch", + THROW: "throw", + RETURN: "return", + TYPEOF: "typeof", + DELETE: "delete", + SWITCH: "switch", + DEFAULT: "default", + FINALLY: "finally", + FUNCTION: "function", + CONTINUE: "continue", + DEBUGGER: "debugger", + INSTANCEOF: "instanceof", +} + +var keywordTable = map[string]_keyword{ + "if": _keyword{ + token: IF, + }, + "in": _keyword{ + token: IN, + }, + "do": _keyword{ + token: DO, + }, + "var": _keyword{ + token: VAR, + }, + "for": _keyword{ + token: FOR, + }, + "new": _keyword{ + token: NEW, + }, + "try": _keyword{ + token: TRY, + }, + "this": _keyword{ + token: THIS, + }, + "else": _keyword{ + token: ELSE, + }, + "case": _keyword{ + token: CASE, + }, + "void": _keyword{ + token: VOID, + }, + "with": _keyword{ + token: WITH, + }, + "while": _keyword{ + token: WHILE, + }, + "break": _keyword{ + token: BREAK, + }, + "catch": _keyword{ + token: CATCH, + }, + "throw": _keyword{ + token: THROW, + }, + "return": _keyword{ + token: RETURN, + }, + "typeof": _keyword{ + token: TYPEOF, + }, + "delete": _keyword{ + token: DELETE, + }, + "switch": _keyword{ + token: SWITCH, + }, + "default": _keyword{ + token: DEFAULT, + }, + "finally": _keyword{ + token: FINALLY, + }, + "function": _keyword{ + token: FUNCTION, + }, + "continue": _keyword{ + token: CONTINUE, + }, + "debugger": _keyword{ + token: DEBUGGER, + }, + "instanceof": _keyword{ + token: INSTANCEOF, + }, + "const": _keyword{ + token: KEYWORD, + futureKeyword: true, + }, + "class": _keyword{ + token: KEYWORD, + futureKeyword: true, + }, + "enum": _keyword{ + token: KEYWORD, + futureKeyword: true, + }, + "export": _keyword{ + token: KEYWORD, + futureKeyword: true, + }, + "extends": _keyword{ + token: KEYWORD, + futureKeyword: true, + }, + "import": _keyword{ + token: KEYWORD, + futureKeyword: true, + }, + "super": _keyword{ + token: KEYWORD, + futureKeyword: true, + }, + "implements": _keyword{ + token: KEYWORD, + futureKeyword: true, + strict: true, + }, + "interface": _keyword{ + token: KEYWORD, + futureKeyword: true, + strict: true, + }, + "let": _keyword{ + token: KEYWORD, + futureKeyword: true, + strict: true, + }, + "package": _keyword{ + token: KEYWORD, + futureKeyword: true, + strict: true, + }, + "private": _keyword{ + token: KEYWORD, + futureKeyword: true, + strict: true, + }, + "protected": _keyword{ + token: KEYWORD, + futureKeyword: true, + strict: true, + }, + "public": _keyword{ + token: KEYWORD, + futureKeyword: true, + strict: true, + }, + "static": _keyword{ + token: KEYWORD, + futureKeyword: true, + strict: true, + }, +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/token/tokenfmt b/Godeps/_workspace/src/github.com/robertkrimen/otto/token/tokenfmt new file mode 100644 index 0000000000..63dd5d9e6d --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/token/tokenfmt @@ -0,0 +1,222 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +my (%token, @order, @keywords); + +{ + my $keywords; + my @const; + push @const, <<_END_; +package token + +const( + _ Token = iota +_END_ + + for (split m/\n/, <<_END_) { +ILLEGAL +EOF +COMMENT +KEYWORD + +STRING +BOOLEAN +NULL +NUMBER +IDENTIFIER + +PLUS + +MINUS - +MULTIPLY * +SLASH / +REMAINDER % + +AND & +OR | +EXCLUSIVE_OR ^ +SHIFT_LEFT << +SHIFT_RIGHT >> +UNSIGNED_SHIFT_RIGHT >>> +AND_NOT &^ + +ADD_ASSIGN += +SUBTRACT_ASSIGN -= +MULTIPLY_ASSIGN *= +QUOTIENT_ASSIGN /= +REMAINDER_ASSIGN %= + +AND_ASSIGN &= +OR_ASSIGN |= +EXCLUSIVE_OR_ASSIGN ^= +SHIFT_LEFT_ASSIGN <<= +SHIFT_RIGHT_ASSIGN >>= +UNSIGNED_SHIFT_RIGHT_ASSIGN >>>= +AND_NOT_ASSIGN &^= + +LOGICAL_AND && +LOGICAL_OR || +INCREMENT ++ +DECREMENT -- + +EQUAL == +STRICT_EQUAL === +LESS < +GREATER > +ASSIGN = +NOT ! + +BITWISE_NOT ~ + +NOT_EQUAL != +STRICT_NOT_EQUAL !== +LESS_OR_EQUAL <= +GREATER_OR_EQUAL <= + +LEFT_PARENTHESIS ( +LEFT_BRACKET [ +LEFT_BRACE { +COMMA , +PERIOD . + +RIGHT_PARENTHESIS ) +RIGHT_BRACKET ] +RIGHT_BRACE } +SEMICOLON ; +COLON : +QUESTION_MARK ? + +firstKeyword +IF +IN +DO + +VAR +FOR +NEW +TRY + +THIS +ELSE +CASE +VOID +WITH + +WHILE +BREAK +CATCH +THROW + +RETURN +TYPEOF +DELETE +SWITCH + +DEFAULT +FINALLY + +FUNCTION +CONTINUE +DEBUGGER + +INSTANCEOF +lastKeyword +_END_ + chomp; + + next if m/^\s*#/; + + my ($name, $symbol) = m/(\w+)\s*(\S+)?/; + + if (defined $symbol) { + push @order, $name; + push @const, "$name // $symbol"; + $token{$name} = $symbol; + } elsif (defined $name) { + $keywords ||= $name eq 'firstKeyword'; + + push @const, $name; + #$const[-1] .= " Token = iota" if 2 == @const; + if ($name =~ m/^([A-Z]+)/) { + push @keywords, $name if $keywords; + push @order, $name; + if ($token{SEMICOLON}) { + $token{$name} = lc $1; + } else { + $token{$name} = $name; + } + } + } else { + push @const, ""; + } + + } + push @const, ")"; + print join "\n", @const, ""; +} + +{ + print <<_END_; + +var token2string = [...]string{ +_END_ + for my $name (@order) { + print "$name: \"$token{$name}\",\n"; + } + print <<_END_; +} +_END_ + + print <<_END_; + +var keywordTable = map[string]_keyword{ +_END_ + for my $name (@keywords) { + print <<_END_ + "@{[ lc $name ]}": _keyword{ + token: $name, + }, +_END_ + } + + for my $name (qw/ + const + class + enum + export + extends + import + super + /) { + print <<_END_ + "$name": _keyword{ + token: KEYWORD, + futureKeyword: true, + }, +_END_ + } + + for my $name (qw/ + implements + interface + let + package + private + protected + public + static + /) { + print <<_END_ + "$name": _keyword{ + token: KEYWORD, + futureKeyword: true, + strict: true, + }, +_END_ + } + + print <<_END_; +} +_END_ +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_arguments.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_arguments.go new file mode 100644 index 0000000000..841d758553 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_arguments.go @@ -0,0 +1,106 @@ +package otto + +import ( + "strconv" +) + +func (runtime *_runtime) newArgumentsObject(indexOfParameterName []string, stash _stash, length int) *_object { + self := runtime.newClassObject("Arguments") + + for index, _ := range indexOfParameterName { + name := strconv.FormatInt(int64(index), 10) + objectDefineOwnProperty(self, name, _property{Value{}, 0111}, false) + } + + self.objectClass = _classArguments + self.value = _argumentsObject{ + indexOfParameterName: indexOfParameterName, + stash: stash, + } + + self.prototype = runtime.global.ObjectPrototype + + self.defineProperty("length", toValue_int(length), 0101, false) + + return self +} + +type _argumentsObject struct { + indexOfParameterName []string + // function(abc, def, ghi) + // indexOfParameterName[0] = "abc" + // indexOfParameterName[1] = "def" + // indexOfParameterName[2] = "ghi" + // ... + stash _stash +} + +func (in _argumentsObject) clone(clone *_clone) _argumentsObject { + indexOfParameterName := make([]string, len(in.indexOfParameterName)) + copy(indexOfParameterName, in.indexOfParameterName) + return _argumentsObject{ + indexOfParameterName, + clone.stash(in.stash), + } +} + +func (self _argumentsObject) get(name string) (Value, bool) { + index := stringToArrayIndex(name) + if index >= 0 && index < int64(len(self.indexOfParameterName)) { + name := self.indexOfParameterName[index] + if name == "" { + return Value{}, false + } + return self.stash.getBinding(name, false), true + } + return Value{}, false +} + +func (self _argumentsObject) put(name string, value Value) { + index := stringToArrayIndex(name) + name = self.indexOfParameterName[index] + self.stash.setBinding(name, value, false) +} + +func (self _argumentsObject) delete(name string) { + index := stringToArrayIndex(name) + self.indexOfParameterName[index] = "" +} + +func argumentsGet(self *_object, name string) Value { + if value, exists := self.value.(_argumentsObject).get(name); exists { + return value + } + return objectGet(self, name) +} + +func argumentsGetOwnProperty(self *_object, name string) *_property { + property := objectGetOwnProperty(self, name) + if value, exists := self.value.(_argumentsObject).get(name); exists { + property.value = value + } + return property +} + +func argumentsDefineOwnProperty(self *_object, name string, descriptor _property, throw bool) bool { + if _, exists := self.value.(_argumentsObject).get(name); exists { + if !objectDefineOwnProperty(self, name, descriptor, false) { + return self.runtime.typeErrorResult(throw) + } + if value, valid := descriptor.value.(Value); valid { + self.value.(_argumentsObject).put(name, value) + } + return true + } + return objectDefineOwnProperty(self, name, descriptor, throw) +} + +func argumentsDelete(self *_object, name string, throw bool) bool { + if !objectDelete(self, name, throw) { + return false + } + if _, exists := self.value.(_argumentsObject).get(name); exists { + self.value.(_argumentsObject).delete(name) + } + return true +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_array.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_array.go new file mode 100644 index 0000000000..236376a8e4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_array.go @@ -0,0 +1,109 @@ +package otto + +import ( + "strconv" +) + +func (runtime *_runtime) newArrayObject(length uint32) *_object { + self := runtime.newObject() + self.class = "Array" + self.defineProperty("length", toValue_uint32(length), 0100, false) + self.objectClass = _classArray + return self +} + +func isArray(object *_object) bool { + return object != nil && (object.class == "Array" || object.class == "GoArray") +} + +func objectLength(object *_object) uint32 { + if object == nil { + return 0 + } + switch object.class { + case "Array": + return object.get("length").value.(uint32) + case "String": + return uint32(object.get("length").value.(int)) + case "GoArray": + return uint32(object.get("length").value.(int)) + } + return 0 +} + +func arrayUint32(rt *_runtime, value Value) uint32 { + nm := value.number() + if nm.kind != numberInteger || !isUint32(nm.int64) { + // FIXME + panic(rt.panicRangeError()) + } + return uint32(nm.int64) +} + +func arrayDefineOwnProperty(self *_object, name string, descriptor _property, throw bool) bool { + lengthProperty := self.getOwnProperty("length") + lengthValue, valid := lengthProperty.value.(Value) + if !valid { + panic("Array.length != Value{}") + } + length := lengthValue.value.(uint32) + if name == "length" { + if descriptor.value == nil { + return objectDefineOwnProperty(self, name, descriptor, throw) + } + newLengthValue, isValue := descriptor.value.(Value) + if !isValue { + panic(self.runtime.panicTypeError()) + } + newLength := arrayUint32(self.runtime, newLengthValue) + descriptor.value = toValue_uint32(newLength) + if newLength > length { + return objectDefineOwnProperty(self, name, descriptor, throw) + } + if !lengthProperty.writable() { + goto Reject + } + newWritable := true + if descriptor.mode&0700 == 0 { + // If writable is off + newWritable = false + descriptor.mode |= 0100 + } + if !objectDefineOwnProperty(self, name, descriptor, throw) { + return false + } + for newLength < length { + length -= 1 + if !self.delete(strconv.FormatInt(int64(length), 10), false) { + descriptor.value = toValue_uint32(length + 1) + if !newWritable { + descriptor.mode &= 0077 + } + objectDefineOwnProperty(self, name, descriptor, false) + goto Reject + } + } + if !newWritable { + descriptor.mode &= 0077 + objectDefineOwnProperty(self, name, descriptor, false) + } + } else if index := stringToArrayIndex(name); index >= 0 { + if index >= int64(length) && !lengthProperty.writable() { + goto Reject + } + if !objectDefineOwnProperty(self, strconv.FormatInt(index, 10), descriptor, false) { + goto Reject + } + if index >= int64(length) { + lengthProperty.value = toValue_uint32(uint32(index + 1)) + objectDefineOwnProperty(self, "length", *lengthProperty, false) + return true + } + } + return objectDefineOwnProperty(self, name, descriptor, throw) +Reject: + if throw { + panic(self.runtime.panicTypeError()) + } + return false +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_boolean.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_boolean.go new file mode 100644 index 0000000000..afc45c69b3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_boolean.go @@ -0,0 +1,13 @@ +package otto + +import ( + "strconv" +) + +func (runtime *_runtime) newBooleanObject(value Value) *_object { + return runtime.newPrimitiveObject("Boolean", toValue_bool(value.bool())) +} + +func booleanToString(value bool) string { + return strconv.FormatBool(value) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_date.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_date.go new file mode 100644 index 0000000000..7079e649c7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_date.go @@ -0,0 +1,299 @@ +package otto + +import ( + "fmt" + "math" + "regexp" + Time "time" +) + +type _dateObject struct { + time Time.Time // Time from the "time" package, a cached version of time + epoch int64 + value Value + isNaN bool +} + +var ( + invalidDateObject = _dateObject{ + time: Time.Time{}, + epoch: -1, + value: NaNValue(), + isNaN: true, + } +) + +type _ecmaTime struct { + year int + month int + day int + hour int + minute int + second int + millisecond int + location *Time.Location // Basically, either local or UTC +} + +func ecmaTime(goTime Time.Time) _ecmaTime { + return _ecmaTime{ + goTime.Year(), + dateFromGoMonth(goTime.Month()), + goTime.Day(), + goTime.Hour(), + goTime.Minute(), + goTime.Second(), + goTime.Nanosecond() / (100 * 100 * 100), + goTime.Location(), + } +} + +func (self *_ecmaTime) goTime() Time.Time { + return Time.Date( + self.year, + dateToGoMonth(self.month), + self.day, + self.hour, + self.minute, + self.second, + self.millisecond*(100*100*100), + self.location, + ) +} + +func (self *_dateObject) Time() Time.Time { + return self.time +} + +func (self *_dateObject) Epoch() int64 { + return self.epoch +} + +func (self *_dateObject) Value() Value { + return self.value +} + +// FIXME A date should only be in the range of -100,000,000 to +100,000,000 (1970): 15.9.1.1 +func (self *_dateObject) SetNaN() { + self.time = Time.Time{} + self.epoch = -1 + self.value = NaNValue() + self.isNaN = true +} + +func (self *_dateObject) SetTime(time Time.Time) { + self.Set(timeToEpoch(time)) +} + +func epoch2dateObject(epoch float64) _dateObject { + date := _dateObject{} + date.Set(epoch) + return date +} + +func (self *_dateObject) Set(epoch float64) { + // epoch + self.epoch = epochToInteger(epoch) + + // time + time, err := epochToTime(epoch) + self.time = time // Is either a valid time, or the zero-value for time.Time + + // value & isNaN + if err != nil { + self.isNaN = true + self.epoch = -1 + self.value = NaNValue() + } else { + self.value = toValue_int64(self.epoch) + } +} + +func epochToInteger(value float64) int64 { + if value > 0 { + return int64(math.Floor(value)) + } + return int64(math.Ceil(value)) +} + +func epochToTime(value float64) (time Time.Time, err error) { + epochWithMilli := value + if math.IsNaN(epochWithMilli) || math.IsInf(epochWithMilli, 0) { + err = fmt.Errorf("Invalid time %v", value) + return + } + + epoch := int64(epochWithMilli / 1000) + milli := int64(epochWithMilli) % 1000 + + time = Time.Unix(int64(epoch), milli*1000000).UTC() + return +} + +func timeToEpoch(time Time.Time) float64 { + return float64(time.UnixNano() / (1000 * 1000)) +} + +func (runtime *_runtime) newDateObject(epoch float64) *_object { + self := runtime.newObject() + self.class = "Date" + + // FIXME This is ugly... + date := _dateObject{} + date.Set(epoch) + self.value = date + return self +} + +func (self *_object) dateValue() _dateObject { + value, _ := self.value.(_dateObject) + return value +} + +func dateObjectOf(rt *_runtime, _dateObject *_object) _dateObject { + if _dateObject == nil || _dateObject.class != "Date" { + panic(rt.panicTypeError()) + } + return _dateObject.dateValue() +} + +// JavaScript is 0-based, Go is 1-based (15.9.1.4) +func dateToGoMonth(month int) Time.Month { + return Time.Month(month + 1) +} + +func dateFromGoMonth(month Time.Month) int { + return int(month) - 1 +} + +// Both JavaScript & Go are 0-based (Sunday == 0) +func dateToGoDay(day int) Time.Weekday { + return Time.Weekday(day) +} + +func dateFromGoDay(day Time.Weekday) int { + return int(day) +} + +func newDateTime(argumentList []Value, location *Time.Location) (epoch float64) { + + pick := func(index int, default_ float64) (float64, bool) { + if index >= len(argumentList) { + return default_, false + } + value := argumentList[index].float64() + if math.IsNaN(value) || math.IsInf(value, 0) { + return 0, true + } + return value, false + } + + if len(argumentList) >= 2 { // 2-argument, 3-argument, ... + var year, month, day, hour, minute, second, millisecond float64 + var invalid bool + if year, invalid = pick(0, 1900.0); invalid { + goto INVALID + } + if month, invalid = pick(1, 0.0); invalid { + goto INVALID + } + if day, invalid = pick(2, 1.0); invalid { + goto INVALID + } + if hour, invalid = pick(3, 0.0); invalid { + goto INVALID + } + if minute, invalid = pick(4, 0.0); invalid { + goto INVALID + } + if second, invalid = pick(5, 0.0); invalid { + goto INVALID + } + if millisecond, invalid = pick(6, 0.0); invalid { + goto INVALID + } + + if year >= 0 && year <= 99 { + year += 1900 + } + + time := Time.Date(int(year), dateToGoMonth(int(month)), int(day), int(hour), int(minute), int(second), int(millisecond)*1000*1000, location) + return timeToEpoch(time) + + } else if len(argumentList) == 0 { // 0-argument + time := Time.Now().UTC() + return timeToEpoch(time) + } else { // 1-argument + value := valueOfArrayIndex(argumentList, 0) + value = toPrimitive(value) + if value.IsString() { + return dateParse(value.string()) + } + + return value.float64() + } + +INVALID: + epoch = math.NaN() + return +} + +var ( + dateLayoutList = []string{ + "2006", + "2006-01", + "2006-01-02", + + "2006T15:04", + "2006-01T15:04", + "2006-01-02T15:04", + + "2006T15:04:05", + "2006-01T15:04:05", + "2006-01-02T15:04:05", + + "2006T15:04:05.000", + "2006-01T15:04:05.000", + "2006-01-02T15:04:05.000", + + "2006T15:04-0700", + "2006-01T15:04-0700", + "2006-01-02T15:04-0700", + + "2006T15:04:05-0700", + "2006-01T15:04:05-0700", + "2006-01-02T15:04:05-0700", + + "2006T15:04:05.000-0700", + "2006-01T15:04:05.000-0700", + "2006-01-02T15:04:05.000-0700", + + Time.RFC1123, + } + matchDateTimeZone = regexp.MustCompile(`^(.*)(?:(Z)|([\+\-]\d{2}):(\d{2}))$`) +) + +func dateParse(date string) (epoch float64) { + // YYYY-MM-DDTHH:mm:ss.sssZ + var time Time.Time + var err error + { + date := date + if match := matchDateTimeZone.FindStringSubmatch(date); match != nil { + if match[2] == "Z" { + date = match[1] + "+0000" + } else { + date = match[1] + match[3] + match[4] + } + } + for _, layout := range dateLayoutList { + time, err = Time.Parse(layout, date) + if err == nil { + break + } + } + } + if err != nil { + return math.NaN() + } + return float64(time.UnixNano()) / (1000 * 1000) // UnixMilli() +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_error.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_error.go new file mode 100644 index 0000000000..c469f5fcb2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_error.go @@ -0,0 +1,13 @@ +package otto + +func (rt *_runtime) newErrorObject(name string, message Value) *_object { + self := rt.newClassObject("Error") + if message.IsDefined() { + msg := message.string() + self.defineProperty("message", toValue_string(msg), 0111, false) + self.value = newError(rt, name, msg) + } else { + self.value = newError(rt, name) + } + return self +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_function.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_function.go new file mode 100644 index 0000000000..a5eb7554a2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_function.go @@ -0,0 +1,262 @@ +package otto + +// _constructFunction +type _constructFunction func(*_object, []Value) Value + +// 13.2.2 [[Construct]] +func defaultConstruct(fn *_object, argumentList []Value) Value { + object := fn.runtime.newObject() + object.class = "Object" + + prototype := fn.get("prototype") + if prototype.kind != valueObject { + prototype = toValue_object(fn.runtime.global.ObjectPrototype) + } + object.prototype = prototype._object() + + this := toValue_object(object) + value := fn.call(this, argumentList, false, nativeFrame) + if value.kind == valueObject { + return value + } + return this +} + +// _nativeFunction +type _nativeFunction func(FunctionCall) Value + +// ===================== // +// _nativeFunctionObject // +// ===================== // + +type _nativeFunctionObject struct { + name string + call _nativeFunction // [[Call]] + construct _constructFunction // [[Construct]] +} + +func (runtime *_runtime) newNativeFunctionObject(name string, native _nativeFunction, length int) *_object { + self := runtime.newClassObject("Function") + self.value = _nativeFunctionObject{ + call: native, + construct: defaultConstruct, + } + self.defineProperty("length", toValue_int(length), 0000, false) + return self +} + +// =================== // +// _bindFunctionObject // +// =================== // + +type _bindFunctionObject struct { + target *_object + this Value + argumentList []Value +} + +func (runtime *_runtime) newBoundFunctionObject(target *_object, this Value, argumentList []Value) *_object { + self := runtime.newClassObject("Function") + self.value = _bindFunctionObject{ + target: target, + this: this, + argumentList: argumentList, + } + length := int(toInt32(target.get("length"))) + length -= len(argumentList) + if length < 0 { + length = 0 + } + self.defineProperty("length", toValue_int(length), 0000, false) + self.defineProperty("caller", Value{}, 0000, false) // TODO Should throw a TypeError + self.defineProperty("arguments", Value{}, 0000, false) // TODO Should throw a TypeError + return self +} + +// [[Construct]] +func (fn _bindFunctionObject) construct(argumentList []Value) Value { + object := fn.target + switch value := object.value.(type) { + case _nativeFunctionObject: + return value.construct(object, fn.argumentList) + case _nodeFunctionObject: + argumentList = append(fn.argumentList, argumentList...) + return object.construct(argumentList) + } + panic(fn.target.runtime.panicTypeError()) +} + +// =================== // +// _nodeFunctionObject // +// =================== // + +type _nodeFunctionObject struct { + node *_nodeFunctionLiteral + stash _stash +} + +func (runtime *_runtime) newNodeFunctionObject(node *_nodeFunctionLiteral, stash _stash) *_object { + self := runtime.newClassObject("Function") + self.value = _nodeFunctionObject{ + node: node, + stash: stash, + } + self.defineProperty("length", toValue_int(len(node.parameterList)), 0000, false) + return self +} + +// ======= // +// _object // +// ======= // + +func (self *_object) isCall() bool { + switch fn := self.value.(type) { + case _nativeFunctionObject: + return fn.call != nil + case _bindFunctionObject: + return true + case _nodeFunctionObject: + return true + } + return false +} + +func (self *_object) call(this Value, argumentList []Value, eval bool, frame _frame) Value { + switch fn := self.value.(type) { + + case _nativeFunctionObject: + // TODO Enter a scope, name from the native object... + // Since eval is a native function, we only have to check for it here + if eval { + eval = self == self.runtime.eval // If eval is true, then it IS a direct eval + } + return fn.call(FunctionCall{ + runtime: self.runtime, + eval: eval, + + This: this, + ArgumentList: argumentList, + Otto: self.runtime.otto, + }) + + case _bindFunctionObject: + // TODO Passthrough site, do not enter a scope + argumentList = append(fn.argumentList, argumentList...) + return fn.target.call(fn.this, argumentList, false, frame) + + case _nodeFunctionObject: + rt := self.runtime + stash := rt.enterFunctionScope(fn.stash, this) + defer func() { + rt.leaveScope() + }() + rt.scope.frame = frame + callValue := rt.cmpl_call_nodeFunction(self, stash, fn.node, this, argumentList) + if value, valid := callValue.value.(_result); valid { + return value.value + } + return callValue + } + + panic(self.runtime.panicTypeError("%v is not a function", toValue_object(self))) +} + +func (self *_object) construct(argumentList []Value) Value { + switch fn := self.value.(type) { + + case _nativeFunctionObject: + if fn.call == nil { + panic(self.runtime.panicTypeError("%v is not a function", toValue_object(self))) + } + if fn.construct == nil { + panic(self.runtime.panicTypeError("%v is not a constructor", toValue_object(self))) + } + return fn.construct(self, argumentList) + + case _bindFunctionObject: + return fn.construct(argumentList) + + case _nodeFunctionObject: + return defaultConstruct(self, argumentList) + } + + panic(self.runtime.panicTypeError("%v is not a function", toValue_object(self))) +} + +// 15.3.5.3 +func (self *_object) hasInstance(of Value) bool { + if !self.isCall() { + // We should not have a hasInstance method + panic(self.runtime.panicTypeError()) + } + if !of.IsObject() { + return false + } + prototype := self.get("prototype") + if !prototype.IsObject() { + panic(self.runtime.panicTypeError()) + } + prototypeObject := prototype._object() + + value := of._object().prototype + for value != nil { + if value == prototypeObject { + return true + } + value = value.prototype + } + return false +} + +// ============ // +// FunctionCall // +// ============ // + +// FunctionCall is an encapsulation of a JavaScript function call. +type FunctionCall struct { + runtime *_runtime + _thisObject *_object + eval bool // This call is a direct call to eval + + This Value + ArgumentList []Value + Otto *Otto +} + +// Argument will return the value of the argument at the given index. +// +// If no such argument exists, undefined is returned. +func (self FunctionCall) Argument(index int) Value { + return valueOfArrayIndex(self.ArgumentList, index) +} + +func (self FunctionCall) getArgument(index int) (Value, bool) { + return getValueOfArrayIndex(self.ArgumentList, index) +} + +func (self FunctionCall) slice(index int) []Value { + if index < len(self.ArgumentList) { + return self.ArgumentList[index:] + } + return []Value{} +} + +func (self *FunctionCall) thisObject() *_object { + if self._thisObject == nil { + this := self.This.resolve() // FIXME Is this right? + self._thisObject = self.runtime.toObject(this) + } + return self._thisObject +} + +func (self *FunctionCall) thisClassObject(class string) *_object { + thisObject := self.thisObject() + if thisObject.class != class { + panic(self.runtime.panicTypeError()) + } + return self._thisObject +} + +func (self FunctionCall) toObject(value Value) *_object { + return self.runtime.toObject(value) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_array.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_array.go new file mode 100644 index 0000000000..13a0b10f2b --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_array.go @@ -0,0 +1,134 @@ +package otto + +import ( + "reflect" + "strconv" +) + +func (runtime *_runtime) newGoArrayObject(value reflect.Value) *_object { + self := runtime.newObject() + self.class = "GoArray" + self.objectClass = _classGoArray + self.value = _newGoArrayObject(value) + return self +} + +type _goArrayObject struct { + value reflect.Value + writable bool + propertyMode _propertyMode +} + +func _newGoArrayObject(value reflect.Value) *_goArrayObject { + writable := value.Kind() == reflect.Ptr // The Array is addressable (like a Slice) + mode := _propertyMode(0010) + if writable { + mode = 0110 + } + self := &_goArrayObject{ + value: value, + writable: writable, + propertyMode: mode, + } + return self +} + +func (self _goArrayObject) getValue(index int64) (reflect.Value, bool) { + value := reflect.Indirect(self.value) + if index < int64(value.Len()) { + return value.Index(int(index)), true + } + return reflect.Value{}, false +} + +func (self _goArrayObject) setValue(index int64, value Value) bool { + indexValue, exists := self.getValue(index) + if !exists { + return false + } + reflectValue, err := value.toReflectValue(reflect.Indirect(self.value).Type().Elem().Kind()) + if err != nil { + panic(err) + } + indexValue.Set(reflectValue) + return true +} + +func goArrayGetOwnProperty(self *_object, name string) *_property { + // length + if name == "length" { + return &_property{ + value: toValue(reflect.Indirect(self.value.(*_goArrayObject).value).Len()), + mode: 0, + } + } + + // .0, .1, .2, ... + index := stringToArrayIndex(name) + if index >= 0 { + object := self.value.(*_goArrayObject) + value := Value{} + reflectValue, exists := object.getValue(index) + if exists { + value = self.runtime.toValue(reflectValue.Interface()) + } + return &_property{ + value: value, + mode: object.propertyMode, + } + } + + return objectGetOwnProperty(self, name) +} + +func goArrayEnumerate(self *_object, all bool, each func(string) bool) { + object := self.value.(*_goArrayObject) + // .0, .1, .2, ... + + for index, length := 0, object.value.Len(); index < length; index++ { + name := strconv.FormatInt(int64(index), 10) + if !each(name) { + return + } + } + + objectEnumerate(self, all, each) +} + +func goArrayDefineOwnProperty(self *_object, name string, descriptor _property, throw bool) bool { + if name == "length" { + return self.runtime.typeErrorResult(throw) + } else if index := stringToArrayIndex(name); index >= 0 { + object := self.value.(*_goArrayObject) + if object.writable { + if self.value.(*_goArrayObject).setValue(index, descriptor.value.(Value)) { + return true + } + } + return self.runtime.typeErrorResult(throw) + } + return objectDefineOwnProperty(self, name, descriptor, throw) +} + +func goArrayDelete(self *_object, name string, throw bool) bool { + // length + if name == "length" { + return self.runtime.typeErrorResult(throw) + } + + // .0, .1, .2, ... + index := stringToArrayIndex(name) + if index >= 0 { + object := self.value.(*_goArrayObject) + if object.writable { + indexValue, exists := object.getValue(index) + if exists { + indexValue.Set(reflect.Zero(reflect.Indirect(object.value).Type().Elem())) + return true + } + } + return self.runtime.typeErrorResult(throw) + } + + return self.delete(name, throw) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_map.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_map.go new file mode 100644 index 0000000000..542a2c29d9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_map.go @@ -0,0 +1,87 @@ +package otto + +import ( + "reflect" +) + +func (runtime *_runtime) newGoMapObject(value reflect.Value) *_object { + self := runtime.newObject() + self.class = "Object" // TODO Should this be something else? + self.objectClass = _classGoMap + self.value = _newGoMapObject(value) + return self +} + +type _goMapObject struct { + value reflect.Value + keyKind reflect.Kind + valueKind reflect.Kind +} + +func _newGoMapObject(value reflect.Value) *_goMapObject { + if value.Kind() != reflect.Map { + dbgf("%/panic//%@: %v != reflect.Map", value.Kind()) + } + self := &_goMapObject{ + value: value, + keyKind: value.Type().Key().Kind(), + valueKind: value.Type().Elem().Kind(), + } + return self +} + +func (self _goMapObject) toKey(name string) reflect.Value { + reflectValue, err := stringToReflectValue(name, self.keyKind) + if err != nil { + panic(err) + } + return reflectValue +} + +func (self _goMapObject) toValue(value Value) reflect.Value { + reflectValue, err := value.toReflectValue(self.valueKind) + if err != nil { + panic(err) + } + return reflectValue +} + +func goMapGetOwnProperty(self *_object, name string) *_property { + object := self.value.(*_goMapObject) + value := object.value.MapIndex(object.toKey(name)) + if value.IsValid() { + return &_property{self.runtime.toValue(value.Interface()), 0111} + } + + return nil +} + +func goMapEnumerate(self *_object, all bool, each func(string) bool) { + object := self.value.(*_goMapObject) + keys := object.value.MapKeys() + for _, key := range keys { + if !each(key.String()) { + return + } + } +} + +func goMapDefineOwnProperty(self *_object, name string, descriptor _property, throw bool) bool { + object := self.value.(*_goMapObject) + // TODO ...or 0222 + if descriptor.mode != 0111 { + return self.runtime.typeErrorResult(throw) + } + if !descriptor.isDataDescriptor() { + return self.runtime.typeErrorResult(throw) + } + object.value.SetMapIndex(object.toKey(name), object.toValue(descriptor.value.(Value))) + return true +} + +func goMapDelete(self *_object, name string, throw bool) bool { + object := self.value.(*_goMapObject) + object.value.SetMapIndex(object.toKey(name), reflect.Value{}) + // FIXME + return true +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_slice.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_slice.go new file mode 100644 index 0000000000..7143531a81 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_slice.go @@ -0,0 +1,118 @@ +package otto + +import ( + "reflect" + "strconv" +) + +func (runtime *_runtime) newGoSliceObject(value reflect.Value) *_object { + self := runtime.newObject() + self.class = "GoArray" // TODO GoSlice? + self.objectClass = _classGoSlice + self.value = _newGoSliceObject(value) + return self +} + +type _goSliceObject struct { + value reflect.Value +} + +func _newGoSliceObject(value reflect.Value) *_goSliceObject { + self := &_goSliceObject{ + value: value, + } + return self +} + +func (self _goSliceObject) getValue(index int64) (reflect.Value, bool) { + if index < int64(self.value.Len()) { + return self.value.Index(int(index)), true + } + return reflect.Value{}, false +} + +func (self _goSliceObject) setValue(index int64, value Value) bool { + indexValue, exists := self.getValue(index) + if !exists { + return false + } + reflectValue, err := value.toReflectValue(self.value.Type().Elem().Kind()) + if err != nil { + panic(err) + } + indexValue.Set(reflectValue) + return true +} + +func goSliceGetOwnProperty(self *_object, name string) *_property { + // length + if name == "length" { + return &_property{ + value: toValue(self.value.(*_goSliceObject).value.Len()), + mode: 0, + } + } + + // .0, .1, .2, ... + index := stringToArrayIndex(name) + if index >= 0 { + value := Value{} + reflectValue, exists := self.value.(*_goSliceObject).getValue(index) + if exists { + value = self.runtime.toValue(reflectValue.Interface()) + } + return &_property{ + value: value, + mode: 0110, + } + } + + return objectGetOwnProperty(self, name) +} + +func goSliceEnumerate(self *_object, all bool, each func(string) bool) { + object := self.value.(*_goSliceObject) + // .0, .1, .2, ... + + for index, length := 0, object.value.Len(); index < length; index++ { + name := strconv.FormatInt(int64(index), 10) + if !each(name) { + return + } + } + + objectEnumerate(self, all, each) +} + +func goSliceDefineOwnProperty(self *_object, name string, descriptor _property, throw bool) bool { + if name == "length" { + return self.runtime.typeErrorResult(throw) + } else if index := stringToArrayIndex(name); index >= 0 { + if self.value.(*_goSliceObject).setValue(index, descriptor.value.(Value)) { + return true + } + return self.runtime.typeErrorResult(throw) + } + return objectDefineOwnProperty(self, name, descriptor, throw) +} + +func goSliceDelete(self *_object, name string, throw bool) bool { + // length + if name == "length" { + return self.runtime.typeErrorResult(throw) + } + + // .0, .1, .2, ... + index := stringToArrayIndex(name) + if index >= 0 { + object := self.value.(*_goSliceObject) + indexValue, exists := object.getValue(index) + if exists { + indexValue.Set(reflect.Zero(object.value.Type().Elem())) + return true + } + return self.runtime.typeErrorResult(throw) + } + + return self.delete(name, throw) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_struct.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_struct.go new file mode 100644 index 0000000000..608ac66609 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_struct.go @@ -0,0 +1,146 @@ +package otto + +import ( + "encoding/json" + "reflect" +) + +// FIXME Make a note about not being able to modify a struct unless it was +// passed as a pointer-to: &struct{ ... } +// This seems to be a limitation of the reflect package. +// This goes for the other Go constructs too. +// I guess we could get around it by either: +// 1. Creating a new struct every time +// 2. Creating an addressable? struct in the constructor + +func (runtime *_runtime) newGoStructObject(value reflect.Value) *_object { + self := runtime.newObject() + self.class = "Object" // TODO Should this be something else? + self.objectClass = _classGoStruct + self.value = _newGoStructObject(value) + return self +} + +type _goStructObject struct { + value reflect.Value +} + +func _newGoStructObject(value reflect.Value) *_goStructObject { + if reflect.Indirect(value).Kind() != reflect.Struct { + dbgf("%/panic//%@: %v != reflect.Struct", value.Kind()) + } + self := &_goStructObject{ + value: value, + } + return self +} + +func (self _goStructObject) getValue(name string) reflect.Value { + if validGoStructName(name) { + // Do not reveal hidden or unexported fields + if field := reflect.Indirect(self.value).FieldByName(name); (field != reflect.Value{}) { + return field + } + + if method := self.value.MethodByName(name); (method != reflect.Value{}) { + return method + } + } + + return reflect.Value{} +} + +func (self _goStructObject) field(name string) (reflect.StructField, bool) { + return reflect.Indirect(self.value).Type().FieldByName(name) +} + +func (self _goStructObject) method(name string) (reflect.Method, bool) { + return reflect.Indirect(self.value).Type().MethodByName(name) +} + +func (self _goStructObject) setValue(name string, value Value) bool { + field, exists := self.field(name) + if !exists { + return false + } + fieldValue := self.getValue(name) + reflectValue, err := value.toReflectValue(field.Type.Kind()) + if err != nil { + panic(err) + } + fieldValue.Set(reflectValue) + + return true +} + +func goStructGetOwnProperty(self *_object, name string) *_property { + object := self.value.(*_goStructObject) + value := object.getValue(name) + if value.IsValid() { + return &_property{self.runtime.toValue(value.Interface()), 0110} + } + + return objectGetOwnProperty(self, name) +} + +func validGoStructName(name string) bool { + if name == "" { + return false + } + return 'A' <= name[0] && name[0] <= 'Z' // TODO What about Unicode? +} + +func goStructEnumerate(self *_object, all bool, each func(string) bool) { + object := self.value.(*_goStructObject) + + // Enumerate fields + for index := 0; index < reflect.Indirect(object.value).NumField(); index++ { + name := reflect.Indirect(object.value).Type().Field(index).Name + if validGoStructName(name) { + if !each(name) { + return + } + } + } + + // Enumerate methods + for index := 0; index < object.value.NumMethod(); index++ { + name := object.value.Type().Method(index).Name + if validGoStructName(name) { + if !each(name) { + return + } + } + } + + objectEnumerate(self, all, each) +} + +func goStructCanPut(self *_object, name string) bool { + object := self.value.(*_goStructObject) + value := object.getValue(name) + if value.IsValid() { + return true + } + + return objectCanPut(self, name) +} + +func goStructPut(self *_object, name string, value Value, throw bool) { + object := self.value.(*_goStructObject) + if object.setValue(name, value) { + return + } + + objectPut(self, name, value, throw) +} + +func goStructMarshalJSON(self *_object) json.Marshaler { + object := self.value.(*_goStructObject) + goValue := reflect.Indirect(object.value).Interface() + switch marshaler := goValue.(type) { + case json.Marshaler: + return marshaler + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_number.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_number.go new file mode 100644 index 0000000000..28de4444c7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_number.go @@ -0,0 +1,5 @@ +package otto + +func (runtime *_runtime) newNumberObject(value Value) *_object { + return runtime.newPrimitiveObject("Number", value.numberValue()) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_reference.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_reference.go new file mode 100644 index 0000000000..fd770c6f4e --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_reference.go @@ -0,0 +1,103 @@ +package otto + +type _reference interface { + invalid() bool // IsUnresolvableReference + getValue() Value // getValue + putValue(Value) string // PutValue + delete() bool +} + +// PropertyReference + +type _propertyReference struct { + name string + strict bool + base *_object + runtime *_runtime + at _at +} + +func newPropertyReference(rt *_runtime, base *_object, name string, strict bool, at _at) *_propertyReference { + return &_propertyReference{ + runtime: rt, + name: name, + strict: strict, + base: base, + at: at, + } +} + +func (self *_propertyReference) invalid() bool { + return self.base == nil +} + +func (self *_propertyReference) getValue() Value { + if self.base == nil { + panic(self.runtime.panicReferenceError("'%s' is not defined", self.name, self.at)) + } + return self.base.get(self.name) +} + +func (self *_propertyReference) putValue(value Value) string { + if self.base == nil { + return self.name + } + self.base.put(self.name, value, self.strict) + return "" +} + +func (self *_propertyReference) delete() bool { + if self.base == nil { + // TODO Throw an error if strict + return true + } + return self.base.delete(self.name, self.strict) +} + +// ArgumentReference + +func newArgumentReference(runtime *_runtime, base *_object, name string, strict bool, at _at) *_propertyReference { + if base == nil { + panic(hereBeDragons()) + } + return newPropertyReference(runtime, base, name, strict, at) +} + +type _stashReference struct { + name string + strict bool + base _stash +} + +func (self *_stashReference) invalid() bool { + return false // The base (an environment) will never be nil +} + +func (self *_stashReference) getValue() Value { + return self.base.getBinding(self.name, self.strict) +} + +func (self *_stashReference) putValue(value Value) string { + self.base.setValue(self.name, value, self.strict) + return "" +} + +func (self *_stashReference) delete() bool { + if self.base == nil { + // This should never be reached, but just in case + return false + } + return self.base.deleteBinding(self.name) +} + +// getIdentifierReference + +func getIdentifierReference(runtime *_runtime, stash _stash, name string, strict bool, at _at) _reference { + if stash == nil { + return newPropertyReference(runtime, nil, name, strict, at) + } + if stash.hasBinding(name) { + return stash.newReference(name, strict, at) + } + return getIdentifierReference(runtime, stash.outer(), name, strict, at) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_regexp.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_regexp.go new file mode 100644 index 0000000000..57fe316405 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_regexp.go @@ -0,0 +1,146 @@ +package otto + +import ( + "fmt" + "regexp" + "unicode/utf8" + + "github.com/robertkrimen/otto/parser" +) + +type _regExpObject struct { + regularExpression *regexp.Regexp + global bool + ignoreCase bool + multiline bool + source string + flags string +} + +func (runtime *_runtime) newRegExpObject(pattern string, flags string) *_object { + self := runtime.newObject() + self.class = "RegExp" + + global := false + ignoreCase := false + multiline := false + re2flags := "" + + // TODO Maybe clean up the panicking here... TypeError, SyntaxError, ? + + for _, chr := range flags { + switch chr { + case 'g': + if global { + panic(runtime.panicSyntaxError("newRegExpObject: %s %s", pattern, flags)) + } + global = true + case 'm': + if multiline { + panic(runtime.panicSyntaxError("newRegExpObject: %s %s", pattern, flags)) + } + multiline = true + re2flags += "m" + case 'i': + if ignoreCase { + panic(runtime.panicSyntaxError("newRegExpObject: %s %s", pattern, flags)) + } + ignoreCase = true + re2flags += "i" + } + } + + re2pattern, err := parser.TransformRegExp(pattern) + if err != nil { + panic(runtime.panicTypeError("Invalid regular expression: %s", err.Error())) + } + if len(re2flags) > 0 { + re2pattern = fmt.Sprintf("(?%s:%s)", re2flags, re2pattern) + } + + regularExpression, err := regexp.Compile(re2pattern) + if err != nil { + panic(runtime.panicSyntaxError("Invalid regular expression: %s", err.Error()[22:])) + } + + self.value = _regExpObject{ + regularExpression: regularExpression, + global: global, + ignoreCase: ignoreCase, + multiline: multiline, + source: pattern, + flags: flags, + } + self.defineProperty("global", toValue_bool(global), 0, false) + self.defineProperty("ignoreCase", toValue_bool(ignoreCase), 0, false) + self.defineProperty("multiline", toValue_bool(multiline), 0, false) + self.defineProperty("lastIndex", toValue_int(0), 0100, false) + self.defineProperty("source", toValue_string(pattern), 0, false) + return self +} + +func (self *_object) regExpValue() _regExpObject { + value, _ := self.value.(_regExpObject) + return value +} + +func execRegExp(this *_object, target string) (match bool, result []int) { + if this.class != "RegExp" { + panic(this.runtime.panicTypeError("Calling RegExp.exec on a non-RegExp object")) + } + lastIndex := this.get("lastIndex").number().int64 + index := lastIndex + global := this.get("global").bool() + if !global { + index = 0 + } + if 0 > index || index > int64(len(target)) { + } else { + result = this.regExpValue().regularExpression.FindStringSubmatchIndex(target[index:]) + } + if result == nil { + //this.defineProperty("lastIndex", toValue_(0), 0111, true) + this.put("lastIndex", toValue_int(0), true) + return // !match + } + match = true + startIndex := index + endIndex := int(lastIndex) + result[1] + // We do this shift here because the .FindStringSubmatchIndex above + // was done on a local subordinate slice of the string, not the whole string + for index, _ := range result { + result[index] += int(startIndex) + } + if global { + //this.defineProperty("lastIndex", toValue_(endIndex), 0111, true) + this.put("lastIndex", toValue_int(endIndex), true) + } + return // match +} + +func execResultToArray(runtime *_runtime, target string, result []int) *_object { + captureCount := len(result) / 2 + valueArray := make([]Value, captureCount) + for index := 0; index < captureCount; index++ { + offset := 2 * index + if result[offset] != -1 { + valueArray[index] = toValue_string(target[result[offset]:result[offset+1]]) + } else { + valueArray[index] = Value{} + } + } + matchIndex := result[0] + if matchIndex != 0 { + matchIndex = 0 + // Find the rune index in the string, not the byte index + for index := 0; index < result[0]; { + _, size := utf8.DecodeRuneInString(target[index:]) + matchIndex += 1 + index += size + } + } + match := runtime.newArrayOf(valueArray) + match.defineProperty("input", toValue_string(target), 0111, false) + match.defineProperty("index", toValue_int(matchIndex), 0111, false) + return match +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_string.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_string.go new file mode 100644 index 0000000000..ef3afa42ba --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_string.go @@ -0,0 +1,112 @@ +package otto + +import ( + "strconv" + "unicode/utf8" +) + +type _stringObject interface { + Length() int + At(int) rune + String() string +} + +type _stringASCII string + +func (str _stringASCII) Length() int { + return len(str) +} + +func (str _stringASCII) At(at int) rune { + return rune(str[at]) +} + +func (str _stringASCII) String() string { + return string(str) +} + +type _stringWide struct { + string string + length int + runes []rune +} + +func (str _stringWide) Length() int { + return str.length +} + +func (str _stringWide) At(at int) rune { + if str.runes == nil { + str.runes = []rune(str.string) + } + return str.runes[at] +} + +func (str _stringWide) String() string { + return str.string +} + +func _newStringObject(str string) _stringObject { + for i := 0; i < len(str); i++ { + if str[i] >= utf8.RuneSelf { + goto wide + } + } + + return _stringASCII(str) + +wide: + return &_stringWide{ + string: str, + length: utf8.RuneCountInString(str), + } +} + +func stringAt(str _stringObject, index int) rune { + if 0 <= index && index < str.Length() { + return str.At(index) + } + return utf8.RuneError +} + +func (runtime *_runtime) newStringObject(value Value) *_object { + str := _newStringObject(value.string()) + + self := runtime.newClassObject("String") + self.defineProperty("length", toValue_int(str.Length()), 0, false) + self.objectClass = _classString + self.value = str + return self +} + +func (self *_object) stringValue() _stringObject { + if str, ok := self.value.(_stringObject); ok { + return str + } + return nil +} + +func stringEnumerate(self *_object, all bool, each func(string) bool) { + if str := self.stringValue(); str != nil { + length := str.Length() + for index := 0; index < length; index++ { + if !each(strconv.FormatInt(int64(index), 10)) { + return + } + } + } + objectEnumerate(self, all, each) +} + +func stringGetOwnProperty(self *_object, name string) *_property { + if property := objectGetOwnProperty(self, name); property != nil { + return property + } + // TODO Test a string of length >= +int32 + 1? + if index := stringToArrayIndex(name); index >= 0 { + if chr := stringAt(self.stringValue(), int(index)); chr != utf8.RuneError { + return &_property{toValue_string(string(chr)), 0} + } + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/Makefile b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/Makefile new file mode 100644 index 0000000000..fc872917f0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/Makefile @@ -0,0 +1,11 @@ +.PHONY: source + +source: source.go + +underscore.js: + curl -kL http://underscorejs.org/underscore.js > $@ + +source.go: underscore.js + go-bindata -f underscore -p underscore -u true < $< 2>/dev/null | grep -v '^//' | gofmt > $@ + head -4 $< >> $@ + mv $< .. diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/README.markdown b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/README.markdown new file mode 100644 index 0000000000..bce37b6953 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/README.markdown @@ -0,0 +1,53 @@ +# underscore +-- + import "github.com/robertkrimen/otto/underscore" + +Package underscore contains the source for the JavaScript utility-belt library. + + import ( + _ "github.com/robertkrimen/otto/underscore" + ) + // Every Otto runtime will now include underscore + +http://underscorejs.org + +https://github.com/documentcloud/underscore + +By importing this package, you'll automatically load underscore every time you +create a new Otto runtime. + +To prevent this behavior, you can do the following: + + import ( + "github.com/robertkrimen/otto/underscore" + ) + + func init() { + underscore.Disable() + } + +## Usage + +#### func Disable + +```go +func Disable() +``` +Disable underscore runtime inclusion. + +#### func Enable + +```go +func Enable() +``` +Enable underscore runtime inclusion. + +#### func Source + +```go +func Source() string +``` +Source returns the underscore source. + +-- +**godocdown** http://github.com/robertkrimen/godocdown diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/source.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/source.go new file mode 100644 index 0000000000..65754ab715 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/source.go @@ -0,0 +1,3462 @@ +package underscore + +func underscore() []byte { + return []byte{ + 0x2f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x55, 0x6e, 0x64, 0x65, 0x72, + 0x73, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x6a, 0x73, 0x20, 0x31, 0x2e, 0x34, + 0x2e, 0x34, 0x0a, 0x2f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x73, 0x63, + 0x6f, 0x72, 0x65, 0x6a, 0x73, 0x2e, 0x6f, 0x72, 0x67, 0x0a, 0x2f, 0x2f, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, + 0x39, 0x2d, 0x32, 0x30, 0x31, 0x33, 0x20, 0x4a, 0x65, 0x72, 0x65, 0x6d, + 0x79, 0x20, 0x41, 0x73, 0x68, 0x6b, 0x65, 0x6e, 0x61, 0x73, 0x2c, 0x20, + 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x6c, 0x6f, 0x75, + 0x64, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x2f, 0x2f, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x55, 0x6e, 0x64, 0x65, 0x72, 0x73, 0x63, 0x6f, 0x72, 0x65, + 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, 0x20, 0x66, 0x72, 0x65, 0x65, + 0x6c, 0x79, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x64, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4d, 0x49, 0x54, 0x20, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, + 0x2e, 0x0a, 0x0a, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x42, + 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x73, 0x65, 0x74, 0x75, + 0x70, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2c, 0x20, 0x60, 0x77, 0x69, 0x6e, 0x64, + 0x6f, 0x77, 0x60, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, + 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x60, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x60, 0x20, 0x6f, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x0a, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x3d, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x53, 0x61, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, + 0x76, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x60, 0x5f, 0x60, 0x20, 0x76, + 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x76, + 0x61, 0x72, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x55, + 0x6e, 0x64, 0x65, 0x72, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x3d, 0x20, + 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x5f, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x67, 0x65, 0x74, 0x73, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x72, 0x65, + 0x61, 0x6b, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, + 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x62, 0x72, + 0x65, 0x61, 0x6b, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x53, 0x61, 0x76, 0x65, 0x20, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6d, 0x69, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x28, 0x62, 0x75, + 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x67, 0x7a, 0x69, 0x70, 0x70, 0x65, + 0x64, 0x29, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x0a, + 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x20, 0x3d, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, + 0x4f, 0x62, 0x6a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x20, 0x3d, 0x20, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, + 0x79, 0x70, 0x65, 0x2c, 0x20, 0x46, 0x75, 0x6e, 0x63, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x20, 0x3d, 0x20, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x3b, + 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x20, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, + 0x6c, 0x65, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x73, 0x70, 0x65, 0x65, + 0x64, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x6f, 0x20, + 0x63, 0x6f, 0x72, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, + 0x70, 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x70, + 0x75, 0x73, 0x68, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, + 0x6c, 0x69, 0x63, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x6f, 0x53, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3d, 0x20, 0x4f, 0x62, 0x6a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x68, 0x61, 0x73, 0x4f, 0x77, 0x6e, 0x50, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x4f, + 0x62, 0x6a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x68, 0x61, 0x73, 0x4f, + 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x2a, 0x2a, + 0x45, 0x43, 0x4d, 0x41, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x35, + 0x2a, 0x2a, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x77, 0x65, 0x20, 0x68, 0x6f, 0x70, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x61, 0x72, 0x65, 0x20, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 0x64, + 0x20, 0x68, 0x65, 0x72, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x76, 0x61, 0x72, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x46, + 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x70, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x41, + 0x72, 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x61, + 0x70, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, + 0x65, 0x52, 0x65, 0x64, 0x75, 0x63, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x3d, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x64, + 0x75, 0x63, 0x65, 0x52, 0x69, 0x67, 0x68, 0x74, 0x20, 0x20, 0x3d, 0x20, + 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, + 0x65, 0x64, 0x75, 0x63, 0x65, 0x52, 0x69, 0x67, 0x68, 0x74, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, + 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x45, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x41, 0x72, 0x72, + 0x61, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x76, 0x65, 0x72, + 0x79, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, + 0x65, 0x53, 0x6f, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x3d, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x73, 0x6f, 0x6d, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x4f, 0x66, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x41, 0x72, + 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x4f, 0x66, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, + 0x74, 0x69, 0x76, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x4f, 0x66, 0x20, 0x20, 0x3d, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x4f, 0x66, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6e, + 0x61, 0x74, 0x69, 0x76, 0x65, 0x49, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x41, 0x72, 0x72, 0x61, + 0x79, 0x2e, 0x69, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4b, 0x65, 0x79, + 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x42, + 0x69, 0x6e, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3d, 0x20, 0x46, 0x75, 0x6e, 0x63, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x62, 0x69, 0x6e, 0x64, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x73, 0x61, 0x66, + 0x65, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x6e, 0x64, 0x65, 0x72, + 0x73, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x75, 0x73, 0x65, 0x20, 0x62, 0x65, 0x6c, + 0x6f, 0x77, 0x2e, 0x0a, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x5f, 0x20, + 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, + 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x6f, 0x62, 0x6a, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x6f, 0x66, 0x20, 0x5f, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x21, 0x28, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6f, 0x66, 0x20, 0x5f, 0x29, + 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x65, 0x77, + 0x20, 0x5f, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x5f, 0x77, 0x72, 0x61, 0x70, 0x70, + 0x65, 0x64, 0x20, 0x3d, 0x20, 0x6f, 0x62, 0x6a, 0x3b, 0x0a, 0x20, 0x20, + 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x45, 0x78, 0x70, + 0x6f, 0x72, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x6e, 0x64, 0x65, + 0x72, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x2a, 0x2a, 0x4e, 0x6f, 0x64, 0x65, + 0x2e, 0x6a, 0x73, 0x2a, 0x2a, 0x2c, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x77, 0x61, 0x72, + 0x64, 0x73, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x69, + 0x6c, 0x69, 0x74, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6f, 0x6c, 0x64, 0x20, 0x60, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x28, 0x29, 0x60, 0x20, 0x41, 0x50, 0x49, 0x2e, 0x20, 0x49, 0x66, + 0x20, 0x77, 0x65, 0x27, 0x72, 0x65, 0x20, 0x69, 0x6e, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x73, + 0x65, 0x72, 0x2c, 0x20, 0x61, 0x64, 0x64, 0x20, 0x60, 0x5f, 0x60, 0x20, + 0x61, 0x73, 0x20, 0x61, 0x20, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x76, 0x69, 0x61, 0x20, 0x61, + 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x2c, 0x0a, 0x20, 0x20, 0x2f, 0x2f, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x43, 0x6c, 0x6f, 0x73, 0x75, 0x72, 0x65, + 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x22, 0x61, + 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x22, 0x20, 0x6d, 0x6f, 0x64, + 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x79, 0x70, + 0x65, 0x6f, 0x66, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x20, + 0x21, 0x3d, 0x3d, 0x20, 0x27, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, + 0x65, 0x64, 0x27, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x6d, 0x6f, + 0x64, 0x75, 0x6c, 0x65, 0x20, 0x21, 0x3d, 0x3d, 0x20, 0x27, 0x75, 0x6e, + 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x27, 0x20, 0x26, 0x26, 0x20, + 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, + 0x74, 0x73, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x20, 0x3d, 0x20, 0x6d, 0x6f, + 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, + 0x20, 0x3d, 0x20, 0x5f, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2e, + 0x5f, 0x20, 0x3d, 0x20, 0x5f, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x20, 0x65, + 0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x6f, + 0x6f, 0x74, 0x2e, 0x5f, 0x20, 0x3d, 0x20, 0x5f, 0x3b, 0x0a, 0x20, 0x20, + 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x43, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e, + 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, + 0x20, 0x3d, 0x20, 0x27, 0x31, 0x2e, 0x34, 0x2e, 0x34, 0x27, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x54, + 0x68, 0x65, 0x20, 0x63, 0x6f, 0x72, 0x6e, 0x65, 0x72, 0x73, 0x74, 0x6f, + 0x6e, 0x65, 0x2c, 0x20, 0x61, 0x6e, 0x20, 0x60, 0x65, 0x61, 0x63, 0x68, + 0x60, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x6b, 0x61, 0x20, 0x60, 0x66, + 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x60, 0x2e, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x20, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x20, + 0x60, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x60, 0x2c, 0x20, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x72, + 0x61, 0x77, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2e, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, + 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x2a, 0x2a, 0x45, 0x43, 0x4d, 0x41, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x35, 0x2a, 0x2a, 0x27, 0x73, + 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x60, 0x66, 0x6f, 0x72, + 0x45, 0x61, 0x63, 0x68, 0x60, 0x20, 0x69, 0x66, 0x20, 0x61, 0x76, 0x61, + 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x76, 0x61, + 0x72, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x65, + 0x61, 0x63, 0x68, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x66, 0x6f, 0x72, 0x45, + 0x61, 0x63, 0x68, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x69, 0x74, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x28, 0x6f, 0x62, 0x6a, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, + 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x46, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x20, 0x26, 0x26, 0x20, 0x6f, + 0x62, 0x6a, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x20, 0x3d, + 0x3d, 0x3d, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x46, 0x6f, 0x72, + 0x45, 0x61, 0x63, 0x68, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x66, 0x6f, 0x72, 0x45, 0x61, 0x63, + 0x68, 0x28, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, + 0x28, 0x6f, 0x62, 0x6a, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, + 0x3d, 0x3d, 0x3d, 0x20, 0x2b, 0x6f, 0x62, 0x6a, 0x2e, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x69, 0x20, + 0x3d, 0x20, 0x30, 0x2c, 0x20, 0x6c, 0x20, 0x3d, 0x20, 0x6f, 0x62, 0x6a, + 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x20, 0x69, 0x20, 0x3c, + 0x20, 0x6c, 0x3b, 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, + 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, + 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x6f, 0x62, + 0x6a, 0x5b, 0x69, 0x5d, 0x2c, 0x20, 0x69, 0x2c, 0x20, 0x6f, 0x62, 0x6a, + 0x29, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x65, + 0x72, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x6b, + 0x65, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x28, 0x5f, 0x2e, 0x68, 0x61, 0x73, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, + 0x6b, 0x65, 0x79, 0x29, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x74, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x6f, 0x62, 0x6a, + 0x5b, 0x6b, 0x65, 0x79, 0x5d, 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x2c, 0x20, + 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x62, 0x72, 0x65, + 0x61, 0x6b, 0x65, 0x72, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, + 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, + 0x70, 0x70, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, + 0x65, 0x61, 0x63, 0x68, 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x2e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44, 0x65, 0x6c, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x2a, 0x2a, 0x45, 0x43, + 0x4d, 0x41, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x35, 0x2a, 0x2a, + 0x27, 0x73, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x60, 0x6d, + 0x61, 0x70, 0x60, 0x20, 0x69, 0x66, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x6d, 0x61, + 0x70, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, + 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6f, 0x62, 0x6a, + 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x61, + 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x70, 0x20, 0x26, 0x26, 0x20, 0x6f, + 0x62, 0x6a, 0x2e, 0x6d, 0x61, 0x70, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x6e, + 0x61, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x70, 0x29, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x6d, 0x61, 0x70, + 0x28, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x65, 0x61, 0x63, 0x68, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, 0x6c, 0x69, + 0x73, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5b, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x73, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5d, 0x20, + 0x3d, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x63, + 0x61, 0x6c, 0x6c, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x2c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, + 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x76, 0x61, + 0x72, 0x20, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x20, 0x3d, 0x20, 0x27, 0x52, 0x65, 0x64, 0x75, 0x63, 0x65, 0x20, + 0x6f, 0x66, 0x20, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6e, 0x6f, 0x20, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x27, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x2a, 0x2a, 0x52, + 0x65, 0x64, 0x75, 0x63, 0x65, 0x2a, 0x2a, 0x20, 0x62, 0x75, 0x69, 0x6c, + 0x64, 0x73, 0x20, 0x75, 0x70, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, + 0x6c, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x66, 0x72, + 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2c, 0x20, 0x61, 0x6b, 0x61, + 0x20, 0x60, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x60, 0x2c, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x6f, 0x72, 0x20, 0x60, 0x66, 0x6f, 0x6c, 0x64, + 0x6c, 0x60, 0x2e, 0x20, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x73, 0x20, 0x74, 0x6f, 0x20, 0x2a, 0x2a, 0x45, 0x43, 0x4d, 0x41, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x35, 0x2a, 0x2a, 0x27, 0x73, 0x20, + 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x60, 0x72, 0x65, 0x64, 0x75, + 0x63, 0x65, 0x60, 0x20, 0x69, 0x66, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x72, 0x65, + 0x64, 0x75, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x66, 0x6f, 0x6c, + 0x64, 0x6c, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x69, 0x6e, 0x6a, 0x65, 0x63, + 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x2c, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x2c, 0x20, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, + 0x20, 0x3d, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x3e, 0x20, 0x32, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6f, 0x62, 0x6a, + 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x6f, 0x62, + 0x6a, 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, + 0x64, 0x75, 0x63, 0x65, 0x20, 0x26, 0x26, 0x20, 0x6f, 0x62, 0x6a, 0x2e, + 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x6e, + 0x61, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x64, 0x75, 0x63, 0x65, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x20, 0x69, 0x74, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x62, + 0x69, 0x6e, 0x64, 0x28, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x3f, 0x20, 0x6f, + 0x62, 0x6a, 0x2e, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x28, 0x69, 0x74, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x6d, 0x65, 0x6d, 0x6f, + 0x29, 0x20, 0x3a, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x72, 0x65, 0x64, 0x75, + 0x63, 0x65, 0x28, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x65, 0x61, 0x63, 0x68, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, 0x6c, 0x69, 0x73, + 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x21, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, + 0x65, 0x6d, 0x6f, 0x20, 0x3d, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, + 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x6d, 0x65, 0x6d, 0x6f, 0x20, 0x3d, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x2c, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x2c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x61, 0x6c, 0x29, 0x20, 0x74, 0x68, 0x72, 0x6f, 0x77, + 0x20, 0x6e, 0x65, 0x77, 0x20, 0x54, 0x79, 0x70, 0x65, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x28, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x3b, 0x0a, 0x20, 0x20, + 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x2d, 0x61, 0x73, 0x73, 0x6f, 0x63, + 0x69, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, + 0x2c, 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, + 0x20, 0x61, 0x73, 0x20, 0x60, 0x66, 0x6f, 0x6c, 0x64, 0x72, 0x60, 0x2e, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, + 0x74, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x2a, 0x2a, 0x45, 0x43, 0x4d, + 0x41, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x35, 0x2a, 0x2a, 0x27, + 0x73, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x60, 0x72, 0x65, + 0x64, 0x75, 0x63, 0x65, 0x52, 0x69, 0x67, 0x68, 0x74, 0x60, 0x20, 0x69, + 0x66, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, + 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x52, + 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x66, 0x6f, 0x6c, + 0x64, 0x72, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x2c, 0x20, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, + 0x6c, 0x20, 0x3d, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x3e, 0x20, 0x32, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6f, 0x62, + 0x6a, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x6f, + 0x62, 0x6a, 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x52, + 0x65, 0x64, 0x75, 0x63, 0x65, 0x52, 0x69, 0x67, 0x68, 0x74, 0x20, 0x26, + 0x26, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, + 0x52, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x6e, 0x61, + 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x64, 0x75, 0x63, 0x65, 0x52, 0x69, + 0x67, 0x68, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x29, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x3d, + 0x20, 0x5f, 0x2e, 0x62, 0x69, 0x6e, 0x64, 0x28, 0x69, 0x74, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, + 0x20, 0x3f, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x72, 0x65, 0x64, 0x75, 0x63, + 0x65, 0x52, 0x69, 0x67, 0x68, 0x74, 0x28, 0x69, 0x74, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x29, 0x20, 0x3a, + 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x52, + 0x69, 0x67, 0x68, 0x74, 0x28, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, + 0x20, 0x3d, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6c, + 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x21, 0x3d, 0x3d, 0x20, 0x2b, 0x6c, + 0x65, 0x6e, 0x67, 0x74, 0x68, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x20, + 0x3d, 0x20, 0x5f, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6f, 0x62, 0x6a, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x6c, + 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x61, 0x63, 0x68, 0x28, 0x6f, 0x62, + 0x6a, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x2c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3d, 0x20, + 0x6b, 0x65, 0x79, 0x73, 0x20, 0x3f, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x5b, + 0x2d, 0x2d, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5d, 0x20, 0x3a, 0x20, + 0x2d, 0x2d, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x61, 0x6c, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x20, 0x3d, 0x20, 0x6f, + 0x62, 0x6a, 0x5b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5d, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, + 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, + 0x6d, 0x6f, 0x20, 0x3d, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x2c, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x2c, 0x20, 0x6f, 0x62, + 0x6a, 0x5b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5d, 0x2c, 0x20, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x2c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, + 0x21, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x29, 0x20, 0x74, 0x68, + 0x72, 0x6f, 0x77, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x54, 0x79, 0x70, 0x65, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x3b, + 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, + 0x69, 0x72, 0x73, 0x74, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x77, + 0x68, 0x69, 0x63, 0x68, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x72, 0x75, 0x74, 0x68, 0x20, 0x74, 0x65, 0x73, 0x74, + 0x2e, 0x20, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, 0x61, 0x73, + 0x20, 0x60, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x60, 0x2e, 0x0a, 0x20, + 0x20, 0x5f, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x5f, 0x2e, + 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x69, + 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x61, 0x6e, 0x79, 0x28, 0x6f, 0x62, 0x6a, 0x2c, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, + 0x6c, 0x69, 0x73, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x29, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x72, 0x75, 0x65, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x70, 0x61, 0x73, 0x73, 0x20, 0x61, 0x20, 0x74, + 0x72, 0x75, 0x74, 0x68, 0x20, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x73, 0x20, 0x74, 0x6f, 0x20, 0x2a, 0x2a, 0x45, 0x43, 0x4d, 0x41, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x35, 0x2a, 0x2a, 0x27, 0x73, 0x20, + 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x60, 0x66, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x60, 0x20, 0x69, 0x66, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, + 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x60, 0x73, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x60, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x73, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x69, 0x74, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, + 0x61, 0x72, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x3d, + 0x20, 0x5b, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x28, 0x6f, 0x62, 0x6a, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, + 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x46, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x20, 0x26, 0x26, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x6e, 0x61, 0x74, + 0x69, 0x76, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x29, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x28, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x61, 0x63, 0x68, 0x28, 0x6f, 0x62, + 0x6a, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x2c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x74, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, 0x6c, 0x69, 0x73, + 0x74, 0x29, 0x29, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5b, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x6c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x5d, 0x20, 0x3d, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, + 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63, + 0x68, 0x20, 0x61, 0x20, 0x74, 0x72, 0x75, 0x74, 0x68, 0x20, 0x74, 0x65, + 0x73, 0x74, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x0a, 0x20, 0x20, + 0x5f, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, + 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x66, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, 0x6c, 0x69, + 0x73, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x21, 0x69, 0x74, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, 0x6c, 0x69, 0x73, + 0x74, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x20, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44, 0x65, 0x74, 0x65, + 0x72, 0x6d, 0x69, 0x6e, 0x65, 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x20, 0x61, 0x20, 0x74, 0x72, 0x75, 0x74, 0x68, 0x20, + 0x74, 0x65, 0x73, 0x74, 0x2e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44, + 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, + 0x2a, 0x2a, 0x45, 0x43, 0x4d, 0x41, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x20, 0x35, 0x2a, 0x2a, 0x27, 0x73, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, + 0x65, 0x20, 0x60, 0x65, 0x76, 0x65, 0x72, 0x79, 0x60, 0x20, 0x69, 0x66, + 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, + 0x20, 0x61, 0x73, 0x20, 0x60, 0x61, 0x6c, 0x6c, 0x60, 0x2e, 0x0a, 0x20, + 0x20, 0x5f, 0x2e, 0x65, 0x76, 0x65, 0x72, 0x79, 0x20, 0x3d, 0x20, 0x5f, + 0x2e, 0x61, 0x6c, 0x6c, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x69, 0x74, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x74, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x69, + 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x5f, 0x2e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6f, 0x62, 0x6a, 0x20, 0x3d, 0x3d, + 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x45, 0x76, 0x65, 0x72, 0x79, 0x20, 0x26, 0x26, 0x20, 0x6f, 0x62, 0x6a, + 0x2e, 0x65, 0x76, 0x65, 0x72, 0x79, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x6e, + 0x61, 0x74, 0x69, 0x76, 0x65, 0x45, 0x76, 0x65, 0x72, 0x79, 0x29, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x65, + 0x76, 0x65, 0x72, 0x79, 0x28, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x61, 0x63, 0x68, 0x28, 0x6f, 0x62, + 0x6a, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x2c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x28, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x20, 0x26, 0x26, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x29, 0x29, + 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x72, 0x65, + 0x61, 0x6b, 0x65, 0x72, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x21, 0x21, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3b, 0x0a, 0x20, + 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44, 0x65, + 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x65, 0x20, 0x69, 0x66, 0x20, 0x61, + 0x74, 0x20, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x20, 0x6f, 0x6e, 0x65, 0x20, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x65, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x75, 0x74, + 0x68, 0x20, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, + 0x20, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, + 0x6f, 0x20, 0x2a, 0x2a, 0x45, 0x43, 0x4d, 0x41, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x20, 0x35, 0x2a, 0x2a, 0x27, 0x73, 0x20, 0x6e, 0x61, 0x74, + 0x69, 0x76, 0x65, 0x20, 0x60, 0x73, 0x6f, 0x6d, 0x65, 0x60, 0x20, 0x69, + 0x66, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, + 0x64, 0x20, 0x61, 0x73, 0x20, 0x60, 0x61, 0x6e, 0x79, 0x60, 0x2e, 0x0a, + 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x3d, 0x20, + 0x5f, 0x2e, 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x61, + 0x6e, 0x79, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x74, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x69, 0x74, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, + 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x6f, 0x62, 0x6a, 0x20, 0x3d, 0x3d, 0x20, + 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x53, + 0x6f, 0x6d, 0x65, 0x20, 0x26, 0x26, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x73, + 0x6f, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x6e, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x53, 0x6f, 0x6d, 0x65, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x73, 0x6f, 0x6d, 0x65, 0x28, + 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x65, 0x61, 0x63, 0x68, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, 0x6c, 0x69, 0x73, + 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x7c, 0x7c, + 0x20, 0x28, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x69, + 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, + 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, + 0x6c, 0x69, 0x73, 0x74, 0x29, 0x29, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x65, 0x72, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x21, 0x21, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x44, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, + 0x65, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x61, 0x20, + 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, + 0x28, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x60, 0x3d, 0x3d, 0x3d, 0x60, + 0x29, 0x2e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, 0x6c, 0x69, 0x61, + 0x73, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x60, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x60, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x69, + 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x6f, 0x62, 0x6a, 0x20, 0x3d, 0x3d, 0x20, + 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x4f, 0x66, 0x20, 0x26, 0x26, 0x20, 0x6f, 0x62, 0x6a, + 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x20, 0x3d, 0x3d, 0x3d, + 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x4f, 0x66, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, + 0x62, 0x6a, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x28, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x2d, 0x31, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x61, 0x6e, 0x79, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, + 0x3d, 0x3d, 0x20, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, + 0x20, 0x61, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x28, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x29, 0x20, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x69, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x63, 0x6f, + 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x20, + 0x5f, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x20, 0x3d, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, + 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x61, 0x72, 0x67, 0x73, 0x20, + 0x3d, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, + 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, + 0x32, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x69, 0x73, 0x46, 0x75, 0x6e, 0x63, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x69, + 0x73, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x6d, 0x61, 0x70, 0x28, + 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x28, 0x69, 0x73, 0x46, 0x75, 0x6e, 0x63, 0x20, 0x3f, 0x20, 0x6d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x20, 0x3a, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x5b, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5d, 0x29, 0x2e, 0x61, 0x70, + 0x70, 0x6c, 0x79, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x61, + 0x72, 0x67, 0x73, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, + 0x20, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x6e, 0x69, 0x65, 0x6e, 0x63, 0x65, + 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, + 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x6d, 0x61, + 0x70, 0x60, 0x3a, 0x20, 0x66, 0x65, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, + 0x20, 0x61, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x2e, + 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x70, 0x6c, 0x75, 0x63, 0x6b, 0x20, 0x3d, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, + 0x6a, 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x6d, + 0x61, 0x70, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x7b, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x5b, 0x6b, 0x65, 0x79, 0x5d, 0x3b, 0x20, 0x7d, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x43, + 0x6f, 0x6e, 0x76, 0x65, 0x6e, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20, 0x63, + 0x61, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x66, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x60, 0x3a, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, + 0x6e, 0x67, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x73, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x63, 0x20, 0x60, 0x6b, 0x65, 0x79, 0x3a, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x60, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2e, 0x0a, + 0x20, 0x20, 0x5f, 0x2e, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, + 0x2c, 0x20, 0x61, 0x74, 0x74, 0x72, 0x73, 0x2c, 0x20, 0x66, 0x69, 0x72, + 0x73, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x5f, 0x2e, 0x69, 0x73, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, + 0x61, 0x74, 0x74, 0x72, 0x73, 0x29, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x3f, 0x20, 0x6e, + 0x75, 0x6c, 0x6c, 0x20, 0x3a, 0x20, 0x5b, 0x5d, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x5b, 0x66, + 0x69, 0x72, 0x73, 0x74, 0x20, 0x3f, 0x20, 0x27, 0x66, 0x69, 0x6e, 0x64, + 0x27, 0x20, 0x3a, 0x20, 0x27, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x27, + 0x5d, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, + 0x76, 0x61, 0x72, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x61, + 0x74, 0x74, 0x72, 0x73, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x61, 0x74, 0x74, 0x72, + 0x73, 0x5b, 0x6b, 0x65, 0x79, 0x5d, 0x20, 0x21, 0x3d, 0x3d, 0x20, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x5b, 0x6b, 0x65, 0x79, 0x5d, 0x29, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x72, + 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x43, + 0x6f, 0x6e, 0x76, 0x65, 0x6e, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20, 0x63, + 0x61, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x66, 0x69, 0x6e, 0x64, + 0x60, 0x3a, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x63, 0x20, 0x60, 0x6b, 0x65, 0x79, 0x3a, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x60, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2e, 0x0a, + 0x20, 0x20, 0x5f, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x57, 0x68, 0x65, 0x72, + 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x61, 0x74, 0x74, 0x72, 0x73, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x5f, 0x2e, 0x77, 0x68, 0x65, 0x72, 0x65, 0x28, 0x6f, 0x62, + 0x6a, 0x2c, 0x20, 0x61, 0x74, 0x74, 0x72, 0x73, 0x2c, 0x20, 0x74, 0x72, + 0x75, 0x65, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x65, + 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x28, 0x65, + 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, 0x64, + 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x29, 0x2e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x43, 0x61, 0x6e, 0x27, + 0x74, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x20, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x69, 0x6e, 0x74, + 0x65, 0x67, 0x65, 0x72, 0x73, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, + 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x36, 0x35, 0x2c, 0x35, 0x33, 0x35, + 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x53, 0x65, 0x65, 0x3a, 0x20, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x62, 0x75, 0x67, 0x73, 0x2e, 0x77, 0x65, + 0x62, 0x6b, 0x69, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x73, 0x68, 0x6f, + 0x77, 0x5f, 0x62, 0x75, 0x67, 0x2e, 0x63, 0x67, 0x69, 0x3f, 0x69, 0x64, + 0x3d, 0x38, 0x30, 0x37, 0x39, 0x37, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x6d, + 0x61, 0x78, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, + 0x21, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x26, 0x26, + 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x28, 0x6f, + 0x62, 0x6a, 0x29, 0x20, 0x26, 0x26, 0x20, 0x6f, 0x62, 0x6a, 0x5b, 0x30, + 0x5d, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x2b, 0x6f, 0x62, 0x6a, 0x5b, 0x30, + 0x5d, 0x20, 0x26, 0x26, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x20, 0x3c, 0x20, 0x36, 0x35, 0x35, 0x33, 0x35, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x6d, 0x61, 0x78, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x4d, 0x61, 0x74, 0x68, 0x2c, + 0x20, 0x6f, 0x62, 0x6a, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x69, 0x74, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x26, 0x26, 0x20, 0x5f, 0x2e, + 0x69, 0x73, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x6f, 0x62, 0x6a, 0x29, + 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x2d, 0x49, 0x6e, + 0x66, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, + 0x20, 0x7b, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x20, 0x3a, + 0x20, 0x2d, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x2c, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x20, 0x2d, 0x49, 0x6e, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x79, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, + 0x61, 0x63, 0x68, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, + 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, 0x6c, 0x69, 0x73, 0x74, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, + 0x72, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x20, 0x3d, + 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x3f, 0x20, + 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x63, 0x61, 0x6c, + 0x6c, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, + 0x20, 0x6c, 0x69, 0x73, 0x74, 0x29, 0x20, 0x3a, 0x20, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, + 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x20, 0x3e, 0x3d, 0x20, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, + 0x64, 0x20, 0x26, 0x26, 0x20, 0x28, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x20, 0x3d, 0x20, 0x7b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3a, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, + 0x74, 0x65, 0x64, 0x20, 0x3a, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, + 0x65, 0x64, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x65, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x28, 0x6f, 0x72, 0x20, 0x65, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x63, + 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x2e, + 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x6d, 0x69, 0x6e, 0x20, 0x3d, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, + 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x69, 0x74, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x20, 0x26, 0x26, 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x41, + 0x72, 0x72, 0x61, 0x79, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x26, 0x26, + 0x20, 0x6f, 0x62, 0x6a, 0x5b, 0x30, 0x5d, 0x20, 0x3d, 0x3d, 0x3d, 0x20, + 0x2b, 0x6f, 0x62, 0x6a, 0x5b, 0x30, 0x5d, 0x20, 0x26, 0x26, 0x20, 0x6f, + 0x62, 0x6a, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x3c, 0x20, + 0x36, 0x35, 0x35, 0x33, 0x35, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4d, 0x61, + 0x74, 0x68, 0x2e, 0x6d, 0x69, 0x6e, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, + 0x28, 0x4d, 0x61, 0x74, 0x68, 0x2c, 0x20, 0x6f, 0x62, 0x6a, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x21, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x20, 0x26, 0x26, 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x63, 0x6f, 0x6d, 0x70, 0x75, + 0x74, 0x65, 0x64, 0x20, 0x3a, 0x20, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69, + 0x74, 0x79, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x20, 0x49, + 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x7d, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x65, 0x61, 0x63, 0x68, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, 0x6c, + 0x69, 0x73, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, + 0x64, 0x20, 0x3d, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x20, 0x3f, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, + 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x2c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x29, 0x20, 0x3a, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x20, 0x3c, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x75, + 0x74, 0x65, 0x64, 0x20, 0x26, 0x26, 0x20, 0x28, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, + 0x3a, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x63, 0x6f, 0x6d, + 0x70, 0x75, 0x74, 0x65, 0x64, 0x20, 0x3a, 0x20, 0x63, 0x6f, 0x6d, 0x70, + 0x75, 0x74, 0x65, 0x64, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x53, 0x68, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x20, + 0x61, 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x0a, 0x20, 0x20, + 0x5f, 0x2e, 0x73, 0x68, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x72, 0x61, 0x6e, 0x64, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, + 0x72, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3d, 0x20, 0x30, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x73, 0x68, 0x75, + 0x66, 0x66, 0x6c, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x65, 0x61, 0x63, 0x68, 0x28, 0x6f, 0x62, 0x6a, + 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x72, + 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x28, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2b, + 0x2b, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, + 0x75, 0x66, 0x66, 0x6c, 0x65, 0x64, 0x5b, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x20, 0x2d, 0x20, 0x31, 0x5d, 0x20, 0x3d, 0x20, 0x73, 0x68, 0x75, 0x66, + 0x66, 0x6c, 0x65, 0x64, 0x5b, 0x72, 0x61, 0x6e, 0x64, 0x5d, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x75, 0x66, 0x66, 0x6c, + 0x65, 0x64, 0x5b, 0x72, 0x61, 0x6e, 0x64, 0x5d, 0x20, 0x3d, 0x20, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x73, 0x68, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x64, 0x3b, 0x0a, 0x20, + 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, 0x6e, + 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x67, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, + 0x70, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2e, + 0x0a, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, + 0x70, 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x46, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, + 0x20, 0x3f, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3a, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, + 0x7b, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, + 0x5b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5d, 0x3b, 0x20, 0x7d, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x53, + 0x6f, 0x72, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x27, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, + 0x62, 0x79, 0x20, 0x61, 0x20, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, + 0x6f, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, + 0x62, 0x79, 0x20, 0x61, 0x6e, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x73, 0x6f, 0x72, 0x74, + 0x42, 0x79, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x74, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, + 0x75, 0x70, 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x28, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x70, 0x6c, 0x75, 0x63, + 0x6b, 0x28, 0x5f, 0x2e, 0x6d, 0x61, 0x70, 0x28, 0x6f, 0x62, 0x6a, 0x2c, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, + 0x6c, 0x69, 0x73, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x20, 0x3a, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, + 0x3a, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, + 0x61, 0x20, 0x3a, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x2c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x29, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x29, 0x2e, 0x73, 0x6f, 0x72, 0x74, 0x28, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x65, 0x66, 0x74, 0x2c, 0x20, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x6c, 0x65, + 0x66, 0x74, 0x2e, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x62, + 0x20, 0x3d, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x2e, 0x63, 0x72, 0x69, + 0x74, 0x65, 0x72, 0x69, 0x61, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x61, 0x20, 0x21, 0x3d, 0x3d, 0x20, 0x62, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x61, 0x20, 0x3e, 0x20, 0x62, 0x20, 0x7c, 0x7c, + 0x20, 0x61, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x76, 0x6f, 0x69, 0x64, 0x20, + 0x30, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x28, 0x61, 0x20, 0x3c, 0x20, 0x62, 0x20, 0x7c, 0x7c, 0x20, 0x62, 0x20, + 0x3d, 0x3d, 0x3d, 0x20, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x30, 0x29, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x2d, 0x31, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x65, 0x66, 0x74, + 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3c, 0x20, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3f, 0x20, 0x2d, + 0x31, 0x20, 0x3a, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x29, 0x2c, 0x20, 0x27, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x27, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x41, 0x6e, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x75, 0x73, 0x65, + 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x20, 0x22, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x62, + 0x79, 0x22, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x62, + 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x76, 0x61, 0x72, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, + 0x7c, 0x7c, 0x20, 0x5f, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x61, 0x63, 0x68, + 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x3d, 0x20, 0x69, + 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, + 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, + 0x6f, 0x62, 0x6a, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x28, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x2c, 0x20, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x7d, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x27, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x62, + 0x79, 0x20, 0x61, 0x20, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x6f, + 0x6e, 0x2e, 0x20, 0x50, 0x61, 0x73, 0x73, 0x20, 0x65, 0x69, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x61, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x74, 0x6f, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, + 0x62, 0x79, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x20, + 0x5f, 0x2e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x79, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, + 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, + 0x5f, 0x2e, 0x68, 0x61, 0x73, 0x28, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x20, 0x3f, 0x20, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x5b, 0x6b, 0x65, 0x79, 0x5d, 0x20, 0x3a, 0x20, 0x28, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5b, 0x6b, 0x65, 0x79, 0x5d, 0x20, + 0x3d, 0x20, 0x5b, 0x5d, 0x29, 0x29, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x20, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, + 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x62, 0x79, 0x20, 0x61, + 0x20, 0x63, 0x65, 0x72, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x63, 0x72, 0x69, + 0x74, 0x65, 0x72, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x50, 0x61, 0x73, 0x73, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x61, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x62, 0x79, 0x2c, 0x20, 0x6f, 0x72, 0x20, + 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x63, 0x72, 0x69, + 0x74, 0x65, 0x72, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x20, 0x3d, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x6f, + 0x62, 0x6a, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2c, + 0x20, 0x6b, 0x65, 0x79, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x5f, 0x2e, 0x68, 0x61, 0x73, + 0x28, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2c, 0x20, 0x6b, 0x65, 0x79, + 0x29, 0x29, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5b, 0x6b, 0x65, + 0x79, 0x5d, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5b, 0x6b, 0x65, 0x79, + 0x5d, 0x2b, 0x2b, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x55, 0x73, 0x65, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x20, + 0x6f, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6d, 0x61, 0x6c, + 0x6c, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x61, + 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x0a, 0x20, 0x20, 0x2f, 0x2f, + 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x73, + 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6e, 0x73, + 0x65, 0x72, 0x74, 0x65, 0x64, 0x20, 0x73, 0x6f, 0x20, 0x61, 0x73, 0x20, + 0x74, 0x6f, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x20, 0x55, 0x73, 0x65, 0x73, 0x20, + 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x73, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, + 0x20, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x3f, + 0x20, 0x5f, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, + 0x3a, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x28, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, 0x20, 0x69, 0x74, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x6f, 0x62, 0x6a, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6c, 0x6f, 0x77, + 0x20, 0x3d, 0x20, 0x30, 0x2c, 0x20, 0x68, 0x69, 0x67, 0x68, 0x20, 0x3d, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, + 0x20, 0x28, 0x6c, 0x6f, 0x77, 0x20, 0x3c, 0x20, 0x68, 0x69, 0x67, 0x68, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, + 0x72, 0x20, 0x6d, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x28, 0x6c, 0x6f, 0x77, + 0x20, 0x2b, 0x20, 0x68, 0x69, 0x67, 0x68, 0x29, 0x20, 0x3e, 0x3e, 0x3e, + 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x74, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x5b, 0x6d, 0x69, 0x64, 0x5d, 0x29, 0x20, 0x3c, 0x20, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3f, 0x20, 0x6c, 0x6f, 0x77, 0x20, 0x3d, + 0x20, 0x6d, 0x69, 0x64, 0x20, 0x2b, 0x20, 0x31, 0x20, 0x3a, 0x20, 0x68, + 0x69, 0x67, 0x68, 0x20, 0x3d, 0x20, 0x6d, 0x69, 0x64, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x77, 0x3b, 0x0a, 0x20, 0x20, 0x7d, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x53, 0x61, 0x66, 0x65, + 0x6c, 0x79, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x20, 0x61, + 0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, 0x65, 0x72, + 0x61, 0x62, 0x6c, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x61, 0x20, + 0x72, 0x65, 0x61, 0x6c, 0x2c, 0x20, 0x6c, 0x69, 0x76, 0x65, 0x20, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x74, 0x6f, + 0x41, 0x72, 0x72, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x6f, 0x62, 0x6a, + 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5b, 0x5d, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x5f, 0x2e, 0x69, + 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x29, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x6c, 0x69, 0x63, + 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6f, 0x62, 0x6a, + 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x3d, 0x3d, 0x3d, 0x20, + 0x2b, 0x6f, 0x62, 0x6a, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x29, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x6d, 0x61, + 0x70, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x5f, 0x2e, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x73, 0x69, 0x7a, + 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x6f, 0x62, 0x6a, 0x20, 0x3d, 0x3d, 0x20, 0x6e, + 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x28, 0x6f, 0x62, 0x6a, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x2b, 0x6f, 0x62, 0x6a, 0x2e, 0x6c, + 0x65, 0x6e, 0x67, 0x74, 0x68, 0x29, 0x20, 0x3f, 0x20, 0x6f, 0x62, 0x6a, + 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x3a, 0x20, 0x5f, 0x2e, + 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x2e, 0x6c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x20, 0x46, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x47, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, + 0x74, 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x61, 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x20, 0x50, + 0x61, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x2a, 0x2a, 0x6e, 0x2a, 0x2a, + 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x4e, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x2e, 0x20, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, 0x61, + 0x73, 0x20, 0x60, 0x68, 0x65, 0x61, 0x64, 0x60, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x60, 0x74, 0x61, 0x6b, 0x65, 0x60, 0x2e, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x2a, 0x2a, 0x67, 0x75, 0x61, 0x72, 0x64, 0x2a, 0x2a, 0x20, 0x63, + 0x68, 0x65, 0x63, 0x6b, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x61, 0x6c, + 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x69, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x77, + 0x6f, 0x72, 0x6b, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x60, 0x5f, 0x2e, + 0x6d, 0x61, 0x70, 0x60, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x66, 0x69, + 0x72, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x68, 0x65, 0x61, 0x64, + 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x74, 0x61, 0x6b, 0x65, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x2c, 0x20, 0x6e, 0x2c, 0x20, 0x67, 0x75, 0x61, 0x72, 0x64, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, + 0x6c, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x6f, + 0x69, 0x64, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x6e, 0x20, 0x21, 0x3d, 0x20, 0x6e, + 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x26, 0x26, 0x20, 0x21, 0x67, 0x75, 0x61, + 0x72, 0x64, 0x20, 0x3f, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, + 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, 0x30, + 0x2c, 0x20, 0x6e, 0x29, 0x20, 0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x5b, 0x30, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, + 0x65, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x20, + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x20, 0x45, 0x73, 0x70, 0x65, + 0x63, 0x69, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x75, 0x73, 0x65, 0x66, 0x75, + 0x6c, 0x20, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x20, 0x50, 0x61, 0x73, 0x73, + 0x69, 0x6e, 0x67, 0x20, 0x2a, 0x2a, 0x6e, 0x2a, 0x2a, 0x20, 0x77, 0x69, + 0x6c, 0x6c, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x6c, + 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x20, 0x69, 0x6e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, 0x65, 0x78, 0x63, 0x6c, + 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, + 0x73, 0x74, 0x20, 0x4e, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x2a, 0x2a, + 0x67, 0x75, 0x61, 0x72, 0x64, 0x2a, 0x2a, 0x20, 0x63, 0x68, 0x65, 0x63, + 0x6b, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x69, 0x74, 0x20, + 0x74, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x60, 0x5f, 0x2e, 0x6d, 0x61, 0x70, + 0x60, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x69, + 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, 0x6e, 0x2c, 0x20, + 0x67, 0x75, 0x61, 0x72, 0x64, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x6c, 0x69, 0x63, + 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x6c, + 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x2d, 0x20, 0x28, 0x28, 0x6e, 0x20, + 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x7c, 0x7c, 0x20, + 0x67, 0x75, 0x61, 0x72, 0x64, 0x20, 0x3f, 0x20, 0x31, 0x20, 0x3a, 0x20, + 0x6e, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x47, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6c, 0x61, 0x73, 0x74, 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x2e, 0x20, 0x50, 0x61, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x2a, 0x2a, + 0x6e, 0x2a, 0x2a, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74, + 0x20, 0x4e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x2a, 0x2a, 0x67, + 0x75, 0x61, 0x72, 0x64, 0x2a, 0x2a, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, + 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x69, 0x74, 0x20, 0x74, + 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x60, 0x5f, 0x2e, 0x6d, 0x61, 0x70, 0x60, 0x2e, 0x0a, 0x20, 0x20, 0x5f, + 0x2e, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, + 0x6e, 0x2c, 0x20, 0x67, 0x75, 0x61, 0x72, 0x64, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x30, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x28, 0x6e, + 0x20, 0x21, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x26, 0x26, + 0x20, 0x21, 0x67, 0x75, 0x61, 0x72, 0x64, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x6d, + 0x61, 0x78, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x20, 0x2d, 0x20, 0x6e, 0x2c, 0x20, 0x30, 0x29, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5b, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x2d, + 0x20, 0x31, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, + 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x65, 0x76, 0x65, 0x72, 0x79, 0x74, + 0x68, 0x69, 0x6e, 0x67, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x2e, 0x20, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, 0x61, + 0x73, 0x20, 0x60, 0x74, 0x61, 0x69, 0x6c, 0x60, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x60, 0x64, 0x72, 0x6f, 0x70, 0x60, 0x2e, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x45, 0x73, 0x70, 0x65, 0x63, 0x69, 0x61, 0x6c, 0x6c, 0x79, + 0x20, 0x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x20, 0x6f, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x20, 0x50, 0x61, 0x73, + 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x20, 0x2a, 0x2a, 0x6e, 0x2a, + 0x2a, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, + 0x65, 0x73, 0x74, 0x20, 0x4e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x2a, 0x2a, 0x67, 0x75, 0x61, + 0x72, 0x64, 0x2a, 0x2a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x69, + 0x74, 0x20, 0x74, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x60, 0x5f, 0x2e, 0x6d, 0x61, 0x70, 0x60, 0x2e, 0x0a, + 0x20, 0x20, 0x5f, 0x2e, 0x72, 0x65, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x5f, + 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x64, 0x72, + 0x6f, 0x70, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, 0x6e, 0x2c, 0x20, + 0x67, 0x75, 0x61, 0x72, 0x64, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x6c, 0x69, 0x63, + 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x2c, 0x20, 0x28, 0x6e, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, + 0x29, 0x20, 0x7c, 0x7c, 0x20, 0x67, 0x75, 0x61, 0x72, 0x64, 0x20, 0x3f, + 0x20, 0x31, 0x20, 0x3a, 0x20, 0x6e, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x54, 0x72, 0x69, 0x6d, + 0x20, 0x6f, 0x75, 0x74, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x66, 0x61, 0x6c, + 0x73, 0x79, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x66, 0x72, + 0x6f, 0x6d, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, + 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, + 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, + 0x5f, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x69, 0x6d, 0x70, + 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x6f, 0x66, 0x20, 0x61, 0x20, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, + 0x76, 0x65, 0x20, 0x60, 0x66, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x60, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x66, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x6e, + 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x2c, 0x20, 0x73, 0x68, 0x61, 0x6c, 0x6c, + 0x6f, 0x77, 0x2c, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x61, 0x63, 0x68, 0x28, 0x69, + 0x6e, 0x70, 0x75, 0x74, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x5f, 0x2e, + 0x69, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x28, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x29, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x73, 0x68, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x20, 0x3f, 0x20, + 0x70, 0x75, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x29, 0x20, 0x3a, 0x20, 0x66, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x28, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x73, 0x68, 0x61, 0x6c, 0x6c, + 0x6f, 0x77, 0x2c, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, + 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x6c, + 0x79, 0x20, 0x66, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x65, 0x64, 0x20, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x61, + 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x0a, 0x20, 0x20, 0x5f, + 0x2e, 0x66, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x2c, 0x20, 0x73, 0x68, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x66, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x28, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x2c, 0x20, 0x73, 0x68, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x2c, + 0x20, 0x5b, 0x5d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x61, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x28, 0x73, 0x29, 0x2e, 0x0a, 0x20, 0x20, 0x5f, + 0x2e, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, + 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, + 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x31, 0x29, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x61, 0x20, + 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x2d, 0x66, 0x72, + 0x65, 0x65, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, + 0x20, 0x49, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x20, 0x68, 0x61, 0x73, 0x20, 0x61, 0x6c, 0x72, 0x65, 0x61, 0x64, + 0x79, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, + 0x73, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x79, 0x6f, 0x75, 0x20, + 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, + 0x20, 0x61, 0x20, 0x66, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x61, 0x6c, + 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, 0x61, 0x73, + 0x20, 0x60, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x60, 0x2e, 0x0a, 0x20, + 0x20, 0x5f, 0x2e, 0x75, 0x6e, 0x69, 0x71, 0x20, 0x3d, 0x20, 0x5f, 0x2e, + 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, + 0x20, 0x69, 0x73, 0x53, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x69, + 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x5f, 0x2e, 0x69, 0x73, 0x46, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x69, 0x73, 0x53, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x29, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x3d, 0x20, 0x69, 0x74, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x3d, + 0x20, 0x69, 0x73, 0x53, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x73, 0x53, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, + 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x69, + 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x3f, 0x20, 0x5f, 0x2e, + 0x6d, 0x61, 0x70, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, 0x69, + 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x29, 0x20, 0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x73, 0x65, 0x65, + 0x6e, 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x65, 0x61, 0x63, 0x68, 0x28, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, + 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x28, 0x69, 0x73, 0x53, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x3f, 0x20, + 0x28, 0x21, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x7c, 0x7c, 0x20, 0x73, + 0x65, 0x65, 0x6e, 0x5b, 0x73, 0x65, 0x65, 0x6e, 0x2e, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x20, 0x2d, 0x20, 0x31, 0x5d, 0x20, 0x21, 0x3d, 0x3d, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x20, 0x3a, 0x20, 0x21, 0x5f, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x28, 0x73, 0x65, + 0x65, 0x6e, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, + 0x65, 0x6e, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x70, 0x75, 0x73, 0x68, + 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5b, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x5d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x61, + 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x65, 0x61, 0x63, + 0x68, 0x20, 0x64, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x63, 0x74, 0x20, 0x65, + 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, + 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x66, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x2d, 0x69, + 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x73, 0x2e, 0x0a, 0x20, 0x20, + 0x5f, 0x2e, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, + 0x75, 0x6e, 0x69, 0x71, 0x28, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, + 0x65, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, + 0x20, 0x65, 0x76, 0x65, 0x72, 0x79, 0x20, 0x69, 0x74, 0x65, 0x6d, 0x20, + 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, + 0x65, 0x6e, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x2d, 0x69, + 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x73, 0x2e, 0x0a, 0x20, 0x20, + 0x5f, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x73, 0x74, 0x20, + 0x3d, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, + 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, + 0x31, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x28, + 0x5f, 0x2e, 0x75, 0x6e, 0x69, 0x71, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x29, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x69, 0x74, 0x65, 0x6d, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x65, + 0x76, 0x65, 0x72, 0x79, 0x28, 0x72, 0x65, 0x73, 0x74, 0x2c, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x74, 0x68, 0x65, + 0x72, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x4f, 0x66, 0x28, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2c, + 0x20, 0x69, 0x74, 0x65, 0x6d, 0x29, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x54, 0x61, 0x6b, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x6f, 0x6e, + 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x61, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, + 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x73, + 0x2e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x20, + 0x6a, 0x75, 0x73, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, + 0x73, 0x74, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x77, 0x69, 0x6c, + 0x6c, 0x20, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x0a, 0x20, 0x20, + 0x5f, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x73, 0x74, 0x20, 0x3d, 0x20, + 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, + 0x28, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2c, + 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, + 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x31, + 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x28, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x7b, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x21, 0x5f, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x28, 0x72, 0x65, 0x73, 0x74, 0x2c, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x3b, 0x20, 0x7d, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x5a, 0x69, 0x70, 0x20, 0x74, 0x6f, 0x67, 0x65, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x6c, 0x69, + 0x73, 0x74, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x73, + 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, + 0x2d, 0x2d, 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x61, 0x6e, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x20, 0x67, 0x6f, 0x20, 0x74, 0x6f, 0x67, 0x65, 0x74, 0x68, 0x65, 0x72, + 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x7a, 0x69, 0x70, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x61, 0x72, 0x67, + 0x73, 0x20, 0x3d, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, + 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6c, + 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x6d, 0x61, + 0x78, 0x28, 0x5f, 0x2e, 0x70, 0x6c, 0x75, 0x63, 0x6b, 0x28, 0x61, 0x72, + 0x67, 0x73, 0x2c, 0x20, 0x27, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x27, + 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x3d, 0x20, 0x6e, 0x65, + 0x77, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x28, 0x6c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x30, 0x3b, + 0x20, 0x69, 0x20, 0x3c, 0x20, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, + 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5b, 0x69, 0x5d, + 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x70, 0x6c, 0x75, 0x63, 0x6b, 0x28, 0x61, + 0x72, 0x67, 0x73, 0x2c, 0x20, 0x22, 0x22, 0x20, 0x2b, 0x20, 0x69, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x73, 0x20, + 0x6c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2e, 0x20, 0x50, 0x61, 0x73, 0x73, + 0x20, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x20, 0x73, 0x69, + 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, + 0x66, 0x20, 0x60, 0x5b, 0x6b, 0x65, 0x79, 0x2c, 0x20, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x5d, 0x60, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x70, 0x61, + 0x69, 0x72, 0x73, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x77, 0x6f, 0x20, + 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x20, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x61, 0x6d, 0x65, 0x20, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x2d, + 0x2d, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x6b, 0x65, 0x79, + 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x6f, + 0x66, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x6f, 0x72, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x5f, + 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x69, 0x73, 0x74, 0x2c, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6c, 0x69, 0x73, 0x74, 0x20, + 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x7b, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, + 0x20, 0x7b, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x30, 0x2c, + 0x20, 0x6c, 0x20, 0x3d, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x6c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x20, 0x69, 0x20, 0x3c, 0x20, 0x6c, 0x3b, + 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5b, 0x6c, 0x69, 0x73, 0x74, 0x5b, + 0x69, 0x5d, 0x5d, 0x20, 0x3d, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x5b, 0x69, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5b, 0x6c, + 0x69, 0x73, 0x74, 0x5b, 0x69, 0x5d, 0x5b, 0x30, 0x5d, 0x5d, 0x20, 0x3d, + 0x20, 0x6c, 0x69, 0x73, 0x74, 0x5b, 0x69, 0x5d, 0x5b, 0x31, 0x5d, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3b, 0x0a, 0x20, 0x20, + 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x20, + 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x73, 0x75, 0x70, 0x70, + 0x6c, 0x79, 0x20, 0x75, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x20, 0x28, 0x49, 0x27, 0x6d, 0x20, + 0x6c, 0x6f, 0x6f, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x74, 0x20, 0x79, + 0x6f, 0x75, 0x2c, 0x20, 0x2a, 0x2a, 0x4d, 0x53, 0x49, 0x45, 0x2a, 0x2a, + 0x29, 0x2c, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x77, 0x65, 0x20, 0x6e, + 0x65, 0x65, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, + 0x72, 0x73, 0x74, 0x20, 0x6f, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x69, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x6e, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x2d, + 0x31, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x74, 0x65, + 0x6d, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, + 0x20, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, + 0x6f, 0x20, 0x2a, 0x2a, 0x45, 0x43, 0x4d, 0x41, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x20, 0x35, 0x2a, 0x2a, 0x27, 0x73, 0x20, 0x6e, 0x61, 0x74, + 0x69, 0x76, 0x65, 0x20, 0x60, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, + 0x60, 0x20, 0x69, 0x66, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, + 0x6c, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x69, 0x73, + 0x20, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, + 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x73, 0x6f, + 0x72, 0x74, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2c, 0x20, 0x70, 0x61, + 0x73, 0x73, 0x20, 0x60, 0x74, 0x72, 0x75, 0x65, 0x60, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x2a, 0x2a, 0x69, 0x73, 0x53, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x2a, 0x2a, 0x20, 0x74, 0x6f, 0x20, 0x75, + 0x73, 0x65, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x73, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x4f, 0x66, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, + 0x69, 0x74, 0x65, 0x6d, 0x2c, 0x20, 0x69, 0x73, 0x53, 0x6f, 0x72, 0x74, + 0x65, 0x64, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x3d, 0x3d, 0x20, 0x6e, + 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x2d, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x69, 0x20, 0x3d, 0x20, 0x30, 0x2c, 0x20, 0x6c, 0x20, 0x3d, 0x20, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x73, 0x53, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x79, 0x70, 0x65, 0x6f, + 0x66, 0x20, 0x69, 0x73, 0x53, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x3d, + 0x3d, 0x20, 0x27, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x27, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, + 0x3d, 0x20, 0x28, 0x69, 0x73, 0x53, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, + 0x3c, 0x20, 0x30, 0x20, 0x3f, 0x20, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x6d, + 0x61, 0x78, 0x28, 0x30, 0x2c, 0x20, 0x6c, 0x20, 0x2b, 0x20, 0x69, 0x73, + 0x53, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x29, 0x20, 0x3a, 0x20, 0x69, 0x73, + 0x53, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, 0x3d, 0x20, + 0x5f, 0x2e, 0x73, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2c, 0x20, 0x69, 0x74, 0x65, + 0x6d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x69, 0x74, 0x65, 0x6d, + 0x20, 0x3f, 0x20, 0x69, 0x20, 0x3a, 0x20, 0x2d, 0x31, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x61, 0x74, + 0x69, 0x76, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x20, 0x26, + 0x26, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x4f, 0x66, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x6e, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x29, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x28, 0x69, 0x74, 0x65, 0x6d, + 0x2c, 0x20, 0x69, 0x73, 0x53, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x3b, 0x20, + 0x69, 0x20, 0x3c, 0x20, 0x6c, 0x3b, 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5b, 0x69, 0x5d, + 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x69, 0x74, 0x65, 0x6d, 0x29, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x2d, 0x31, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44, + 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, + 0x2a, 0x2a, 0x45, 0x43, 0x4d, 0x41, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x20, 0x35, 0x2a, 0x2a, 0x27, 0x73, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, + 0x65, 0x20, 0x60, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x4f, 0x66, 0x60, 0x20, 0x69, 0x66, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x6c, 0x61, + 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x2c, 0x20, 0x69, 0x74, 0x65, 0x6d, 0x2c, 0x20, 0x66, 0x72, + 0x6f, 0x6d, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x3d, 0x3d, 0x20, 0x6e, + 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x2d, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x68, 0x61, 0x73, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3d, 0x20, 0x66, + 0x72, 0x6f, 0x6d, 0x20, 0x21, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x61, 0x74, + 0x69, 0x76, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x4f, 0x66, 0x20, 0x26, 0x26, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, + 0x6c, 0x61, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x20, + 0x3d, 0x3d, 0x3d, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4c, 0x61, + 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x68, 0x61, 0x73, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3f, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x6c, 0x61, 0x73, 0x74, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x28, 0x69, 0x74, 0x65, 0x6d, 0x2c, + 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x29, 0x20, 0x3a, 0x20, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x2e, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x4f, 0x66, 0x28, 0x69, 0x74, 0x65, 0x6d, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x69, 0x20, 0x3d, 0x20, 0x28, 0x68, 0x61, 0x73, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x20, 0x3f, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x3a, 0x20, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, + 0x28, 0x69, 0x2d, 0x2d, 0x29, 0x20, 0x69, 0x66, 0x20, 0x28, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x69, + 0x74, 0x65, 0x6d, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x69, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x2d, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x65, 0x20, 0x61, 0x6e, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, + 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x72, 0x69, + 0x74, 0x68, 0x6d, 0x65, 0x74, 0x69, 0x63, 0x20, 0x70, 0x72, 0x6f, 0x67, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x41, 0x20, 0x70, + 0x6f, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x50, + 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x20, 0x60, 0x72, 0x61, 0x6e, 0x67, 0x65, + 0x28, 0x29, 0x60, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x20, 0x53, 0x65, 0x65, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x5b, + 0x74, 0x68, 0x65, 0x20, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x20, 0x64, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5d, 0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x64, 0x6f, 0x63, + 0x73, 0x2e, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x2e, 0x6f, 0x72, 0x67, + 0x2f, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x2f, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x23, + 0x72, 0x61, 0x6e, 0x67, 0x65, 0x29, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, + 0x72, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x73, 0x74, 0x61, 0x72, 0x74, 0x2c, 0x20, + 0x73, 0x74, 0x6f, 0x70, 0x2c, 0x20, 0x73, 0x74, 0x65, 0x70, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x61, 0x72, + 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x6c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x6f, 0x70, 0x20, 0x3d, 0x20, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x7c, 0x7c, 0x20, 0x30, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, + 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x73, 0x74, 0x65, 0x70, 0x20, 0x3d, 0x20, 0x61, 0x72, + 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x5b, 0x32, 0x5d, 0x20, 0x7c, + 0x7c, 0x20, 0x31, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, + 0x72, 0x20, 0x6c, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x4d, 0x61, 0x74, 0x68, + 0x2e, 0x6d, 0x61, 0x78, 0x28, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x63, 0x65, + 0x69, 0x6c, 0x28, 0x28, 0x73, 0x74, 0x6f, 0x70, 0x20, 0x2d, 0x20, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x29, 0x20, 0x2f, 0x20, 0x73, 0x74, 0x65, 0x70, + 0x29, 0x2c, 0x20, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, + 0x61, 0x72, 0x20, 0x69, 0x64, 0x78, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x61, 0x6e, 0x67, + 0x65, 0x20, 0x3d, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x41, 0x72, 0x72, 0x61, + 0x79, 0x28, 0x6c, 0x65, 0x6e, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x28, 0x69, 0x64, 0x78, 0x20, 0x3c, + 0x20, 0x6c, 0x65, 0x6e, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x5b, 0x69, 0x64, 0x78, 0x2b, + 0x2b, 0x5d, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, + 0x2b, 0x3d, 0x20, 0x73, 0x74, 0x65, 0x70, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3b, 0x0a, 0x20, 0x20, + 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x46, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x68, 0x65, 0x6d, 0x29, + 0x20, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, + 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x62, + 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x67, 0x69, + 0x76, 0x65, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x28, + 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x60, 0x74, + 0x68, 0x69, 0x73, 0x60, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x72, + 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x6c, 0x79, + 0x29, 0x2e, 0x20, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, + 0x20, 0x74, 0x6f, 0x20, 0x2a, 0x2a, 0x45, 0x43, 0x4d, 0x41, 0x53, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x20, 0x35, 0x2a, 0x2a, 0x27, 0x73, 0x20, 0x6e, + 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x60, 0x46, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x62, 0x69, 0x6e, 0x64, 0x60, 0x20, 0x69, 0x66, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, + 0x62, 0x6c, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x62, 0x69, 0x6e, + 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x66, 0x75, 0x6e, 0x63, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x2e, 0x62, 0x69, 0x6e, 0x64, 0x20, + 0x3d, 0x3d, 0x3d, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x42, 0x69, + 0x6e, 0x64, 0x20, 0x26, 0x26, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x42, 0x69, 0x6e, 0x64, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x42, 0x69, 0x6e, 0x64, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x2c, 0x20, + 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, + 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x31, 0x29, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x61, + 0x72, 0x67, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, + 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x2c, 0x20, 0x32, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x73, 0x2e, 0x63, 0x6f, + 0x6e, 0x63, 0x61, 0x74, 0x28, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, + 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x29, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, + 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x61, 0x70, + 0x70, 0x6c, 0x79, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x62, 0x79, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x20, 0x61, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x68, 0x61, + 0x64, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x69, 0x74, + 0x73, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x20, 0x70, 0x72, 0x65, 0x2d, 0x66, 0x69, 0x6c, + 0x6c, 0x65, 0x64, 0x2c, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, + 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, + 0x73, 0x20, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x20, 0x60, 0x74, + 0x68, 0x69, 0x73, 0x60, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, + 0x6c, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x66, 0x75, 0x6e, 0x63, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x61, 0x72, 0x67, 0x73, 0x20, 0x3d, 0x20, + 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, + 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x31, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x79, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x73, + 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x73, 0x6c, 0x69, 0x63, + 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x29, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x42, 0x69, 0x6e, 0x64, 0x20, 0x61, 0x6c, 0x6c, 0x20, + 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x27, 0x73, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x2e, 0x20, 0x55, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x65, 0x6e, 0x73, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x61, 0x6c, 0x6c, + 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x20, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x6e, + 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x62, 0x65, 0x6c, 0x6f, + 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x74, 0x2e, 0x0a, 0x20, 0x20, + 0x5f, 0x2e, 0x62, 0x69, 0x6e, 0x64, 0x41, 0x6c, 0x6c, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x6c, 0x69, 0x63, + 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x31, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x2e, + 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x30, + 0x29, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x2e, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x28, 0x6f, 0x62, + 0x6a, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x61, 0x63, 0x68, + 0x28, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x66, 0x29, 0x20, 0x7b, 0x20, 0x6f, 0x62, + 0x6a, 0x5b, 0x66, 0x5d, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x62, 0x69, 0x6e, + 0x64, 0x28, 0x6f, 0x62, 0x6a, 0x5b, 0x66, 0x5d, 0x2c, 0x20, 0x6f, 0x62, + 0x6a, 0x29, 0x3b, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x4d, + 0x65, 0x6d, 0x6f, 0x69, 0x7a, 0x65, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x78, + 0x70, 0x65, 0x6e, 0x73, 0x69, 0x76, 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x62, 0x79, 0x20, 0x73, 0x74, 0x6f, 0x72, + 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, 0x73, 0x20, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x6d, 0x65, 0x6d, + 0x6f, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x2c, 0x20, 0x68, 0x61, + 0x73, 0x68, 0x65, 0x72, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x76, 0x61, 0x72, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x20, 0x3d, 0x20, 0x7b, + 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, + 0x72, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x68, 0x61, 0x73, 0x68, 0x65, 0x72, + 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, + 0x72, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x3d, 0x20, 0x68, 0x61, 0x73, 0x68, + 0x65, 0x72, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x74, 0x68, 0x69, + 0x73, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x68, 0x61, 0x73, 0x28, 0x6d, 0x65, + 0x6d, 0x6f, 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x20, 0x3f, 0x20, 0x6d, + 0x65, 0x6d, 0x6f, 0x5b, 0x6b, 0x65, 0x79, 0x5d, 0x20, 0x3a, 0x20, 0x28, + 0x6d, 0x65, 0x6d, 0x6f, 0x5b, 0x6b, 0x65, 0x79, 0x5d, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x74, + 0x68, 0x69, 0x73, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, + 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x44, 0x65, 0x6c, 0x61, 0x79, 0x73, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x73, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x6e, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x69, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x2e, 0x0a, + 0x20, 0x20, 0x5f, 0x2e, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x66, 0x75, 0x6e, + 0x63, 0x2c, 0x20, 0x77, 0x61, 0x69, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x61, 0x72, 0x67, 0x73, 0x20, + 0x3d, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, + 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, + 0x32, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x73, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, + 0x74, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, + 0x7b, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x6e, 0x75, 0x6c, 0x6c, + 0x2c, 0x20, 0x61, 0x72, 0x67, 0x73, 0x29, 0x3b, 0x20, 0x7d, 0x2c, 0x20, + 0x77, 0x61, 0x69, 0x74, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44, 0x65, 0x66, 0x65, 0x72, 0x73, + 0x20, 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2c, + 0x20, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x69, 0x6e, 0x67, 0x20, + 0x69, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x61, 0x66, + 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x20, 0x73, 0x74, 0x61, + 0x63, 0x6b, 0x20, 0x68, 0x61, 0x73, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x63, 0x6c, 0x65, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x0a, 0x20, 0x20, 0x5f, + 0x2e, 0x64, 0x65, 0x66, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x5f, 0x2e, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, + 0x6c, 0x79, 0x28, 0x5f, 0x2c, 0x20, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x2c, + 0x20, 0x31, 0x5d, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x73, + 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, + 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x31, 0x29, 0x29, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x2c, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x69, 0x6e, 0x76, + 0x6f, 0x6b, 0x65, 0x64, 0x2c, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x6f, + 0x6e, 0x6c, 0x79, 0x20, 0x62, 0x65, 0x20, 0x74, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x6d, 0x6f, 0x73, 0x74, + 0x20, 0x6f, 0x6e, 0x63, 0x65, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x64, + 0x75, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, + 0x6e, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x74, 0x68, + 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x2c, 0x20, + 0x77, 0x61, 0x69, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x76, 0x61, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, + 0x20, 0x61, 0x72, 0x67, 0x73, 0x2c, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x2c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x70, 0x72, 0x65, 0x76, + 0x69, 0x6f, 0x75, 0x73, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6c, 0x61, 0x74, 0x65, 0x72, 0x20, + 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x65, + 0x76, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x3d, 0x20, 0x6e, 0x65, 0x77, 0x20, + 0x44, 0x61, 0x74, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x6e, 0x75, + 0x6c, 0x6c, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x73, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, + 0x61, 0x72, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x6e, 0x65, 0x77, + 0x20, 0x44, 0x61, 0x74, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, + 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x77, 0x61, 0x69, 0x74, 0x20, 0x2d, 0x20, + 0x28, 0x6e, 0x6f, 0x77, 0x20, 0x2d, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, + 0x6f, 0x75, 0x73, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x72, + 0x67, 0x73, 0x20, 0x3d, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, + 0x3c, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x54, 0x69, 0x6d, + 0x65, 0x6f, 0x75, 0x74, 0x28, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x6e, 0x75, 0x6c, + 0x6c, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, + 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x3d, 0x20, 0x6e, 0x6f, + 0x77, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x73, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x21, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x65, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x28, 0x6c, 0x61, 0x74, + 0x65, 0x72, 0x2c, 0x20, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, + 0x67, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x2c, 0x20, 0x61, 0x73, 0x20, 0x6c, 0x6f, 0x6e, 0x67, + 0x20, 0x61, 0x73, 0x20, 0x69, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x69, + 0x6e, 0x75, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x69, + 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x2c, 0x20, 0x77, 0x69, 0x6c, 0x6c, + 0x20, 0x6e, 0x6f, 0x74, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x62, 0x65, + 0x20, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x65, 0x64, 0x2e, 0x20, + 0x54, 0x68, 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x63, 0x61, 0x6c, + 0x6c, 0x65, 0x64, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x69, 0x74, + 0x20, 0x73, 0x74, 0x6f, 0x70, 0x73, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, + 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x4e, 0x20, 0x6d, 0x69, 0x6c, 0x6c, 0x69, + 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x2e, 0x20, 0x49, 0x66, 0x20, + 0x60, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x60, 0x20, + 0x69, 0x73, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x2c, 0x20, 0x74, + 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x6c, 0x65, 0x61, 0x64, + 0x69, 0x6e, 0x67, 0x20, 0x65, 0x64, 0x67, 0x65, 0x2c, 0x20, 0x69, 0x6e, + 0x73, 0x74, 0x65, 0x61, 0x64, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x2e, 0x0a, 0x20, + 0x20, 0x5f, 0x2e, 0x64, 0x65, 0x62, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x20, + 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x66, + 0x75, 0x6e, 0x63, 0x2c, 0x20, 0x77, 0x61, 0x69, 0x74, 0x2c, 0x20, 0x69, + 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x2c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x73, 0x20, 0x3d, 0x20, 0x61, 0x72, + 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6c, 0x61, 0x74, 0x65, 0x72, + 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x6e, 0x75, + 0x6c, 0x6c, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x21, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, + 0x74, 0x65, 0x29, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x61, 0x72, 0x67, + 0x73, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x63, + 0x61, 0x6c, 0x6c, 0x4e, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x69, 0x6d, 0x6d, + 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x26, 0x26, 0x20, 0x21, 0x74, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x28, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x28, 0x6c, 0x61, 0x74, 0x65, 0x72, 0x2c, 0x20, 0x77, + 0x61, 0x69, 0x74, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x63, 0x61, 0x6c, 0x6c, 0x4e, 0x6f, 0x77, 0x29, + 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x73, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, + 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, + 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, + 0x6d, 0x6f, 0x73, 0x74, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x69, 0x6d, + 0x65, 0x2c, 0x20, 0x6e, 0x6f, 0x20, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x20, 0x68, 0x6f, 0x77, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x6f, 0x66, + 0x74, 0x65, 0x6e, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x63, 0x61, 0x6c, 0x6c, + 0x20, 0x69, 0x74, 0x2e, 0x20, 0x55, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x6f, 0x6e, 0x63, 0x65, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x66, 0x75, 0x6e, + 0x63, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, + 0x20, 0x72, 0x61, 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, + 0x2c, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x61, 0x6e, 0x29, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x61, 0x6e, 0x20, 0x3d, 0x20, + 0x74, 0x72, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x6d, 0x65, 0x6d, 0x6f, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2c, 0x20, + 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x20, 0x3d, + 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x65, 0x6d, 0x6f, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x7d, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, + 0x74, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, + 0x61, 0x73, 0x73, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x61, 0x6e, 0x20, + 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x2c, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, + 0x67, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x64, 0x6a, + 0x75, 0x73, 0x74, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x2c, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, + 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, + 0x66, 0x74, 0x65, 0x72, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, + 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, + 0x20, 0x20, 0x5f, 0x2e, 0x77, 0x72, 0x61, 0x70, 0x20, 0x3d, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x66, 0x75, 0x6e, 0x63, + 0x2c, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x61, + 0x72, 0x67, 0x73, 0x20, 0x3d, 0x20, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x5d, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x75, 0x73, 0x68, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x61, 0x72, 0x67, 0x73, 0x2c, + 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x2e, 0x61, 0x70, + 0x70, 0x6c, 0x79, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2c, 0x20, 0x61, 0x72, + 0x67, 0x73, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x6c, + 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x65, 0x61, 0x63, 0x68, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x69, 0x6e, + 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x2e, + 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x65, + 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x73, 0x20, 0x3d, 0x20, 0x61, 0x72, 0x67, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x61, 0x72, 0x67, 0x73, 0x20, 0x3d, 0x20, + 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, + 0x72, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x2e, + 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x2d, 0x20, 0x31, 0x3b, 0x20, + 0x69, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x3b, 0x20, 0x69, 0x2d, 0x2d, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, + 0x72, 0x67, 0x73, 0x20, 0x3d, 0x20, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x73, + 0x5b, 0x69, 0x5d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x74, 0x68, + 0x69, 0x73, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x73, 0x29, 0x5d, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x72, 0x67, + 0x73, 0x5b, 0x30, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, + 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x62, 0x65, + 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x20, 0x61, 0x66, + 0x74, 0x65, 0x72, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x61, + 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x4e, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, + 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x20, 0x3c, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x28, 0x29, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x2d, + 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x20, 0x3c, 0x20, 0x31, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x2e, 0x61, 0x70, + 0x70, 0x6c, 0x79, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2c, 0x20, 0x61, 0x72, + 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, + 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x46, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, + 0x72, 0x69, 0x65, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x27, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x69, 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x6f, + 0x20, 0x2a, 0x2a, 0x45, 0x43, 0x4d, 0x41, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x20, 0x35, 0x2a, 0x2a, 0x27, 0x73, 0x20, 0x6e, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x20, 0x60, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x6b, + 0x65, 0x79, 0x73, 0x60, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x6b, 0x65, 0x79, + 0x73, 0x20, 0x3d, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4b, 0x65, + 0x79, 0x73, 0x20, 0x7c, 0x7c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6f, 0x62, 0x6a, 0x20, 0x21, 0x3d, + 0x3d, 0x20, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x6f, 0x62, 0x6a, + 0x29, 0x29, 0x20, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x6e, 0x65, 0x77, + 0x20, 0x54, 0x79, 0x70, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x27, + 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x27, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, + 0x72, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, + 0x72, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x62, 0x6a, + 0x29, 0x20, 0x69, 0x66, 0x20, 0x28, 0x5f, 0x2e, 0x68, 0x61, 0x73, 0x28, + 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x29, 0x20, 0x6b, + 0x65, 0x79, 0x73, 0x5b, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x5d, 0x20, 0x3d, 0x20, 0x6b, 0x65, 0x79, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6b, + 0x65, 0x79, 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, + 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x27, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, + 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x76, 0x61, 0x72, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x3d, + 0x20, 0x5b, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x69, 0x6e, + 0x20, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x69, 0x66, 0x20, 0x28, 0x5f, 0x2e, + 0x68, 0x61, 0x73, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x6b, 0x65, 0x79, + 0x29, 0x29, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x70, 0x75, + 0x73, 0x68, 0x28, 0x6f, 0x62, 0x6a, 0x5b, 0x6b, 0x65, 0x79, 0x5d, 0x29, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x7d, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x6e, 0x76, + 0x65, 0x72, 0x74, 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, + 0x74, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x5b, 0x6b, 0x65, 0x79, 0x2c, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5d, 0x60, 0x20, 0x70, 0x61, 0x69, 0x72, + 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x70, 0x61, 0x69, 0x72, 0x73, + 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, + 0x61, 0x72, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x5b, + 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, + 0x76, 0x61, 0x72, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x6f, + 0x62, 0x6a, 0x29, 0x20, 0x69, 0x66, 0x20, 0x28, 0x5f, 0x2e, 0x68, 0x61, + 0x73, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x29, + 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, + 0x5b, 0x6b, 0x65, 0x79, 0x2c, 0x20, 0x6f, 0x62, 0x6a, 0x5b, 0x6b, 0x65, + 0x79, 0x5d, 0x5d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, + 0x6e, 0x76, 0x65, 0x72, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6b, 0x65, + 0x79, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x73, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x62, 0x6c, 0x65, 0x2e, + 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x69, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x20, + 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, + 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, + 0x72, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x7b, + 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, + 0x76, 0x61, 0x72, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x6f, + 0x62, 0x6a, 0x29, 0x20, 0x69, 0x66, 0x20, 0x28, 0x5f, 0x2e, 0x68, 0x61, + 0x73, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x29, + 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5b, 0x6f, 0x62, 0x6a, 0x5b, + 0x6b, 0x65, 0x79, 0x5d, 0x5d, 0x20, 0x3d, 0x20, 0x6b, 0x65, 0x79, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, + 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x61, 0x20, 0x73, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x6c, + 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x2e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, 0x6c, 0x69, 0x61, + 0x73, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x60, 0x6d, 0x65, 0x74, 0x68, + 0x6f, 0x64, 0x73, 0x60, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x6d, + 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x6b, 0x65, + 0x79, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x5f, 0x2e, + 0x69, 0x73, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, + 0x62, 0x6a, 0x5b, 0x6b, 0x65, 0x79, 0x5d, 0x29, 0x29, 0x20, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, 0x6b, 0x65, 0x79, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x2e, 0x73, 0x6f, 0x72, 0x74, 0x28, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x45, 0x78, 0x74, + 0x65, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x61, + 0x73, 0x73, 0x65, 0x64, 0x2d, 0x69, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x28, 0x73, 0x29, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x65, + 0x78, 0x74, 0x65, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x65, 0x61, 0x63, 0x68, 0x28, 0x73, 0x6c, 0x69, + 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x67, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x31, 0x29, 0x2c, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x20, + 0x69, 0x6e, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, + 0x62, 0x6a, 0x5b, 0x70, 0x72, 0x6f, 0x70, 0x5d, 0x20, 0x3d, 0x20, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5b, 0x70, 0x72, 0x6f, 0x70, 0x5d, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x61, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x6f, 0x6e, + 0x6c, 0x79, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, + 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, + 0x69, 0x73, 0x74, 0x65, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, + 0x74, 0x69, 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x70, 0x69, + 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x3d, 0x20, + 0x7b, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x6b, 0x65, 0x79, 0x73, 0x20, 0x3d, 0x20, 0x63, 0x6f, 0x6e, 0x63, 0x61, + 0x74, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x41, 0x72, 0x72, 0x61, + 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2c, 0x20, 0x73, 0x6c, 0x69, 0x63, + 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x31, 0x29, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x65, 0x61, 0x63, 0x68, 0x28, 0x6b, 0x65, 0x79, 0x73, + 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6b, + 0x65, 0x79, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x6b, 0x65, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x6f, + 0x62, 0x6a, 0x29, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x5b, 0x6b, 0x65, 0x79, + 0x5d, 0x20, 0x3d, 0x20, 0x6f, 0x62, 0x6a, 0x5b, 0x6b, 0x65, 0x79, 0x5d, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6f, 0x70, + 0x79, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, + 0x63, 0x6f, 0x70, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, + 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x61, 0x63, 0x6b, + 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x69, 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x6f, + 0x6d, 0x69, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x3d, + 0x20, 0x7b, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, + 0x20, 0x6b, 0x65, 0x79, 0x73, 0x20, 0x3d, 0x20, 0x63, 0x6f, 0x6e, 0x63, + 0x61, 0x74, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x41, 0x72, 0x72, + 0x61, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2c, 0x20, 0x73, 0x6c, 0x69, + 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x67, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x31, 0x29, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, + 0x20, 0x6b, 0x65, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x28, 0x21, 0x5f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, + 0x28, 0x6b, 0x65, 0x79, 0x73, 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x29, + 0x20, 0x63, 0x6f, 0x70, 0x79, 0x5b, 0x6b, 0x65, 0x79, 0x5d, 0x20, 0x3d, + 0x20, 0x6f, 0x62, 0x6a, 0x5b, 0x6b, 0x65, 0x79, 0x5d, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x3b, 0x0a, 0x20, 0x20, + 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x46, 0x69, 0x6c, + 0x6c, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, + 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x70, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x5f, + 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x61, 0x63, 0x68, + 0x28, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, + 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x31, + 0x29, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x70, + 0x72, 0x6f, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6f, 0x62, 0x6a, 0x5b, 0x70, + 0x72, 0x6f, 0x70, 0x5d, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, + 0x29, 0x20, 0x6f, 0x62, 0x6a, 0x5b, 0x70, 0x72, 0x6f, 0x70, 0x5d, 0x20, + 0x3d, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5b, 0x70, 0x72, 0x6f, + 0x70, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x3b, 0x0a, 0x20, 0x20, + 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x28, 0x73, 0x68, 0x61, 0x6c, 0x6c, + 0x6f, 0x77, 0x2d, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x29, 0x20, 0x64, + 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x6f, 0x66, 0x20, + 0x61, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x0a, 0x20, + 0x20, 0x5f, 0x2e, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x20, 0x3d, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, + 0x5f, 0x2e, 0x69, 0x73, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x6f, + 0x62, 0x6a, 0x29, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x6f, 0x62, 0x6a, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x41, 0x72, 0x72, 0x61, + 0x79, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x3f, 0x20, 0x6f, 0x62, 0x6a, + 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x29, 0x20, 0x3a, 0x20, 0x5f, + 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x28, 0x7b, 0x7d, 0x2c, 0x20, + 0x6f, 0x62, 0x6a, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x73, + 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x62, + 0x6a, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x6f, 0x62, 0x6a, 0x2e, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x72, + 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, + 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x20, 0x69, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x22, + 0x74, 0x61, 0x70, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x22, 0x20, 0x61, 0x20, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x2c, 0x20, 0x69, 0x6e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x65, 0x72, 0x66, 0x6f, + 0x72, 0x6d, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, + 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, + 0x74, 0x61, 0x70, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, + 0x6f, 0x72, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x3b, + 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x63, + 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x60, 0x69, 0x73, 0x45, 0x71, + 0x75, 0x61, 0x6c, 0x60, 0x2e, 0x0a, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x65, 0x71, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x61, 0x53, 0x74, 0x61, + 0x63, 0x6b, 0x2c, 0x20, 0x62, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x65, 0x71, 0x75, 0x61, 0x6c, + 0x2e, 0x20, 0x60, 0x30, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x2d, 0x30, 0x60, + 0x2c, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x61, + 0x72, 0x65, 0x6e, 0x27, 0x74, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x63, 0x61, 0x6c, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x53, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x72, 0x6d, + 0x6f, 0x6e, 0x79, 0x20, 0x60, 0x65, 0x67, 0x61, 0x6c, 0x60, 0x20, 0x70, + 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x3a, 0x20, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6b, 0x69, 0x2e, 0x65, 0x63, 0x6d, + 0x61, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x2f, + 0x64, 0x6f, 0x6b, 0x75, 0x2e, 0x70, 0x68, 0x70, 0x3f, 0x69, 0x64, 0x3d, + 0x68, 0x61, 0x72, 0x6d, 0x6f, 0x6e, 0x79, 0x3a, 0x65, 0x67, 0x61, 0x6c, + 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x61, 0x20, + 0x3d, 0x3d, 0x3d, 0x20, 0x62, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x61, 0x20, 0x21, 0x3d, 0x3d, 0x20, 0x30, 0x20, 0x7c, 0x7c, + 0x20, 0x31, 0x20, 0x2f, 0x20, 0x61, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, + 0x2f, 0x20, 0x62, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x41, 0x20, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x20, 0x63, 0x6f, 0x6d, + 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x6e, + 0x65, 0x63, 0x65, 0x73, 0x73, 0x61, 0x72, 0x79, 0x20, 0x62, 0x65, 0x63, + 0x61, 0x75, 0x73, 0x65, 0x20, 0x60, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x3d, + 0x3d, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x60, + 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x61, 0x20, + 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, 0x62, + 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x62, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x55, 0x6e, 0x77, + 0x72, 0x61, 0x70, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x77, 0x72, 0x61, 0x70, + 0x70, 0x65, 0x64, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2e, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x61, 0x20, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6f, 0x66, 0x20, 0x5f, 0x29, + 0x20, 0x61, 0x20, 0x3d, 0x20, 0x61, 0x2e, 0x5f, 0x77, 0x72, 0x61, 0x70, + 0x70, 0x65, 0x64, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x28, 0x62, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6f, + 0x66, 0x20, 0x5f, 0x29, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x62, 0x2e, 0x5f, + 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x20, + 0x60, 0x5b, 0x5b, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x5d, 0x5d, 0x60, 0x20, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, + 0x61, 0x72, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, + 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, + 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4e, 0x61, + 0x6d, 0x65, 0x20, 0x21, 0x3d, 0x20, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x62, 0x29, 0x29, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, + 0x20, 0x28, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x2c, 0x20, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2c, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, + 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, + 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, + 0x27, 0x5b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x5d, 0x27, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x20, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, + 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x20, 0x61, 0x72, 0x65, + 0x20, 0x65, 0x71, 0x75, 0x69, 0x76, 0x61, 0x6c, 0x65, 0x6e, 0x74, 0x3b, + 0x20, 0x74, 0x68, 0x75, 0x73, 0x2c, 0x20, 0x60, 0x22, 0x35, 0x22, 0x60, + 0x20, 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x65, 0x71, 0x75, 0x69, 0x76, 0x61, 0x6c, 0x65, 0x6e, + 0x74, 0x20, 0x74, 0x6f, 0x20, 0x60, 0x6e, 0x65, 0x77, 0x20, 0x53, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x28, 0x22, 0x35, 0x22, 0x29, 0x60, 0x2e, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x61, 0x20, 0x3d, 0x3d, 0x20, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x28, 0x62, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x27, 0x5b, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x20, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x5d, 0x27, 0x3a, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x60, 0x4e, 0x61, 0x4e, 0x60, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x65, + 0x71, 0x75, 0x69, 0x76, 0x61, 0x6c, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x6e, 0x6f, 0x6e, 0x2d, 0x72, 0x65, 0x66, 0x6c, 0x65, + 0x78, 0x69, 0x76, 0x65, 0x2e, 0x20, 0x41, 0x6e, 0x20, 0x60, 0x65, 0x67, + 0x61, 0x6c, 0x60, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, + 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, + 0x6d, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x20, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x21, 0x3d, + 0x20, 0x2b, 0x61, 0x20, 0x3f, 0x20, 0x62, 0x20, 0x21, 0x3d, 0x20, 0x2b, + 0x62, 0x20, 0x3a, 0x20, 0x28, 0x61, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x20, + 0x3f, 0x20, 0x31, 0x20, 0x2f, 0x20, 0x61, 0x20, 0x3d, 0x3d, 0x20, 0x31, + 0x20, 0x2f, 0x20, 0x62, 0x20, 0x3a, 0x20, 0x61, 0x20, 0x3d, 0x3d, 0x20, + 0x2b, 0x62, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, + 0x61, 0x73, 0x65, 0x20, 0x27, 0x5b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x20, 0x44, 0x61, 0x74, 0x65, 0x5d, 0x27, 0x3a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x27, 0x5b, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x20, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, + 0x5d, 0x27, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x65, 0x72, 0x63, 0x65, 0x20, 0x64, 0x61, + 0x74, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x62, 0x6f, 0x6f, 0x6c, + 0x65, 0x61, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x6e, 0x75, 0x6d, 0x65, + 0x72, 0x69, 0x63, 0x20, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x20, 0x44, 0x61, + 0x74, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x70, + 0x61, 0x72, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x69, + 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, + 0x20, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x20, 0x4e, 0x6f, 0x74, 0x65, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, + 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6d, + 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x72, + 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x4e, 0x61, 0x4e, 0x60, 0x20, 0x61, + 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x71, 0x75, 0x69, 0x76, + 0x61, 0x6c, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x2b, 0x61, + 0x20, 0x3d, 0x3d, 0x20, 0x2b, 0x62, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x67, 0x45, 0x78, 0x70, 0x73, + 0x20, 0x61, 0x72, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, + 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, + 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x73, 0x65, + 0x20, 0x27, 0x5b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x52, 0x65, + 0x67, 0x45, 0x78, 0x70, 0x5d, 0x27, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, + 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x62, + 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x26, 0x26, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x61, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x3d, + 0x3d, 0x20, 0x62, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x26, + 0x26, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x69, + 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x62, 0x2e, 0x6d, 0x75, + 0x6c, 0x74, 0x69, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x26, 0x26, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x61, 0x2e, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x43, 0x61, + 0x73, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x62, 0x2e, 0x69, 0x67, 0x6e, 0x6f, + 0x72, 0x65, 0x43, 0x61, 0x73, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x79, + 0x70, 0x65, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x27, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x79, + 0x70, 0x65, 0x6f, 0x66, 0x20, 0x62, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x27, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, 0x73, 0x73, 0x75, 0x6d, 0x65, 0x20, + 0x65, 0x71, 0x75, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x63, 0x79, 0x63, 0x6c, 0x69, 0x63, 0x20, 0x73, 0x74, 0x72, 0x75, + 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, + 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x20, + 0x63, 0x79, 0x63, 0x6c, 0x69, 0x63, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, + 0x20, 0x69, 0x73, 0x20, 0x61, 0x64, 0x61, 0x70, 0x74, 0x65, 0x64, 0x20, + 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x45, 0x53, 0x20, 0x35, 0x2e, 0x31, 0x20, + 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x35, 0x2e, 0x31, + 0x32, 0x2e, 0x33, 0x2c, 0x20, 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x60, 0x4a, 0x4f, 0x60, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, + 0x72, 0x20, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x61, + 0x53, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, + 0x28, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x2d, 0x2d, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x4c, 0x69, + 0x6e, 0x65, 0x61, 0x72, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, + 0x20, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, + 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x65, 0x6c, + 0x79, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, + 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x75, 0x72, 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x61, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x5b, + 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5d, 0x20, 0x3d, 0x3d, 0x20, 0x61, + 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x53, 0x74, + 0x61, 0x63, 0x6b, 0x5b, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5d, 0x20, + 0x3d, 0x3d, 0x20, 0x62, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, 0x64, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x74, 0x61, 0x63, 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x72, 0x61, 0x76, + 0x65, 0x72, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x53, 0x74, 0x61, 0x63, + 0x6b, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, 0x61, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x62, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x70, 0x75, + 0x73, 0x68, 0x28, 0x62, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, + 0x61, 0x72, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x30, 0x2c, + 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, + 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, + 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x6c, 0x79, 0x20, 0x63, + 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x20, + 0x27, 0x5b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x41, 0x72, 0x72, + 0x61, 0x79, 0x5d, 0x27, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65, 0x74, 0x65, 0x72, 0x6d, + 0x69, 0x6e, 0x65, 0x20, 0x69, 0x66, 0x20, 0x61, 0x20, 0x64, 0x65, 0x65, + 0x70, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, + 0x20, 0x69, 0x73, 0x20, 0x6e, 0x65, 0x63, 0x65, 0x73, 0x73, 0x61, 0x72, + 0x79, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, + 0x65, 0x20, 0x3d, 0x20, 0x61, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x3d, + 0x20, 0x62, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44, 0x65, 0x65, 0x70, 0x20, 0x63, + 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x69, 0x67, 0x6e, + 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f, 0x6e, 0x2d, 0x6e, 0x75, + 0x6d, 0x65, 0x72, 0x69, 0x63, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, + 0x74, 0x69, 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x28, 0x73, 0x69, 0x7a, + 0x65, 0x2d, 0x2d, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x28, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x65, 0x71, 0x28, 0x61, + 0x5b, 0x73, 0x69, 0x7a, 0x65, 0x5d, 0x2c, 0x20, 0x62, 0x5b, 0x73, 0x69, + 0x7a, 0x65, 0x5d, 0x2c, 0x20, 0x61, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x2c, + 0x20, 0x62, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x29, 0x29, 0x29, 0x20, 0x62, + 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x64, + 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6e, + 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x20, 0x61, 0x72, + 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x71, 0x75, 0x69, 0x76, 0x61, + 0x6c, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x62, 0x75, 0x74, 0x20, 0x60, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x60, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x64, 0x69, + 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x72, 0x61, 0x6d, + 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x61, 0x43, 0x74, 0x6f, 0x72, 0x20, + 0x3d, 0x20, 0x61, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x62, 0x43, 0x74, 0x6f, 0x72, 0x20, 0x3d, + 0x20, 0x62, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, + 0x6f, 0x72, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x61, 0x43, 0x74, 0x6f, 0x72, 0x20, 0x21, 0x3d, 0x3d, 0x20, + 0x62, 0x43, 0x74, 0x6f, 0x72, 0x20, 0x26, 0x26, 0x20, 0x21, 0x28, 0x5f, + 0x2e, 0x69, 0x73, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x61, 0x43, 0x74, 0x6f, 0x72, 0x29, 0x20, 0x26, 0x26, 0x20, 0x28, 0x61, + 0x43, 0x74, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x6f, 0x66, 0x20, 0x61, 0x43, 0x74, 0x6f, 0x72, 0x29, 0x20, 0x26, + 0x26, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x2e, 0x69, + 0x73, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x62, 0x43, + 0x74, 0x6f, 0x72, 0x29, 0x20, 0x26, 0x26, 0x20, 0x28, 0x62, 0x43, 0x74, + 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6f, + 0x66, 0x20, 0x62, 0x43, 0x74, 0x6f, 0x72, 0x29, 0x29, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x44, 0x65, 0x65, 0x70, 0x20, 0x63, 0x6f, 0x6d, + 0x70, 0x61, 0x72, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, + 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x28, 0x76, 0x61, 0x72, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x69, 0x6e, 0x20, + 0x61, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x5f, 0x2e, 0x68, 0x61, 0x73, 0x28, 0x61, + 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x70, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x20, 0x6f, 0x66, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2b, 0x2b, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44, + 0x65, 0x65, 0x70, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x20, + 0x65, 0x61, 0x63, 0x68, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x2e, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x21, 0x28, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, + 0x3d, 0x20, 0x5f, 0x2e, 0x68, 0x61, 0x73, 0x28, 0x62, 0x2c, 0x20, 0x6b, + 0x65, 0x79, 0x29, 0x20, 0x26, 0x26, 0x20, 0x65, 0x71, 0x28, 0x61, 0x5b, + 0x6b, 0x65, 0x79, 0x5d, 0x2c, 0x20, 0x62, 0x5b, 0x6b, 0x65, 0x79, 0x5d, + 0x2c, 0x20, 0x61, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x2c, 0x20, 0x62, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x29, 0x29, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, + 0x6b, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x62, 0x6f, 0x74, 0x68, 0x20, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x70, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x6b, 0x65, 0x79, 0x20, 0x69, + 0x6e, 0x20, 0x62, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x5f, 0x2e, 0x68, + 0x61, 0x73, 0x28, 0x62, 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x20, 0x26, + 0x26, 0x20, 0x21, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x2d, 0x2d, 0x29, 0x29, + 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x21, + 0x73, 0x69, 0x7a, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x73, 0x74, 0x61, 0x63, 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x72, 0x61, + 0x76, 0x65, 0x72, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x53, 0x74, 0x61, + 0x63, 0x6b, 0x2e, 0x70, 0x6f, 0x70, 0x28, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x62, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x70, 0x6f, 0x70, + 0x28, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3b, 0x0a, 0x20, + 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x50, 0x65, + 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x61, 0x20, 0x64, 0x65, 0x65, 0x70, + 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x20, + 0x74, 0x6f, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x69, 0x66, 0x20, + 0x74, 0x77, 0x6f, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x20, + 0x61, 0x72, 0x65, 0x20, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x2e, 0x0a, 0x20, + 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x45, 0x71, 0x75, 0x61, 0x6c, 0x20, 0x3d, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x2c, + 0x20, 0x62, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x71, 0x28, 0x61, 0x2c, 0x20, 0x62, + 0x2c, 0x20, 0x5b, 0x5d, 0x2c, 0x20, 0x5b, 0x5d, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x73, + 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2c, 0x20, + 0x6f, 0x72, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x65, 0x6d, + 0x70, 0x74, 0x79, 0x3f, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, 0x6e, + 0x20, 0x22, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x20, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x20, 0x65, + 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6f, 0x77, + 0x6e, 0x2d, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, + 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x28, 0x6f, 0x62, 0x6a, 0x20, 0x3d, 0x3d, 0x20, 0x6e, + 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x74, 0x72, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x5f, 0x2e, 0x69, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x28, + 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7c, 0x7c, 0x20, 0x5f, 0x2e, 0x69, 0x73, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x29, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x2e, + 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x30, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, + 0x61, 0x72, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x62, + 0x6a, 0x29, 0x20, 0x69, 0x66, 0x20, 0x28, 0x5f, 0x2e, 0x68, 0x61, 0x73, + 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x29, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x74, 0x72, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x73, 0x20, 0x61, 0x20, 0x67, + 0x69, 0x76, 0x65, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x61, + 0x20, 0x44, 0x4f, 0x4d, 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x3f, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x45, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x21, 0x21, 0x28, + 0x6f, 0x62, 0x6a, 0x20, 0x26, 0x26, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x3d, 0x3d, 0x20, + 0x31, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x49, 0x73, 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, + 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x61, 0x6e, 0x20, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x3f, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44, + 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, + 0x45, 0x43, 0x4d, 0x41, 0x35, 0x27, 0x73, 0x20, 0x6e, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x69, 0x73, 0x41, + 0x72, 0x72, 0x61, 0x79, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x41, + 0x72, 0x72, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x6e, 0x61, 0x74, 0x69, 0x76, + 0x65, 0x49, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x20, 0x7c, 0x7c, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, + 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x3d, 0x3d, + 0x20, 0x27, 0x5b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x41, 0x72, + 0x72, 0x61, 0x79, 0x5d, 0x27, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x73, 0x20, 0x61, 0x20, 0x67, + 0x69, 0x76, 0x65, 0x6e, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, + 0x65, 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3f, + 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x20, 0x3d, + 0x3d, 0x3d, 0x20, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x6f, 0x62, + 0x6a, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x41, 0x64, 0x64, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x20, + 0x69, 0x73, 0x54, 0x79, 0x70, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x73, 0x3a, 0x20, 0x69, 0x73, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x69, 0x73, 0x46, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x69, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x2c, 0x20, 0x69, 0x73, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x2c, + 0x20, 0x69, 0x73, 0x44, 0x61, 0x74, 0x65, 0x2c, 0x20, 0x69, 0x73, 0x52, + 0x65, 0x67, 0x45, 0x78, 0x70, 0x2e, 0x0a, 0x20, 0x20, 0x65, 0x61, 0x63, + 0x68, 0x28, 0x5b, 0x27, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x27, 0x2c, 0x20, 0x27, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x27, 0x2c, 0x20, 0x27, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x27, + 0x2c, 0x20, 0x27, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x27, 0x2c, 0x20, + 0x27, 0x44, 0x61, 0x74, 0x65, 0x27, 0x2c, 0x20, 0x27, 0x52, 0x65, 0x67, + 0x45, 0x78, 0x70, 0x27, 0x5d, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x5f, 0x5b, 0x27, 0x69, 0x73, 0x27, 0x20, 0x2b, + 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x63, + 0x61, 0x6c, 0x6c, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x3d, 0x3d, 0x20, + 0x27, 0x5b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x27, 0x20, 0x2b, + 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x2b, 0x20, 0x27, 0x5d, 0x27, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x29, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44, 0x65, 0x66, 0x69, + 0x6e, 0x65, 0x20, 0x61, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, + 0x6b, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, + 0x69, 0x6e, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x73, 0x20, + 0x28, 0x61, 0x68, 0x65, 0x6d, 0x2c, 0x20, 0x49, 0x45, 0x29, 0x2c, 0x20, + 0x77, 0x68, 0x65, 0x72, 0x65, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x74, + 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x61, + 0x6e, 0x79, 0x20, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x20, 0x22, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x22, 0x20, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x21, 0x5f, 0x2e, 0x69, 0x73, 0x41, 0x72, 0x67, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x28, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x29, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x5f, 0x2e, 0x69, 0x73, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x21, 0x21, 0x28, + 0x6f, 0x62, 0x6a, 0x20, 0x26, 0x26, 0x20, 0x5f, 0x2e, 0x68, 0x61, 0x73, + 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x27, 0x63, 0x61, 0x6c, 0x6c, 0x65, + 0x65, 0x27, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, + 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x4f, + 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x20, 0x60, 0x69, 0x73, 0x46, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x60, 0x20, 0x69, 0x66, 0x20, + 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72, 0x69, 0x61, 0x74, 0x65, 0x2e, + 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x79, 0x70, 0x65, 0x6f, + 0x66, 0x20, 0x28, 0x2f, 0x2e, 0x2f, 0x29, 0x20, 0x21, 0x3d, 0x3d, 0x20, + 0x27, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x27, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x46, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x6f, 0x62, 0x6a, + 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x27, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x27, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x73, + 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x20, 0x61, 0x20, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x65, + 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x3f, 0x0a, 0x20, 0x20, 0x5f, + 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6e, 0x69, 0x74, 0x65, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x69, 0x73, 0x46, 0x69, 0x6e, 0x69, 0x74, 0x65, 0x28, + 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x26, 0x26, 0x20, 0x21, 0x69, 0x73, 0x4e, + 0x61, 0x4e, 0x28, 0x70, 0x61, 0x72, 0x73, 0x65, 0x46, 0x6c, 0x6f, 0x61, + 0x74, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x20, 0x60, 0x4e, 0x61, 0x4e, 0x60, 0x3f, 0x20, 0x28, 0x4e, + 0x61, 0x4e, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x6e, + 0x6c, 0x79, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x77, 0x68, + 0x69, 0x63, 0x68, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, + 0x20, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x20, 0x69, 0x74, 0x73, 0x65, 0x6c, + 0x66, 0x29, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x4e, 0x61, + 0x4e, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x26, + 0x26, 0x20, 0x6f, 0x62, 0x6a, 0x20, 0x21, 0x3d, 0x20, 0x2b, 0x6f, 0x62, + 0x6a, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x49, 0x73, 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, + 0x6c, 0x65, 0x61, 0x6e, 0x3f, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x69, 0x73, + 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x6f, 0x62, 0x6a, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x74, 0x72, 0x75, + 0x65, 0x20, 0x7c, 0x7c, 0x20, 0x6f, 0x62, 0x6a, 0x20, 0x3d, 0x3d, 0x3d, + 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x6f, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, + 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x5b, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x20, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, + 0x5d, 0x27, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x49, 0x73, 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, + 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x65, 0x71, 0x75, 0x61, + 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x3f, 0x0a, 0x20, + 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x6e, + 0x75, 0x6c, 0x6c, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x73, 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, + 0x65, 0x6e, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x3f, 0x0a, 0x20, + 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x55, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, + 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x20, + 0x3d, 0x3d, 0x3d, 0x20, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x30, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x53, + 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x68, 0x65, + 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x66, 0x20, 0x61, 0x6e, 0x20, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x61, + 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x79, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6c, 0x79, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x6f, 0x6e, 0x20, 0x69, 0x74, 0x73, + 0x65, 0x6c, 0x66, 0x20, 0x28, 0x69, 0x6e, 0x20, 0x6f, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x2c, 0x20, 0x6e, 0x6f, 0x74, + 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, + 0x79, 0x70, 0x65, 0x29, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x68, 0x61, + 0x73, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x68, 0x61, 0x73, 0x4f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, + 0x74, 0x79, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6f, 0x62, 0x6a, 0x2c, + 0x20, 0x6b, 0x65, 0x79, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x55, 0x74, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x20, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x75, 0x6e, 0x20, 0x55, 0x6e, 0x64, + 0x65, 0x72, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x6a, 0x73, 0x20, 0x69, + 0x6e, 0x20, 0x2a, 0x6e, 0x6f, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, + 0x74, 0x2a, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x60, + 0x5f, 0x60, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x69, 0x74, 0x73, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x6f, 0x77, 0x6e, + 0x65, 0x72, 0x2e, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, + 0x61, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x6e, 0x64, 0x65, 0x72, + 0x73, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x6e, 0x6f, 0x43, 0x6f, 0x6e, 0x66, + 0x6c, 0x69, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x5f, 0x20, 0x3d, 0x20, 0x70, 0x72, 0x65, + 0x76, 0x69, 0x6f, 0x75, 0x73, 0x55, 0x6e, 0x64, 0x65, 0x72, 0x73, 0x63, + 0x6f, 0x72, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x3b, 0x0a, 0x20, 0x20, + 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x4b, 0x65, 0x65, + 0x70, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x64, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x7d, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x75, 0x6e, 0x20, + 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x2a, + 0x2a, 0x6e, 0x2a, 0x2a, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x2e, 0x0a, + 0x20, 0x20, 0x5f, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x2c, 0x20, + 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x61, 0x63, 0x63, 0x75, 0x6d, 0x20, 0x3d, + 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x28, 0x6e, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, + 0x69, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x20, 0x69, 0x20, 0x3c, 0x20, 0x6e, + 0x3b, 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x61, 0x63, 0x63, 0x75, 0x6d, + 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x2c, 0x20, 0x69, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x63, 0x63, 0x75, + 0x6d, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x72, + 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, + 0x72, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x6d, 0x69, + 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x61, 0x78, 0x20, 0x28, 0x69, + 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x29, 0x2e, 0x0a, 0x20, + 0x20, 0x5f, 0x2e, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6d, 0x69, 0x6e, + 0x2c, 0x20, 0x6d, 0x61, 0x78, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x6d, 0x61, 0x78, 0x20, 0x3d, 0x3d, 0x20, + 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x6d, 0x61, 0x78, 0x20, 0x3d, 0x20, 0x6d, 0x69, 0x6e, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x20, 0x3d, + 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x69, 0x6e, + 0x20, 0x2b, 0x20, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x66, 0x6c, 0x6f, 0x6f, + 0x72, 0x28, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x72, 0x61, 0x6e, 0x64, 0x6f, + 0x6d, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x28, 0x6d, 0x61, 0x78, 0x20, 0x2d, + 0x20, 0x6d, 0x69, 0x6e, 0x20, 0x2b, 0x20, 0x31, 0x29, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x4c, + 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x48, 0x54, 0x4d, 0x4c, 0x20, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x65, 0x73, 0x63, 0x61, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x0a, 0x20, + 0x20, 0x76, 0x61, 0x72, 0x20, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4d, + 0x61, 0x70, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, + 0x73, 0x63, 0x61, 0x70, 0x65, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x27, 0x26, 0x27, 0x3a, 0x20, 0x27, 0x26, 0x61, 0x6d, + 0x70, 0x3b, 0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, + 0x3c, 0x27, 0x3a, 0x20, 0x27, 0x26, 0x6c, 0x74, 0x3b, 0x27, 0x2c, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x3e, 0x27, 0x3a, 0x20, 0x27, + 0x26, 0x67, 0x74, 0x3b, 0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x27, 0x22, 0x27, 0x3a, 0x20, 0x27, 0x26, 0x71, 0x75, 0x6f, 0x74, + 0x3b, 0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x27, + 0x22, 0x3a, 0x20, 0x27, 0x26, 0x23, 0x78, 0x32, 0x37, 0x3b, 0x27, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x2f, 0x27, 0x3a, 0x20, + 0x27, 0x26, 0x23, 0x78, 0x32, 0x46, 0x3b, 0x27, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x4d, 0x61, 0x70, 0x2e, 0x75, 0x6e, 0x65, 0x73, + 0x63, 0x61, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x69, 0x6e, 0x76, + 0x65, 0x72, 0x74, 0x28, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4d, 0x61, + 0x70, 0x2e, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x29, 0x3b, 0x0a, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x67, 0x65, 0x78, 0x65, 0x73, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x6c, 0x69, 0x73, 0x74, + 0x65, 0x64, 0x20, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, + 0x6c, 0x79, 0x20, 0x61, 0x62, 0x6f, 0x76, 0x65, 0x2e, 0x0a, 0x20, 0x20, + 0x76, 0x61, 0x72, 0x20, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, + 0x67, 0x65, 0x78, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3a, 0x20, 0x20, 0x20, + 0x6e, 0x65, 0x77, 0x20, 0x52, 0x65, 0x67, 0x45, 0x78, 0x70, 0x28, 0x27, + 0x5b, 0x27, 0x20, 0x2b, 0x20, 0x5f, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x28, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4d, 0x61, 0x70, 0x2e, 0x65, 0x73, + 0x63, 0x61, 0x70, 0x65, 0x29, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x27, + 0x27, 0x29, 0x20, 0x2b, 0x20, 0x27, 0x5d, 0x27, 0x2c, 0x20, 0x27, 0x67, + 0x27, 0x29, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, 0x6e, 0x65, 0x73, + 0x63, 0x61, 0x70, 0x65, 0x3a, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x52, 0x65, + 0x67, 0x45, 0x78, 0x70, 0x28, 0x27, 0x28, 0x27, 0x20, 0x2b, 0x20, 0x5f, + 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x4d, 0x61, 0x70, 0x2e, 0x75, 0x6e, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, + 0x29, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x27, 0x7c, 0x27, 0x29, 0x20, + 0x2b, 0x20, 0x27, 0x29, 0x27, 0x2c, 0x20, 0x27, 0x67, 0x27, 0x29, 0x0a, + 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x46, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x65, 0x73, 0x63, 0x61, 0x70, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x75, 0x6e, 0x65, 0x73, 0x63, 0x61, 0x70, 0x69, 0x6e, 0x67, + 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x74, 0x6f, 0x2f, + 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x65, 0x61, 0x63, 0x68, 0x28, 0x5b, 0x27, + 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x27, 0x2c, 0x20, 0x27, 0x75, 0x6e, + 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x27, 0x5d, 0x2c, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x5b, 0x6d, + 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5d, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x3d, 0x20, + 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x27, 0x27, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x27, 0x27, 0x20, 0x2b, 0x20, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x29, 0x2e, 0x72, 0x65, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x28, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, + 0x67, 0x65, 0x78, 0x65, 0x73, 0x5b, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x5d, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4d, 0x61, 0x70, 0x5b, 0x6d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x5d, 0x5b, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5d, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x29, 0x3b, + 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x20, 0x70, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x6e, + 0x20, 0x69, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x20, 0x69, 0x74, 0x3b, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x77, 0x69, + 0x73, 0x65, 0x2c, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, + 0x74, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2c, 0x20, 0x70, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x79, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x28, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, + 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x29, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, + 0x3d, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5b, 0x70, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x79, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x2e, 0x69, 0x73, 0x46, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x29, 0x20, 0x3f, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x63, + 0x61, 0x6c, 0x6c, 0x28, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x29, 0x20, + 0x3a, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x7d, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, 0x64, 0x64, 0x20, + 0x79, 0x6f, 0x75, 0x72, 0x20, 0x6f, 0x77, 0x6e, 0x20, 0x63, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x6e, 0x64, + 0x65, 0x72, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x6d, 0x69, 0x78, 0x69, + 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x65, 0x61, 0x63, 0x68, 0x28, 0x5f, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x2c, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, + 0x29, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x20, 0x3d, 0x20, 0x5f, 0x5b, 0x6e, 0x61, + 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x6f, 0x62, 0x6a, 0x5b, 0x6e, 0x61, + 0x6d, 0x65, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x5b, 0x6e, + 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x61, 0x72, 0x67, 0x73, + 0x20, 0x3d, 0x20, 0x5b, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x5f, 0x77, 0x72, + 0x61, 0x70, 0x70, 0x65, 0x64, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x70, + 0x6c, 0x79, 0x28, 0x61, 0x72, 0x67, 0x73, 0x2c, 0x20, 0x61, 0x72, 0x67, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, + 0x74, 0x68, 0x69, 0x73, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x79, 0x28, 0x5f, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x73, + 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x47, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, + 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x20, 0x69, 0x64, + 0x20, 0x28, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x74, 0x69, + 0x72, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x29, 0x2e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, + 0x20, 0x55, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x20, 0x44, 0x4f, + 0x4d, 0x20, 0x69, 0x64, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x76, 0x61, 0x72, + 0x20, 0x69, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x3d, + 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x75, 0x6e, 0x69, 0x71, + 0x75, 0x65, 0x49, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x29, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x64, + 0x20, 0x3d, 0x20, 0x2b, 0x2b, 0x69, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x65, 0x72, 0x20, 0x2b, 0x20, 0x27, 0x27, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70, 0x72, 0x65, 0x66, + 0x69, 0x78, 0x20, 0x3f, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, + 0x2b, 0x20, 0x69, 0x64, 0x20, 0x3a, 0x20, 0x69, 0x64, 0x3b, 0x0a, 0x20, + 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x42, 0x79, + 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2c, 0x20, 0x55, 0x6e, + 0x64, 0x65, 0x72, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x75, 0x73, 0x65, + 0x73, 0x20, 0x45, 0x52, 0x42, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x20, + 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x20, 0x64, 0x65, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x2f, 0x2f, + 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x20, 0x74, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x20, 0x73, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, + 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, + 0x64, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x0a, + 0x20, 0x20, 0x5f, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x3d, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, + 0x65, 0x20, 0x20, 0x20, 0x20, 0x3a, 0x20, 0x2f, 0x3c, 0x25, 0x28, 0x5b, + 0x5c, 0x73, 0x5c, 0x53, 0x5d, 0x2b, 0x3f, 0x29, 0x25, 0x3e, 0x2f, 0x67, + 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, + 0x6f, 0x6c, 0x61, 0x74, 0x65, 0x20, 0x3a, 0x20, 0x2f, 0x3c, 0x25, 0x3d, + 0x28, 0x5b, 0x5c, 0x73, 0x5c, 0x53, 0x5d, 0x2b, 0x3f, 0x29, 0x25, 0x3e, + 0x2f, 0x67, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x73, 0x63, 0x61, + 0x70, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3a, 0x20, 0x2f, 0x3c, + 0x25, 0x2d, 0x28, 0x5b, 0x5c, 0x73, 0x5c, 0x53, 0x5d, 0x2b, 0x3f, 0x29, + 0x25, 0x3e, 0x2f, 0x67, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x57, 0x68, 0x65, 0x6e, 0x20, 0x63, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x69, 0x7a, 0x69, 0x6e, 0x67, 0x20, 0x60, 0x74, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x60, 0x2c, 0x20, 0x69, 0x66, 0x20, 0x79, 0x6f, 0x75, 0x20, + 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, 0x74, + 0x6f, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x61, 0x6e, 0x0a, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x65, 0x76, 0x61, 0x6c, + 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x73, + 0x63, 0x61, 0x70, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x67, 0x65, 0x78, + 0x2c, 0x20, 0x77, 0x65, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x20, 0x6f, 0x6e, + 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x67, 0x75, 0x61, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x65, + 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x2e, 0x0a, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6e, 0x6f, + 0x4d, 0x61, 0x74, 0x63, 0x68, 0x20, 0x3d, 0x20, 0x2f, 0x28, 0x2e, 0x29, + 0x5e, 0x2f, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x43, 0x65, + 0x72, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, + 0x74, 0x65, 0x72, 0x73, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, + 0x20, 0x62, 0x65, 0x20, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x64, 0x20, + 0x73, 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x70, 0x75, 0x74, 0x20, + 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x61, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x69, 0x74, 0x65, 0x72, + 0x61, 0x6c, 0x2e, 0x0a, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x65, 0x73, + 0x63, 0x61, 0x70, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x27, 0x22, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x27, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x27, 0x5c, 0x5c, + 0x27, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x5c, 0x5c, 0x27, 0x2c, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x27, 0x5c, 0x72, 0x27, 0x3a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x27, 0x72, 0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x27, 0x5c, 0x6e, 0x27, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x6e, + 0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x27, 0x5c, 0x74, 0x27, 0x3a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x74, 0x27, 0x2c, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x27, 0x5c, 0x75, 0x32, 0x30, 0x32, 0x38, 0x27, 0x3a, 0x20, + 0x27, 0x75, 0x32, 0x30, 0x32, 0x38, 0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x27, 0x5c, 0x75, 0x32, 0x30, 0x32, 0x39, 0x27, 0x3a, 0x20, 0x27, + 0x75, 0x32, 0x30, 0x32, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x0a, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x65, 0x73, 0x63, 0x61, 0x70, + 0x65, 0x72, 0x20, 0x3d, 0x20, 0x2f, 0x5c, 0x5c, 0x7c, 0x27, 0x7c, 0x5c, + 0x72, 0x7c, 0x5c, 0x6e, 0x7c, 0x5c, 0x74, 0x7c, 0x5c, 0x75, 0x32, 0x30, + 0x32, 0x38, 0x7c, 0x5c, 0x75, 0x32, 0x30, 0x32, 0x39, 0x2f, 0x67, 0x3b, + 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x4a, 0x61, 0x76, 0x61, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2d, + 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2c, 0x20, + 0x73, 0x69, 0x6d, 0x69, 0x6c, 0x61, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x4a, + 0x6f, 0x68, 0x6e, 0x20, 0x52, 0x65, 0x73, 0x69, 0x67, 0x27, 0x73, 0x20, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x55, 0x6e, 0x64, + 0x65, 0x72, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x74, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, + 0x65, 0x73, 0x20, 0x61, 0x72, 0x62, 0x69, 0x74, 0x72, 0x61, 0x72, 0x79, + 0x20, 0x64, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x73, 0x2c, + 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x73, 0x20, 0x77, + 0x68, 0x69, 0x74, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2c, 0x0a, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x6f, 0x72, 0x72, + 0x65, 0x63, 0x74, 0x6c, 0x79, 0x20, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, + 0x73, 0x20, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x69, 0x6e, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, + 0x61, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x0a, 0x20, + 0x20, 0x5f, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x20, + 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, + 0x65, 0x78, 0x74, 0x2c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2c, 0x20, 0x73, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x20, 0x7b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x6e, 0x64, 0x65, + 0x72, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x2e, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x73, 0x28, 0x7b, 0x7d, 0x2c, 0x20, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2c, 0x20, 0x5f, 0x2e, 0x74, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x64, 0x65, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x65, 0x72, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, + 0x6f, 0x6e, 0x65, 0x20, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x20, + 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x76, + 0x69, 0x61, 0x20, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6e, 0x65, + 0x77, 0x20, 0x52, 0x65, 0x67, 0x45, 0x78, 0x70, 0x28, 0x5b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x2e, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x20, 0x7c, 0x7c, + 0x20, 0x6e, 0x6f, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x29, 0x2e, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x28, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, 0x61, 0x74, 0x65, 0x20, 0x7c, 0x7c, + 0x20, 0x6e, 0x6f, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x29, 0x2e, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x28, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x65, 0x76, + 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x7c, 0x7c, 0x20, 0x6e, 0x6f, + 0x4d, 0x61, 0x74, 0x63, 0x68, 0x29, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, + 0x28, 0x27, 0x7c, 0x27, 0x29, 0x20, 0x2b, 0x20, 0x27, 0x7c, 0x24, 0x27, + 0x2c, 0x20, 0x27, 0x67, 0x27, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2c, 0x20, 0x65, 0x73, 0x63, + 0x61, 0x70, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x20, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x73, 0x20, 0x61, 0x70, + 0x70, 0x72, 0x6f, 0x70, 0x72, 0x69, 0x61, 0x74, 0x65, 0x6c, 0x79, 0x2e, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x76, 0x61, 0x72, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x3d, + 0x20, 0x22, 0x5f, 0x5f, 0x70, 0x2b, 0x3d, 0x27, 0x22, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x72, 0x65, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x28, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2c, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x2c, 0x20, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2c, + 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, 0x61, 0x74, 0x65, + 0x2c, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x2c, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x2b, + 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x73, 0x6c, 0x69, 0x63, 0x65, + 0x28, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x2e, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x28, 0x65, 0x73, 0x63, + 0x61, 0x70, 0x65, 0x72, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x28, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x29, 0x20, 0x7b, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x27, 0x5c, 0x5c, 0x27, 0x20, + 0x2b, 0x20, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x73, 0x5b, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x5d, 0x3b, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x65, 0x73, 0x63, + 0x61, 0x70, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x2b, 0x3d, + 0x20, 0x22, 0x27, 0x2b, 0x5c, 0x6e, 0x28, 0x28, 0x5f, 0x5f, 0x74, 0x3d, + 0x28, 0x22, 0x20, 0x2b, 0x20, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x20, + 0x2b, 0x20, 0x22, 0x29, 0x29, 0x3d, 0x3d, 0x6e, 0x75, 0x6c, 0x6c, 0x3f, + 0x27, 0x27, 0x3a, 0x5f, 0x2e, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x28, + 0x5f, 0x5f, 0x74, 0x29, 0x29, 0x2b, 0x5c, 0x6e, 0x27, 0x22, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, + 0x6f, 0x6c, 0x61, 0x74, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, + 0x2b, 0x3d, 0x20, 0x22, 0x27, 0x2b, 0x5c, 0x6e, 0x28, 0x28, 0x5f, 0x5f, + 0x74, 0x3d, 0x28, 0x22, 0x20, 0x2b, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x70, 0x6f, 0x6c, 0x61, 0x74, 0x65, 0x20, 0x2b, 0x20, 0x22, 0x29, 0x29, + 0x3d, 0x3d, 0x6e, 0x75, 0x6c, 0x6c, 0x3f, 0x27, 0x27, 0x3a, 0x5f, 0x5f, + 0x74, 0x29, 0x2b, 0x5c, 0x6e, 0x27, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x29, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x2b, 0x3d, 0x20, 0x22, 0x27, 0x3b, + 0x5c, 0x6e, 0x22, 0x20, 0x2b, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, + 0x74, 0x65, 0x20, 0x2b, 0x20, 0x22, 0x5c, 0x6e, 0x5f, 0x5f, 0x70, 0x2b, + 0x3d, 0x27, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x20, 0x3d, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x2b, 0x20, + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x20, 0x2b, 0x3d, 0x20, 0x22, 0x27, 0x3b, 0x5c, + 0x6e, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, + 0x49, 0x66, 0x20, 0x61, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, + 0x65, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x70, 0x65, + 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2c, 0x20, 0x70, 0x6c, 0x61, 0x63, + 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, + 0x63, 0x6f, 0x70, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x28, 0x21, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, + 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x29, 0x20, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x27, 0x77, 0x69, 0x74, 0x68, + 0x28, 0x6f, 0x62, 0x6a, 0x7c, 0x7c, 0x7b, 0x7d, 0x29, 0x7b, 0x5c, 0x6e, + 0x27, 0x20, 0x2b, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x2b, + 0x20, 0x27, 0x7d, 0x5c, 0x6e, 0x27, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x76, + 0x61, 0x72, 0x20, 0x5f, 0x5f, 0x74, 0x2c, 0x5f, 0x5f, 0x70, 0x3d, 0x27, + 0x27, 0x2c, 0x5f, 0x5f, 0x6a, 0x3d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x6a, 0x6f, + 0x69, 0x6e, 0x2c, 0x22, 0x20, 0x2b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3d, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x5f, 0x5f, 0x70, 0x2b, 0x3d, + 0x5f, 0x5f, 0x6a, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x72, 0x67, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x27, 0x27, 0x29, 0x3b, 0x7d, + 0x3b, 0x5c, 0x6e, 0x22, 0x20, 0x2b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x2b, 0x20, 0x22, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x5f, 0x70, 0x3b, 0x5c, 0x6e, + 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x72, 0x79, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x6e, 0x64, + 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x46, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x2e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x7c, 0x7c, 0x20, 0x27, 0x6f, 0x62, 0x6a, 0x27, 0x2c, 0x20, 0x27, 0x5f, + 0x27, 0x2c, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x63, 0x61, 0x74, 0x63, 0x68, 0x20, + 0x28, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x65, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x74, 0x68, 0x72, 0x6f, 0x77, 0x20, 0x65, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x28, 0x64, 0x61, 0x74, 0x61, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x28, 0x64, 0x61, 0x74, + 0x61, 0x2c, 0x20, 0x5f, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, + 0x61, 0x72, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x20, + 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x64, + 0x61, 0x74, 0x61, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x6e, 0x64, + 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x74, 0x68, 0x69, 0x73, + 0x2c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2c, 0x20, 0x5f, 0x29, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6e, + 0x76, 0x65, 0x6e, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x20, 0x3d, 0x20, 0x27, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x27, 0x20, 0x2b, 0x20, 0x28, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x2e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x7c, 0x7c, 0x20, 0x27, 0x6f, 0x62, 0x6a, 0x27, 0x29, 0x20, 0x2b, 0x20, + 0x27, 0x29, 0x7b, 0x5c, 0x6e, 0x27, 0x20, 0x2b, 0x20, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x20, 0x2b, 0x20, 0x27, 0x7d, 0x27, 0x3b, 0x0a, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x7d, + 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, 0x64, 0x64, 0x20, + 0x61, 0x20, 0x22, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x22, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x77, 0x68, 0x69, 0x63, + 0x68, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x64, 0x65, 0x6c, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, + 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, + 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x28, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x4f, 0x4f, 0x50, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x66, 0x20, 0x55, + 0x6e, 0x64, 0x65, 0x72, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x69, 0x73, + 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x61, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x69, + 0x74, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x20, + 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x20, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x0a, 0x20, 0x20, 0x2f, 0x2f, + 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, + 0x20, 0x4f, 0x4f, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x20, 0x54, + 0x68, 0x69, 0x73, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x20, + 0x68, 0x6f, 0x6c, 0x64, 0x73, 0x20, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x65, + 0x64, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, + 0x66, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x73, 0x63, 0x6f, 0x72, + 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x20, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x20, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, 0x20, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x20, 0x20, + 0x2f, 0x2f, 0x20, 0x48, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6f, + 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x20, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, + 0x69, 0x61, 0x74, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, + 0x2e, 0x0a, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, 0x3f, 0x20, 0x5f, 0x28, + 0x6f, 0x62, 0x6a, 0x29, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x28, 0x29, + 0x20, 0x3a, 0x20, 0x6f, 0x62, 0x6a, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x3b, + 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, 0x64, 0x64, 0x20, 0x61, + 0x6c, 0x6c, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x6e, + 0x64, 0x65, 0x72, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x20, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x6d, 0x69, + 0x78, 0x69, 0x6e, 0x28, 0x5f, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x41, 0x64, 0x64, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6d, 0x75, + 0x74, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, + 0x2e, 0x0a, 0x20, 0x20, 0x65, 0x61, 0x63, 0x68, 0x28, 0x5b, 0x27, 0x70, + 0x6f, 0x70, 0x27, 0x2c, 0x20, 0x27, 0x70, 0x75, 0x73, 0x68, 0x27, 0x2c, + 0x20, 0x27, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x27, 0x2c, 0x20, + 0x27, 0x73, 0x68, 0x69, 0x66, 0x74, 0x27, 0x2c, 0x20, 0x27, 0x73, 0x6f, + 0x72, 0x74, 0x27, 0x2c, 0x20, 0x27, 0x73, 0x70, 0x6c, 0x69, 0x63, 0x65, + 0x27, 0x2c, 0x20, 0x27, 0x75, 0x6e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x27, + 0x5d, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x76, 0x61, 0x72, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x3d, + 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x5b, + 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x5b, 0x6e, + 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x62, 0x6a, 0x20, 0x3d, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x2e, 0x5f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, + 0x64, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x28, 0x6f, 0x62, + 0x6a, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x28, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x73, + 0x68, 0x69, 0x66, 0x74, 0x27, 0x20, 0x7c, 0x7c, 0x20, 0x6e, 0x61, 0x6d, + 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x73, 0x70, 0x6c, 0x69, 0x63, 0x65, + 0x27, 0x29, 0x20, 0x26, 0x26, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x6c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, + 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x5b, 0x30, + 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x63, + 0x61, 0x6c, 0x6c, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2c, 0x20, 0x6f, 0x62, + 0x6a, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x20, + 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x41, + 0x64, 0x64, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x6f, 0x72, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x2e, 0x0a, + 0x20, 0x20, 0x65, 0x61, 0x63, 0x68, 0x28, 0x5b, 0x27, 0x63, 0x6f, 0x6e, + 0x63, 0x61, 0x74, 0x27, 0x2c, 0x20, 0x27, 0x6a, 0x6f, 0x69, 0x6e, 0x27, + 0x2c, 0x20, 0x27, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x27, 0x5d, 0x2c, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x61, 0x6d, + 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, + 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x3d, 0x20, 0x41, 0x72, + 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x5b, 0x6e, 0x61, 0x6d, + 0x65, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x5b, 0x6e, 0x61, 0x6d, 0x65, + 0x5d, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2c, 0x20, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x79, + 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x5f, 0x77, 0x72, 0x61, 0x70, 0x70, + 0x65, 0x64, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, 0x0a, + 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x5f, 0x2e, 0x65, + 0x78, 0x74, 0x65, 0x6e, 0x64, 0x28, 0x5f, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x7b, 0x0a, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x53, 0x74, 0x61, 0x72, 0x74, 0x20, 0x63, + 0x68, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x77, 0x72, + 0x61, 0x70, 0x70, 0x65, 0x64, 0x20, 0x55, 0x6e, 0x64, 0x65, 0x72, 0x73, + 0x63, 0x6f, 0x72, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x3a, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, + 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, + 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, + 0x20, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x66, 0x72, 0x6f, + 0x6d, 0x20, 0x61, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x20, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x5f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x3b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x7d, 0x29, 0x3b, + 0x0a, 0x0a, 0x7d, 0x29, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x74, 0x68, + 0x69, 0x73, 0x29, 0x3b, 0x0a, + } +} +// Underscore.js 1.4.4 +// http://underscorejs.org +// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore may be freely distributed under the MIT license. diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/testify b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/testify new file mode 100644 index 0000000000..7f6e0f7c11 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/testify @@ -0,0 +1,84 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +my $underscore_test = shift @ARGV || ""; +if (!-d $underscore_test) { + print <<_END_; +Usage: + + testify ./underscore/test + + # Should look something like: + arrays.js + chaining.js + collections.js + functions.js + index.html + objects.js + speed.js + utility.js + vendor + +_END_ + if ($underscore_test) { + die "!: Not a directory: $underscore_test\n" + } + exit; +} + +chdir $underscore_test or die "!: $!"; + +my @js = <*.js>; + +for my $file (@js) { + open my $fh, '<', $file or die "!: $!"; + my $tests = join "", <$fh>; + my @tests = $tests =~ m/ + ^(\s{2}test\(.*? + ^\s{2}}\);)$ + /mgxs; + close $fh; + next unless @tests; + print "$file: ", scalar(@tests), "\n"; + my $underscore_name = "underscore_$file"; + $underscore_name =~ s/.js$//; + my $go_file = "${underscore_name}_test.go"; + $go_file =~ s/.js$/.go/; + open $fh, '>', $go_file or die "!: $!"; + + $fh->print(<<_END_); +package otto + +import ( + "testing" +) + +_END_ + + my $count = 0; + for my $test (@tests) { + $test =~ s/`([^`]+)`/<$1>/g; + my ($name) = $test =~ m/^\s*test\(['"]([^'"]+)['"]/; + $fh->print(<<_END_); +// $name +func Test_${underscore_name}_$count(t *testing.T) { + tt(t, func(){ + test := underscoreTest() + + test(` +$test + `) + }) +} + +_END_ + $count++; + } +} + +# test('#779 - delimeters are applied to unescaped text.', 1, function() { +# var template = _.template('<<\nx\n>>', null, {evaluate: /<<(.*?)>>/g}); +# strictEqual(template(), '<<\nx\n>>'); +# }); diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/underscore.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/underscore.go new file mode 100644 index 0000000000..714b8f3cf9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/underscore.go @@ -0,0 +1,49 @@ +/* +Package underscore contains the source for the JavaScript utility-belt library. + + import ( + _ "github.com/robertkrimen/otto/underscore" + ) + // Every Otto runtime will now include underscore + +http://underscorejs.org + +https://github.com/documentcloud/underscore + +By importing this package, you'll automatically load underscore every time you create a new Otto runtime. + +To prevent this behavior, you can do the following: + + import ( + "github.com/robertkrimen/otto/underscore" + ) + + func init() { + underscore.Disable() + } + +*/ +package underscore + +import ( + "github.com/robertkrimen/otto/registry" +) + +var entry *registry.Entry = registry.Register(func() string { + return Source() +}) + +// Enable underscore runtime inclusion. +func Enable() { + entry.Enable() +} + +// Disable underscore runtime inclusion. +func Disable() { + entry.Disable() +} + +// Source returns the underscore source. +func Source() string { + return string(underscore()) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_arrays_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_arrays_test.go new file mode 100644 index 0000000000..9d62978203 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_arrays_test.go @@ -0,0 +1,344 @@ +package otto + +import ( + "testing" +) + +// first +func Test_underscore_arrays_0(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("first", function() { + equal(_.first([1,2,3]), 1, 'can pull out the first element of an array'); + equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"'); + equal(_.first([1,2,3], 0).join(', '), "", 'can pass an index to first'); + equal(_.first([1,2,3], 2).join(', '), '1, 2', 'can pass an index to first'); + equal(_.first([1,2,3], 5).join(', '), '1, 2, 3', 'can pass an index to first'); + var result = (function(){ return _.first(arguments); })(4, 3, 2, 1); + equal(result, 4, 'works on an arguments object.'); + result = _.map([[1,2,3],[1,2,3]], _.first); + equal(result.join(','), '1,1', 'works well with _.map'); + result = (function() { return _.take([1,2,3], 2); })(); + equal(result.join(','), '1,2', 'aliased as take'); + + equal(_.first(null), undefined, 'handles nulls'); + }); + `) + }) +} + +// rest +func Test_underscore_arrays_1(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("rest", function() { + var numbers = [1, 2, 3, 4]; + equal(_.rest(numbers).join(", "), "2, 3, 4", 'working rest()'); + equal(_.rest(numbers, 0).join(", "), "1, 2, 3, 4", 'working rest(0)'); + equal(_.rest(numbers, 2).join(', '), '3, 4', 'rest can take an index'); + var result = (function(){ return _(arguments).tail(); })(1, 2, 3, 4); + equal(result.join(', '), '2, 3, 4', 'aliased as tail and works on arguments object'); + result = _.map([[1,2,3],[1,2,3]], _.rest); + equal(_.flatten(result).join(','), '2,3,2,3', 'works well with _.map'); + result = (function(){ return _(arguments).drop(); })(1, 2, 3, 4); + equal(result.join(', '), '2, 3, 4', 'aliased as drop and works on arguments object'); + }); + `) + }) +} + +// initial +func Test_underscore_arrays_2(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("initial", function() { + equal(_.initial([1,2,3,4,5]).join(", "), "1, 2, 3, 4", 'working initial()'); + equal(_.initial([1,2,3,4],2).join(", "), "1, 2", 'initial can take an index'); + var result = (function(){ return _(arguments).initial(); })(1, 2, 3, 4); + equal(result.join(", "), "1, 2, 3", 'initial works on arguments object'); + result = _.map([[1,2,3],[1,2,3]], _.initial); + equal(_.flatten(result).join(','), '1,2,1,2', 'initial works with _.map'); + }); + `) + }) +} + +// last +func Test_underscore_arrays_3(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("last", function() { + equal(_.last([1,2,3]), 3, 'can pull out the last element of an array'); + equal(_.last([1,2,3], 0).join(', '), "", 'can pass an index to last'); + equal(_.last([1,2,3], 2).join(', '), '2, 3', 'can pass an index to last'); + equal(_.last([1,2,3], 5).join(', '), '1, 2, 3', 'can pass an index to last'); + var result = (function(){ return _(arguments).last(); })(1, 2, 3, 4); + equal(result, 4, 'works on an arguments object'); + result = _.map([[1,2,3],[1,2,3]], _.last); + equal(result.join(','), '3,3', 'works well with _.map'); + + equal(_.last(null), undefined, 'handles nulls'); + }); + `) + }) +} + +// compact +func Test_underscore_arrays_4(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("compact", function() { + equal(_.compact([0, 1, false, 2, false, 3]).length, 3, 'can trim out all falsy values'); + var result = (function(){ return _.compact(arguments).length; })(0, 1, false, 2, false, 3); + equal(result, 3, 'works on an arguments object'); + }); + `) + }) +} + +// flatten +func Test_underscore_arrays_5(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("flatten", function() { + var list = [1, [2], [3, [[[4]]]]]; + deepEqual(_.flatten(list), [1,2,3,4], 'can flatten nested arrays'); + deepEqual(_.flatten(list, true), [1,2,3,[[[4]]]], 'can shallowly flatten nested arrays'); + var result = (function(){ return _.flatten(arguments); })(1, [2], [3, [[[4]]]]); + deepEqual(result, [1,2,3,4], 'works on an arguments object'); + }); + `) + }) +} + +// without +func Test_underscore_arrays_6(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("without", function() { + var list = [1, 2, 1, 0, 3, 1, 4]; + equal(_.without(list, 0, 1).join(', '), '2, 3, 4', 'can remove all instances of an object'); + var result = (function(){ return _.without(arguments, 0, 1); })(1, 2, 1, 0, 3, 1, 4); + equal(result.join(', '), '2, 3, 4', 'works on an arguments object'); + + var list = [{one : 1}, {two : 2}]; + ok(_.without(list, {one : 1}).length == 2, 'uses real object identity for comparisons.'); + ok(_.without(list, list[0]).length == 1, 'ditto.'); + }); + `) + }) +} + +// uniq +func Test_underscore_arrays_7(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("uniq", function() { + var list = [1, 2, 1, 3, 1, 4]; + equal(_.uniq(list).join(', '), '1, 2, 3, 4', 'can find the unique values of an unsorted array'); + + var list = [1, 1, 1, 2, 2, 3]; + equal(_.uniq(list, true).join(', '), '1, 2, 3', 'can find the unique values of a sorted array faster'); + + var list = [{name:'moe'}, {name:'curly'}, {name:'larry'}, {name:'curly'}]; + var iterator = function(value) { return value.name; }; + equal(_.map(_.uniq(list, false, iterator), iterator).join(', '), 'moe, curly, larry', 'can find the unique values of an array using a custom iterator'); + + equal(_.map(_.uniq(list, iterator), iterator).join(', '), 'moe, curly, larry', 'can find the unique values of an array using a custom iterator without specifying whether array is sorted'); + + var iterator = function(value) { return value +1; }; + var list = [1, 2, 2, 3, 4, 4]; + equal(_.uniq(list, true, iterator).join(', '), '1, 2, 3, 4', 'iterator works with sorted array'); + + var result = (function(){ return _.uniq(arguments); })(1, 2, 1, 3, 1, 4); + equal(result.join(', '), '1, 2, 3, 4', 'works on an arguments object'); + }); + `) + }) +} + +// intersection +func Test_underscore_arrays_8(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("intersection", function() { + var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho']; + equal(_.intersection(stooges, leaders).join(''), 'moe', 'can take the set intersection of two arrays'); + equal(_(stooges).intersection(leaders).join(''), 'moe', 'can perform an OO-style intersection'); + var result = (function(){ return _.intersection(arguments, leaders); })('moe', 'curly', 'larry'); + equal(result.join(''), 'moe', 'works on an arguments object'); + }); + `) + }) +} + +// union +func Test_underscore_arrays_9(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("union", function() { + var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]); + equal(result.join(' '), '1 2 3 30 40', 'takes the union of a list of arrays'); + + var result = _.union([1, 2, 3], [2, 30, 1], [1, 40, [1]]); + equal(result.join(' '), '1 2 3 30 40 1', 'takes the union of a list of nested arrays'); + }); + `) + }) +} + +// difference +func Test_underscore_arrays_10(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("difference", function() { + var result = _.difference([1, 2, 3], [2, 30, 40]); + equal(result.join(' '), '1 3', 'takes the difference of two arrays'); + + var result = _.difference([1, 2, 3, 4], [2, 30, 40], [1, 11, 111]); + equal(result.join(' '), '3 4', 'takes the difference of three arrays'); + }); + `) + }) +} + +// zip +func Test_underscore_arrays_11(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('zip', function() { + var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true]; + var stooges = _.zip(names, ages, leaders); + equal(String(stooges), 'moe,30,true,larry,40,,curly,50,', 'zipped together arrays of different lengths'); + }); + `) + }) +} + +// object +func Test_underscore_arrays_12(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('object', function() { + var result = _.object(['moe', 'larry', 'curly'], [30, 40, 50]); + var shouldBe = {moe: 30, larry: 40, curly: 50}; + ok(_.isEqual(result, shouldBe), 'two arrays zipped together into an object'); + + result = _.object([['one', 1], ['two', 2], ['three', 3]]); + shouldBe = {one: 1, two: 2, three: 3}; + ok(_.isEqual(result, shouldBe), 'an array of pairs zipped together into an object'); + + var stooges = {moe: 30, larry: 40, curly: 50}; + ok(_.isEqual(_.object(_.pairs(stooges)), stooges), 'an object converted to pairs and back to an object'); + + ok(_.isEqual(_.object(null), {}), 'handles nulls'); + }); + `) + }) +} + +// indexOf +func Test_underscore_arrays_13(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("indexOf", function() { + var numbers = [1, 2, 3]; + numbers.indexOf = null; + equal(_.indexOf(numbers, 2), 1, 'can compute indexOf, even without the native function'); + var result = (function(){ return _.indexOf(arguments, 2); })(1, 2, 3); + equal(result, 1, 'works on an arguments object'); + equal(_.indexOf(null, 2), -1, 'handles nulls properly'); + + var numbers = [10, 20, 30, 40, 50], num = 35; + var index = _.indexOf(numbers, num, true); + equal(index, -1, '35 is not in the list'); + + numbers = [10, 20, 30, 40, 50]; num = 40; + index = _.indexOf(numbers, num, true); + equal(index, 3, '40 is in the list'); + + numbers = [1, 40, 40, 40, 40, 40, 40, 40, 50, 60, 70]; num = 40; + index = _.indexOf(numbers, num, true); + equal(index, 1, '40 is in the list'); + + numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; + index = _.indexOf(numbers, 2, 5); + equal(index, 7, 'supports the fromIndex argument'); + }); + `) + }) +} + +// lastIndexOf +func Test_underscore_arrays_14(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("lastIndexOf", function() { + var numbers = [1, 0, 1]; + equal(_.lastIndexOf(numbers, 1), 2); + + numbers = [1, 0, 1, 0, 0, 1, 0, 0, 0]; + numbers.lastIndexOf = null; + equal(_.lastIndexOf(numbers, 1), 5, 'can compute lastIndexOf, even without the native function'); + equal(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element'); + var result = (function(){ return _.lastIndexOf(arguments, 1); })(1, 0, 1, 0, 0, 1, 0, 0, 0); + equal(result, 5, 'works on an arguments object'); + equal(_.indexOf(null, 2), -1, 'handles nulls properly'); + + numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; + var index = _.lastIndexOf(numbers, 2, 2); + equal(index, 1, 'supports the fromIndex argument'); + }); + `) + }) +} + +// range +func Test_underscore_arrays_15(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("range", function() { + equal(_.range(0).join(''), '', 'range with 0 as a first argument generates an empty array'); + equal(_.range(4).join(' '), '0 1 2 3', 'range with a single positive argument generates an array of elements 0,1,2,...,n-1'); + equal(_.range(5, 8).join(' '), '5 6 7', 'range with two arguments a & b, a<b generates an array of elements a,a+1,a+2,...,b-2,b-1'); + equal(_.range(8, 5).join(''), '', 'range with two arguments a & b, b<a generates an empty array'); + equal(_.range(3, 10, 3).join(' '), '3 6 9', 'range with three arguments a & b & c, c < b-a, a < b generates an array of elements a,a+c,a+2c,...,b - (multiplier of a) < c'); + equal(_.range(3, 10, 15).join(''), '3', 'range with three arguments a & b & c, c > b-a, a < b generates an array with a single element, equal to a'); + equal(_.range(12, 7, -2).join(' '), '12 10 8', 'range with three arguments a & b & c, a > b, c < 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b'); + equal(_.range(0, -10, -1).join(' '), '0 -1 -2 -3 -4 -5 -6 -7 -8 -9', 'final example in the Python docs'); + }); + `) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_chaining_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_chaining_test.go new file mode 100644 index 0000000000..accf04fdc6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_chaining_test.go @@ -0,0 +1,95 @@ +package otto + +import ( + "testing" +) + +// map/flatten/reduce +func Test_underscore_chaining_0(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("map/flatten/reduce", function() { + var lyrics = [ + "I'm a lumberjack and I'm okay", + "I sleep all night and I work all day", + "He's a lumberjack and he's okay", + "He sleeps all night and he works all day" + ]; + var counts = _(lyrics).chain() + .map(function(line) { return line.split(''); }) + .flatten() + .reduce(function(hash, l) { + hash[l] = hash[l] || 0; + hash[l]++; + return hash; + }, {}).value(); + ok(counts['a'] == 16 && counts['e'] == 10, 'counted all the letters in the song'); + }); + `) + }) +} + +// select/reject/sortBy +func Test_underscore_chaining_1(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("select/reject/sortBy", function() { + var numbers = [1,2,3,4,5,6,7,8,9,10]; + numbers = _(numbers).chain().select(function(n) { + return n % 2 == 0; + }).reject(function(n) { + return n % 4 == 0; + }).sortBy(function(n) { + return -n; + }).value(); + equal(numbers.join(', '), "10, 6, 2", "filtered and reversed the numbers"); + }); + `) + }) +} + +// select/reject/sortBy in functional style +func Test_underscore_chaining_2(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("select/reject/sortBy in functional style", function() { + var numbers = [1,2,3,4,5,6,7,8,9,10]; + numbers = _.chain(numbers).select(function(n) { + return n % 2 == 0; + }).reject(function(n) { + return n % 4 == 0; + }).sortBy(function(n) { + return -n; + }).value(); + equal(numbers.join(', '), "10, 6, 2", "filtered and reversed the numbers"); + }); + `) + }) +} + +// reverse/concat/unshift/pop/map +func Test_underscore_chaining_3(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("reverse/concat/unshift/pop/map", function() { + var numbers = [1,2,3,4,5]; + numbers = _(numbers).chain() + .reverse() + .concat([5, 5, 5]) + .unshift(17) + .pop() + .map(function(n){ return n * 2; }) + .value(); + equal(numbers.join(', '), "34, 10, 8, 6, 4, 2, 10, 10", 'can chain together array functions.'); + }); + `) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_collections_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_collections_test.go new file mode 100644 index 0000000000..9afc2a2b23 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_collections_test.go @@ -0,0 +1,698 @@ +package otto + +import ( + "testing" +) + +// each +func Test_underscore_collections_0(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("each", function() { + _.each([1, 2, 3], function(num, i) { + equal(num, i + 1, 'each iterators provide value and iteration count'); + }); + + var answers = []; + _.each([1, 2, 3], function(num){ answers.push(num * this.multiplier);}, {multiplier : 5}); + equal(answers.join(', '), '5, 10, 15', 'context object property accessed'); + + answers = []; + _.forEach([1, 2, 3], function(num){ answers.push(num); }); + equal(answers.join(', '), '1, 2, 3', 'aliased as "forEach"'); + + answers = []; + var obj = {one : 1, two : 2, three : 3}; + obj.constructor.prototype.four = 4; + _.each(obj, function(value, key){ answers.push(key); }); + equal(answers.join(", "), 'one, two, three', 'iterating over objects works, and ignores the object prototype.'); + delete obj.constructor.prototype.four; + + var answer = null; + _.each([1, 2, 3], function(num, index, arr){ if (_.include(arr, num)) answer = true; }); + ok(answer, 'can reference the original collection from inside the iterator'); + + answers = 0; + _.each(null, function(){ ++answers; }); + equal(answers, 0, 'handles a null properly'); + }); + `) + }) +} + +// map +func Test_underscore_collections_1(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('map', function() { + var doubled = _.map([1, 2, 3], function(num){ return num * 2; }); + equal(doubled.join(', '), '2, 4, 6', 'doubled numbers'); + + doubled = _.collect([1, 2, 3], function(num){ return num * 2; }); + equal(doubled.join(', '), '2, 4, 6', 'aliased as "collect"'); + + var tripled = _.map([1, 2, 3], function(num){ return num * this.multiplier; }, {multiplier : 3}); + equal(tripled.join(', '), '3, 6, 9', 'tripled numbers with context'); + + var doubled = _([1, 2, 3]).map(function(num){ return num * 2; }); + equal(doubled.join(', '), '2, 4, 6', 'OO-style doubled numbers'); + + // TEST: ReferenceError: document is not defined + return; + + if (document.querySelectorAll) { + var ids = _.map(document.querySelectorAll('#map-test *'), function(n){ return n.id; }); + deepEqual(ids, ['id1', 'id2'], 'Can use collection methods on NodeLists.'); + } + + var ids = _.map($('#map-test').children(), function(n){ return n.id; }); + deepEqual(ids, ['id1', 'id2'], 'Can use collection methods on jQuery Array-likes.'); + + var ids = _.map(document.images, function(n){ return n.id; }); + ok(ids[0] == 'chart_image', 'can use collection methods on HTMLCollections'); + + var ifnull = _.map(null, function(){}); + ok(_.isArray(ifnull) && ifnull.length === 0, 'handles a null properly'); + }); + `) + }) +} + +// reduce +func Test_underscore_collections_2(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('reduce', function() { + var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; }, 0); + equal(sum, 6, 'can sum up an array'); + + var context = {multiplier : 3}; + sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num * this.multiplier; }, 0, context); + equal(sum, 18, 'can reduce with a context object'); + + sum = _.inject([1, 2, 3], function(sum, num){ return sum + num; }, 0); + equal(sum, 6, 'aliased as "inject"'); + + sum = _([1, 2, 3]).reduce(function(sum, num){ return sum + num; }, 0); + equal(sum, 6, 'OO-style reduce'); + + var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; }); + equal(sum, 6, 'default initial value'); + + var ifnull; + try { + _.reduce(null, function(){}); + } catch (ex) { + ifnull = ex; + } + ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly'); + + ok(_.reduce(null, function(){}, 138) === 138, 'handles a null (with initial value) properly'); + equal(_.reduce([], function(){}, undefined), undefined, 'undefined can be passed as a special case'); + raises(function() { _.reduce([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value'); + }); + `) + }) +} + +// reduceRight +func Test_underscore_collections_3(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('reduceRight', function() { + var list = _.reduceRight(["foo", "bar", "baz"], function(memo, str){ return memo + str; }, ''); + equal(list, 'bazbarfoo', 'can perform right folds'); + + var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; }, ''); + equal(list, 'bazbarfoo', 'aliased as "foldr"'); + + var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; }); + equal(list, 'bazbarfoo', 'default initial value'); + + var ifnull; + try { + _.reduceRight(null, function(){}); + } catch (ex) { + ifnull = ex; + } + ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly'); + + var sum = _.reduceRight({a: 1, b: 2, c: 3}, function(sum, num){ return sum + num; }); + equal(sum, 6, 'default initial value on object'); + + ok(_.reduceRight(null, function(){}, 138) === 138, 'handles a null (with initial value) properly'); + + equal(_.reduceRight([], function(){}, undefined), undefined, 'undefined can be passed as a special case'); + raises(function() { _.reduceRight([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value'); + + // Assert that the correct arguments are being passed. + + var args, + memo = {}, + object = {a: 1, b: 2}, + lastKey = _.keys(object).pop(); + + var expected = lastKey == 'a' + ? [memo, 1, 'a', object] + : [memo, 2, 'b', object]; + + _.reduceRight(object, function() { + args || (args = _.toArray(arguments)); + }, memo); + + deepEqual(args, expected); + + // And again, with numeric keys. + + object = {'2': 'a', '1': 'b'}; + lastKey = _.keys(object).pop(); + args = null; + + expected = lastKey == '2' + ? [memo, 'a', '2', object] + : [memo, 'b', '1', object]; + + _.reduceRight(object, function() { + args || (args = _.toArray(arguments)); + }, memo); + + deepEqual(args, expected); + }); + `) + }) +} + +// find +func Test_underscore_collections_4(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('find', function() { + var array = [1, 2, 3, 4]; + strictEqual(_.find(array, function(n) { return n > 2; }), 3, 'should return first found '); + strictEqual(_.find(array, function() { return false; }), void 0, 'should return if is not found'); + }); + `) + }) +} + +// detect +func Test_underscore_collections_5(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('detect', function() { + var result = _.detect([1, 2, 3], function(num){ return num * 2 == 4; }); + equal(result, 2, 'found the first "2" and broke the loop'); + }); + `) + }) +} + +// select +func Test_underscore_collections_6(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('select', function() { + var evens = _.select([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); + equal(evens.join(', '), '2, 4, 6', 'selected each even number'); + + evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); + equal(evens.join(', '), '2, 4, 6', 'aliased as "filter"'); + }); + `) + }) +} + +// reject +func Test_underscore_collections_7(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('reject', function() { + var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); + equal(odds.join(', '), '1, 3, 5', 'rejected each even number'); + + var context = "obj"; + + var evens = _.reject([1, 2, 3, 4, 5, 6], function(num){ + equal(context, "obj"); + return num % 2 != 0; + }, context); + equal(evens.join(', '), '2, 4, 6', 'rejected each odd number'); + }); + `) + }) +} + +// all +func Test_underscore_collections_8(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('all', function() { + ok(_.all([], _.identity), 'the empty set'); + ok(_.all([true, true, true], _.identity), 'all true values'); + ok(!_.all([true, false, true], _.identity), 'one false value'); + ok(_.all([0, 10, 28], function(num){ return num % 2 == 0; }), 'even numbers'); + ok(!_.all([0, 11, 28], function(num){ return num % 2 == 0; }), 'an odd number'); + ok(_.all([1], _.identity) === true, 'cast to boolean - true'); + ok(_.all([0], _.identity) === false, 'cast to boolean - false'); + ok(_.every([true, true, true], _.identity), 'aliased as "every"'); + ok(!_.all([undefined, undefined, undefined], _.identity), 'works with arrays of undefined'); + }); + `) + }) +} + +// any +func Test_underscore_collections_9(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('any', function() { + var nativeSome = Array.prototype.some; + Array.prototype.some = null; + ok(!_.any([]), 'the empty set'); + ok(!_.any([false, false, false]), 'all false values'); + ok(_.any([false, false, true]), 'one true value'); + ok(_.any([null, 0, 'yes', false]), 'a string'); + ok(!_.any([null, 0, '', false]), 'falsy values'); + ok(!_.any([1, 11, 29], function(num){ return num % 2 == 0; }), 'all odd numbers'); + ok(_.any([1, 10, 29], function(num){ return num % 2 == 0; }), 'an even number'); + ok(_.any([1], _.identity) === true, 'cast to boolean - true'); + ok(_.any([0], _.identity) === false, 'cast to boolean - false'); + ok(_.some([false, false, true]), 'aliased as "some"'); + Array.prototype.some = nativeSome; + }); + `) + }) +} + +// include +func Test_underscore_collections_10(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('include', function() { + ok(_.include([1,2,3], 2), 'two is in the array'); + ok(!_.include([1,3,9], 2), 'two is not in the array'); + ok(_.contains({moe:1, larry:3, curly:9}, 3) === true, '_.include on objects checks their values'); + ok(_([1,2,3]).include(2), 'OO-style include'); + }); + `) + }) +} + +// invoke +func Test_underscore_collections_11(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('invoke', function() { + var list = [[5, 1, 7], [3, 2, 1]]; + var result = _.invoke(list, 'sort'); + equal(result[0].join(', '), '1, 5, 7', 'first array sorted'); + equal(result[1].join(', '), '1, 2, 3', 'second array sorted'); + }); + `) + }) +} + +// invoke w/ function reference +func Test_underscore_collections_12(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('invoke w/ function reference', function() { + var list = [[5, 1, 7], [3, 2, 1]]; + var result = _.invoke(list, Array.prototype.sort); + equal(result[0].join(', '), '1, 5, 7', 'first array sorted'); + equal(result[1].join(', '), '1, 2, 3', 'second array sorted'); + }); + `) + }) +} + +// invoke when strings have a call method +func Test_underscore_collections_13(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('invoke when strings have a call method', function() { + String.prototype.call = function() { + return 42; + }; + var list = [[5, 1, 7], [3, 2, 1]]; + var s = "foo"; + equal(s.call(), 42, "call function exists"); + var result = _.invoke(list, 'sort'); + equal(result[0].join(', '), '1, 5, 7', 'first array sorted'); + equal(result[1].join(', '), '1, 2, 3', 'second array sorted'); + delete String.prototype.call; + equal(s.call, undefined, "call function removed"); + }); + `) + }) +} + +// pluck +func Test_underscore_collections_14(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('pluck', function() { + var people = [{name : 'moe', age : 30}, {name : 'curly', age : 50}]; + equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'pulls names out of objects'); + }); + `) + }) +} + +// where +func Test_underscore_collections_15(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('where', function() { + var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]; + var result = _.where(list, {a: 1}); + equal(result.length, 3); + equal(result[result.length - 1].b, 4); + result = _.where(list, {b: 2}); + equal(result.length, 2); + equal(result[0].a, 1); + }); + `) + }) +} + +// findWhere +func Test_underscore_collections_16(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('findWhere', function() { + var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}, {a: 2, b: 4}]; + var result = _.findWhere(list, {a: 1}); + deepEqual(result, {a: 1, b: 2}); + result = _.findWhere(list, {b: 4}); + deepEqual(result, {a: 1, b: 4}); + }); + `) + }) +} + +// max +func Test_underscore_collections_17(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('max', function() { + equal(3, _.max([1, 2, 3]), 'can perform a regular Math.max'); + + var neg = _.max([1, 2, 3], function(num){ return -num; }); + equal(neg, 1, 'can perform a computation-based max'); + + equal(-Infinity, _.max({}), 'Maximum value of an empty object'); + equal(-Infinity, _.max([]), 'Maximum value of an empty array'); + equal(_.max({'a': 'a'}), -Infinity, 'Maximum value of a non-numeric collection'); + + // TEST: Takes too long + return; + + equal(299999, _.max(_.range(1,300000)), "Maximum value of a too-big array"); + }); + `) + }) +} + +// min +func Test_underscore_collections_18(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('min', function() { + equal(1, _.min([1, 2, 3]), 'can perform a regular Math.min'); + + var neg = _.min([1, 2, 3], function(num){ return -num; }); + equal(neg, 3, 'can perform a computation-based min'); + + equal(Infinity, _.min({}), 'Minimum value of an empty object'); + equal(Infinity, _.min([]), 'Minimum value of an empty array'); + equal(_.min({'a': 'a'}), Infinity, 'Minimum value of a non-numeric collection'); + + var now = new Date(9999999999); + var then = new Date(0); + equal(_.min([now, then]), then); + + // TEST: Takes too long + return; + + equal(1, _.min(_.range(1,300000)), "Minimum value of a too-big array"); + }); + `) + }) +} + +// sortBy +func Test_underscore_collections_19(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('sortBy', function() { + var people = [{name : 'curly', age : 50}, {name : 'moe', age : 30}]; + people = _.sortBy(people, function(person){ return person.age; }); + equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'stooges sorted by age'); + + var list = [undefined, 4, 1, undefined, 3, 2]; + equal(_.sortBy(list, _.identity).join(','), '1,2,3,4,,', 'sortBy with undefined values'); + + var list = ["one", "two", "three", "four", "five"]; + var sorted = _.sortBy(list, 'length'); + equal(sorted.join(' '), 'one two four five three', 'sorted by length'); + + function Pair(x, y) { + this.x = x; + this.y = y; + } + + var collection = [ + new Pair(1, 1), new Pair(1, 2), + new Pair(1, 3), new Pair(1, 4), + new Pair(1, 5), new Pair(1, 6), + new Pair(2, 1), new Pair(2, 2), + new Pair(2, 3), new Pair(2, 4), + new Pair(2, 5), new Pair(2, 6), + new Pair(undefined, 1), new Pair(undefined, 2), + new Pair(undefined, 3), new Pair(undefined, 4), + new Pair(undefined, 5), new Pair(undefined, 6) + ]; + + var actual = _.sortBy(collection, function(pair) { + return pair.x; + }); + + deepEqual(actual, collection, 'sortBy should be stable'); + }); + `) + }) +} + +// groupBy +func Test_underscore_collections_20(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('groupBy', function() { + var parity = _.groupBy([1, 2, 3, 4, 5, 6], function(num){ return num % 2; }); + ok('0' in parity && '1' in parity, 'created a group for each value'); + equal(parity[0].join(', '), '2, 4, 6', 'put each even number in the right group'); + + var list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"]; + var grouped = _.groupBy(list, 'length'); + equal(grouped['3'].join(' '), 'one two six ten'); + equal(grouped['4'].join(' '), 'four five nine'); + equal(grouped['5'].join(' '), 'three seven eight'); + + var context = {}; + _.groupBy([{}], function(){ ok(this === context); }, context); + + grouped = _.groupBy([4.2, 6.1, 6.4], function(num) { + return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor'; + }); + equal(grouped.constructor.length, 1); + equal(grouped.hasOwnProperty.length, 2); + + var array = [{}]; + _.groupBy(array, function(value, index, obj){ ok(obj === array); }); + + var array = [1, 2, 1, 2, 3]; + var grouped = _.groupBy(array); + equal(grouped['1'].length, 2); + equal(grouped['3'].length, 1); + }); + `) + }) +} + +// countBy +func Test_underscore_collections_21(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('countBy', function() { + var parity = _.countBy([1, 2, 3, 4, 5], function(num){ return num % 2 == 0; }); + equal(parity['true'], 2); + equal(parity['false'], 3); + + var list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"]; + var grouped = _.countBy(list, 'length'); + equal(grouped['3'], 4); + equal(grouped['4'], 3); + equal(grouped['5'], 3); + + var context = {}; + _.countBy([{}], function(){ ok(this === context); }, context); + + grouped = _.countBy([4.2, 6.1, 6.4], function(num) { + return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor'; + }); + equal(grouped.constructor, 1); + equal(grouped.hasOwnProperty, 2); + + var array = [{}]; + _.countBy(array, function(value, index, obj){ ok(obj === array); }); + + var array = [1, 2, 1, 2, 3]; + var grouped = _.countBy(array); + equal(grouped['1'], 2); + equal(grouped['3'], 1); + }); + `) + }) +} + +// sortedIndex +func Test_underscore_collections_22(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('sortedIndex', function() { + var numbers = [10, 20, 30, 40, 50], num = 35; + var indexForNum = _.sortedIndex(numbers, num); + equal(indexForNum, 3, '35 should be inserted at index 3'); + + var indexFor30 = _.sortedIndex(numbers, 30); + equal(indexFor30, 2, '30 should be inserted at index 2'); + + var objects = [{x: 10}, {x: 20}, {x: 30}, {x: 40}]; + var iterator = function(obj){ return obj.x; }; + strictEqual(_.sortedIndex(objects, {x: 25}, iterator), 2); + strictEqual(_.sortedIndex(objects, {x: 35}, 'x'), 3); + + var context = {1: 2, 2: 3, 3: 4}; + iterator = function(obj){ return this[obj]; }; + strictEqual(_.sortedIndex([1, 3], 2, iterator, context), 1); + }); + `) + }) +} + +// shuffle +func Test_underscore_collections_23(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('shuffle', function() { + var numbers = _.range(10); + var shuffled = _.shuffle(numbers).sort(); + notStrictEqual(numbers, shuffled, 'original object is unmodified'); + equal(shuffled.join(','), numbers.join(','), 'contains the same members before and after shuffle'); + }); + `) + }) +} + +// toArray +func Test_underscore_collections_24(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('toArray', function() { + ok(!_.isArray(arguments), 'arguments object is not an array'); + ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array'); + var a = [1,2,3]; + ok(_.toArray(a) !== a, 'array is cloned'); + equal(_.toArray(a).join(', '), '1, 2, 3', 'cloned array contains same elements'); + + var numbers = _.toArray({one : 1, two : 2, three : 3}); + equal(numbers.join(', '), '1, 2, 3', 'object flattened into array'); + + // TEST: ReferenceError: document is not defined + return; + + // test in IE < 9 + try { + var actual = _.toArray(document.childNodes); + } catch(ex) { } + + ok(_.isArray(actual), 'should not throw converting a node list'); + }); + `) + }) +} + +// size +func Test_underscore_collections_25(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test('size', function() { + equal(_.size({one : 1, two : 2, three : 3}), 3, 'can compute the size of an object'); + equal(_.size([1, 2, 3]), 3, 'can compute the size of an array'); + + var func = function() { + return _.size(arguments); + }; + + equal(func(1, 2, 3, 4), 4, 'can test the size of the arguments object'); + + equal(_.size('hello'), 5, 'can compute the size of a string'); + + equal(_.size(null), 0, 'handles nulls'); + }); + `) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_functions_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_functions_test.go new file mode 100644 index 0000000000..be59e16b3e --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_functions_test.go @@ -0,0 +1,208 @@ +package otto + +import ( + "testing" +) + +// bind +func Test_underscore_functions_0(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("bind", function() { + var context = {name : 'moe'}; + var func = function(arg) { return "name: " + (this.name || arg); }; + var bound = _.bind(func, context); + equal(bound(), 'name: moe', 'can bind a function to a context'); + + bound = _(func).bind(context); + equal(bound(), 'name: moe', 'can do OO-style binding'); + + bound = _.bind(func, null, 'curly'); + equal(bound(), 'name: curly', 'can bind without specifying a context'); + + func = function(salutation, name) { return salutation + ': ' + name; }; + func = _.bind(func, this, 'hello'); + equal(func('moe'), 'hello: moe', 'the function was partially applied in advance'); + + func = _.bind(func, this, 'curly'); + equal(func(), 'hello: curly', 'the function was completely applied in advance'); + + func = function(salutation, firstname, lastname) { return salutation + ': ' + firstname + ' ' + lastname; }; + func = _.bind(func, this, 'hello', 'moe', 'curly'); + equal(func(), 'hello: moe curly', 'the function was partially applied in advance and can accept multiple arguments'); + + func = function(context, message) { equal(this, context, message); }; + _.bind(func, 0, 0, 'can bind a function to <0>')(); + _.bind(func, '', '', 'can bind a function to an empty string')(); + _.bind(func, false, false, 'can bind a function to ')(); + + // These tests are only meaningful when using a browser without a native bind function + // To test this with a modern browser, set underscore's nativeBind to undefined + var F = function () { return this; }; + var Boundf = _.bind(F, {hello: "moe curly"}); + equal(Boundf().hello, "moe curly", "When called without the new operator, it's OK to be bound to the context"); + }); + `) + }) +} + +// partial +func Test_underscore_functions_1(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("partial", function() { + var obj = {name: 'moe'}; + var func = function() { return this.name + ' ' + _.toArray(arguments).join(' '); }; + + obj.func = _.partial(func, 'a', 'b'); + equal(obj.func('c', 'd'), 'moe a b c d', 'can partially apply'); + }); + `) + }) +} + +// bindAll +func Test_underscore_functions_2(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("bindAll", function() { + var curly = {name : 'curly'}, moe = { + name : 'moe', + getName : function() { return 'name: ' + this.name; }, + sayHi : function() { return 'hi: ' + this.name; } + }; + curly.getName = moe.getName; + _.bindAll(moe, 'getName', 'sayHi'); + curly.sayHi = moe.sayHi; + equal(curly.getName(), 'name: curly', 'unbound function is bound to current object'); + equal(curly.sayHi(), 'hi: moe', 'bound function is still bound to original object'); + + curly = {name : 'curly'}; + moe = { + name : 'moe', + getName : function() { return 'name: ' + this.name; }, + sayHi : function() { return 'hi: ' + this.name; } + }; + _.bindAll(moe); + curly.sayHi = moe.sayHi; + equal(curly.sayHi(), 'hi: moe', 'calling bindAll with no arguments binds all functions to the object'); + }); + `) + }) +} + +// memoize +func Test_underscore_functions_3(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("memoize", function() { + var fib = function(n) { + return n < 2 ? n : fib(n - 1) + fib(n - 2); + }; + var fastFib = _.memoize(fib); + equal(fib(10), 55, 'a memoized version of fibonacci produces identical results'); + equal(fastFib(10), 55, 'a memoized version of fibonacci produces identical results'); + + var o = function(str) { + return str; + }; + var fastO = _.memoize(o); + equal(o('toString'), 'toString', 'checks hasOwnProperty'); + equal(fastO('toString'), 'toString', 'checks hasOwnProperty'); + }); + `) + }) +} + +// once +func Test_underscore_functions_4(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("once", function() { + var num = 0; + var increment = _.once(function(){ num++; }); + increment(); + increment(); + equal(num, 1); + }); + `) + }) +} + +// wrap +func Test_underscore_functions_5(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("wrap", function() { + var greet = function(name){ return "hi: " + name; }; + var backwards = _.wrap(greet, function(func, name){ return func(name) + ' ' + name.split('').reverse().join(''); }); + equal(backwards('moe'), 'hi: moe eom', 'wrapped the saluation function'); + + var inner = function(){ return "Hello "; }; + var obj = {name : "Moe"}; + obj.hi = _.wrap(inner, function(fn){ return fn() + this.name; }); + equal(obj.hi(), "Hello Moe"); + + var noop = function(){}; + var wrapped = _.wrap(noop, function(fn){ return Array.prototype.slice.call(arguments, 0); }); + var ret = wrapped(['whats', 'your'], 'vector', 'victor'); + deepEqual(ret, [noop, ['whats', 'your'], 'vector', 'victor']); + }); + `) + }) +} + +// compose +func Test_underscore_functions_6(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("compose", function() { + var greet = function(name){ return "hi: " + name; }; + var exclaim = function(sentence){ return sentence + '!'; }; + var composed = _.compose(exclaim, greet); + equal(composed('moe'), 'hi: moe!', 'can compose a function that takes another'); + + composed = _.compose(greet, exclaim); + equal(composed('moe'), 'hi: moe!', 'in this case, the functions are also commutative'); + }); + `) + }) +} + +// after +func Test_underscore_functions_7(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("after", function() { + var testAfter = function(afterAmount, timesCalled) { + var afterCalled = 0; + var after = _.after(afterAmount, function() { + afterCalled++; + }); + while (timesCalled--) after(); + return afterCalled; + }; + + equal(testAfter(5, 5), 1, "after(N) should fire after being called N times"); + equal(testAfter(5, 4), 0, "after(N) should not fire unless called N times"); + equal(testAfter(0, 0), 1, "after(0) should fire immediately"); + }); + `) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_objects_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_objects_test.go new file mode 100644 index 0000000000..1973af8ddf --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_objects_test.go @@ -0,0 +1,826 @@ +package otto + +import ( + "testing" +) + +// keys +func Test_underscore_objects_0(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("keys", function() { + equal(_.keys({one : 1, two : 2}).join(', '), 'one, two', 'can extract the keys from an object'); + // the test above is not safe because it relies on for-in enumeration order + var a = []; a[1] = 0; + equal(_.keys(a).join(', '), '1', 'is not fooled by sparse arrays; see issue #95'); + raises(function() { _.keys(null); }, TypeError, 'throws an error for values'); + raises(function() { _.keys(void 0); }, TypeError, 'throws an error for values'); + raises(function() { _.keys(1); }, TypeError, 'throws an error for number primitives'); + raises(function() { _.keys('a'); }, TypeError, 'throws an error for string primitives'); + raises(function() { _.keys(true); }, TypeError, 'throws an error for boolean primitives'); + }); + `) + }) +} + +// values +func Test_underscore_objects_1(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("values", function() { + equal(_.values({one: 1, two: 2}).join(', '), '1, 2', 'can extract the values from an object'); + equal(_.values({one: 1, two: 2, length: 3}).join(', '), '1, 2, 3', '... even when one of them is "length"'); + }); + `) + }) +} + +// pairs +func Test_underscore_objects_2(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("pairs", function() { + deepEqual(_.pairs({one: 1, two: 2}), [['one', 1], ['two', 2]], 'can convert an object into pairs'); + deepEqual(_.pairs({one: 1, two: 2, length: 3}), [['one', 1], ['two', 2], ['length', 3]], '... even when one of them is "length"'); + }); + `) + }) +} + +// invert +func Test_underscore_objects_3(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("invert", function() { + var obj = {first: 'Moe', second: 'Larry', third: 'Curly'}; + equal(_.keys(_.invert(obj)).join(' '), 'Moe Larry Curly', 'can invert an object'); + ok(_.isEqual(_.invert(_.invert(obj)), obj), 'two inverts gets you back where you started'); + + var obj = {length: 3}; + ok(_.invert(obj)['3'] == 'length', 'can invert an object with "length"') + }); + `) + }) +} + +// functions +func Test_underscore_objects_4(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("functions", function() { + var obj = {a : 'dash', b : _.map, c : (/yo/), d : _.reduce}; + ok(_.isEqual(['b', 'd'], _.functions(obj)), 'can grab the function names of any passed-in object'); + + var Animal = function(){}; + Animal.prototype.run = function(){}; + equal(_.functions(new Animal).join(''), 'run', 'also looks up functions on the prototype'); + }); + `) + }) +} + +// extend +func Test_underscore_objects_5(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("extend", function() { + var result; + equal(_.extend({}, {a:'b'}).a, 'b', 'can extend an object with the attributes of another'); + equal(_.extend({a:'x'}, {a:'b'}).a, 'b', 'properties in source override destination'); + equal(_.extend({x:'x'}, {a:'b'}).x, 'x', 'properties not in source dont get overriden'); + result = _.extend({x:'x'}, {a:'a'}, {b:'b'}); + ok(_.isEqual(result, {x:'x', a:'a', b:'b'}), 'can extend from multiple source objects'); + result = _.extend({x:'x'}, {a:'a', x:2}, {a:'b'}); + ok(_.isEqual(result, {x:2, a:'b'}), 'extending from multiple source objects last property trumps'); + result = _.extend({}, {a: void 0, b: null}); + equal(_.keys(result).join(''), 'ab', 'extend does not copy undefined values'); + + try { + result = {}; + _.extend(result, null, undefined, {a:1}); + } catch(ex) {} + + equal(result.a, 1, 'should not error on or sources'); + }); + `) + }) +} + +// pick +func Test_underscore_objects_6(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("pick", function() { + var result; + result = _.pick({a:1, b:2, c:3}, 'a', 'c'); + ok(_.isEqual(result, {a:1, c:3}), 'can restrict properties to those named'); + result = _.pick({a:1, b:2, c:3}, ['b', 'c']); + ok(_.isEqual(result, {b:2, c:3}), 'can restrict properties to those named in an array'); + result = _.pick({a:1, b:2, c:3}, ['a'], 'b'); + ok(_.isEqual(result, {a:1, b:2}), 'can restrict properties to those named in mixed args'); + + var Obj = function(){}; + Obj.prototype = {a: 1, b: 2, c: 3}; + ok(_.isEqual(_.pick(new Obj, 'a', 'c'), {a:1, c: 3}), 'include prototype props'); + }); + `) + }) +} + +// omit +func Test_underscore_objects_7(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("omit", function() { + var result; + result = _.omit({a:1, b:2, c:3}, 'b'); + ok(_.isEqual(result, {a:1, c:3}), 'can omit a single named property'); + result = _.omit({a:1, b:2, c:3}, 'a', 'c'); + ok(_.isEqual(result, {b:2}), 'can omit several named properties'); + result = _.omit({a:1, b:2, c:3}, ['b', 'c']); + ok(_.isEqual(result, {a:1}), 'can omit properties named in an array'); + + var Obj = function(){}; + Obj.prototype = {a: 1, b: 2, c: 3}; + ok(_.isEqual(_.omit(new Obj, 'b'), {a:1, c: 3}), 'include prototype props'); + }); + `) + }) +} + +// defaults +func Test_underscore_objects_8(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("defaults", function() { + var result; + var options = {zero: 0, one: 1, empty: "", nan: NaN, string: "string"}; + + _.defaults(options, {zero: 1, one: 10, twenty: 20}); + equal(options.zero, 0, 'value exists'); + equal(options.one, 1, 'value exists'); + equal(options.twenty, 20, 'default applied'); + + _.defaults(options, {empty: "full"}, {nan: "nan"}, {word: "word"}, {word: "dog"}); + equal(options.empty, "", 'value exists'); + ok(_.isNaN(options.nan), "NaN isn't overridden"); + equal(options.word, "word", 'new value is added, first one wins'); + + try { + options = {}; + _.defaults(options, null, undefined, {a:1}); + } catch(ex) {} + + equal(options.a, 1, 'should not error on or sources'); + }); + `) + }) +} + +// clone +func Test_underscore_objects_9(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("clone", function() { + var moe = {name : 'moe', lucky : [13, 27, 34]}; + var clone = _.clone(moe); + equal(clone.name, 'moe', 'the clone as the attributes of the original'); + + clone.name = 'curly'; + ok(clone.name == 'curly' && moe.name == 'moe', 'clones can change shallow attributes without affecting the original'); + + clone.lucky.push(101); + equal(_.last(moe.lucky), 101, 'changes to deep attributes are shared with the original'); + + equal(_.clone(undefined), void 0, 'non objects should not be changed by clone'); + equal(_.clone(1), 1, 'non objects should not be changed by clone'); + equal(_.clone(null), null, 'non objects should not be changed by clone'); + }); + `) + }) +} + +// isEqual +func Test_underscore_objects_10(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isEqual", function() { + function First() { + this.value = 1; + } + First.prototype.value = 1; + function Second() { + this.value = 1; + } + Second.prototype.value = 2; + + // Basic equality and identity comparisons. + ok(_.isEqual(null, null), " is equal to "); + ok(_.isEqual(), " is equal to "); + + ok(!_.isEqual(0, -0), "<0> is not equal to <-0>"); + ok(!_.isEqual(-0, 0), "Commutative equality is implemented for <0> and <-0>"); + ok(!_.isEqual(null, undefined), " is not equal to "); + ok(!_.isEqual(undefined, null), "Commutative equality is implemented for and "); + + // String object and primitive comparisons. + ok(_.isEqual("Curly", "Curly"), "Identical string primitives are equal"); + ok(_.isEqual(new String("Curly"), new String("Curly")), "String objects with identical primitive values are equal"); + ok(_.isEqual(new String("Curly"), "Curly"), "String primitives and their corresponding object wrappers are equal"); + ok(_.isEqual("Curly", new String("Curly")), "Commutative equality is implemented for string objects and primitives"); + + ok(!_.isEqual("Curly", "Larry"), "String primitives with different values are not equal"); + ok(!_.isEqual(new String("Curly"), new String("Larry")), "String objects with different primitive values are not equal"); + ok(!_.isEqual(new String("Curly"), {toString: function(){ return "Curly"; }}), "String objects and objects with a custom method are not equal"); + + // Number object and primitive comparisons. + ok(_.isEqual(75, 75), "Identical number primitives are equal"); + ok(_.isEqual(new Number(75), new Number(75)), "Number objects with identical primitive values are equal"); + ok(_.isEqual(75, new Number(75)), "Number primitives and their corresponding object wrappers are equal"); + ok(_.isEqual(new Number(75), 75), "Commutative equality is implemented for number objects and primitives"); + ok(!_.isEqual(new Number(0), -0), " and <-0> are not equal"); + ok(!_.isEqual(0, new Number(-0)), "Commutative equality is implemented for and <-0>"); + + ok(!_.isEqual(new Number(75), new Number(63)), "Number objects with different primitive values are not equal"); + ok(!_.isEqual(new Number(63), {valueOf: function(){ return 63; }}), "Number objects and objects with a method are not equal"); + + // Comparisons involving . + ok(_.isEqual(NaN, NaN), " is equal to "); + ok(!_.isEqual(61, NaN), "A number primitive is not equal to "); + ok(!_.isEqual(new Number(79), NaN), "A number object is not equal to "); + ok(!_.isEqual(Infinity, NaN), " is not equal to "); + + // Boolean object and primitive comparisons. + ok(_.isEqual(true, true), "Identical boolean primitives are equal"); + ok(_.isEqual(new Boolean, new Boolean), "Boolean objects with identical primitive values are equal"); + ok(_.isEqual(true, new Boolean(true)), "Boolean primitives and their corresponding object wrappers are equal"); + ok(_.isEqual(new Boolean(true), true), "Commutative equality is implemented for booleans"); + ok(!_.isEqual(new Boolean(true), new Boolean), "Boolean objects with different primitive values are not equal"); + + // Common type coercions. + ok(!_.isEqual(true, new Boolean(false)), "Boolean objects are not equal to the boolean primitive "); + ok(!_.isEqual("75", 75), "String and number primitives with like values are not equal"); + ok(!_.isEqual(new Number(63), new String(63)), "String and number objects with like values are not equal"); + ok(!_.isEqual(75, "75"), "Commutative equality is implemented for like string and number values"); + ok(!_.isEqual(0, ""), "Number and string primitives with like values are not equal"); + ok(!_.isEqual(1, true), "Number and boolean primitives with like values are not equal"); + ok(!_.isEqual(new Boolean(false), new Number(0)), "Boolean and number objects with like values are not equal"); + ok(!_.isEqual(false, new String("")), "Boolean primitives and string objects with like values are not equal"); + ok(!_.isEqual(12564504e5, new Date(2009, 9, 25)), "Dates and their corresponding numeric primitive values are not equal"); + + // Dates. + ok(_.isEqual(new Date(2009, 9, 25), new Date(2009, 9, 25)), "Date objects referencing identical times are equal"); + ok(!_.isEqual(new Date(2009, 9, 25), new Date(2009, 11, 13)), "Date objects referencing different times are not equal"); + ok(!_.isEqual(new Date(2009, 11, 13), { + getTime: function(){ + return 12606876e5; + } + }), "Date objects and objects with a method are not equal"); + ok(!_.isEqual(new Date("Curly"), new Date("Curly")), "Invalid dates are not equal"); + + // Functions. + ok(!_.isEqual(First, Second), "Different functions with identical bodies and source code representations are not equal"); + + // RegExps. + ok(_.isEqual(/(?:)/gim, /(?:)/gim), "RegExps with equivalent patterns and flags are equal"); + ok(!_.isEqual(/(?:)/g, /(?:)/gi), "RegExps with equivalent patterns and different flags are not equal"); + ok(!_.isEqual(/Moe/gim, /Curly/gim), "RegExps with different patterns and equivalent flags are not equal"); + ok(!_.isEqual(/(?:)/gi, /(?:)/g), "Commutative equality is implemented for RegExps"); + ok(!_.isEqual(/Curly/g, {source: "Larry", global: true, ignoreCase: false, multiline: false}), "RegExps and RegExp-like objects are not equal"); + + // Empty arrays, array-like objects, and object literals. + ok(_.isEqual({}, {}), "Empty object literals are equal"); + ok(_.isEqual([], []), "Empty array literals are equal"); + ok(_.isEqual([{}], [{}]), "Empty nested arrays and objects are equal"); + ok(!_.isEqual({length: 0}, []), "Array-like objects and arrays are not equal."); + ok(!_.isEqual([], {length: 0}), "Commutative equality is implemented for array-like objects"); + + ok(!_.isEqual({}, []), "Object literals and array literals are not equal"); + ok(!_.isEqual([], {}), "Commutative equality is implemented for objects and arrays"); + + // Arrays with primitive and object values. + ok(_.isEqual([1, "Larry", true], [1, "Larry", true]), "Arrays containing identical primitives are equal"); + ok(_.isEqual([(/Moe/g), new Date(2009, 9, 25)], [(/Moe/g), new Date(2009, 9, 25)]), "Arrays containing equivalent elements are equal"); + + // Multi-dimensional arrays. + var a = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}]; + var b = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}]; + ok(_.isEqual(a, b), "Arrays containing nested arrays and objects are recursively compared"); + + // Overwrite the methods defined in ES 5.1 section 15.4.4. + a.forEach = a.map = a.filter = a.every = a.indexOf = a.lastIndexOf = a.some = a.reduce = a.reduceRight = null; + b.join = b.pop = b.reverse = b.shift = b.slice = b.splice = b.concat = b.sort = b.unshift = null; + + // Array elements and properties. + ok(_.isEqual(a, b), "Arrays containing equivalent elements and different non-numeric properties are equal"); + a.push("White Rocks"); + ok(!_.isEqual(a, b), "Arrays of different lengths are not equal"); + a.push("East Boulder"); + b.push("Gunbarrel Ranch", "Teller Farm"); + ok(!_.isEqual(a, b), "Arrays of identical lengths containing different elements are not equal"); + + // Sparse arrays. + ok(_.isEqual(Array(3), Array(3)), "Sparse arrays of identical lengths are equal"); + ok(!_.isEqual(Array(3), Array(6)), "Sparse arrays of different lengths are not equal when both are empty"); + + // Simple objects. + ok(_.isEqual({a: "Curly", b: 1, c: true}, {a: "Curly", b: 1, c: true}), "Objects containing identical primitives are equal"); + ok(_.isEqual({a: /Curly/g, b: new Date(2009, 11, 13)}, {a: /Curly/g, b: new Date(2009, 11, 13)}), "Objects containing equivalent members are equal"); + ok(!_.isEqual({a: 63, b: 75}, {a: 61, b: 55}), "Objects of identical sizes with different values are not equal"); + ok(!_.isEqual({a: 63, b: 75}, {a: 61, c: 55}), "Objects of identical sizes with different property names are not equal"); + ok(!_.isEqual({a: 1, b: 2}, {a: 1}), "Objects of different sizes are not equal"); + ok(!_.isEqual({a: 1}, {a: 1, b: 2}), "Commutative equality is implemented for objects"); + ok(!_.isEqual({x: 1, y: undefined}, {x: 1, z: 2}), "Objects with identical keys and different values are not equivalent"); + + // contains nested objects and arrays. + a = { + name: new String("Moe Howard"), + age: new Number(77), + stooge: true, + hobbies: ["acting"], + film: { + name: "Sing a Song of Six Pants", + release: new Date(1947, 9, 30), + stars: [new String("Larry Fine"), "Shemp Howard"], + minutes: new Number(16), + seconds: 54 + } + }; + + // contains equivalent nested objects and arrays. + b = { + name: new String("Moe Howard"), + age: new Number(77), + stooge: true, + hobbies: ["acting"], + film: { + name: "Sing a Song of Six Pants", + release: new Date(1947, 9, 30), + stars: [new String("Larry Fine"), "Shemp Howard"], + minutes: new Number(16), + seconds: 54 + } + }; + ok(_.isEqual(a, b), "Objects with nested equivalent members are recursively compared"); + + // Instances. + ok(_.isEqual(new First, new First), "Object instances are equal"); + ok(!_.isEqual(new First, new Second), "Objects with different constructors and identical own properties are not equal"); + ok(!_.isEqual({value: 1}, new First), "Object instances and objects sharing equivalent properties are not equal"); + ok(!_.isEqual({value: 2}, new Second), "The prototype chain of objects should not be examined"); + + // Circular Arrays. + (a = []).push(a); + (b = []).push(b); + ok(_.isEqual(a, b), "Arrays containing circular references are equal"); + a.push(new String("Larry")); + b.push(new String("Larry")); + ok(_.isEqual(a, b), "Arrays containing circular references and equivalent properties are equal"); + a.push("Shemp"); + b.push("Curly"); + ok(!_.isEqual(a, b), "Arrays containing circular references and different properties are not equal"); + + // More circular arrays #767. + a = ["everything is checked but", "this", "is not"]; + a[1] = a; + b = ["everything is checked but", ["this", "array"], "is not"]; + ok(!_.isEqual(a, b), "Comparison of circular references with non-circular references are not equal"); + + // Circular Objects. + a = {abc: null}; + b = {abc: null}; + a.abc = a; + b.abc = b; + ok(_.isEqual(a, b), "Objects containing circular references are equal"); + a.def = 75; + b.def = 75; + ok(_.isEqual(a, b), "Objects containing circular references and equivalent properties are equal"); + a.def = new Number(75); + b.def = new Number(63); + ok(!_.isEqual(a, b), "Objects containing circular references and different properties are not equal"); + + // More circular objects #767. + a = {everything: "is checked", but: "this", is: "not"}; + a.but = a; + b = {everything: "is checked", but: {that:"object"}, is: "not"}; + ok(!_.isEqual(a, b), "Comparison of circular references with non-circular object references are not equal"); + + // Cyclic Structures. + a = [{abc: null}]; + b = [{abc: null}]; + (a[0].abc = a).push(a); + (b[0].abc = b).push(b); + ok(_.isEqual(a, b), "Cyclic structures are equal"); + a[0].def = "Larry"; + b[0].def = "Larry"; + ok(_.isEqual(a, b), "Cyclic structures containing equivalent properties are equal"); + a[0].def = new String("Larry"); + b[0].def = new String("Curly"); + ok(!_.isEqual(a, b), "Cyclic structures containing different properties are not equal"); + + // Complex Circular References. + a = {foo: {b: {foo: {c: {foo: null}}}}}; + b = {foo: {b: {foo: {c: {foo: null}}}}}; + a.foo.b.foo.c.foo = a; + b.foo.b.foo.c.foo = b; + ok(_.isEqual(a, b), "Cyclic structures with nested and identically-named properties are equal"); + + // Chaining. + ok(!_.isEqual(_({x: 1, y: undefined}).chain(), _({x: 1, z: 2}).chain()), 'Chained objects containing different values are not equal'); + + a = _({x: 1, y: 2}).chain(); + b = _({x: 1, y: 2}).chain(); + equal(_.isEqual(a.isEqual(b), _(true)), true, ' can be chained'); + + // TEST: ??? + return; + + // Objects from another frame. + ok(_.isEqual({}, iObject)); + }); + `) + }) +} + +// isEmpty +func Test_underscore_objects_11(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isEmpty", function() { + ok(!_([1]).isEmpty(), '[1] is not empty'); + ok(_.isEmpty([]), '[] is empty'); + ok(!_.isEmpty({one : 1}), '{one : 1} is not empty'); + ok(_.isEmpty({}), '{} is empty'); + ok(_.isEmpty(new RegExp('')), 'objects with prototype properties are empty'); + ok(_.isEmpty(null), 'null is empty'); + ok(_.isEmpty(), 'undefined is empty'); + ok(_.isEmpty(''), 'the empty string is empty'); + ok(!_.isEmpty('moe'), 'but other strings are not'); + + var obj = {one : 1}; + delete obj.one; + ok(_.isEmpty(obj), 'deleting all the keys from an object empties it'); + }); + `) + }) +} + +// isElement +func Test_underscore_objects_12(t *testing.T) { + // TEST: ReferenceError: $ is not defined + if true { + return + } + + tt(t, func() { + test, _ := test_() + + test(` + test("isElement", function() { + ok(!_.isElement('div'), 'strings are not dom elements'); + ok(_.isElement($('html')[0]), 'the html tag is a DOM element'); + ok(_.isElement(iElement), 'even from another frame'); + }); + `) + }) +} + +// isArguments +func Test_underscore_objects_13(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isArguments", function() { + var args = (function(){ return arguments; })(1, 2, 3); + ok(!_.isArguments('string'), 'a string is not an arguments object'); + ok(!_.isArguments(_.isArguments), 'a function is not an arguments object'); + ok(_.isArguments(args), 'but the arguments object is an arguments object'); + ok(!_.isArguments(_.toArray(args)), 'but not when it\'s converted into an array'); + ok(!_.isArguments([1,2,3]), 'and not vanilla arrays.'); + + // TEST: ReferenceError: iArguments is not defined + return; + ok(_.isArguments(iArguments), 'even from another frame'); + }); + `) + }) +} + +// isObject +func Test_underscore_objects_14(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isObject", function() { + ok(_.isObject(arguments), 'the arguments object is object'); + ok(_.isObject([1, 2, 3]), 'and arrays'); + // TEST: ReferenceError: $ is not defined + return; + ok(_.isObject($('html')[0]), 'and DOM element'); + ok(_.isObject(iElement), 'even from another frame'); + ok(_.isObject(function () {}), 'and functions'); + ok(_.isObject(iFunction), 'even from another frame'); + ok(!_.isObject(null), 'but not null'); + ok(!_.isObject(undefined), 'and not undefined'); + ok(!_.isObject('string'), 'and not string'); + ok(!_.isObject(12), 'and not number'); + ok(!_.isObject(true), 'and not boolean'); + ok(_.isObject(new String('string')), 'but new String()'); + }); + `) + }) +} + +// isArray +func Test_underscore_objects_15(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isArray", function() { + ok(!_.isArray(arguments), 'the arguments object is not an array'); + ok(_.isArray([1, 2, 3]), 'but arrays are'); + // TEST: ??? + return; + ok(_.isArray(iArray), 'even from another frame'); + }); + `) + }) +} + +// isString +func Test_underscore_objects_16(t *testing.T) { + // TEST: ReferenceError: document is not defined + if true { + return + } + + tt(t, func() { + test, _ := test_() + + test(` + test("isString", function() { + ok(!_.isString(document.body), 'the document body is not a string'); + ok(_.isString([1, 2, 3].join(', ')), 'but strings are'); + // TEST: ??? + return; + ok(_.isString(iString), 'even from another frame'); + }); + `) + }) +} + +// isNumber +func Test_underscore_objects_17(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isNumber", function() { + ok(!_.isNumber('string'), 'a string is not a number'); + ok(!_.isNumber(arguments), 'the arguments object is not a number'); + ok(!_.isNumber(undefined), 'undefined is not a number'); + ok(_.isNumber(3 * 4 - 7 / 10), 'but numbers are'); + ok(_.isNumber(NaN), 'NaN *is* a number'); + ok(_.isNumber(Infinity), 'Infinity is a number'); + // TEST: ??? + return; + ok(_.isNumber(iNumber), 'even from another frame'); + ok(!_.isNumber('1'), 'numeric strings are not numbers'); + }); + `) + }) +} + +// isBoolean +func Test_underscore_objects_18(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isBoolean", function() { + ok(!_.isBoolean(2), 'a number is not a boolean'); + ok(!_.isBoolean("string"), 'a string is not a boolean'); + ok(!_.isBoolean("false"), 'the string "false" is not a boolean'); + ok(!_.isBoolean("true"), 'the string "true" is not a boolean'); + ok(!_.isBoolean(arguments), 'the arguments object is not a boolean'); + ok(!_.isBoolean(undefined), 'undefined is not a boolean'); + ok(!_.isBoolean(NaN), 'NaN is not a boolean'); + ok(!_.isBoolean(null), 'null is not a boolean'); + ok(_.isBoolean(true), 'but true is'); + ok(_.isBoolean(false), 'and so is false'); + // TEST: ??? + return; + ok(_.isBoolean(iBoolean), 'even from another frame'); + }); + `) + }) +} + +// isFunction +func Test_underscore_objects_19(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isFunction", function() { + ok(!_.isFunction([1, 2, 3]), 'arrays are not functions'); + ok(!_.isFunction('moe'), 'strings are not functions'); + ok(_.isFunction(_.isFunction), 'but functions are'); + // TEST: ??? + return; + ok(_.isFunction(iFunction), 'even from another frame'); + }); + `) + }) +} + +// isDate +func Test_underscore_objects_20(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isDate", function() { + ok(!_.isDate(100), 'numbers are not dates'); + ok(!_.isDate({}), 'objects are not dates'); + ok(_.isDate(new Date()), 'but dates are'); + // TEST: ??? + return; + ok(_.isDate(iDate), 'even from another frame'); + }); + `) + }) +} + +// isRegExp +func Test_underscore_objects_21(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isRegExp", function() { + ok(!_.isRegExp(_.identity), 'functions are not RegExps'); + ok(_.isRegExp(/identity/), 'but RegExps are'); + // TEST: ??? + return; + ok(_.isRegExp(iRegExp), 'even from another frame'); + }); + `) + }) +} + +// isFinite +func Test_underscore_objects_22(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isFinite", function() { + ok(!_.isFinite(undefined), 'undefined is not Finite'); + ok(!_.isFinite(null), 'null is not Finite'); + ok(!_.isFinite(NaN), 'NaN is not Finite'); + ok(!_.isFinite(Infinity), 'Infinity is not Finite'); + ok(!_.isFinite(-Infinity), '-Infinity is not Finite'); + ok(_.isFinite('12'), 'Numeric strings are numbers'); + ok(!_.isFinite('1a'), 'Non numeric strings are not numbers'); + ok(!_.isFinite(''), 'Empty strings are not numbers'); + var obj = new Number(5); + ok(_.isFinite(obj), 'Number instances can be finite'); + ok(_.isFinite(0), '0 is Finite'); + ok(_.isFinite(123), 'Ints are Finite'); + ok(_.isFinite(-12.44), 'Floats are Finite'); + }); + `) + }) +} + +// isNaN +func Test_underscore_objects_23(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isNaN", function() { + ok(!_.isNaN(undefined), 'undefined is not NaN'); + ok(!_.isNaN(null), 'null is not NaN'); + ok(!_.isNaN(0), '0 is not NaN'); + ok(_.isNaN(NaN), 'but NaN is'); + // TEST: ??? + return; + ok(_.isNaN(iNaN), 'even from another frame'); + ok(_.isNaN(new Number(NaN)), 'wrapped NaN is still NaN'); + }); + `) + }) +} + +// isNull +func Test_underscore_objects_24(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isNull", function() { + ok(!_.isNull(undefined), 'undefined is not null'); + ok(!_.isNull(NaN), 'NaN is not null'); + ok(_.isNull(null), 'but null is'); + // TEST: ??? + return; + ok(_.isNull(iNull), 'even from another frame'); + }); + `) + }) +} + +// isUndefined +func Test_underscore_objects_25(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("isUndefined", function() { + ok(!_.isUndefined(1), 'numbers are defined'); + ok(!_.isUndefined(null), 'null is defined'); + ok(!_.isUndefined(false), 'false is defined'); + ok(!_.isUndefined(NaN), 'NaN is defined'); + ok(_.isUndefined(), 'nothing is undefined'); + ok(_.isUndefined(undefined), 'undefined is undefined'); + // TEST: ??? + return; + ok(_.isUndefined(iUndefined), 'even from another frame'); + }); + `) + }) +} + +// tap +func Test_underscore_objects_26(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("tap", function() { + var intercepted = null; + var interceptor = function(obj) { intercepted = obj; }; + var returned = _.tap(1, interceptor); + equal(intercepted, 1, "passes tapped object to interceptor"); + equal(returned, 1, "returns tapped object"); + + returned = _([1,2,3]).chain(). + map(function(n){ return n * 2; }). + max(). + tap(interceptor). + value(); + ok(returned == 6 && intercepted == 6, 'can use tapped objects in a chain'); + }); + `) + }) +} + +// has +func Test_underscore_objects_27(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("has", function () { + var obj = {foo: "bar", func: function () {} }; + ok (_.has(obj, "foo"), "has() checks that the object has a property."); + ok (_.has(obj, "baz") == false, "has() returns false if the object doesn't have the property."); + ok (_.has(obj, "func"), "has() works for functions too."); + obj.hasOwnProperty = null; + ok (_.has(obj, "foo"), "has() works even when the hasOwnProperty method is deleted."); + var child = {}; + child.prototype = obj; + ok (_.has(child, "foo") == false, "has() does not check the prototype chain for a property.") + }); + `) + }) +} diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_test.go new file mode 100644 index 0000000000..d8bf2da18d --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_test.go @@ -0,0 +1,165 @@ +package otto + +import ( + "./terst" + "testing" + + "github.com/robertkrimen/otto/underscore" +) + +func init() { + underscore.Disable() +} + +// A persistent handle for the underscore tester +// We do not run underscore tests in parallel, so it is okay to stash globally +// (Maybe use sync.Pool in the future...) +var tester_ *_tester + +// A tester for underscore: test_ => test(underscore) :) +func test_(arguments ...interface{}) (func(string, ...interface{}) Value, *_tester) { + tester := tester_ + if tester == nil { + tester = newTester() + tester.underscore() // Load underscore and testing shim, etc. + tester_ = tester + } + + return tester.test, tester +} + +func (self *_tester) underscore() { + vm := self.vm + _, err := vm.Run(underscore.Source()) + if err != nil { + panic(err) + } + + vm.Set("assert", func(call FunctionCall) Value { + if !call.Argument(0).bool() { + message := "Assertion failed" + if len(call.ArgumentList) > 1 { + message = call.ArgumentList[1].string() + } + t := terst.Caller().T() + is(message, nil) + t.Fail() + return falseValue + } + return trueValue + }) + + vm.Run(` + var templateSettings; + + function _setup() { + templateSettings = _.clone(_.templateSettings); + } + + function _teardown() { + _.templateSettings = templateSettings; + } + + function module() { + /* Nothing happens. */ + } + + function equals(a, b, emit) { + assert(a == b, emit + ", <" + a + "> != <" + b + ">"); + } + var equal = equals; + + function notStrictEqual(a, b, emit) { + assert(a !== b, emit); + } + + function strictEqual(a, b, emit) { + assert(a === b, emit); + } + + function ok(a, emit) { + assert(a, emit); + } + + function raises(fn, want, emit) { + var have, _ok = false; + if (typeof want === "string") { + emit = want; + want = null; + } + + try { + fn(); + } catch(tmp) { + have = tmp; + } + + if (have) { + if (!want) { + _ok = true; + } + else if (want instanceof RegExp) { + _ok = want.test(have); + } + else if (have instanceof want) { + _ok = true + } + else if (want.call({}, have) === true) { + _ok = true; + } + } + + ok(_ok, emit); + } + + function test(name){ + _setup() + try { + templateSettings = _.clone(_.templateSettings); + if (arguments.length == 3) { + count = 0 + for (count = 0; count < arguments[1]; count++) { + arguments[2]() + } + } else { + // For now. + arguments[1]() + } + } + finally { + _teardown() + } + } + + function deepEqual(a, b, emit) { + // Also, for now. + assert(_.isEqual(a, b), emit) + } + `) +} + +func Test_underscore(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + _.map([1, 2, 3], function(value){ + return value + 1 + }) + `, "2,3,4") + + test(` + abc = _.find([1, 2, 3, -1], function(value) { return value == -1 }) + `, -1) + + test(`_.isEqual(1, 1)`, true) + test(`_.isEqual([], [])`, true) + test(`_.isEqual(['b', 'd'], ['b', 'd'])`, true) + test(`_.isEqual(['b', 'd', 'c'], ['b', 'd', 'e'])`, false) + test(`_.isFunction(function(){})`, true) + test(`_.template('

\u2028<%= "\\u2028\\u2029" %>\u2029

')()`, "

\u2028\u2028\u2029\u2029

") + }) +} + +// TODO Test: typeof An argument reference +// TODO Test: abc = {}; abc == Object(abc) diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_utility_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_utility_test.go new file mode 100644 index 0000000000..ebabb083be --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_utility_test.go @@ -0,0 +1,419 @@ +package otto + +import ( + "testing" +) + +// #750 - Return _ instance. +func Test_underscore_utility_0(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("#750 - Return _ instance.", 2, function() { + var instance = _([]); + ok(_(instance) === instance); + ok(new _(instance) === instance); + }); + `) + }) +} + +// identity +func Test_underscore_utility_1(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("identity", function() { + var moe = {name : 'moe'}; + equal(_.identity(moe), moe, 'moe is the same as his identity'); + }); + `) + }) +} + +// random +func Test_underscore_utility_2(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("random", function() { + var array = _.range(1000); + var min = Math.pow(2, 31); + var max = Math.pow(2, 62); + + ok(_.every(array, function() { + return _.random(min, max) >= min; + }), "should produce a random number greater than or equal to the minimum number"); + + ok(_.some(array, function() { + return _.random(Number.MAX_VALUE) > 0; + }), "should produce a random number when passed "); + }); + `) + }) +} + +// uniqueId +func Test_underscore_utility_3(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("uniqueId", function() { + var ids = [], i = 0; + while(i++ < 100) ids.push(_.uniqueId()); + equal(_.uniq(ids).length, ids.length, 'can generate a globally-unique stream of ids'); + }); + `) + }) +} + +// times +func Test_underscore_utility_4(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("times", function() { + var vals = []; + _.times(3, function (i) { vals.push(i); }); + ok(_.isEqual(vals, [0,1,2]), "is 0 indexed"); + // + vals = []; + _(3).times(function(i) { vals.push(i); }); + ok(_.isEqual(vals, [0,1,2]), "works as a wrapper"); + // collects return values + ok(_.isEqual([0, 1, 2], _.times(3, function(i) { return i; })), "collects return values"); + }); + `) + }) +} + +// mixin +func Test_underscore_utility_5(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("mixin", function() { + _.mixin({ + myReverse: function(string) { + return string.split('').reverse().join(''); + } + }); + equal(_.myReverse('panacea'), 'aecanap', 'mixed in a function to _'); + equal(_('champ').myReverse(), 'pmahc', 'mixed in a function to the OOP wrapper'); + }); + `) + }) +} + +// _.escape +func Test_underscore_utility_6(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("_.escape", function() { + equal(_.escape("Curly & Moe"), "Curly & Moe"); + equal(_.escape("Curly & Moe"), "Curly &amp; Moe"); + equal(_.escape(null), ''); + }); + `) + }) +} + +// _.unescape +func Test_underscore_utility_7(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("_.unescape", function() { + var string = "Curly & Moe"; + equal(_.unescape("Curly & Moe"), string); + equal(_.unescape("Curly &amp; Moe"), "Curly & Moe"); + equal(_.unescape(null), ''); + equal(_.unescape(_.escape(string)), string); + }); + `) + }) +} + +// template +func Test_underscore_utility_8(t *testing.T) { + tt(t, func() { + test, _ := test_() + + test(` + test("template", function() { + var basicTemplate = _.template("<%= thing %> is gettin' on my noives!"); + var result = basicTemplate({thing : 'This'}); + equal(result, "This is gettin' on my noives!", 'can do basic attribute interpolation'); + + var sansSemicolonTemplate = _.template("A <% this %> B"); + equal(sansSemicolonTemplate(), "A B"); + + var backslashTemplate = _.template("<%= thing %> is \\ridanculous"); + equal(backslashTemplate({thing: 'This'}), "This is \\ridanculous"); + + var escapeTemplate = _.template('<%= a ? "checked=\\"checked\\"" : "" %>'); + equal(escapeTemplate({a: true}), 'checked="checked"', 'can handle slash escapes in interpolations.'); + + var fancyTemplate = _.template("
    <% \ + for (var key in people) { \ + %>
  • <%= people[key] %>
  • <% } %>
"); + result = fancyTemplate({people : {moe : "Moe", larry : "Larry", curly : "Curly"}}); + equal(result, "
  • Moe
  • Larry
  • Curly
", 'can run arbitrary javascript in templates'); + + var escapedCharsInJavascriptTemplate = _.template("
    <% _.each(numbers.split('\\n'), function(item) { %>
  • <%= item %>
  • <% }) %>
"); + result = escapedCharsInJavascriptTemplate({numbers: "one\ntwo\nthree\nfour"}); + equal(result, "
  • one
  • two
  • three
  • four
", 'Can use escaped characters (e.g. \\n) in Javascript'); + + var namespaceCollisionTemplate = _.template("<%= pageCount %> <%= thumbnails[pageCount] %> <% _.each(thumbnails, function(p) { %>
\">
<% }); %>"); + result = namespaceCollisionTemplate({ + pageCount: 3, + thumbnails: { + 1: "p1-thumbnail.gif", + 2: "p2-thumbnail.gif", + 3: "p3-thumbnail.gif" + } + }); + equal(result, "3 p3-thumbnail.gif
"); + + var noInterpolateTemplate = _.template("

Just some text. Hey, I know this is silly but it aids consistency.

"); + result = noInterpolateTemplate(); + equal(result, "

Just some text. Hey, I know this is silly but it aids consistency.

"); + + var quoteTemplate = _.template("It's its, not it's"); + equal(quoteTemplate({}), "It's its, not it's"); + + var quoteInStatementAndBody = _.template("<%\ + if(foo == 'bar'){ \ + %>Statement quotes and 'quotes'.<% } %>"); + equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'."); + + var withNewlinesAndTabs = _.template('This\n\t\tis: <%= x %>.\n\tok.\nend.'); + equal(withNewlinesAndTabs({x: 'that'}), 'This\n\t\tis: that.\n\tok.\nend.'); + + var template = _.template("<%- value %>"); + var result = template({value: " + + + + + + + +

HTTP charset

+ + +
+ + +
 
+ + + + + +
+

The character encoding of a page can be set using the HTTP header charset declaration.

+

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

The only character encoding declaration for this HTML file is in the HTTP header, which sets the encoding to ISO 8859-15.

+
+
+
HTML5
+

the-input-byte-stream-001
Result summary & related tests
Detailed results for this test
Link to spec

+
Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • +
  • The test is read from a server that supports HTTP.
+
+ + + + + + diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/HTTP-vs-UTF-8-BOM.html b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/HTTP-vs-UTF-8-BOM.html new file mode 100644 index 0000000000..26e5d8b4eb --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/HTTP-vs-UTF-8-BOM.html @@ -0,0 +1,48 @@ + + + + HTTP vs UTF-8 BOM + + + + + + + + + + + +

HTTP vs UTF-8 BOM

+ + +
+ + +
 
+ + + + + +
+

A character encoding set in the HTTP header has lower precedence than the UTF-8 signature.

+

The HTTP header attempts to set the character encoding to ISO 8859-15. The page starts with a UTF-8 signature.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ýäè. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.

If the test is unsuccessful, the characters  should appear at the top of the page. These represent the bytes that make up the UTF-8 signature when encountered in the ISO 8859-15 encoding.

+
+
+
HTML5
+

the-input-byte-stream-034
Result summary & related tests
Detailed results for this test
Link to spec

+
Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • +
  • The test is read from a server that supports HTTP.
+
+ + + + + + diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-charset.html b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-charset.html new file mode 100644 index 0000000000..2f07e95158 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-charset.html @@ -0,0 +1,49 @@ + + + + HTTP vs meta charset + + + + + + + + + + + +

HTTP vs meta charset

+ + +
+ + +
 
+ + + + + +
+

The HTTP header has a higher precedence than an encoding declaration in a meta charset attribute.

+

The HTTP header attempts to set the character encoding to ISO 8859-15. The page contains an encoding declaration in a meta charset attribute that attempts to set the character encoding to ISO 8859-1.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

+
+
+
HTML5
+

the-input-byte-stream-018
Result summary & related tests
Detailed results for this test
Link to spec

+
Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • +
  • The test is read from a server that supports HTTP.
+
+ + + + + + diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-content.html b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-content.html new file mode 100644 index 0000000000..6853cddecc --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-content.html @@ -0,0 +1,49 @@ + + + + HTTP vs meta content + + + + + + + + + + + +

HTTP vs meta content

+ + +
+ + +
 
+ + + + + +
+

The HTTP header has a higher precedence than an encoding declaration in a meta content attribute.

+

The HTTP header attempts to set the character encoding to ISO 8859-15. The page contains an encoding declaration in a meta content attribute that attempts to set the character encoding to ISO 8859-1.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

+
+
+
HTML5
+

the-input-byte-stream-016
Result summary & related tests
Detailed results for this test
Link to spec

+
Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • +
  • The test is read from a server that supports HTTP.
+
+ + + + + + diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/No-encoding-declaration.html b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/No-encoding-declaration.html new file mode 100644 index 0000000000..612e26c6c5 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/No-encoding-declaration.html @@ -0,0 +1,47 @@ + + + + No encoding declaration + + + + + + + + + + + +

No encoding declaration

+ + +
+ + +
 
+ + + + + +
+

A page with no encoding information in HTTP, BOM, XML declaration or meta element will be treated as UTF-8.

+

The test on this page contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ýäè. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.

+
+
+
HTML5
+

the-input-byte-stream-015
Result summary & related tests
Detailed results for this test
Link to spec

+
Assumptions:
  • The test is read from a server that supports HTTP.
+
+ + + + + + diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/README b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/README new file mode 100644 index 0000000000..38ef0f9f12 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/README @@ -0,0 +1,9 @@ +These test cases come from +http://www.w3.org/International/tests/repository/html5/the-input-byte-stream/results-basics + +Distributed under both the W3C Test Suite License +(http://www.w3.org/Consortium/Legal/2008/04-testsuite-license) +and the W3C 3-clause BSD License +(http://www.w3.org/Consortium/Legal/2008/03-bsd-license). +To contribute to a W3C Test Suite, see the policies and contribution +forms (http://www.w3.org/2004/10/27-testcases). diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/UTF-16BE-BOM.html b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/UTF-16BE-BOM.html new file mode 100644 index 0000000000000000000000000000000000000000..3abf7a9343c20518e57dfea58b374fb0f4fb58a1 GIT binary patch literal 2670 zcmcJR?QRoS5Qc}JAoU&=BQ-(7b^;2j8i*i3RV1JlO@;VXIsPurV!WHiDdLW}i`*CO z^UnC>tih=KsVr;H&Y7?C&O3AV(?534uG?e##U9y_y|!QNi4``n+D>d{2lky^LnFNx z?9HrarH$>rwQR_$g)Hk0*&STI*EYq|47~&U9sfUB+ji})9eR{QqCUra7oDsZ5obtB zdxP%<)-$4Q;rSHJiM>U(#ZI=;?n^BC?Dp6lu=~_1-lnX3u03&2BlmQIY>L+!Uq7XoytKw^Q#oZSM?3*J?)&ojG&yzQRkC!Ml5JE?ax;lp_NYEcdUht`ZswOviB~L5hmJ|pXI71nn20w;>vG! zQGB$EE9&wC``&J#_Ym~PgRu-Bd>1!pOp0||k`kr=VJ zfH6I6rmRaeHA7U-A^OTsT+|d2a^i(>DePzZ{)ibXoCBvJnuYrd-3kkN$uy{qQK;=*Y;S87ro12aTgu^i*%f8zC3>a}9DIe4cfxOzsCw&(cqvP9{ud{N6f` z#TNDY(B6@Gpr|uN+%&x^XZjBHdc@2vsM(Tyc2=vshHQ5w+obmp>tuWT(t4BTUGAQw zxeI$UGSLUBg=WFbF;4f@4=^P2AgY@CFn8A`bcC=_&~)fiDe)#cUARRBzJ^k|%X)69 z+{Cb`wq}Rsg%B62CC_tK!AV(W{(MV?#mndR46CU#BUN<{8e?*oT+!pE5wF#O#TR#a z$9qRT)tpbw8zAI~QQJg2C3|6$I%(T(;`zOMy6SO+&;pG=c#2P|P-WZn$$DpWJlC3U z3*nvmz zwP{u~r$L?-m3uqp9I1+#3yE|3M$(s-BEtih=LQ>`qYoiktOop(wi%!;yh%+Rm z{e|xntY<{q!1F1Z6MKtngPm-p-4|H&+3m4AVE3_AyiHm6Tzlf4M(*ht*%YrezJ6kr zHGj45pc?64*$Cm%-zseWMA`x;)v*~jA=i}szqts9xmQkS`M11|(H7bTXAycsXU53+ zJ?120SRZeyiFjW7enPN`bxk$IaWV3o48oJF7D&2ysoY;6(s6%6vVfaYd&mC=erK!) zNGI^7upQgN)53OHe_VE<@J+G8*Y|p*)zB2Thdi}+YR<5QWHm!|a_*AoZXuv7)$xe| zm3Q$D7{|#}{m4X&UY!6(ZhyYi2(5JLzGE$H)W6BQklnjPMwn<Yvv7Z*TVWwD*=E3QpH37* z#lqXJA0A~J9T_<^W5smspmDg2p6ac5Bjn+~LAoow%1TCdZ*$K8`O zw_$HaCi+0N&@7la#_7KL5r$+QL{)Pi=I&aDjt~|Knht#`CEi4*3%97i_fSfASlwUz0=3V0GCxY}z81UC-nP=CGt2OqYV$ zoRCo+qM9YX*3FFORLC=E3B~S@+KROyk4r5 yX7?DaslDfIebqXgC!KKp4IYy+W~X?ddE6o=`A+x#x0AK&6MF#W&AXxbRrv+SX}PNa literal 0 HcmV?d00001 diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-charset.html b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-charset.html new file mode 100644 index 0000000000..83de43338e --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-charset.html @@ -0,0 +1,49 @@ + + + + UTF-8 BOM vs meta charset + + + + + + + + + + + +

UTF-8 BOM vs meta charset

+ + +
+ + +
 
+ + + + + +
+

A page with a UTF-8 BOM will be recognized as UTF-8 even if the meta charset attribute declares a different encoding.

+

The page contains an encoding declaration in a meta charset attribute that attempts to set the character encoding to ISO 8859-15, but the file starts with a UTF-8 signature.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ýäè. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.

+
+
+
HTML5
+

the-input-byte-stream-038
Result summary & related tests
Detailed results for this test
Link to spec

+
Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • +
  • The test is read from a server that supports HTTP.
+
+ + + + + + diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-content.html b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-content.html new file mode 100644 index 0000000000..501aac2d6a --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-content.html @@ -0,0 +1,48 @@ + + + + UTF-8 BOM vs meta content + + + + + + + + + + + +

UTF-8 BOM vs meta content

+ + +
+ + +
 
+ + + + + +
+

A page with a UTF-8 BOM will be recognized as UTF-8 even if the meta content attribute declares a different encoding.

+

The page contains an encoding declaration in a meta content attribute that attempts to set the character encoding to ISO 8859-15, but the file starts with a UTF-8 signature.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ýäè. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.

+
+
+
HTML5
+

the-input-byte-stream-037
Result summary & related tests
Detailed results for this test
Link to spec

+
Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • +
  • The test is read from a server that supports HTTP.
+
+ + + + + + diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/meta-charset-attribute.html b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/meta-charset-attribute.html new file mode 100644 index 0000000000..2d7d25aba1 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/meta-charset-attribute.html @@ -0,0 +1,48 @@ + + + + meta charset attribute + + + + + + + + + + + +

meta charset attribute

+ + +
+ + +
 
+ + + + + +
+

The character encoding of the page can be set by a meta element with charset attribute.

+

The only character encoding declaration for this HTML file is in the charset attribute of the meta element, which declares the encoding to be ISO 8859-15.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

+
+
+
HTML5
+

the-input-byte-stream-009
Result summary & related tests
Detailed results for this test
Link to spec

+
Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • +
  • The test is read from a server that supports HTTP.
+
+ + + + + + diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/meta-content-attribute.html b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/meta-content-attribute.html new file mode 100644 index 0000000000..1c3f228e7c --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/meta-content-attribute.html @@ -0,0 +1,48 @@ + + + + meta content attribute + + + + + + + + + + + +

meta content attribute

+ + +
+ + +
 
+ + + + + +
+

The character encoding of the page can be set by a meta element with http-equiv and content attributes.

+

The only character encoding declaration for this HTML file is in the content attribute of the meta element, which declares the encoding to be ISO 8859-15.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

+
+
+
HTML5
+

the-input-byte-stream-007
Result summary & related tests
Detailed results for this test
Link to spec

+
Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • +
  • The test is read from a server that supports HTTP.
+
+ + + + + + diff --git a/Godeps/_workspace/src/golang.org/x/net/html/const.go b/Godeps/_workspace/src/golang.org/x/net/html/const.go new file mode 100644 index 0000000000..52f651ff6d --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/const.go @@ -0,0 +1,102 @@ +// 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. + +package html + +// Section 12.2.3.2 of the HTML5 specification says "The following elements +// have varying levels of special parsing rules". +// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements +var isSpecialElementMap = map[string]bool{ + "address": true, + "applet": true, + "area": true, + "article": true, + "aside": true, + "base": true, + "basefont": true, + "bgsound": true, + "blockquote": true, + "body": true, + "br": true, + "button": true, + "caption": true, + "center": true, + "col": true, + "colgroup": true, + "dd": true, + "details": true, + "dir": true, + "div": true, + "dl": true, + "dt": true, + "embed": true, + "fieldset": true, + "figcaption": true, + "figure": true, + "footer": true, + "form": true, + "frame": true, + "frameset": true, + "h1": true, + "h2": true, + "h3": true, + "h4": true, + "h5": true, + "h6": true, + "head": true, + "header": true, + "hgroup": true, + "hr": true, + "html": true, + "iframe": true, + "img": true, + "input": true, + "isindex": true, + "li": true, + "link": true, + "listing": true, + "marquee": true, + "menu": true, + "meta": true, + "nav": true, + "noembed": true, + "noframes": true, + "noscript": true, + "object": true, + "ol": true, + "p": true, + "param": true, + "plaintext": true, + "pre": true, + "script": true, + "section": true, + "select": true, + "source": true, + "style": true, + "summary": true, + "table": true, + "tbody": true, + "td": true, + "template": true, + "textarea": true, + "tfoot": true, + "th": true, + "thead": true, + "title": true, + "tr": true, + "track": true, + "ul": true, + "wbr": true, + "xmp": true, +} + +func isSpecialElement(element *Node) bool { + switch element.Namespace { + case "", "html": + return isSpecialElementMap[element.Data] + case "svg": + return element.Data == "foreignObject" + } + return false +} diff --git a/Godeps/_workspace/src/golang.org/x/net/html/doc.go b/Godeps/_workspace/src/golang.org/x/net/html/doc.go new file mode 100644 index 0000000000..b453fe1e4c --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/doc.go @@ -0,0 +1,106 @@ +// 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 html implements an HTML5-compliant tokenizer and parser. + +Tokenization is done by creating a Tokenizer for an io.Reader r. It is the +caller's responsibility to ensure that r provides UTF-8 encoded HTML. + + z := html.NewTokenizer(r) + +Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(), +which parses the next token and returns its type, or an error: + + for { + tt := z.Next() + if tt == html.ErrorToken { + // ... + return ... + } + // Process the current token. + } + +There are two APIs for retrieving the current token. The high-level API is to +call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs +allow optionally calling Raw after Next but before Token, Text, TagName, or +TagAttr. In EBNF notation, the valid call sequence per token is: + + Next {Raw} [ Token | Text | TagName {TagAttr} ] + +Token returns an independent data structure that completely describes a token. +Entities (such as "<") are unescaped, tag names and attribute keys are +lower-cased, and attributes are collected into a []Attribute. For example: + + for { + if z.Next() == html.ErrorToken { + // Returning io.EOF indicates success. + return z.Err() + } + emitToken(z.Token()) + } + +The low-level API performs fewer allocations and copies, but the contents of +the []byte values returned by Text, TagName and TagAttr may change on the next +call to Next. For example, to extract an HTML page's anchor text: + + depth := 0 + for { + tt := z.Next() + switch tt { + case ErrorToken: + return z.Err() + case TextToken: + if depth > 0 { + // emitBytes should copy the []byte it receives, + // if it doesn't process it immediately. + emitBytes(z.Text()) + } + case StartTagToken, EndTagToken: + tn, _ := z.TagName() + if len(tn) == 1 && tn[0] == 'a' { + if tt == StartTagToken { + depth++ + } else { + depth-- + } + } + } + } + +Parsing is done by calling Parse with an io.Reader, which returns the root of +the parse tree (the document element) as a *Node. It is the caller's +responsibility to ensure that the Reader provides UTF-8 encoded HTML. For +example, to process each anchor node in depth-first order: + + doc, err := html.Parse(r) + if err != nil { + // ... + } + var f func(*html.Node) + f = func(n *html.Node) { + if n.Type == html.ElementNode && n.Data == "a" { + // Do something with n... + } + for c := n.FirstChild; c != nil; c = c.NextSibling { + f(c) + } + } + f(doc) + +The relevant specifications include: +https://html.spec.whatwg.org/multipage/syntax.html and +https://html.spec.whatwg.org/multipage/syntax.html#tokenization +*/ +package html + +// The tokenization algorithm implemented by this package is not a line-by-line +// transliteration of the relatively verbose state-machine in the WHATWG +// specification. A more direct approach is used instead, where the program +// counter implies the state, such as whether it is tokenizing a tag or a text +// node. Specification compliance is verified by checking expected and actual +// outputs over a test suite rather than aiming for algorithmic fidelity. + +// TODO(nigeltao): Does a DOM API belong in this package or a separate one? +// TODO(nigeltao): How does parsing interact with a JavaScript engine? diff --git a/Godeps/_workspace/src/golang.org/x/net/html/doctype.go b/Godeps/_workspace/src/golang.org/x/net/html/doctype.go new file mode 100644 index 0000000000..c484e5a94f --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/doctype.go @@ -0,0 +1,156 @@ +// 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. + +package html + +import ( + "strings" +) + +// parseDoctype parses the data from a DoctypeToken into a name, +// public identifier, and system identifier. It returns a Node whose Type +// is DoctypeNode, whose Data is the name, and which has attributes +// named "system" and "public" for the two identifiers if they were present. +// quirks is whether the document should be parsed in "quirks mode". +func parseDoctype(s string) (n *Node, quirks bool) { + n = &Node{Type: DoctypeNode} + + // Find the name. + space := strings.IndexAny(s, whitespace) + if space == -1 { + space = len(s) + } + n.Data = s[:space] + // The comparison to "html" is case-sensitive. + if n.Data != "html" { + quirks = true + } + n.Data = strings.ToLower(n.Data) + s = strings.TrimLeft(s[space:], whitespace) + + if len(s) < 6 { + // It can't start with "PUBLIC" or "SYSTEM". + // Ignore the rest of the string. + return n, quirks || s != "" + } + + key := strings.ToLower(s[:6]) + s = s[6:] + for key == "public" || key == "system" { + s = strings.TrimLeft(s, whitespace) + if s == "" { + break + } + quote := s[0] + if quote != '"' && quote != '\'' { + break + } + s = s[1:] + q := strings.IndexRune(s, rune(quote)) + var id string + if q == -1 { + id = s + s = "" + } else { + id = s[:q] + s = s[q+1:] + } + n.Attr = append(n.Attr, Attribute{Key: key, Val: id}) + if key == "public" { + key = "system" + } else { + key = "" + } + } + + if key != "" || s != "" { + quirks = true + } else if len(n.Attr) > 0 { + if n.Attr[0].Key == "public" { + public := strings.ToLower(n.Attr[0].Val) + switch public { + case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html": + quirks = true + default: + for _, q := range quirkyIDs { + if strings.HasPrefix(public, q) { + quirks = true + break + } + } + } + // The following two public IDs only cause quirks mode if there is no system ID. + if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") || + strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) { + quirks = true + } + } + if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" && + strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" { + quirks = true + } + } + + return n, quirks +} + +// quirkyIDs is a list of public doctype identifiers that cause a document +// to be interpreted in quirks mode. The identifiers should be in lower case. +var quirkyIDs = []string{ + "+//silmaril//dtd html pro v0r11 19970101//", + "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", + "-//as//dtd html 3.0 aswedit + extensions//", + "-//ietf//dtd html 2.0 level 1//", + "-//ietf//dtd html 2.0 level 2//", + "-//ietf//dtd html 2.0 strict level 1//", + "-//ietf//dtd html 2.0 strict level 2//", + "-//ietf//dtd html 2.0 strict//", + "-//ietf//dtd html 2.0//", + "-//ietf//dtd html 2.1e//", + "-//ietf//dtd html 3.0//", + "-//ietf//dtd html 3.2 final//", + "-//ietf//dtd html 3.2//", + "-//ietf//dtd html 3//", + "-//ietf//dtd html level 0//", + "-//ietf//dtd html level 1//", + "-//ietf//dtd html level 2//", + "-//ietf//dtd html level 3//", + "-//ietf//dtd html strict level 0//", + "-//ietf//dtd html strict level 1//", + "-//ietf//dtd html strict level 2//", + "-//ietf//dtd html strict level 3//", + "-//ietf//dtd html strict//", + "-//ietf//dtd html//", + "-//metrius//dtd metrius presentational//", + "-//microsoft//dtd internet explorer 2.0 html strict//", + "-//microsoft//dtd internet explorer 2.0 html//", + "-//microsoft//dtd internet explorer 2.0 tables//", + "-//microsoft//dtd internet explorer 3.0 html strict//", + "-//microsoft//dtd internet explorer 3.0 html//", + "-//microsoft//dtd internet explorer 3.0 tables//", + "-//netscape comm. corp.//dtd html//", + "-//netscape comm. corp.//dtd strict html//", + "-//o'reilly and associates//dtd html 2.0//", + "-//o'reilly and associates//dtd html extended 1.0//", + "-//o'reilly and associates//dtd html extended relaxed 1.0//", + "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", + "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", + "-//spyglass//dtd html 2.0 extended//", + "-//sq//dtd html 2.0 hotmetal + extensions//", + "-//sun microsystems corp.//dtd hotjava html//", + "-//sun microsystems corp.//dtd hotjava strict html//", + "-//w3c//dtd html 3 1995-03-24//", + "-//w3c//dtd html 3.2 draft//", + "-//w3c//dtd html 3.2 final//", + "-//w3c//dtd html 3.2//", + "-//w3c//dtd html 3.2s draft//", + "-//w3c//dtd html 4.0 frameset//", + "-//w3c//dtd html 4.0 transitional//", + "-//w3c//dtd html experimental 19960712//", + "-//w3c//dtd html experimental 970421//", + "-//w3c//dtd w3 html//", + "-//w3o//dtd w3 html 3.0//", + "-//webtechs//dtd mozilla html 2.0//", + "-//webtechs//dtd mozilla html//", +} diff --git a/Godeps/_workspace/src/golang.org/x/net/html/entity.go b/Godeps/_workspace/src/golang.org/x/net/html/entity.go new file mode 100644 index 0000000000..a50c04c60e --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/entity.go @@ -0,0 +1,2253 @@ +// 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 html + +// All entities that do not end with ';' are 6 or fewer bytes long. +const longestEntityWithoutSemicolon = 6 + +// entity is a map from HTML entity names to their values. The semicolon matters: +// https://html.spec.whatwg.org/multipage/syntax.html#named-character-references +// lists both "amp" and "amp;" as two separate entries. +// +// Note that the HTML5 list is larger than the HTML4 list at +// http://www.w3.org/TR/html4/sgml/entities.html +var entity = map[string]rune{ + "AElig;": '\U000000C6', + "AMP;": '\U00000026', + "Aacute;": '\U000000C1', + "Abreve;": '\U00000102', + "Acirc;": '\U000000C2', + "Acy;": '\U00000410', + "Afr;": '\U0001D504', + "Agrave;": '\U000000C0', + "Alpha;": '\U00000391', + "Amacr;": '\U00000100', + "And;": '\U00002A53', + "Aogon;": '\U00000104', + "Aopf;": '\U0001D538', + "ApplyFunction;": '\U00002061', + "Aring;": '\U000000C5', + "Ascr;": '\U0001D49C', + "Assign;": '\U00002254', + "Atilde;": '\U000000C3', + "Auml;": '\U000000C4', + "Backslash;": '\U00002216', + "Barv;": '\U00002AE7', + "Barwed;": '\U00002306', + "Bcy;": '\U00000411', + "Because;": '\U00002235', + "Bernoullis;": '\U0000212C', + "Beta;": '\U00000392', + "Bfr;": '\U0001D505', + "Bopf;": '\U0001D539', + "Breve;": '\U000002D8', + "Bscr;": '\U0000212C', + "Bumpeq;": '\U0000224E', + "CHcy;": '\U00000427', + "COPY;": '\U000000A9', + "Cacute;": '\U00000106', + "Cap;": '\U000022D2', + "CapitalDifferentialD;": '\U00002145', + "Cayleys;": '\U0000212D', + "Ccaron;": '\U0000010C', + "Ccedil;": '\U000000C7', + "Ccirc;": '\U00000108', + "Cconint;": '\U00002230', + "Cdot;": '\U0000010A', + "Cedilla;": '\U000000B8', + "CenterDot;": '\U000000B7', + "Cfr;": '\U0000212D', + "Chi;": '\U000003A7', + "CircleDot;": '\U00002299', + "CircleMinus;": '\U00002296', + "CirclePlus;": '\U00002295', + "CircleTimes;": '\U00002297', + "ClockwiseContourIntegral;": '\U00002232', + "CloseCurlyDoubleQuote;": '\U0000201D', + "CloseCurlyQuote;": '\U00002019', + "Colon;": '\U00002237', + "Colone;": '\U00002A74', + "Congruent;": '\U00002261', + "Conint;": '\U0000222F', + "ContourIntegral;": '\U0000222E', + "Copf;": '\U00002102', + "Coproduct;": '\U00002210', + "CounterClockwiseContourIntegral;": '\U00002233', + "Cross;": '\U00002A2F', + "Cscr;": '\U0001D49E', + "Cup;": '\U000022D3', + "CupCap;": '\U0000224D', + "DD;": '\U00002145', + "DDotrahd;": '\U00002911', + "DJcy;": '\U00000402', + "DScy;": '\U00000405', + "DZcy;": '\U0000040F', + "Dagger;": '\U00002021', + "Darr;": '\U000021A1', + "Dashv;": '\U00002AE4', + "Dcaron;": '\U0000010E', + "Dcy;": '\U00000414', + "Del;": '\U00002207', + "Delta;": '\U00000394', + "Dfr;": '\U0001D507', + "DiacriticalAcute;": '\U000000B4', + "DiacriticalDot;": '\U000002D9', + "DiacriticalDoubleAcute;": '\U000002DD', + "DiacriticalGrave;": '\U00000060', + "DiacriticalTilde;": '\U000002DC', + "Diamond;": '\U000022C4', + "DifferentialD;": '\U00002146', + "Dopf;": '\U0001D53B', + "Dot;": '\U000000A8', + "DotDot;": '\U000020DC', + "DotEqual;": '\U00002250', + "DoubleContourIntegral;": '\U0000222F', + "DoubleDot;": '\U000000A8', + "DoubleDownArrow;": '\U000021D3', + "DoubleLeftArrow;": '\U000021D0', + "DoubleLeftRightArrow;": '\U000021D4', + "DoubleLeftTee;": '\U00002AE4', + "DoubleLongLeftArrow;": '\U000027F8', + "DoubleLongLeftRightArrow;": '\U000027FA', + "DoubleLongRightArrow;": '\U000027F9', + "DoubleRightArrow;": '\U000021D2', + "DoubleRightTee;": '\U000022A8', + "DoubleUpArrow;": '\U000021D1', + "DoubleUpDownArrow;": '\U000021D5', + "DoubleVerticalBar;": '\U00002225', + "DownArrow;": '\U00002193', + "DownArrowBar;": '\U00002913', + "DownArrowUpArrow;": '\U000021F5', + "DownBreve;": '\U00000311', + "DownLeftRightVector;": '\U00002950', + "DownLeftTeeVector;": '\U0000295E', + "DownLeftVector;": '\U000021BD', + "DownLeftVectorBar;": '\U00002956', + "DownRightTeeVector;": '\U0000295F', + "DownRightVector;": '\U000021C1', + "DownRightVectorBar;": '\U00002957', + "DownTee;": '\U000022A4', + "DownTeeArrow;": '\U000021A7', + "Downarrow;": '\U000021D3', + "Dscr;": '\U0001D49F', + "Dstrok;": '\U00000110', + "ENG;": '\U0000014A', + "ETH;": '\U000000D0', + "Eacute;": '\U000000C9', + "Ecaron;": '\U0000011A', + "Ecirc;": '\U000000CA', + "Ecy;": '\U0000042D', + "Edot;": '\U00000116', + "Efr;": '\U0001D508', + "Egrave;": '\U000000C8', + "Element;": '\U00002208', + "Emacr;": '\U00000112', + "EmptySmallSquare;": '\U000025FB', + "EmptyVerySmallSquare;": '\U000025AB', + "Eogon;": '\U00000118', + "Eopf;": '\U0001D53C', + "Epsilon;": '\U00000395', + "Equal;": '\U00002A75', + "EqualTilde;": '\U00002242', + "Equilibrium;": '\U000021CC', + "Escr;": '\U00002130', + "Esim;": '\U00002A73', + "Eta;": '\U00000397', + "Euml;": '\U000000CB', + "Exists;": '\U00002203', + "ExponentialE;": '\U00002147', + "Fcy;": '\U00000424', + "Ffr;": '\U0001D509', + "FilledSmallSquare;": '\U000025FC', + "FilledVerySmallSquare;": '\U000025AA', + "Fopf;": '\U0001D53D', + "ForAll;": '\U00002200', + "Fouriertrf;": '\U00002131', + "Fscr;": '\U00002131', + "GJcy;": '\U00000403', + "GT;": '\U0000003E', + "Gamma;": '\U00000393', + "Gammad;": '\U000003DC', + "Gbreve;": '\U0000011E', + "Gcedil;": '\U00000122', + "Gcirc;": '\U0000011C', + "Gcy;": '\U00000413', + "Gdot;": '\U00000120', + "Gfr;": '\U0001D50A', + "Gg;": '\U000022D9', + "Gopf;": '\U0001D53E', + "GreaterEqual;": '\U00002265', + "GreaterEqualLess;": '\U000022DB', + "GreaterFullEqual;": '\U00002267', + "GreaterGreater;": '\U00002AA2', + "GreaterLess;": '\U00002277', + "GreaterSlantEqual;": '\U00002A7E', + "GreaterTilde;": '\U00002273', + "Gscr;": '\U0001D4A2', + "Gt;": '\U0000226B', + "HARDcy;": '\U0000042A', + "Hacek;": '\U000002C7', + "Hat;": '\U0000005E', + "Hcirc;": '\U00000124', + "Hfr;": '\U0000210C', + "HilbertSpace;": '\U0000210B', + "Hopf;": '\U0000210D', + "HorizontalLine;": '\U00002500', + "Hscr;": '\U0000210B', + "Hstrok;": '\U00000126', + "HumpDownHump;": '\U0000224E', + "HumpEqual;": '\U0000224F', + "IEcy;": '\U00000415', + "IJlig;": '\U00000132', + "IOcy;": '\U00000401', + "Iacute;": '\U000000CD', + "Icirc;": '\U000000CE', + "Icy;": '\U00000418', + "Idot;": '\U00000130', + "Ifr;": '\U00002111', + "Igrave;": '\U000000CC', + "Im;": '\U00002111', + "Imacr;": '\U0000012A', + "ImaginaryI;": '\U00002148', + "Implies;": '\U000021D2', + "Int;": '\U0000222C', + "Integral;": '\U0000222B', + "Intersection;": '\U000022C2', + "InvisibleComma;": '\U00002063', + "InvisibleTimes;": '\U00002062', + "Iogon;": '\U0000012E', + "Iopf;": '\U0001D540', + "Iota;": '\U00000399', + "Iscr;": '\U00002110', + "Itilde;": '\U00000128', + "Iukcy;": '\U00000406', + "Iuml;": '\U000000CF', + "Jcirc;": '\U00000134', + "Jcy;": '\U00000419', + "Jfr;": '\U0001D50D', + "Jopf;": '\U0001D541', + "Jscr;": '\U0001D4A5', + "Jsercy;": '\U00000408', + "Jukcy;": '\U00000404', + "KHcy;": '\U00000425', + "KJcy;": '\U0000040C', + "Kappa;": '\U0000039A', + "Kcedil;": '\U00000136', + "Kcy;": '\U0000041A', + "Kfr;": '\U0001D50E', + "Kopf;": '\U0001D542', + "Kscr;": '\U0001D4A6', + "LJcy;": '\U00000409', + "LT;": '\U0000003C', + "Lacute;": '\U00000139', + "Lambda;": '\U0000039B', + "Lang;": '\U000027EA', + "Laplacetrf;": '\U00002112', + "Larr;": '\U0000219E', + "Lcaron;": '\U0000013D', + "Lcedil;": '\U0000013B', + "Lcy;": '\U0000041B', + "LeftAngleBracket;": '\U000027E8', + "LeftArrow;": '\U00002190', + "LeftArrowBar;": '\U000021E4', + "LeftArrowRightArrow;": '\U000021C6', + "LeftCeiling;": '\U00002308', + "LeftDoubleBracket;": '\U000027E6', + "LeftDownTeeVector;": '\U00002961', + "LeftDownVector;": '\U000021C3', + "LeftDownVectorBar;": '\U00002959', + "LeftFloor;": '\U0000230A', + "LeftRightArrow;": '\U00002194', + "LeftRightVector;": '\U0000294E', + "LeftTee;": '\U000022A3', + "LeftTeeArrow;": '\U000021A4', + "LeftTeeVector;": '\U0000295A', + "LeftTriangle;": '\U000022B2', + "LeftTriangleBar;": '\U000029CF', + "LeftTriangleEqual;": '\U000022B4', + "LeftUpDownVector;": '\U00002951', + "LeftUpTeeVector;": '\U00002960', + "LeftUpVector;": '\U000021BF', + "LeftUpVectorBar;": '\U00002958', + "LeftVector;": '\U000021BC', + "LeftVectorBar;": '\U00002952', + "Leftarrow;": '\U000021D0', + "Leftrightarrow;": '\U000021D4', + "LessEqualGreater;": '\U000022DA', + "LessFullEqual;": '\U00002266', + "LessGreater;": '\U00002276', + "LessLess;": '\U00002AA1', + "LessSlantEqual;": '\U00002A7D', + "LessTilde;": '\U00002272', + "Lfr;": '\U0001D50F', + "Ll;": '\U000022D8', + "Lleftarrow;": '\U000021DA', + "Lmidot;": '\U0000013F', + "LongLeftArrow;": '\U000027F5', + "LongLeftRightArrow;": '\U000027F7', + "LongRightArrow;": '\U000027F6', + "Longleftarrow;": '\U000027F8', + "Longleftrightarrow;": '\U000027FA', + "Longrightarrow;": '\U000027F9', + "Lopf;": '\U0001D543', + "LowerLeftArrow;": '\U00002199', + "LowerRightArrow;": '\U00002198', + "Lscr;": '\U00002112', + "Lsh;": '\U000021B0', + "Lstrok;": '\U00000141', + "Lt;": '\U0000226A', + "Map;": '\U00002905', + "Mcy;": '\U0000041C', + "MediumSpace;": '\U0000205F', + "Mellintrf;": '\U00002133', + "Mfr;": '\U0001D510', + "MinusPlus;": '\U00002213', + "Mopf;": '\U0001D544', + "Mscr;": '\U00002133', + "Mu;": '\U0000039C', + "NJcy;": '\U0000040A', + "Nacute;": '\U00000143', + "Ncaron;": '\U00000147', + "Ncedil;": '\U00000145', + "Ncy;": '\U0000041D', + "NegativeMediumSpace;": '\U0000200B', + "NegativeThickSpace;": '\U0000200B', + "NegativeThinSpace;": '\U0000200B', + "NegativeVeryThinSpace;": '\U0000200B', + "NestedGreaterGreater;": '\U0000226B', + "NestedLessLess;": '\U0000226A', + "NewLine;": '\U0000000A', + "Nfr;": '\U0001D511', + "NoBreak;": '\U00002060', + "NonBreakingSpace;": '\U000000A0', + "Nopf;": '\U00002115', + "Not;": '\U00002AEC', + "NotCongruent;": '\U00002262', + "NotCupCap;": '\U0000226D', + "NotDoubleVerticalBar;": '\U00002226', + "NotElement;": '\U00002209', + "NotEqual;": '\U00002260', + "NotExists;": '\U00002204', + "NotGreater;": '\U0000226F', + "NotGreaterEqual;": '\U00002271', + "NotGreaterLess;": '\U00002279', + "NotGreaterTilde;": '\U00002275', + "NotLeftTriangle;": '\U000022EA', + "NotLeftTriangleEqual;": '\U000022EC', + "NotLess;": '\U0000226E', + "NotLessEqual;": '\U00002270', + "NotLessGreater;": '\U00002278', + "NotLessTilde;": '\U00002274', + "NotPrecedes;": '\U00002280', + "NotPrecedesSlantEqual;": '\U000022E0', + "NotReverseElement;": '\U0000220C', + "NotRightTriangle;": '\U000022EB', + "NotRightTriangleEqual;": '\U000022ED', + "NotSquareSubsetEqual;": '\U000022E2', + "NotSquareSupersetEqual;": '\U000022E3', + "NotSubsetEqual;": '\U00002288', + "NotSucceeds;": '\U00002281', + "NotSucceedsSlantEqual;": '\U000022E1', + "NotSupersetEqual;": '\U00002289', + "NotTilde;": '\U00002241', + "NotTildeEqual;": '\U00002244', + "NotTildeFullEqual;": '\U00002247', + "NotTildeTilde;": '\U00002249', + "NotVerticalBar;": '\U00002224', + "Nscr;": '\U0001D4A9', + "Ntilde;": '\U000000D1', + "Nu;": '\U0000039D', + "OElig;": '\U00000152', + "Oacute;": '\U000000D3', + "Ocirc;": '\U000000D4', + "Ocy;": '\U0000041E', + "Odblac;": '\U00000150', + "Ofr;": '\U0001D512', + "Ograve;": '\U000000D2', + "Omacr;": '\U0000014C', + "Omega;": '\U000003A9', + "Omicron;": '\U0000039F', + "Oopf;": '\U0001D546', + "OpenCurlyDoubleQuote;": '\U0000201C', + "OpenCurlyQuote;": '\U00002018', + "Or;": '\U00002A54', + "Oscr;": '\U0001D4AA', + "Oslash;": '\U000000D8', + "Otilde;": '\U000000D5', + "Otimes;": '\U00002A37', + "Ouml;": '\U000000D6', + "OverBar;": '\U0000203E', + "OverBrace;": '\U000023DE', + "OverBracket;": '\U000023B4', + "OverParenthesis;": '\U000023DC', + "PartialD;": '\U00002202', + "Pcy;": '\U0000041F', + "Pfr;": '\U0001D513', + "Phi;": '\U000003A6', + "Pi;": '\U000003A0', + "PlusMinus;": '\U000000B1', + "Poincareplane;": '\U0000210C', + "Popf;": '\U00002119', + "Pr;": '\U00002ABB', + "Precedes;": '\U0000227A', + "PrecedesEqual;": '\U00002AAF', + "PrecedesSlantEqual;": '\U0000227C', + "PrecedesTilde;": '\U0000227E', + "Prime;": '\U00002033', + "Product;": '\U0000220F', + "Proportion;": '\U00002237', + "Proportional;": '\U0000221D', + "Pscr;": '\U0001D4AB', + "Psi;": '\U000003A8', + "QUOT;": '\U00000022', + "Qfr;": '\U0001D514', + "Qopf;": '\U0000211A', + "Qscr;": '\U0001D4AC', + "RBarr;": '\U00002910', + "REG;": '\U000000AE', + "Racute;": '\U00000154', + "Rang;": '\U000027EB', + "Rarr;": '\U000021A0', + "Rarrtl;": '\U00002916', + "Rcaron;": '\U00000158', + "Rcedil;": '\U00000156', + "Rcy;": '\U00000420', + "Re;": '\U0000211C', + "ReverseElement;": '\U0000220B', + "ReverseEquilibrium;": '\U000021CB', + "ReverseUpEquilibrium;": '\U0000296F', + "Rfr;": '\U0000211C', + "Rho;": '\U000003A1', + "RightAngleBracket;": '\U000027E9', + "RightArrow;": '\U00002192', + "RightArrowBar;": '\U000021E5', + "RightArrowLeftArrow;": '\U000021C4', + "RightCeiling;": '\U00002309', + "RightDoubleBracket;": '\U000027E7', + "RightDownTeeVector;": '\U0000295D', + "RightDownVector;": '\U000021C2', + "RightDownVectorBar;": '\U00002955', + "RightFloor;": '\U0000230B', + "RightTee;": '\U000022A2', + "RightTeeArrow;": '\U000021A6', + "RightTeeVector;": '\U0000295B', + "RightTriangle;": '\U000022B3', + "RightTriangleBar;": '\U000029D0', + "RightTriangleEqual;": '\U000022B5', + "RightUpDownVector;": '\U0000294F', + "RightUpTeeVector;": '\U0000295C', + "RightUpVector;": '\U000021BE', + "RightUpVectorBar;": '\U00002954', + "RightVector;": '\U000021C0', + "RightVectorBar;": '\U00002953', + "Rightarrow;": '\U000021D2', + "Ropf;": '\U0000211D', + "RoundImplies;": '\U00002970', + "Rrightarrow;": '\U000021DB', + "Rscr;": '\U0000211B', + "Rsh;": '\U000021B1', + "RuleDelayed;": '\U000029F4', + "SHCHcy;": '\U00000429', + "SHcy;": '\U00000428', + "SOFTcy;": '\U0000042C', + "Sacute;": '\U0000015A', + "Sc;": '\U00002ABC', + "Scaron;": '\U00000160', + "Scedil;": '\U0000015E', + "Scirc;": '\U0000015C', + "Scy;": '\U00000421', + "Sfr;": '\U0001D516', + "ShortDownArrow;": '\U00002193', + "ShortLeftArrow;": '\U00002190', + "ShortRightArrow;": '\U00002192', + "ShortUpArrow;": '\U00002191', + "Sigma;": '\U000003A3', + "SmallCircle;": '\U00002218', + "Sopf;": '\U0001D54A', + "Sqrt;": '\U0000221A', + "Square;": '\U000025A1', + "SquareIntersection;": '\U00002293', + "SquareSubset;": '\U0000228F', + "SquareSubsetEqual;": '\U00002291', + "SquareSuperset;": '\U00002290', + "SquareSupersetEqual;": '\U00002292', + "SquareUnion;": '\U00002294', + "Sscr;": '\U0001D4AE', + "Star;": '\U000022C6', + "Sub;": '\U000022D0', + "Subset;": '\U000022D0', + "SubsetEqual;": '\U00002286', + "Succeeds;": '\U0000227B', + "SucceedsEqual;": '\U00002AB0', + "SucceedsSlantEqual;": '\U0000227D', + "SucceedsTilde;": '\U0000227F', + "SuchThat;": '\U0000220B', + "Sum;": '\U00002211', + "Sup;": '\U000022D1', + "Superset;": '\U00002283', + "SupersetEqual;": '\U00002287', + "Supset;": '\U000022D1', + "THORN;": '\U000000DE', + "TRADE;": '\U00002122', + "TSHcy;": '\U0000040B', + "TScy;": '\U00000426', + "Tab;": '\U00000009', + "Tau;": '\U000003A4', + "Tcaron;": '\U00000164', + "Tcedil;": '\U00000162', + "Tcy;": '\U00000422', + "Tfr;": '\U0001D517', + "Therefore;": '\U00002234', + "Theta;": '\U00000398', + "ThinSpace;": '\U00002009', + "Tilde;": '\U0000223C', + "TildeEqual;": '\U00002243', + "TildeFullEqual;": '\U00002245', + "TildeTilde;": '\U00002248', + "Topf;": '\U0001D54B', + "TripleDot;": '\U000020DB', + "Tscr;": '\U0001D4AF', + "Tstrok;": '\U00000166', + "Uacute;": '\U000000DA', + "Uarr;": '\U0000219F', + "Uarrocir;": '\U00002949', + "Ubrcy;": '\U0000040E', + "Ubreve;": '\U0000016C', + "Ucirc;": '\U000000DB', + "Ucy;": '\U00000423', + "Udblac;": '\U00000170', + "Ufr;": '\U0001D518', + "Ugrave;": '\U000000D9', + "Umacr;": '\U0000016A', + "UnderBar;": '\U0000005F', + "UnderBrace;": '\U000023DF', + "UnderBracket;": '\U000023B5', + "UnderParenthesis;": '\U000023DD', + "Union;": '\U000022C3', + "UnionPlus;": '\U0000228E', + "Uogon;": '\U00000172', + "Uopf;": '\U0001D54C', + "UpArrow;": '\U00002191', + "UpArrowBar;": '\U00002912', + "UpArrowDownArrow;": '\U000021C5', + "UpDownArrow;": '\U00002195', + "UpEquilibrium;": '\U0000296E', + "UpTee;": '\U000022A5', + "UpTeeArrow;": '\U000021A5', + "Uparrow;": '\U000021D1', + "Updownarrow;": '\U000021D5', + "UpperLeftArrow;": '\U00002196', + "UpperRightArrow;": '\U00002197', + "Upsi;": '\U000003D2', + "Upsilon;": '\U000003A5', + "Uring;": '\U0000016E', + "Uscr;": '\U0001D4B0', + "Utilde;": '\U00000168', + "Uuml;": '\U000000DC', + "VDash;": '\U000022AB', + "Vbar;": '\U00002AEB', + "Vcy;": '\U00000412', + "Vdash;": '\U000022A9', + "Vdashl;": '\U00002AE6', + "Vee;": '\U000022C1', + "Verbar;": '\U00002016', + "Vert;": '\U00002016', + "VerticalBar;": '\U00002223', + "VerticalLine;": '\U0000007C', + "VerticalSeparator;": '\U00002758', + "VerticalTilde;": '\U00002240', + "VeryThinSpace;": '\U0000200A', + "Vfr;": '\U0001D519', + "Vopf;": '\U0001D54D', + "Vscr;": '\U0001D4B1', + "Vvdash;": '\U000022AA', + "Wcirc;": '\U00000174', + "Wedge;": '\U000022C0', + "Wfr;": '\U0001D51A', + "Wopf;": '\U0001D54E', + "Wscr;": '\U0001D4B2', + "Xfr;": '\U0001D51B', + "Xi;": '\U0000039E', + "Xopf;": '\U0001D54F', + "Xscr;": '\U0001D4B3', + "YAcy;": '\U0000042F', + "YIcy;": '\U00000407', + "YUcy;": '\U0000042E', + "Yacute;": '\U000000DD', + "Ycirc;": '\U00000176', + "Ycy;": '\U0000042B', + "Yfr;": '\U0001D51C', + "Yopf;": '\U0001D550', + "Yscr;": '\U0001D4B4', + "Yuml;": '\U00000178', + "ZHcy;": '\U00000416', + "Zacute;": '\U00000179', + "Zcaron;": '\U0000017D', + "Zcy;": '\U00000417', + "Zdot;": '\U0000017B', + "ZeroWidthSpace;": '\U0000200B', + "Zeta;": '\U00000396', + "Zfr;": '\U00002128', + "Zopf;": '\U00002124', + "Zscr;": '\U0001D4B5', + "aacute;": '\U000000E1', + "abreve;": '\U00000103', + "ac;": '\U0000223E', + "acd;": '\U0000223F', + "acirc;": '\U000000E2', + "acute;": '\U000000B4', + "acy;": '\U00000430', + "aelig;": '\U000000E6', + "af;": '\U00002061', + "afr;": '\U0001D51E', + "agrave;": '\U000000E0', + "alefsym;": '\U00002135', + "aleph;": '\U00002135', + "alpha;": '\U000003B1', + "amacr;": '\U00000101', + "amalg;": '\U00002A3F', + "amp;": '\U00000026', + "and;": '\U00002227', + "andand;": '\U00002A55', + "andd;": '\U00002A5C', + "andslope;": '\U00002A58', + "andv;": '\U00002A5A', + "ang;": '\U00002220', + "ange;": '\U000029A4', + "angle;": '\U00002220', + "angmsd;": '\U00002221', + "angmsdaa;": '\U000029A8', + "angmsdab;": '\U000029A9', + "angmsdac;": '\U000029AA', + "angmsdad;": '\U000029AB', + "angmsdae;": '\U000029AC', + "angmsdaf;": '\U000029AD', + "angmsdag;": '\U000029AE', + "angmsdah;": '\U000029AF', + "angrt;": '\U0000221F', + "angrtvb;": '\U000022BE', + "angrtvbd;": '\U0000299D', + "angsph;": '\U00002222', + "angst;": '\U000000C5', + "angzarr;": '\U0000237C', + "aogon;": '\U00000105', + "aopf;": '\U0001D552', + "ap;": '\U00002248', + "apE;": '\U00002A70', + "apacir;": '\U00002A6F', + "ape;": '\U0000224A', + "apid;": '\U0000224B', + "apos;": '\U00000027', + "approx;": '\U00002248', + "approxeq;": '\U0000224A', + "aring;": '\U000000E5', + "ascr;": '\U0001D4B6', + "ast;": '\U0000002A', + "asymp;": '\U00002248', + "asympeq;": '\U0000224D', + "atilde;": '\U000000E3', + "auml;": '\U000000E4', + "awconint;": '\U00002233', + "awint;": '\U00002A11', + "bNot;": '\U00002AED', + "backcong;": '\U0000224C', + "backepsilon;": '\U000003F6', + "backprime;": '\U00002035', + "backsim;": '\U0000223D', + "backsimeq;": '\U000022CD', + "barvee;": '\U000022BD', + "barwed;": '\U00002305', + "barwedge;": '\U00002305', + "bbrk;": '\U000023B5', + "bbrktbrk;": '\U000023B6', + "bcong;": '\U0000224C', + "bcy;": '\U00000431', + "bdquo;": '\U0000201E', + "becaus;": '\U00002235', + "because;": '\U00002235', + "bemptyv;": '\U000029B0', + "bepsi;": '\U000003F6', + "bernou;": '\U0000212C', + "beta;": '\U000003B2', + "beth;": '\U00002136', + "between;": '\U0000226C', + "bfr;": '\U0001D51F', + "bigcap;": '\U000022C2', + "bigcirc;": '\U000025EF', + "bigcup;": '\U000022C3', + "bigodot;": '\U00002A00', + "bigoplus;": '\U00002A01', + "bigotimes;": '\U00002A02', + "bigsqcup;": '\U00002A06', + "bigstar;": '\U00002605', + "bigtriangledown;": '\U000025BD', + "bigtriangleup;": '\U000025B3', + "biguplus;": '\U00002A04', + "bigvee;": '\U000022C1', + "bigwedge;": '\U000022C0', + "bkarow;": '\U0000290D', + "blacklozenge;": '\U000029EB', + "blacksquare;": '\U000025AA', + "blacktriangle;": '\U000025B4', + "blacktriangledown;": '\U000025BE', + "blacktriangleleft;": '\U000025C2', + "blacktriangleright;": '\U000025B8', + "blank;": '\U00002423', + "blk12;": '\U00002592', + "blk14;": '\U00002591', + "blk34;": '\U00002593', + "block;": '\U00002588', + "bnot;": '\U00002310', + "bopf;": '\U0001D553', + "bot;": '\U000022A5', + "bottom;": '\U000022A5', + "bowtie;": '\U000022C8', + "boxDL;": '\U00002557', + "boxDR;": '\U00002554', + "boxDl;": '\U00002556', + "boxDr;": '\U00002553', + "boxH;": '\U00002550', + "boxHD;": '\U00002566', + "boxHU;": '\U00002569', + "boxHd;": '\U00002564', + "boxHu;": '\U00002567', + "boxUL;": '\U0000255D', + "boxUR;": '\U0000255A', + "boxUl;": '\U0000255C', + "boxUr;": '\U00002559', + "boxV;": '\U00002551', + "boxVH;": '\U0000256C', + "boxVL;": '\U00002563', + "boxVR;": '\U00002560', + "boxVh;": '\U0000256B', + "boxVl;": '\U00002562', + "boxVr;": '\U0000255F', + "boxbox;": '\U000029C9', + "boxdL;": '\U00002555', + "boxdR;": '\U00002552', + "boxdl;": '\U00002510', + "boxdr;": '\U0000250C', + "boxh;": '\U00002500', + "boxhD;": '\U00002565', + "boxhU;": '\U00002568', + "boxhd;": '\U0000252C', + "boxhu;": '\U00002534', + "boxminus;": '\U0000229F', + "boxplus;": '\U0000229E', + "boxtimes;": '\U000022A0', + "boxuL;": '\U0000255B', + "boxuR;": '\U00002558', + "boxul;": '\U00002518', + "boxur;": '\U00002514', + "boxv;": '\U00002502', + "boxvH;": '\U0000256A', + "boxvL;": '\U00002561', + "boxvR;": '\U0000255E', + "boxvh;": '\U0000253C', + "boxvl;": '\U00002524', + "boxvr;": '\U0000251C', + "bprime;": '\U00002035', + "breve;": '\U000002D8', + "brvbar;": '\U000000A6', + "bscr;": '\U0001D4B7', + "bsemi;": '\U0000204F', + "bsim;": '\U0000223D', + "bsime;": '\U000022CD', + "bsol;": '\U0000005C', + "bsolb;": '\U000029C5', + "bsolhsub;": '\U000027C8', + "bull;": '\U00002022', + "bullet;": '\U00002022', + "bump;": '\U0000224E', + "bumpE;": '\U00002AAE', + "bumpe;": '\U0000224F', + "bumpeq;": '\U0000224F', + "cacute;": '\U00000107', + "cap;": '\U00002229', + "capand;": '\U00002A44', + "capbrcup;": '\U00002A49', + "capcap;": '\U00002A4B', + "capcup;": '\U00002A47', + "capdot;": '\U00002A40', + "caret;": '\U00002041', + "caron;": '\U000002C7', + "ccaps;": '\U00002A4D', + "ccaron;": '\U0000010D', + "ccedil;": '\U000000E7', + "ccirc;": '\U00000109', + "ccups;": '\U00002A4C', + "ccupssm;": '\U00002A50', + "cdot;": '\U0000010B', + "cedil;": '\U000000B8', + "cemptyv;": '\U000029B2', + "cent;": '\U000000A2', + "centerdot;": '\U000000B7', + "cfr;": '\U0001D520', + "chcy;": '\U00000447', + "check;": '\U00002713', + "checkmark;": '\U00002713', + "chi;": '\U000003C7', + "cir;": '\U000025CB', + "cirE;": '\U000029C3', + "circ;": '\U000002C6', + "circeq;": '\U00002257', + "circlearrowleft;": '\U000021BA', + "circlearrowright;": '\U000021BB', + "circledR;": '\U000000AE', + "circledS;": '\U000024C8', + "circledast;": '\U0000229B', + "circledcirc;": '\U0000229A', + "circleddash;": '\U0000229D', + "cire;": '\U00002257', + "cirfnint;": '\U00002A10', + "cirmid;": '\U00002AEF', + "cirscir;": '\U000029C2', + "clubs;": '\U00002663', + "clubsuit;": '\U00002663', + "colon;": '\U0000003A', + "colone;": '\U00002254', + "coloneq;": '\U00002254', + "comma;": '\U0000002C', + "commat;": '\U00000040', + "comp;": '\U00002201', + "compfn;": '\U00002218', + "complement;": '\U00002201', + "complexes;": '\U00002102', + "cong;": '\U00002245', + "congdot;": '\U00002A6D', + "conint;": '\U0000222E', + "copf;": '\U0001D554', + "coprod;": '\U00002210', + "copy;": '\U000000A9', + "copysr;": '\U00002117', + "crarr;": '\U000021B5', + "cross;": '\U00002717', + "cscr;": '\U0001D4B8', + "csub;": '\U00002ACF', + "csube;": '\U00002AD1', + "csup;": '\U00002AD0', + "csupe;": '\U00002AD2', + "ctdot;": '\U000022EF', + "cudarrl;": '\U00002938', + "cudarrr;": '\U00002935', + "cuepr;": '\U000022DE', + "cuesc;": '\U000022DF', + "cularr;": '\U000021B6', + "cularrp;": '\U0000293D', + "cup;": '\U0000222A', + "cupbrcap;": '\U00002A48', + "cupcap;": '\U00002A46', + "cupcup;": '\U00002A4A', + "cupdot;": '\U0000228D', + "cupor;": '\U00002A45', + "curarr;": '\U000021B7', + "curarrm;": '\U0000293C', + "curlyeqprec;": '\U000022DE', + "curlyeqsucc;": '\U000022DF', + "curlyvee;": '\U000022CE', + "curlywedge;": '\U000022CF', + "curren;": '\U000000A4', + "curvearrowleft;": '\U000021B6', + "curvearrowright;": '\U000021B7', + "cuvee;": '\U000022CE', + "cuwed;": '\U000022CF', + "cwconint;": '\U00002232', + "cwint;": '\U00002231', + "cylcty;": '\U0000232D', + "dArr;": '\U000021D3', + "dHar;": '\U00002965', + "dagger;": '\U00002020', + "daleth;": '\U00002138', + "darr;": '\U00002193', + "dash;": '\U00002010', + "dashv;": '\U000022A3', + "dbkarow;": '\U0000290F', + "dblac;": '\U000002DD', + "dcaron;": '\U0000010F', + "dcy;": '\U00000434', + "dd;": '\U00002146', + "ddagger;": '\U00002021', + "ddarr;": '\U000021CA', + "ddotseq;": '\U00002A77', + "deg;": '\U000000B0', + "delta;": '\U000003B4', + "demptyv;": '\U000029B1', + "dfisht;": '\U0000297F', + "dfr;": '\U0001D521', + "dharl;": '\U000021C3', + "dharr;": '\U000021C2', + "diam;": '\U000022C4', + "diamond;": '\U000022C4', + "diamondsuit;": '\U00002666', + "diams;": '\U00002666', + "die;": '\U000000A8', + "digamma;": '\U000003DD', + "disin;": '\U000022F2', + "div;": '\U000000F7', + "divide;": '\U000000F7', + "divideontimes;": '\U000022C7', + "divonx;": '\U000022C7', + "djcy;": '\U00000452', + "dlcorn;": '\U0000231E', + "dlcrop;": '\U0000230D', + "dollar;": '\U00000024', + "dopf;": '\U0001D555', + "dot;": '\U000002D9', + "doteq;": '\U00002250', + "doteqdot;": '\U00002251', + "dotminus;": '\U00002238', + "dotplus;": '\U00002214', + "dotsquare;": '\U000022A1', + "doublebarwedge;": '\U00002306', + "downarrow;": '\U00002193', + "downdownarrows;": '\U000021CA', + "downharpoonleft;": '\U000021C3', + "downharpoonright;": '\U000021C2', + "drbkarow;": '\U00002910', + "drcorn;": '\U0000231F', + "drcrop;": '\U0000230C', + "dscr;": '\U0001D4B9', + "dscy;": '\U00000455', + "dsol;": '\U000029F6', + "dstrok;": '\U00000111', + "dtdot;": '\U000022F1', + "dtri;": '\U000025BF', + "dtrif;": '\U000025BE', + "duarr;": '\U000021F5', + "duhar;": '\U0000296F', + "dwangle;": '\U000029A6', + "dzcy;": '\U0000045F', + "dzigrarr;": '\U000027FF', + "eDDot;": '\U00002A77', + "eDot;": '\U00002251', + "eacute;": '\U000000E9', + "easter;": '\U00002A6E', + "ecaron;": '\U0000011B', + "ecir;": '\U00002256', + "ecirc;": '\U000000EA', + "ecolon;": '\U00002255', + "ecy;": '\U0000044D', + "edot;": '\U00000117', + "ee;": '\U00002147', + "efDot;": '\U00002252', + "efr;": '\U0001D522', + "eg;": '\U00002A9A', + "egrave;": '\U000000E8', + "egs;": '\U00002A96', + "egsdot;": '\U00002A98', + "el;": '\U00002A99', + "elinters;": '\U000023E7', + "ell;": '\U00002113', + "els;": '\U00002A95', + "elsdot;": '\U00002A97', + "emacr;": '\U00000113', + "empty;": '\U00002205', + "emptyset;": '\U00002205', + "emptyv;": '\U00002205', + "emsp;": '\U00002003', + "emsp13;": '\U00002004', + "emsp14;": '\U00002005', + "eng;": '\U0000014B', + "ensp;": '\U00002002', + "eogon;": '\U00000119', + "eopf;": '\U0001D556', + "epar;": '\U000022D5', + "eparsl;": '\U000029E3', + "eplus;": '\U00002A71', + "epsi;": '\U000003B5', + "epsilon;": '\U000003B5', + "epsiv;": '\U000003F5', + "eqcirc;": '\U00002256', + "eqcolon;": '\U00002255', + "eqsim;": '\U00002242', + "eqslantgtr;": '\U00002A96', + "eqslantless;": '\U00002A95', + "equals;": '\U0000003D', + "equest;": '\U0000225F', + "equiv;": '\U00002261', + "equivDD;": '\U00002A78', + "eqvparsl;": '\U000029E5', + "erDot;": '\U00002253', + "erarr;": '\U00002971', + "escr;": '\U0000212F', + "esdot;": '\U00002250', + "esim;": '\U00002242', + "eta;": '\U000003B7', + "eth;": '\U000000F0', + "euml;": '\U000000EB', + "euro;": '\U000020AC', + "excl;": '\U00000021', + "exist;": '\U00002203', + "expectation;": '\U00002130', + "exponentiale;": '\U00002147', + "fallingdotseq;": '\U00002252', + "fcy;": '\U00000444', + "female;": '\U00002640', + "ffilig;": '\U0000FB03', + "fflig;": '\U0000FB00', + "ffllig;": '\U0000FB04', + "ffr;": '\U0001D523', + "filig;": '\U0000FB01', + "flat;": '\U0000266D', + "fllig;": '\U0000FB02', + "fltns;": '\U000025B1', + "fnof;": '\U00000192', + "fopf;": '\U0001D557', + "forall;": '\U00002200', + "fork;": '\U000022D4', + "forkv;": '\U00002AD9', + "fpartint;": '\U00002A0D', + "frac12;": '\U000000BD', + "frac13;": '\U00002153', + "frac14;": '\U000000BC', + "frac15;": '\U00002155', + "frac16;": '\U00002159', + "frac18;": '\U0000215B', + "frac23;": '\U00002154', + "frac25;": '\U00002156', + "frac34;": '\U000000BE', + "frac35;": '\U00002157', + "frac38;": '\U0000215C', + "frac45;": '\U00002158', + "frac56;": '\U0000215A', + "frac58;": '\U0000215D', + "frac78;": '\U0000215E', + "frasl;": '\U00002044', + "frown;": '\U00002322', + "fscr;": '\U0001D4BB', + "gE;": '\U00002267', + "gEl;": '\U00002A8C', + "gacute;": '\U000001F5', + "gamma;": '\U000003B3', + "gammad;": '\U000003DD', + "gap;": '\U00002A86', + "gbreve;": '\U0000011F', + "gcirc;": '\U0000011D', + "gcy;": '\U00000433', + "gdot;": '\U00000121', + "ge;": '\U00002265', + "gel;": '\U000022DB', + "geq;": '\U00002265', + "geqq;": '\U00002267', + "geqslant;": '\U00002A7E', + "ges;": '\U00002A7E', + "gescc;": '\U00002AA9', + "gesdot;": '\U00002A80', + "gesdoto;": '\U00002A82', + "gesdotol;": '\U00002A84', + "gesles;": '\U00002A94', + "gfr;": '\U0001D524', + "gg;": '\U0000226B', + "ggg;": '\U000022D9', + "gimel;": '\U00002137', + "gjcy;": '\U00000453', + "gl;": '\U00002277', + "glE;": '\U00002A92', + "gla;": '\U00002AA5', + "glj;": '\U00002AA4', + "gnE;": '\U00002269', + "gnap;": '\U00002A8A', + "gnapprox;": '\U00002A8A', + "gne;": '\U00002A88', + "gneq;": '\U00002A88', + "gneqq;": '\U00002269', + "gnsim;": '\U000022E7', + "gopf;": '\U0001D558', + "grave;": '\U00000060', + "gscr;": '\U0000210A', + "gsim;": '\U00002273', + "gsime;": '\U00002A8E', + "gsiml;": '\U00002A90', + "gt;": '\U0000003E', + "gtcc;": '\U00002AA7', + "gtcir;": '\U00002A7A', + "gtdot;": '\U000022D7', + "gtlPar;": '\U00002995', + "gtquest;": '\U00002A7C', + "gtrapprox;": '\U00002A86', + "gtrarr;": '\U00002978', + "gtrdot;": '\U000022D7', + "gtreqless;": '\U000022DB', + "gtreqqless;": '\U00002A8C', + "gtrless;": '\U00002277', + "gtrsim;": '\U00002273', + "hArr;": '\U000021D4', + "hairsp;": '\U0000200A', + "half;": '\U000000BD', + "hamilt;": '\U0000210B', + "hardcy;": '\U0000044A', + "harr;": '\U00002194', + "harrcir;": '\U00002948', + "harrw;": '\U000021AD', + "hbar;": '\U0000210F', + "hcirc;": '\U00000125', + "hearts;": '\U00002665', + "heartsuit;": '\U00002665', + "hellip;": '\U00002026', + "hercon;": '\U000022B9', + "hfr;": '\U0001D525', + "hksearow;": '\U00002925', + "hkswarow;": '\U00002926', + "hoarr;": '\U000021FF', + "homtht;": '\U0000223B', + "hookleftarrow;": '\U000021A9', + "hookrightarrow;": '\U000021AA', + "hopf;": '\U0001D559', + "horbar;": '\U00002015', + "hscr;": '\U0001D4BD', + "hslash;": '\U0000210F', + "hstrok;": '\U00000127', + "hybull;": '\U00002043', + "hyphen;": '\U00002010', + "iacute;": '\U000000ED', + "ic;": '\U00002063', + "icirc;": '\U000000EE', + "icy;": '\U00000438', + "iecy;": '\U00000435', + "iexcl;": '\U000000A1', + "iff;": '\U000021D4', + "ifr;": '\U0001D526', + "igrave;": '\U000000EC', + "ii;": '\U00002148', + "iiiint;": '\U00002A0C', + "iiint;": '\U0000222D', + "iinfin;": '\U000029DC', + "iiota;": '\U00002129', + "ijlig;": '\U00000133', + "imacr;": '\U0000012B', + "image;": '\U00002111', + "imagline;": '\U00002110', + "imagpart;": '\U00002111', + "imath;": '\U00000131', + "imof;": '\U000022B7', + "imped;": '\U000001B5', + "in;": '\U00002208', + "incare;": '\U00002105', + "infin;": '\U0000221E', + "infintie;": '\U000029DD', + "inodot;": '\U00000131', + "int;": '\U0000222B', + "intcal;": '\U000022BA', + "integers;": '\U00002124', + "intercal;": '\U000022BA', + "intlarhk;": '\U00002A17', + "intprod;": '\U00002A3C', + "iocy;": '\U00000451', + "iogon;": '\U0000012F', + "iopf;": '\U0001D55A', + "iota;": '\U000003B9', + "iprod;": '\U00002A3C', + "iquest;": '\U000000BF', + "iscr;": '\U0001D4BE', + "isin;": '\U00002208', + "isinE;": '\U000022F9', + "isindot;": '\U000022F5', + "isins;": '\U000022F4', + "isinsv;": '\U000022F3', + "isinv;": '\U00002208', + "it;": '\U00002062', + "itilde;": '\U00000129', + "iukcy;": '\U00000456', + "iuml;": '\U000000EF', + "jcirc;": '\U00000135', + "jcy;": '\U00000439', + "jfr;": '\U0001D527', + "jmath;": '\U00000237', + "jopf;": '\U0001D55B', + "jscr;": '\U0001D4BF', + "jsercy;": '\U00000458', + "jukcy;": '\U00000454', + "kappa;": '\U000003BA', + "kappav;": '\U000003F0', + "kcedil;": '\U00000137', + "kcy;": '\U0000043A', + "kfr;": '\U0001D528', + "kgreen;": '\U00000138', + "khcy;": '\U00000445', + "kjcy;": '\U0000045C', + "kopf;": '\U0001D55C', + "kscr;": '\U0001D4C0', + "lAarr;": '\U000021DA', + "lArr;": '\U000021D0', + "lAtail;": '\U0000291B', + "lBarr;": '\U0000290E', + "lE;": '\U00002266', + "lEg;": '\U00002A8B', + "lHar;": '\U00002962', + "lacute;": '\U0000013A', + "laemptyv;": '\U000029B4', + "lagran;": '\U00002112', + "lambda;": '\U000003BB', + "lang;": '\U000027E8', + "langd;": '\U00002991', + "langle;": '\U000027E8', + "lap;": '\U00002A85', + "laquo;": '\U000000AB', + "larr;": '\U00002190', + "larrb;": '\U000021E4', + "larrbfs;": '\U0000291F', + "larrfs;": '\U0000291D', + "larrhk;": '\U000021A9', + "larrlp;": '\U000021AB', + "larrpl;": '\U00002939', + "larrsim;": '\U00002973', + "larrtl;": '\U000021A2', + "lat;": '\U00002AAB', + "latail;": '\U00002919', + "late;": '\U00002AAD', + "lbarr;": '\U0000290C', + "lbbrk;": '\U00002772', + "lbrace;": '\U0000007B', + "lbrack;": '\U0000005B', + "lbrke;": '\U0000298B', + "lbrksld;": '\U0000298F', + "lbrkslu;": '\U0000298D', + "lcaron;": '\U0000013E', + "lcedil;": '\U0000013C', + "lceil;": '\U00002308', + "lcub;": '\U0000007B', + "lcy;": '\U0000043B', + "ldca;": '\U00002936', + "ldquo;": '\U0000201C', + "ldquor;": '\U0000201E', + "ldrdhar;": '\U00002967', + "ldrushar;": '\U0000294B', + "ldsh;": '\U000021B2', + "le;": '\U00002264', + "leftarrow;": '\U00002190', + "leftarrowtail;": '\U000021A2', + "leftharpoondown;": '\U000021BD', + "leftharpoonup;": '\U000021BC', + "leftleftarrows;": '\U000021C7', + "leftrightarrow;": '\U00002194', + "leftrightarrows;": '\U000021C6', + "leftrightharpoons;": '\U000021CB', + "leftrightsquigarrow;": '\U000021AD', + "leftthreetimes;": '\U000022CB', + "leg;": '\U000022DA', + "leq;": '\U00002264', + "leqq;": '\U00002266', + "leqslant;": '\U00002A7D', + "les;": '\U00002A7D', + "lescc;": '\U00002AA8', + "lesdot;": '\U00002A7F', + "lesdoto;": '\U00002A81', + "lesdotor;": '\U00002A83', + "lesges;": '\U00002A93', + "lessapprox;": '\U00002A85', + "lessdot;": '\U000022D6', + "lesseqgtr;": '\U000022DA', + "lesseqqgtr;": '\U00002A8B', + "lessgtr;": '\U00002276', + "lesssim;": '\U00002272', + "lfisht;": '\U0000297C', + "lfloor;": '\U0000230A', + "lfr;": '\U0001D529', + "lg;": '\U00002276', + "lgE;": '\U00002A91', + "lhard;": '\U000021BD', + "lharu;": '\U000021BC', + "lharul;": '\U0000296A', + "lhblk;": '\U00002584', + "ljcy;": '\U00000459', + "ll;": '\U0000226A', + "llarr;": '\U000021C7', + "llcorner;": '\U0000231E', + "llhard;": '\U0000296B', + "lltri;": '\U000025FA', + "lmidot;": '\U00000140', + "lmoust;": '\U000023B0', + "lmoustache;": '\U000023B0', + "lnE;": '\U00002268', + "lnap;": '\U00002A89', + "lnapprox;": '\U00002A89', + "lne;": '\U00002A87', + "lneq;": '\U00002A87', + "lneqq;": '\U00002268', + "lnsim;": '\U000022E6', + "loang;": '\U000027EC', + "loarr;": '\U000021FD', + "lobrk;": '\U000027E6', + "longleftarrow;": '\U000027F5', + "longleftrightarrow;": '\U000027F7', + "longmapsto;": '\U000027FC', + "longrightarrow;": '\U000027F6', + "looparrowleft;": '\U000021AB', + "looparrowright;": '\U000021AC', + "lopar;": '\U00002985', + "lopf;": '\U0001D55D', + "loplus;": '\U00002A2D', + "lotimes;": '\U00002A34', + "lowast;": '\U00002217', + "lowbar;": '\U0000005F', + "loz;": '\U000025CA', + "lozenge;": '\U000025CA', + "lozf;": '\U000029EB', + "lpar;": '\U00000028', + "lparlt;": '\U00002993', + "lrarr;": '\U000021C6', + "lrcorner;": '\U0000231F', + "lrhar;": '\U000021CB', + "lrhard;": '\U0000296D', + "lrm;": '\U0000200E', + "lrtri;": '\U000022BF', + "lsaquo;": '\U00002039', + "lscr;": '\U0001D4C1', + "lsh;": '\U000021B0', + "lsim;": '\U00002272', + "lsime;": '\U00002A8D', + "lsimg;": '\U00002A8F', + "lsqb;": '\U0000005B', + "lsquo;": '\U00002018', + "lsquor;": '\U0000201A', + "lstrok;": '\U00000142', + "lt;": '\U0000003C', + "ltcc;": '\U00002AA6', + "ltcir;": '\U00002A79', + "ltdot;": '\U000022D6', + "lthree;": '\U000022CB', + "ltimes;": '\U000022C9', + "ltlarr;": '\U00002976', + "ltquest;": '\U00002A7B', + "ltrPar;": '\U00002996', + "ltri;": '\U000025C3', + "ltrie;": '\U000022B4', + "ltrif;": '\U000025C2', + "lurdshar;": '\U0000294A', + "luruhar;": '\U00002966', + "mDDot;": '\U0000223A', + "macr;": '\U000000AF', + "male;": '\U00002642', + "malt;": '\U00002720', + "maltese;": '\U00002720', + "map;": '\U000021A6', + "mapsto;": '\U000021A6', + "mapstodown;": '\U000021A7', + "mapstoleft;": '\U000021A4', + "mapstoup;": '\U000021A5', + "marker;": '\U000025AE', + "mcomma;": '\U00002A29', + "mcy;": '\U0000043C', + "mdash;": '\U00002014', + "measuredangle;": '\U00002221', + "mfr;": '\U0001D52A', + "mho;": '\U00002127', + "micro;": '\U000000B5', + "mid;": '\U00002223', + "midast;": '\U0000002A', + "midcir;": '\U00002AF0', + "middot;": '\U000000B7', + "minus;": '\U00002212', + "minusb;": '\U0000229F', + "minusd;": '\U00002238', + "minusdu;": '\U00002A2A', + "mlcp;": '\U00002ADB', + "mldr;": '\U00002026', + "mnplus;": '\U00002213', + "models;": '\U000022A7', + "mopf;": '\U0001D55E', + "mp;": '\U00002213', + "mscr;": '\U0001D4C2', + "mstpos;": '\U0000223E', + "mu;": '\U000003BC', + "multimap;": '\U000022B8', + "mumap;": '\U000022B8', + "nLeftarrow;": '\U000021CD', + "nLeftrightarrow;": '\U000021CE', + "nRightarrow;": '\U000021CF', + "nVDash;": '\U000022AF', + "nVdash;": '\U000022AE', + "nabla;": '\U00002207', + "nacute;": '\U00000144', + "nap;": '\U00002249', + "napos;": '\U00000149', + "napprox;": '\U00002249', + "natur;": '\U0000266E', + "natural;": '\U0000266E', + "naturals;": '\U00002115', + "nbsp;": '\U000000A0', + "ncap;": '\U00002A43', + "ncaron;": '\U00000148', + "ncedil;": '\U00000146', + "ncong;": '\U00002247', + "ncup;": '\U00002A42', + "ncy;": '\U0000043D', + "ndash;": '\U00002013', + "ne;": '\U00002260', + "neArr;": '\U000021D7', + "nearhk;": '\U00002924', + "nearr;": '\U00002197', + "nearrow;": '\U00002197', + "nequiv;": '\U00002262', + "nesear;": '\U00002928', + "nexist;": '\U00002204', + "nexists;": '\U00002204', + "nfr;": '\U0001D52B', + "nge;": '\U00002271', + "ngeq;": '\U00002271', + "ngsim;": '\U00002275', + "ngt;": '\U0000226F', + "ngtr;": '\U0000226F', + "nhArr;": '\U000021CE', + "nharr;": '\U000021AE', + "nhpar;": '\U00002AF2', + "ni;": '\U0000220B', + "nis;": '\U000022FC', + "nisd;": '\U000022FA', + "niv;": '\U0000220B', + "njcy;": '\U0000045A', + "nlArr;": '\U000021CD', + "nlarr;": '\U0000219A', + "nldr;": '\U00002025', + "nle;": '\U00002270', + "nleftarrow;": '\U0000219A', + "nleftrightarrow;": '\U000021AE', + "nleq;": '\U00002270', + "nless;": '\U0000226E', + "nlsim;": '\U00002274', + "nlt;": '\U0000226E', + "nltri;": '\U000022EA', + "nltrie;": '\U000022EC', + "nmid;": '\U00002224', + "nopf;": '\U0001D55F', + "not;": '\U000000AC', + "notin;": '\U00002209', + "notinva;": '\U00002209', + "notinvb;": '\U000022F7', + "notinvc;": '\U000022F6', + "notni;": '\U0000220C', + "notniva;": '\U0000220C', + "notnivb;": '\U000022FE', + "notnivc;": '\U000022FD', + "npar;": '\U00002226', + "nparallel;": '\U00002226', + "npolint;": '\U00002A14', + "npr;": '\U00002280', + "nprcue;": '\U000022E0', + "nprec;": '\U00002280', + "nrArr;": '\U000021CF', + "nrarr;": '\U0000219B', + "nrightarrow;": '\U0000219B', + "nrtri;": '\U000022EB', + "nrtrie;": '\U000022ED', + "nsc;": '\U00002281', + "nsccue;": '\U000022E1', + "nscr;": '\U0001D4C3', + "nshortmid;": '\U00002224', + "nshortparallel;": '\U00002226', + "nsim;": '\U00002241', + "nsime;": '\U00002244', + "nsimeq;": '\U00002244', + "nsmid;": '\U00002224', + "nspar;": '\U00002226', + "nsqsube;": '\U000022E2', + "nsqsupe;": '\U000022E3', + "nsub;": '\U00002284', + "nsube;": '\U00002288', + "nsubseteq;": '\U00002288', + "nsucc;": '\U00002281', + "nsup;": '\U00002285', + "nsupe;": '\U00002289', + "nsupseteq;": '\U00002289', + "ntgl;": '\U00002279', + "ntilde;": '\U000000F1', + "ntlg;": '\U00002278', + "ntriangleleft;": '\U000022EA', + "ntrianglelefteq;": '\U000022EC', + "ntriangleright;": '\U000022EB', + "ntrianglerighteq;": '\U000022ED', + "nu;": '\U000003BD', + "num;": '\U00000023', + "numero;": '\U00002116', + "numsp;": '\U00002007', + "nvDash;": '\U000022AD', + "nvHarr;": '\U00002904', + "nvdash;": '\U000022AC', + "nvinfin;": '\U000029DE', + "nvlArr;": '\U00002902', + "nvrArr;": '\U00002903', + "nwArr;": '\U000021D6', + "nwarhk;": '\U00002923', + "nwarr;": '\U00002196', + "nwarrow;": '\U00002196', + "nwnear;": '\U00002927', + "oS;": '\U000024C8', + "oacute;": '\U000000F3', + "oast;": '\U0000229B', + "ocir;": '\U0000229A', + "ocirc;": '\U000000F4', + "ocy;": '\U0000043E', + "odash;": '\U0000229D', + "odblac;": '\U00000151', + "odiv;": '\U00002A38', + "odot;": '\U00002299', + "odsold;": '\U000029BC', + "oelig;": '\U00000153', + "ofcir;": '\U000029BF', + "ofr;": '\U0001D52C', + "ogon;": '\U000002DB', + "ograve;": '\U000000F2', + "ogt;": '\U000029C1', + "ohbar;": '\U000029B5', + "ohm;": '\U000003A9', + "oint;": '\U0000222E', + "olarr;": '\U000021BA', + "olcir;": '\U000029BE', + "olcross;": '\U000029BB', + "oline;": '\U0000203E', + "olt;": '\U000029C0', + "omacr;": '\U0000014D', + "omega;": '\U000003C9', + "omicron;": '\U000003BF', + "omid;": '\U000029B6', + "ominus;": '\U00002296', + "oopf;": '\U0001D560', + "opar;": '\U000029B7', + "operp;": '\U000029B9', + "oplus;": '\U00002295', + "or;": '\U00002228', + "orarr;": '\U000021BB', + "ord;": '\U00002A5D', + "order;": '\U00002134', + "orderof;": '\U00002134', + "ordf;": '\U000000AA', + "ordm;": '\U000000BA', + "origof;": '\U000022B6', + "oror;": '\U00002A56', + "orslope;": '\U00002A57', + "orv;": '\U00002A5B', + "oscr;": '\U00002134', + "oslash;": '\U000000F8', + "osol;": '\U00002298', + "otilde;": '\U000000F5', + "otimes;": '\U00002297', + "otimesas;": '\U00002A36', + "ouml;": '\U000000F6', + "ovbar;": '\U0000233D', + "par;": '\U00002225', + "para;": '\U000000B6', + "parallel;": '\U00002225', + "parsim;": '\U00002AF3', + "parsl;": '\U00002AFD', + "part;": '\U00002202', + "pcy;": '\U0000043F', + "percnt;": '\U00000025', + "period;": '\U0000002E', + "permil;": '\U00002030', + "perp;": '\U000022A5', + "pertenk;": '\U00002031', + "pfr;": '\U0001D52D', + "phi;": '\U000003C6', + "phiv;": '\U000003D5', + "phmmat;": '\U00002133', + "phone;": '\U0000260E', + "pi;": '\U000003C0', + "pitchfork;": '\U000022D4', + "piv;": '\U000003D6', + "planck;": '\U0000210F', + "planckh;": '\U0000210E', + "plankv;": '\U0000210F', + "plus;": '\U0000002B', + "plusacir;": '\U00002A23', + "plusb;": '\U0000229E', + "pluscir;": '\U00002A22', + "plusdo;": '\U00002214', + "plusdu;": '\U00002A25', + "pluse;": '\U00002A72', + "plusmn;": '\U000000B1', + "plussim;": '\U00002A26', + "plustwo;": '\U00002A27', + "pm;": '\U000000B1', + "pointint;": '\U00002A15', + "popf;": '\U0001D561', + "pound;": '\U000000A3', + "pr;": '\U0000227A', + "prE;": '\U00002AB3', + "prap;": '\U00002AB7', + "prcue;": '\U0000227C', + "pre;": '\U00002AAF', + "prec;": '\U0000227A', + "precapprox;": '\U00002AB7', + "preccurlyeq;": '\U0000227C', + "preceq;": '\U00002AAF', + "precnapprox;": '\U00002AB9', + "precneqq;": '\U00002AB5', + "precnsim;": '\U000022E8', + "precsim;": '\U0000227E', + "prime;": '\U00002032', + "primes;": '\U00002119', + "prnE;": '\U00002AB5', + "prnap;": '\U00002AB9', + "prnsim;": '\U000022E8', + "prod;": '\U0000220F', + "profalar;": '\U0000232E', + "profline;": '\U00002312', + "profsurf;": '\U00002313', + "prop;": '\U0000221D', + "propto;": '\U0000221D', + "prsim;": '\U0000227E', + "prurel;": '\U000022B0', + "pscr;": '\U0001D4C5', + "psi;": '\U000003C8', + "puncsp;": '\U00002008', + "qfr;": '\U0001D52E', + "qint;": '\U00002A0C', + "qopf;": '\U0001D562', + "qprime;": '\U00002057', + "qscr;": '\U0001D4C6', + "quaternions;": '\U0000210D', + "quatint;": '\U00002A16', + "quest;": '\U0000003F', + "questeq;": '\U0000225F', + "quot;": '\U00000022', + "rAarr;": '\U000021DB', + "rArr;": '\U000021D2', + "rAtail;": '\U0000291C', + "rBarr;": '\U0000290F', + "rHar;": '\U00002964', + "racute;": '\U00000155', + "radic;": '\U0000221A', + "raemptyv;": '\U000029B3', + "rang;": '\U000027E9', + "rangd;": '\U00002992', + "range;": '\U000029A5', + "rangle;": '\U000027E9', + "raquo;": '\U000000BB', + "rarr;": '\U00002192', + "rarrap;": '\U00002975', + "rarrb;": '\U000021E5', + "rarrbfs;": '\U00002920', + "rarrc;": '\U00002933', + "rarrfs;": '\U0000291E', + "rarrhk;": '\U000021AA', + "rarrlp;": '\U000021AC', + "rarrpl;": '\U00002945', + "rarrsim;": '\U00002974', + "rarrtl;": '\U000021A3', + "rarrw;": '\U0000219D', + "ratail;": '\U0000291A', + "ratio;": '\U00002236', + "rationals;": '\U0000211A', + "rbarr;": '\U0000290D', + "rbbrk;": '\U00002773', + "rbrace;": '\U0000007D', + "rbrack;": '\U0000005D', + "rbrke;": '\U0000298C', + "rbrksld;": '\U0000298E', + "rbrkslu;": '\U00002990', + "rcaron;": '\U00000159', + "rcedil;": '\U00000157', + "rceil;": '\U00002309', + "rcub;": '\U0000007D', + "rcy;": '\U00000440', + "rdca;": '\U00002937', + "rdldhar;": '\U00002969', + "rdquo;": '\U0000201D', + "rdquor;": '\U0000201D', + "rdsh;": '\U000021B3', + "real;": '\U0000211C', + "realine;": '\U0000211B', + "realpart;": '\U0000211C', + "reals;": '\U0000211D', + "rect;": '\U000025AD', + "reg;": '\U000000AE', + "rfisht;": '\U0000297D', + "rfloor;": '\U0000230B', + "rfr;": '\U0001D52F', + "rhard;": '\U000021C1', + "rharu;": '\U000021C0', + "rharul;": '\U0000296C', + "rho;": '\U000003C1', + "rhov;": '\U000003F1', + "rightarrow;": '\U00002192', + "rightarrowtail;": '\U000021A3', + "rightharpoondown;": '\U000021C1', + "rightharpoonup;": '\U000021C0', + "rightleftarrows;": '\U000021C4', + "rightleftharpoons;": '\U000021CC', + "rightrightarrows;": '\U000021C9', + "rightsquigarrow;": '\U0000219D', + "rightthreetimes;": '\U000022CC', + "ring;": '\U000002DA', + "risingdotseq;": '\U00002253', + "rlarr;": '\U000021C4', + "rlhar;": '\U000021CC', + "rlm;": '\U0000200F', + "rmoust;": '\U000023B1', + "rmoustache;": '\U000023B1', + "rnmid;": '\U00002AEE', + "roang;": '\U000027ED', + "roarr;": '\U000021FE', + "robrk;": '\U000027E7', + "ropar;": '\U00002986', + "ropf;": '\U0001D563', + "roplus;": '\U00002A2E', + "rotimes;": '\U00002A35', + "rpar;": '\U00000029', + "rpargt;": '\U00002994', + "rppolint;": '\U00002A12', + "rrarr;": '\U000021C9', + "rsaquo;": '\U0000203A', + "rscr;": '\U0001D4C7', + "rsh;": '\U000021B1', + "rsqb;": '\U0000005D', + "rsquo;": '\U00002019', + "rsquor;": '\U00002019', + "rthree;": '\U000022CC', + "rtimes;": '\U000022CA', + "rtri;": '\U000025B9', + "rtrie;": '\U000022B5', + "rtrif;": '\U000025B8', + "rtriltri;": '\U000029CE', + "ruluhar;": '\U00002968', + "rx;": '\U0000211E', + "sacute;": '\U0000015B', + "sbquo;": '\U0000201A', + "sc;": '\U0000227B', + "scE;": '\U00002AB4', + "scap;": '\U00002AB8', + "scaron;": '\U00000161', + "sccue;": '\U0000227D', + "sce;": '\U00002AB0', + "scedil;": '\U0000015F', + "scirc;": '\U0000015D', + "scnE;": '\U00002AB6', + "scnap;": '\U00002ABA', + "scnsim;": '\U000022E9', + "scpolint;": '\U00002A13', + "scsim;": '\U0000227F', + "scy;": '\U00000441', + "sdot;": '\U000022C5', + "sdotb;": '\U000022A1', + "sdote;": '\U00002A66', + "seArr;": '\U000021D8', + "searhk;": '\U00002925', + "searr;": '\U00002198', + "searrow;": '\U00002198', + "sect;": '\U000000A7', + "semi;": '\U0000003B', + "seswar;": '\U00002929', + "setminus;": '\U00002216', + "setmn;": '\U00002216', + "sext;": '\U00002736', + "sfr;": '\U0001D530', + "sfrown;": '\U00002322', + "sharp;": '\U0000266F', + "shchcy;": '\U00000449', + "shcy;": '\U00000448', + "shortmid;": '\U00002223', + "shortparallel;": '\U00002225', + "shy;": '\U000000AD', + "sigma;": '\U000003C3', + "sigmaf;": '\U000003C2', + "sigmav;": '\U000003C2', + "sim;": '\U0000223C', + "simdot;": '\U00002A6A', + "sime;": '\U00002243', + "simeq;": '\U00002243', + "simg;": '\U00002A9E', + "simgE;": '\U00002AA0', + "siml;": '\U00002A9D', + "simlE;": '\U00002A9F', + "simne;": '\U00002246', + "simplus;": '\U00002A24', + "simrarr;": '\U00002972', + "slarr;": '\U00002190', + "smallsetminus;": '\U00002216', + "smashp;": '\U00002A33', + "smeparsl;": '\U000029E4', + "smid;": '\U00002223', + "smile;": '\U00002323', + "smt;": '\U00002AAA', + "smte;": '\U00002AAC', + "softcy;": '\U0000044C', + "sol;": '\U0000002F', + "solb;": '\U000029C4', + "solbar;": '\U0000233F', + "sopf;": '\U0001D564', + "spades;": '\U00002660', + "spadesuit;": '\U00002660', + "spar;": '\U00002225', + "sqcap;": '\U00002293', + "sqcup;": '\U00002294', + "sqsub;": '\U0000228F', + "sqsube;": '\U00002291', + "sqsubset;": '\U0000228F', + "sqsubseteq;": '\U00002291', + "sqsup;": '\U00002290', + "sqsupe;": '\U00002292', + "sqsupset;": '\U00002290', + "sqsupseteq;": '\U00002292', + "squ;": '\U000025A1', + "square;": '\U000025A1', + "squarf;": '\U000025AA', + "squf;": '\U000025AA', + "srarr;": '\U00002192', + "sscr;": '\U0001D4C8', + "ssetmn;": '\U00002216', + "ssmile;": '\U00002323', + "sstarf;": '\U000022C6', + "star;": '\U00002606', + "starf;": '\U00002605', + "straightepsilon;": '\U000003F5', + "straightphi;": '\U000003D5', + "strns;": '\U000000AF', + "sub;": '\U00002282', + "subE;": '\U00002AC5', + "subdot;": '\U00002ABD', + "sube;": '\U00002286', + "subedot;": '\U00002AC3', + "submult;": '\U00002AC1', + "subnE;": '\U00002ACB', + "subne;": '\U0000228A', + "subplus;": '\U00002ABF', + "subrarr;": '\U00002979', + "subset;": '\U00002282', + "subseteq;": '\U00002286', + "subseteqq;": '\U00002AC5', + "subsetneq;": '\U0000228A', + "subsetneqq;": '\U00002ACB', + "subsim;": '\U00002AC7', + "subsub;": '\U00002AD5', + "subsup;": '\U00002AD3', + "succ;": '\U0000227B', + "succapprox;": '\U00002AB8', + "succcurlyeq;": '\U0000227D', + "succeq;": '\U00002AB0', + "succnapprox;": '\U00002ABA', + "succneqq;": '\U00002AB6', + "succnsim;": '\U000022E9', + "succsim;": '\U0000227F', + "sum;": '\U00002211', + "sung;": '\U0000266A', + "sup;": '\U00002283', + "sup1;": '\U000000B9', + "sup2;": '\U000000B2', + "sup3;": '\U000000B3', + "supE;": '\U00002AC6', + "supdot;": '\U00002ABE', + "supdsub;": '\U00002AD8', + "supe;": '\U00002287', + "supedot;": '\U00002AC4', + "suphsol;": '\U000027C9', + "suphsub;": '\U00002AD7', + "suplarr;": '\U0000297B', + "supmult;": '\U00002AC2', + "supnE;": '\U00002ACC', + "supne;": '\U0000228B', + "supplus;": '\U00002AC0', + "supset;": '\U00002283', + "supseteq;": '\U00002287', + "supseteqq;": '\U00002AC6', + "supsetneq;": '\U0000228B', + "supsetneqq;": '\U00002ACC', + "supsim;": '\U00002AC8', + "supsub;": '\U00002AD4', + "supsup;": '\U00002AD6', + "swArr;": '\U000021D9', + "swarhk;": '\U00002926', + "swarr;": '\U00002199', + "swarrow;": '\U00002199', + "swnwar;": '\U0000292A', + "szlig;": '\U000000DF', + "target;": '\U00002316', + "tau;": '\U000003C4', + "tbrk;": '\U000023B4', + "tcaron;": '\U00000165', + "tcedil;": '\U00000163', + "tcy;": '\U00000442', + "tdot;": '\U000020DB', + "telrec;": '\U00002315', + "tfr;": '\U0001D531', + "there4;": '\U00002234', + "therefore;": '\U00002234', + "theta;": '\U000003B8', + "thetasym;": '\U000003D1', + "thetav;": '\U000003D1', + "thickapprox;": '\U00002248', + "thicksim;": '\U0000223C', + "thinsp;": '\U00002009', + "thkap;": '\U00002248', + "thksim;": '\U0000223C', + "thorn;": '\U000000FE', + "tilde;": '\U000002DC', + "times;": '\U000000D7', + "timesb;": '\U000022A0', + "timesbar;": '\U00002A31', + "timesd;": '\U00002A30', + "tint;": '\U0000222D', + "toea;": '\U00002928', + "top;": '\U000022A4', + "topbot;": '\U00002336', + "topcir;": '\U00002AF1', + "topf;": '\U0001D565', + "topfork;": '\U00002ADA', + "tosa;": '\U00002929', + "tprime;": '\U00002034', + "trade;": '\U00002122', + "triangle;": '\U000025B5', + "triangledown;": '\U000025BF', + "triangleleft;": '\U000025C3', + "trianglelefteq;": '\U000022B4', + "triangleq;": '\U0000225C', + "triangleright;": '\U000025B9', + "trianglerighteq;": '\U000022B5', + "tridot;": '\U000025EC', + "trie;": '\U0000225C', + "triminus;": '\U00002A3A', + "triplus;": '\U00002A39', + "trisb;": '\U000029CD', + "tritime;": '\U00002A3B', + "trpezium;": '\U000023E2', + "tscr;": '\U0001D4C9', + "tscy;": '\U00000446', + "tshcy;": '\U0000045B', + "tstrok;": '\U00000167', + "twixt;": '\U0000226C', + "twoheadleftarrow;": '\U0000219E', + "twoheadrightarrow;": '\U000021A0', + "uArr;": '\U000021D1', + "uHar;": '\U00002963', + "uacute;": '\U000000FA', + "uarr;": '\U00002191', + "ubrcy;": '\U0000045E', + "ubreve;": '\U0000016D', + "ucirc;": '\U000000FB', + "ucy;": '\U00000443', + "udarr;": '\U000021C5', + "udblac;": '\U00000171', + "udhar;": '\U0000296E', + "ufisht;": '\U0000297E', + "ufr;": '\U0001D532', + "ugrave;": '\U000000F9', + "uharl;": '\U000021BF', + "uharr;": '\U000021BE', + "uhblk;": '\U00002580', + "ulcorn;": '\U0000231C', + "ulcorner;": '\U0000231C', + "ulcrop;": '\U0000230F', + "ultri;": '\U000025F8', + "umacr;": '\U0000016B', + "uml;": '\U000000A8', + "uogon;": '\U00000173', + "uopf;": '\U0001D566', + "uparrow;": '\U00002191', + "updownarrow;": '\U00002195', + "upharpoonleft;": '\U000021BF', + "upharpoonright;": '\U000021BE', + "uplus;": '\U0000228E', + "upsi;": '\U000003C5', + "upsih;": '\U000003D2', + "upsilon;": '\U000003C5', + "upuparrows;": '\U000021C8', + "urcorn;": '\U0000231D', + "urcorner;": '\U0000231D', + "urcrop;": '\U0000230E', + "uring;": '\U0000016F', + "urtri;": '\U000025F9', + "uscr;": '\U0001D4CA', + "utdot;": '\U000022F0', + "utilde;": '\U00000169', + "utri;": '\U000025B5', + "utrif;": '\U000025B4', + "uuarr;": '\U000021C8', + "uuml;": '\U000000FC', + "uwangle;": '\U000029A7', + "vArr;": '\U000021D5', + "vBar;": '\U00002AE8', + "vBarv;": '\U00002AE9', + "vDash;": '\U000022A8', + "vangrt;": '\U0000299C', + "varepsilon;": '\U000003F5', + "varkappa;": '\U000003F0', + "varnothing;": '\U00002205', + "varphi;": '\U000003D5', + "varpi;": '\U000003D6', + "varpropto;": '\U0000221D', + "varr;": '\U00002195', + "varrho;": '\U000003F1', + "varsigma;": '\U000003C2', + "vartheta;": '\U000003D1', + "vartriangleleft;": '\U000022B2', + "vartriangleright;": '\U000022B3', + "vcy;": '\U00000432', + "vdash;": '\U000022A2', + "vee;": '\U00002228', + "veebar;": '\U000022BB', + "veeeq;": '\U0000225A', + "vellip;": '\U000022EE', + "verbar;": '\U0000007C', + "vert;": '\U0000007C', + "vfr;": '\U0001D533', + "vltri;": '\U000022B2', + "vopf;": '\U0001D567', + "vprop;": '\U0000221D', + "vrtri;": '\U000022B3', + "vscr;": '\U0001D4CB', + "vzigzag;": '\U0000299A', + "wcirc;": '\U00000175', + "wedbar;": '\U00002A5F', + "wedge;": '\U00002227', + "wedgeq;": '\U00002259', + "weierp;": '\U00002118', + "wfr;": '\U0001D534', + "wopf;": '\U0001D568', + "wp;": '\U00002118', + "wr;": '\U00002240', + "wreath;": '\U00002240', + "wscr;": '\U0001D4CC', + "xcap;": '\U000022C2', + "xcirc;": '\U000025EF', + "xcup;": '\U000022C3', + "xdtri;": '\U000025BD', + "xfr;": '\U0001D535', + "xhArr;": '\U000027FA', + "xharr;": '\U000027F7', + "xi;": '\U000003BE', + "xlArr;": '\U000027F8', + "xlarr;": '\U000027F5', + "xmap;": '\U000027FC', + "xnis;": '\U000022FB', + "xodot;": '\U00002A00', + "xopf;": '\U0001D569', + "xoplus;": '\U00002A01', + "xotime;": '\U00002A02', + "xrArr;": '\U000027F9', + "xrarr;": '\U000027F6', + "xscr;": '\U0001D4CD', + "xsqcup;": '\U00002A06', + "xuplus;": '\U00002A04', + "xutri;": '\U000025B3', + "xvee;": '\U000022C1', + "xwedge;": '\U000022C0', + "yacute;": '\U000000FD', + "yacy;": '\U0000044F', + "ycirc;": '\U00000177', + "ycy;": '\U0000044B', + "yen;": '\U000000A5', + "yfr;": '\U0001D536', + "yicy;": '\U00000457', + "yopf;": '\U0001D56A', + "yscr;": '\U0001D4CE', + "yucy;": '\U0000044E', + "yuml;": '\U000000FF', + "zacute;": '\U0000017A', + "zcaron;": '\U0000017E', + "zcy;": '\U00000437', + "zdot;": '\U0000017C', + "zeetrf;": '\U00002128', + "zeta;": '\U000003B6', + "zfr;": '\U0001D537', + "zhcy;": '\U00000436', + "zigrarr;": '\U000021DD', + "zopf;": '\U0001D56B', + "zscr;": '\U0001D4CF', + "zwj;": '\U0000200D', + "zwnj;": '\U0000200C', + "AElig": '\U000000C6', + "AMP": '\U00000026', + "Aacute": '\U000000C1', + "Acirc": '\U000000C2', + "Agrave": '\U000000C0', + "Aring": '\U000000C5', + "Atilde": '\U000000C3', + "Auml": '\U000000C4', + "COPY": '\U000000A9', + "Ccedil": '\U000000C7', + "ETH": '\U000000D0', + "Eacute": '\U000000C9', + "Ecirc": '\U000000CA', + "Egrave": '\U000000C8', + "Euml": '\U000000CB', + "GT": '\U0000003E', + "Iacute": '\U000000CD', + "Icirc": '\U000000CE', + "Igrave": '\U000000CC', + "Iuml": '\U000000CF', + "LT": '\U0000003C', + "Ntilde": '\U000000D1', + "Oacute": '\U000000D3', + "Ocirc": '\U000000D4', + "Ograve": '\U000000D2', + "Oslash": '\U000000D8', + "Otilde": '\U000000D5', + "Ouml": '\U000000D6', + "QUOT": '\U00000022', + "REG": '\U000000AE', + "THORN": '\U000000DE', + "Uacute": '\U000000DA', + "Ucirc": '\U000000DB', + "Ugrave": '\U000000D9', + "Uuml": '\U000000DC', + "Yacute": '\U000000DD', + "aacute": '\U000000E1', + "acirc": '\U000000E2', + "acute": '\U000000B4', + "aelig": '\U000000E6', + "agrave": '\U000000E0', + "amp": '\U00000026', + "aring": '\U000000E5', + "atilde": '\U000000E3', + "auml": '\U000000E4', + "brvbar": '\U000000A6', + "ccedil": '\U000000E7', + "cedil": '\U000000B8', + "cent": '\U000000A2', + "copy": '\U000000A9', + "curren": '\U000000A4', + "deg": '\U000000B0', + "divide": '\U000000F7', + "eacute": '\U000000E9', + "ecirc": '\U000000EA', + "egrave": '\U000000E8', + "eth": '\U000000F0', + "euml": '\U000000EB', + "frac12": '\U000000BD', + "frac14": '\U000000BC', + "frac34": '\U000000BE', + "gt": '\U0000003E', + "iacute": '\U000000ED', + "icirc": '\U000000EE', + "iexcl": '\U000000A1', + "igrave": '\U000000EC', + "iquest": '\U000000BF', + "iuml": '\U000000EF', + "laquo": '\U000000AB', + "lt": '\U0000003C', + "macr": '\U000000AF', + "micro": '\U000000B5', + "middot": '\U000000B7', + "nbsp": '\U000000A0', + "not": '\U000000AC', + "ntilde": '\U000000F1', + "oacute": '\U000000F3', + "ocirc": '\U000000F4', + "ograve": '\U000000F2', + "ordf": '\U000000AA', + "ordm": '\U000000BA', + "oslash": '\U000000F8', + "otilde": '\U000000F5', + "ouml": '\U000000F6', + "para": '\U000000B6', + "plusmn": '\U000000B1', + "pound": '\U000000A3', + "quot": '\U00000022', + "raquo": '\U000000BB', + "reg": '\U000000AE', + "sect": '\U000000A7', + "shy": '\U000000AD', + "sup1": '\U000000B9', + "sup2": '\U000000B2', + "sup3": '\U000000B3', + "szlig": '\U000000DF', + "thorn": '\U000000FE', + "times": '\U000000D7', + "uacute": '\U000000FA', + "ucirc": '\U000000FB', + "ugrave": '\U000000F9', + "uml": '\U000000A8', + "uuml": '\U000000FC', + "yacute": '\U000000FD', + "yen": '\U000000A5', + "yuml": '\U000000FF', +} + +// HTML entities that are two unicode codepoints. +var entity2 = map[string][2]rune{ + // TODO(nigeltao): Handle replacements that are wider than their names. + // "nLt;": {'\u226A', '\u20D2'}, + // "nGt;": {'\u226B', '\u20D2'}, + "NotEqualTilde;": {'\u2242', '\u0338'}, + "NotGreaterFullEqual;": {'\u2267', '\u0338'}, + "NotGreaterGreater;": {'\u226B', '\u0338'}, + "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'}, + "NotHumpDownHump;": {'\u224E', '\u0338'}, + "NotHumpEqual;": {'\u224F', '\u0338'}, + "NotLeftTriangleBar;": {'\u29CF', '\u0338'}, + "NotLessLess;": {'\u226A', '\u0338'}, + "NotLessSlantEqual;": {'\u2A7D', '\u0338'}, + "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'}, + "NotNestedLessLess;": {'\u2AA1', '\u0338'}, + "NotPrecedesEqual;": {'\u2AAF', '\u0338'}, + "NotRightTriangleBar;": {'\u29D0', '\u0338'}, + "NotSquareSubset;": {'\u228F', '\u0338'}, + "NotSquareSuperset;": {'\u2290', '\u0338'}, + "NotSubset;": {'\u2282', '\u20D2'}, + "NotSucceedsEqual;": {'\u2AB0', '\u0338'}, + "NotSucceedsTilde;": {'\u227F', '\u0338'}, + "NotSuperset;": {'\u2283', '\u20D2'}, + "ThickSpace;": {'\u205F', '\u200A'}, + "acE;": {'\u223E', '\u0333'}, + "bne;": {'\u003D', '\u20E5'}, + "bnequiv;": {'\u2261', '\u20E5'}, + "caps;": {'\u2229', '\uFE00'}, + "cups;": {'\u222A', '\uFE00'}, + "fjlig;": {'\u0066', '\u006A'}, + "gesl;": {'\u22DB', '\uFE00'}, + "gvertneqq;": {'\u2269', '\uFE00'}, + "gvnE;": {'\u2269', '\uFE00'}, + "lates;": {'\u2AAD', '\uFE00'}, + "lesg;": {'\u22DA', '\uFE00'}, + "lvertneqq;": {'\u2268', '\uFE00'}, + "lvnE;": {'\u2268', '\uFE00'}, + "nGg;": {'\u22D9', '\u0338'}, + "nGtv;": {'\u226B', '\u0338'}, + "nLl;": {'\u22D8', '\u0338'}, + "nLtv;": {'\u226A', '\u0338'}, + "nang;": {'\u2220', '\u20D2'}, + "napE;": {'\u2A70', '\u0338'}, + "napid;": {'\u224B', '\u0338'}, + "nbump;": {'\u224E', '\u0338'}, + "nbumpe;": {'\u224F', '\u0338'}, + "ncongdot;": {'\u2A6D', '\u0338'}, + "nedot;": {'\u2250', '\u0338'}, + "nesim;": {'\u2242', '\u0338'}, + "ngE;": {'\u2267', '\u0338'}, + "ngeqq;": {'\u2267', '\u0338'}, + "ngeqslant;": {'\u2A7E', '\u0338'}, + "nges;": {'\u2A7E', '\u0338'}, + "nlE;": {'\u2266', '\u0338'}, + "nleqq;": {'\u2266', '\u0338'}, + "nleqslant;": {'\u2A7D', '\u0338'}, + "nles;": {'\u2A7D', '\u0338'}, + "notinE;": {'\u22F9', '\u0338'}, + "notindot;": {'\u22F5', '\u0338'}, + "nparsl;": {'\u2AFD', '\u20E5'}, + "npart;": {'\u2202', '\u0338'}, + "npre;": {'\u2AAF', '\u0338'}, + "npreceq;": {'\u2AAF', '\u0338'}, + "nrarrc;": {'\u2933', '\u0338'}, + "nrarrw;": {'\u219D', '\u0338'}, + "nsce;": {'\u2AB0', '\u0338'}, + "nsubE;": {'\u2AC5', '\u0338'}, + "nsubset;": {'\u2282', '\u20D2'}, + "nsubseteqq;": {'\u2AC5', '\u0338'}, + "nsucceq;": {'\u2AB0', '\u0338'}, + "nsupE;": {'\u2AC6', '\u0338'}, + "nsupset;": {'\u2283', '\u20D2'}, + "nsupseteqq;": {'\u2AC6', '\u0338'}, + "nvap;": {'\u224D', '\u20D2'}, + "nvge;": {'\u2265', '\u20D2'}, + "nvgt;": {'\u003E', '\u20D2'}, + "nvle;": {'\u2264', '\u20D2'}, + "nvlt;": {'\u003C', '\u20D2'}, + "nvltrie;": {'\u22B4', '\u20D2'}, + "nvrtrie;": {'\u22B5', '\u20D2'}, + "nvsim;": {'\u223C', '\u20D2'}, + "race;": {'\u223D', '\u0331'}, + "smtes;": {'\u2AAC', '\uFE00'}, + "sqcaps;": {'\u2293', '\uFE00'}, + "sqcups;": {'\u2294', '\uFE00'}, + "varsubsetneq;": {'\u228A', '\uFE00'}, + "varsubsetneqq;": {'\u2ACB', '\uFE00'}, + "varsupsetneq;": {'\u228B', '\uFE00'}, + "varsupsetneqq;": {'\u2ACC', '\uFE00'}, + "vnsub;": {'\u2282', '\u20D2'}, + "vnsup;": {'\u2283', '\u20D2'}, + "vsubnE;": {'\u2ACB', '\uFE00'}, + "vsubne;": {'\u228A', '\uFE00'}, + "vsupnE;": {'\u2ACC', '\uFE00'}, + "vsupne;": {'\u228B', '\uFE00'}, +} diff --git a/Godeps/_workspace/src/golang.org/x/net/html/entity_test.go b/Godeps/_workspace/src/golang.org/x/net/html/entity_test.go new file mode 100644 index 0000000000..b53f866fa2 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/entity_test.go @@ -0,0 +1,29 @@ +// 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 html + +import ( + "testing" + "unicode/utf8" +) + +func TestEntityLength(t *testing.T) { + // We verify that the length of UTF-8 encoding of each value is <= 1 + len(key). + // The +1 comes from the leading "&". This property implies that the length of + // unescaped text is <= the length of escaped text. + for k, v := range entity { + if 1+len(k) < utf8.RuneLen(v) { + t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v)) + } + if len(k) > longestEntityWithoutSemicolon && k[len(k)-1] != ';' { + t.Errorf("entity name %s is %d characters, but longestEntityWithoutSemicolon=%d", k, len(k), longestEntityWithoutSemicolon) + } + } + for k, v := range entity2 { + if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) { + t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v[0]) + string(v[1])) + } + } +} diff --git a/Godeps/_workspace/src/golang.org/x/net/html/escape.go b/Godeps/_workspace/src/golang.org/x/net/html/escape.go new file mode 100644 index 0000000000..d856139620 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/escape.go @@ -0,0 +1,258 @@ +// 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 html + +import ( + "bytes" + "strings" + "unicode/utf8" +) + +// These replacements permit compatibility with old numeric entities that +// assumed Windows-1252 encoding. +// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference +var replacementTable = [...]rune{ + '\u20AC', // First entry is what 0x80 should be replaced with. + '\u0081', + '\u201A', + '\u0192', + '\u201E', + '\u2026', + '\u2020', + '\u2021', + '\u02C6', + '\u2030', + '\u0160', + '\u2039', + '\u0152', + '\u008D', + '\u017D', + '\u008F', + '\u0090', + '\u2018', + '\u2019', + '\u201C', + '\u201D', + '\u2022', + '\u2013', + '\u2014', + '\u02DC', + '\u2122', + '\u0161', + '\u203A', + '\u0153', + '\u009D', + '\u017E', + '\u0178', // Last entry is 0x9F. + // 0x00->'\uFFFD' is handled programmatically. + // 0x0D->'\u000D' is a no-op. +} + +// unescapeEntity reads an entity like "<" from b[src:] and writes the +// corresponding "<" to b[dst:], returning the incremented dst and src cursors. +// Precondition: b[src] == '&' && dst <= src. +// attribute should be true if parsing an attribute value. +func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { + // https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference + + // i starts at 1 because we already know that s[0] == '&'. + i, s := 1, b[src:] + + if len(s) <= 1 { + b[dst] = b[src] + return dst + 1, src + 1 + } + + if s[i] == '#' { + if len(s) <= 3 { // We need to have at least "&#.". + b[dst] = b[src] + return dst + 1, src + 1 + } + i++ + c := s[i] + hex := false + if c == 'x' || c == 'X' { + hex = true + i++ + } + + x := '\x00' + for i < len(s) { + c = s[i] + i++ + if hex { + if '0' <= c && c <= '9' { + x = 16*x + rune(c) - '0' + continue + } else if 'a' <= c && c <= 'f' { + x = 16*x + rune(c) - 'a' + 10 + continue + } else if 'A' <= c && c <= 'F' { + x = 16*x + rune(c) - 'A' + 10 + continue + } + } else if '0' <= c && c <= '9' { + x = 10*x + rune(c) - '0' + continue + } + if c != ';' { + i-- + } + break + } + + if i <= 3 { // No characters matched. + b[dst] = b[src] + return dst + 1, src + 1 + } + + if 0x80 <= x && x <= 0x9F { + // Replace characters from Windows-1252 with UTF-8 equivalents. + x = replacementTable[x-0x80] + } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF { + // Replace invalid characters with the replacement character. + x = '\uFFFD' + } + + return dst + utf8.EncodeRune(b[dst:], x), src + i + } + + // Consume the maximum number of characters possible, with the + // consumed characters matching one of the named references. + + for i < len(s) { + c := s[i] + i++ + // Lower-cased characters are more common in entities, so we check for them first. + if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' { + continue + } + if c != ';' { + i-- + } + break + } + + entityName := string(s[1:i]) + if entityName == "" { + // No-op. + } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' { + // No-op. + } else if x := entity[entityName]; x != 0 { + return dst + utf8.EncodeRune(b[dst:], x), src + i + } else if x := entity2[entityName]; x[0] != 0 { + dst1 := dst + utf8.EncodeRune(b[dst:], x[0]) + return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i + } else if !attribute { + maxLen := len(entityName) - 1 + if maxLen > longestEntityWithoutSemicolon { + maxLen = longestEntityWithoutSemicolon + } + for j := maxLen; j > 1; j-- { + if x := entity[entityName[:j]]; x != 0 { + return dst + utf8.EncodeRune(b[dst:], x), src + j + 1 + } + } + } + + dst1, src1 = dst+i, src+i + copy(b[dst:dst1], b[src:src1]) + return dst1, src1 +} + +// unescape unescapes b's entities in-place, so that "a<b" becomes "a': + esc = ">" + case '"': + // """ is shorter than """. + esc = """ + case '\r': + esc = " " + default: + panic("unrecognized escape character") + } + s = s[i+1:] + if _, err := w.WriteString(esc); err != nil { + return err + } + i = strings.IndexAny(s, escapedChars) + } + _, err := w.WriteString(s) + return err +} + +// EscapeString escapes special characters like "<" to become "<". It +// escapes only five such characters: <, >, &, ' and ". +// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't +// always true. +func EscapeString(s string) string { + if strings.IndexAny(s, escapedChars) == -1 { + return s + } + var buf bytes.Buffer + escape(&buf, s) + return buf.String() +} + +// UnescapeString unescapes entities like "<" to become "<". It unescapes a +// larger range of entities than EscapeString escapes. For example, "á" +// unescapes to "á", as does "á" and "&xE1;". +// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't +// always true. +func UnescapeString(s string) string { + for _, c := range s { + if c == '&' { + return string(unescape([]byte(s), false)) + } + } + return s +} diff --git a/Godeps/_workspace/src/golang.org/x/net/html/escape_test.go b/Godeps/_workspace/src/golang.org/x/net/html/escape_test.go new file mode 100644 index 0000000000..b405d4b4a7 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/escape_test.go @@ -0,0 +1,97 @@ +// 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 html + +import "testing" + +type unescapeTest struct { + // A short description of the test case. + desc string + // The HTML text. + html string + // The unescaped text. + unescaped string +} + +var unescapeTests = []unescapeTest{ + // Handle no entities. + { + "copy", + "A\ttext\nstring", + "A\ttext\nstring", + }, + // Handle simple named entities. + { + "simple", + "& > <", + "& > <", + }, + // Handle hitting the end of the string. + { + "stringEnd", + "& &", + "& &", + }, + // Handle entities with two codepoints. + { + "multiCodepoint", + "text ⋛︀ blah", + "text \u22db\ufe00 blah", + }, + // Handle decimal numeric entities. + { + "decimalEntity", + "Delta = Δ ", + "Delta = Δ ", + }, + // Handle hexadecimal numeric entities. + { + "hexadecimalEntity", + "Lambda = λ = λ ", + "Lambda = λ = λ ", + }, + // Handle numeric early termination. + { + "numericEnds", + "&# &#x €43 © = ©f = ©", + "&# &#x €43 © = ©f = ©", + }, + // Handle numeric ISO-8859-1 entity replacements. + { + "numericReplacements", + "Footnote‡", + "Footnote‡", + }, +} + +func TestUnescape(t *testing.T) { + for _, tt := range unescapeTests { + unescaped := UnescapeString(tt.html) + if unescaped != tt.unescaped { + t.Errorf("TestUnescape %s: want %q, got %q", tt.desc, tt.unescaped, unescaped) + } + } +} + +func TestUnescapeEscape(t *testing.T) { + ss := []string{ + ``, + `abc def`, + `a & b`, + `a&b`, + `a & b`, + `"`, + `"`, + `"<&>"`, + `"<&>"`, + `3&5==1 && 0<1, "0<1", a+acute=á`, + `The special characters are: <, >, &, ' and "`, + } + for _, s := range ss { + if got := UnescapeString(EscapeString(s)); got != s { + t.Errorf("got %q want %q", got, s) + } + } +} diff --git a/Godeps/_workspace/src/golang.org/x/net/html/example_test.go b/Godeps/_workspace/src/golang.org/x/net/html/example_test.go new file mode 100644 index 0000000000..0b06ed7730 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/example_test.go @@ -0,0 +1,40 @@ +// 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 example demonstrates parsing HTML data and walking the resulting tree. +package html_test + +import ( + "fmt" + "log" + "strings" + + "golang.org/x/net/html" +) + +func ExampleParse() { + s := `

Links:

` + doc, err := html.Parse(strings.NewReader(s)) + if err != nil { + log.Fatal(err) + } + 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" { + fmt.Println(a.Val) + break + } + } + } + for c := n.FirstChild; c != nil; c = c.NextSibling { + f(c) + } + } + f(doc) + // Output: + // foo + // /bar/baz +} diff --git a/Godeps/_workspace/src/golang.org/x/net/html/foreign.go b/Godeps/_workspace/src/golang.org/x/net/html/foreign.go new file mode 100644 index 0000000000..d3b3844099 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/foreign.go @@ -0,0 +1,226 @@ +// 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. + +package html + +import ( + "strings" +) + +func adjustAttributeNames(aa []Attribute, nameMap map[string]string) { + for i := range aa { + if newName, ok := nameMap[aa[i].Key]; ok { + aa[i].Key = newName + } + } +} + +func adjustForeignAttributes(aa []Attribute) { + for i, a := range aa { + if a.Key == "" || a.Key[0] != 'x' { + continue + } + switch a.Key { + case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show", + "xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink": + j := strings.Index(a.Key, ":") + aa[i].Namespace = a.Key[:j] + aa[i].Key = a.Key[j+1:] + } + } +} + +func htmlIntegrationPoint(n *Node) bool { + if n.Type != ElementNode { + return false + } + switch n.Namespace { + case "math": + if n.Data == "annotation-xml" { + for _, a := range n.Attr { + if a.Key == "encoding" { + val := strings.ToLower(a.Val) + if val == "text/html" || val == "application/xhtml+xml" { + return true + } + } + } + } + case "svg": + switch n.Data { + case "desc", "foreignObject", "title": + return true + } + } + return false +} + +func mathMLTextIntegrationPoint(n *Node) bool { + if n.Namespace != "math" { + return false + } + switch n.Data { + case "mi", "mo", "mn", "ms", "mtext": + return true + } + return false +} + +// Section 12.2.5.5. +var breakout = map[string]bool{ + "b": true, + "big": true, + "blockquote": true, + "body": true, + "br": true, + "center": true, + "code": true, + "dd": true, + "div": true, + "dl": true, + "dt": true, + "em": true, + "embed": true, + "h1": true, + "h2": true, + "h3": true, + "h4": true, + "h5": true, + "h6": true, + "head": true, + "hr": true, + "i": true, + "img": true, + "li": true, + "listing": true, + "menu": true, + "meta": true, + "nobr": true, + "ol": true, + "p": true, + "pre": true, + "ruby": true, + "s": true, + "small": true, + "span": true, + "strong": true, + "strike": true, + "sub": true, + "sup": true, + "table": true, + "tt": true, + "u": true, + "ul": true, + "var": true, +} + +// Section 12.2.5.5. +var svgTagNameAdjustments = map[string]string{ + "altglyph": "altGlyph", + "altglyphdef": "altGlyphDef", + "altglyphitem": "altGlyphItem", + "animatecolor": "animateColor", + "animatemotion": "animateMotion", + "animatetransform": "animateTransform", + "clippath": "clipPath", + "feblend": "feBlend", + "fecolormatrix": "feColorMatrix", + "fecomponenttransfer": "feComponentTransfer", + "fecomposite": "feComposite", + "feconvolvematrix": "feConvolveMatrix", + "fediffuselighting": "feDiffuseLighting", + "fedisplacementmap": "feDisplacementMap", + "fedistantlight": "feDistantLight", + "feflood": "feFlood", + "fefunca": "feFuncA", + "fefuncb": "feFuncB", + "fefuncg": "feFuncG", + "fefuncr": "feFuncR", + "fegaussianblur": "feGaussianBlur", + "feimage": "feImage", + "femerge": "feMerge", + "femergenode": "feMergeNode", + "femorphology": "feMorphology", + "feoffset": "feOffset", + "fepointlight": "fePointLight", + "fespecularlighting": "feSpecularLighting", + "fespotlight": "feSpotLight", + "fetile": "feTile", + "feturbulence": "feTurbulence", + "foreignobject": "foreignObject", + "glyphref": "glyphRef", + "lineargradient": "linearGradient", + "radialgradient": "radialGradient", + "textpath": "textPath", +} + +// Section 12.2.5.1 +var mathMLAttributeAdjustments = map[string]string{ + "definitionurl": "definitionURL", +} + +var svgAttributeAdjustments = map[string]string{ + "attributename": "attributeName", + "attributetype": "attributeType", + "basefrequency": "baseFrequency", + "baseprofile": "baseProfile", + "calcmode": "calcMode", + "clippathunits": "clipPathUnits", + "contentscripttype": "contentScriptType", + "contentstyletype": "contentStyleType", + "diffuseconstant": "diffuseConstant", + "edgemode": "edgeMode", + "externalresourcesrequired": "externalResourcesRequired", + "filterres": "filterRes", + "filterunits": "filterUnits", + "glyphref": "glyphRef", + "gradienttransform": "gradientTransform", + "gradientunits": "gradientUnits", + "kernelmatrix": "kernelMatrix", + "kernelunitlength": "kernelUnitLength", + "keypoints": "keyPoints", + "keysplines": "keySplines", + "keytimes": "keyTimes", + "lengthadjust": "lengthAdjust", + "limitingconeangle": "limitingConeAngle", + "markerheight": "markerHeight", + "markerunits": "markerUnits", + "markerwidth": "markerWidth", + "maskcontentunits": "maskContentUnits", + "maskunits": "maskUnits", + "numoctaves": "numOctaves", + "pathlength": "pathLength", + "patterncontentunits": "patternContentUnits", + "patterntransform": "patternTransform", + "patternunits": "patternUnits", + "pointsatx": "pointsAtX", + "pointsaty": "pointsAtY", + "pointsatz": "pointsAtZ", + "preservealpha": "preserveAlpha", + "preserveaspectratio": "preserveAspectRatio", + "primitiveunits": "primitiveUnits", + "refx": "refX", + "refy": "refY", + "repeatcount": "repeatCount", + "repeatdur": "repeatDur", + "requiredextensions": "requiredExtensions", + "requiredfeatures": "requiredFeatures", + "specularconstant": "specularConstant", + "specularexponent": "specularExponent", + "spreadmethod": "spreadMethod", + "startoffset": "startOffset", + "stddeviation": "stdDeviation", + "stitchtiles": "stitchTiles", + "surfacescale": "surfaceScale", + "systemlanguage": "systemLanguage", + "tablevalues": "tableValues", + "targetx": "targetX", + "targety": "targetY", + "textlength": "textLength", + "viewbox": "viewBox", + "viewtarget": "viewTarget", + "xchannelselector": "xChannelSelector", + "ychannelselector": "yChannelSelector", + "zoomandpan": "zoomAndPan", +} diff --git a/Godeps/_workspace/src/golang.org/x/net/html/node.go b/Godeps/_workspace/src/golang.org/x/net/html/node.go new file mode 100644 index 0000000000..26b657aec8 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/node.go @@ -0,0 +1,193 @@ +// 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. + +package html + +import ( + "golang.org/x/net/html/atom" +) + +// A NodeType is the type of a Node. +type NodeType uint32 + +const ( + ErrorNode NodeType = iota + TextNode + DocumentNode + ElementNode + CommentNode + DoctypeNode + scopeMarkerNode +) + +// Section 12.2.3.3 says "scope markers are inserted when entering applet +// elements, buttons, object elements, marquees, table cells, and table +// captions, and are used to prevent formatting from 'leaking'". +var scopeMarker = Node{Type: scopeMarkerNode} + +// A Node consists of a NodeType and some Data (tag name for element nodes, +// content for text) and are part of a tree of Nodes. Element nodes may also +// have a Namespace and contain a slice of Attributes. Data is unescaped, so +// that it looks like "a 0 { + return (*s)[i-1] + } + return nil +} + +// index returns the index of the top-most occurrence of n in the stack, or -1 +// if n is not present. +func (s *nodeStack) index(n *Node) int { + for i := len(*s) - 1; i >= 0; i-- { + if (*s)[i] == n { + return i + } + } + return -1 +} + +// insert inserts a node at the given index. +func (s *nodeStack) insert(i int, n *Node) { + (*s) = append(*s, nil) + copy((*s)[i+1:], (*s)[i:]) + (*s)[i] = n +} + +// remove removes a node from the stack. It is a no-op if n is not present. +func (s *nodeStack) remove(n *Node) { + i := s.index(n) + if i == -1 { + return + } + copy((*s)[i:], (*s)[i+1:]) + j := len(*s) - 1 + (*s)[j] = nil + *s = (*s)[:j] +} diff --git a/Godeps/_workspace/src/golang.org/x/net/html/node_test.go b/Godeps/_workspace/src/golang.org/x/net/html/node_test.go new file mode 100644 index 0000000000..471102f3a2 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/node_test.go @@ -0,0 +1,146 @@ +// 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 html + +import ( + "fmt" +) + +// checkTreeConsistency checks that a node and its descendants are all +// consistent in their parent/child/sibling relationships. +func checkTreeConsistency(n *Node) error { + return checkTreeConsistency1(n, 0) +} + +func checkTreeConsistency1(n *Node, depth int) error { + if depth == 1e4 { + return fmt.Errorf("html: tree looks like it contains a cycle") + } + if err := checkNodeConsistency(n); err != nil { + return err + } + for c := n.FirstChild; c != nil; c = c.NextSibling { + if err := checkTreeConsistency1(c, depth+1); err != nil { + return err + } + } + return nil +} + +// checkNodeConsistency checks that a node's parent/child/sibling relationships +// are consistent. +func checkNodeConsistency(n *Node) error { + if n == nil { + return nil + } + + nParent := 0 + for p := n.Parent; p != nil; p = p.Parent { + nParent++ + if nParent == 1e4 { + return fmt.Errorf("html: parent list looks like an infinite loop") + } + } + + nForward := 0 + for c := n.FirstChild; c != nil; c = c.NextSibling { + nForward++ + if nForward == 1e6 { + return fmt.Errorf("html: forward list of children looks like an infinite loop") + } + if c.Parent != n { + return fmt.Errorf("html: inconsistent child/parent relationship") + } + } + + nBackward := 0 + for c := n.LastChild; c != nil; c = c.PrevSibling { + nBackward++ + if nBackward == 1e6 { + return fmt.Errorf("html: backward list of children looks like an infinite loop") + } + if c.Parent != n { + return fmt.Errorf("html: inconsistent child/parent relationship") + } + } + + if n.Parent != nil { + if n.Parent == n { + return fmt.Errorf("html: inconsistent parent relationship") + } + if n.Parent == n.FirstChild { + return fmt.Errorf("html: inconsistent parent/first relationship") + } + if n.Parent == n.LastChild { + return fmt.Errorf("html: inconsistent parent/last relationship") + } + if n.Parent == n.PrevSibling { + return fmt.Errorf("html: inconsistent parent/prev relationship") + } + if n.Parent == n.NextSibling { + return fmt.Errorf("html: inconsistent parent/next relationship") + } + + parentHasNAsAChild := false + for c := n.Parent.FirstChild; c != nil; c = c.NextSibling { + if c == n { + parentHasNAsAChild = true + break + } + } + if !parentHasNAsAChild { + return fmt.Errorf("html: inconsistent parent/child relationship") + } + } + + if n.PrevSibling != nil && n.PrevSibling.NextSibling != n { + return fmt.Errorf("html: inconsistent prev/next relationship") + } + if n.NextSibling != nil && n.NextSibling.PrevSibling != n { + return fmt.Errorf("html: inconsistent next/prev relationship") + } + + if (n.FirstChild == nil) != (n.LastChild == nil) { + return fmt.Errorf("html: inconsistent first/last relationship") + } + if n.FirstChild != nil && n.FirstChild == n.LastChild { + // We have a sole child. + if n.FirstChild.PrevSibling != nil || n.FirstChild.NextSibling != nil { + return fmt.Errorf("html: inconsistent sole child's sibling relationship") + } + } + + seen := map[*Node]bool{} + + var last *Node + for c := n.FirstChild; c != nil; c = c.NextSibling { + if seen[c] { + return fmt.Errorf("html: inconsistent repeated child") + } + seen[c] = true + last = c + } + if last != n.LastChild { + return fmt.Errorf("html: inconsistent last relationship") + } + + var first *Node + for c := n.LastChild; c != nil; c = c.PrevSibling { + if !seen[c] { + return fmt.Errorf("html: inconsistent missing child") + } + delete(seen, c) + first = c + } + if first != n.FirstChild { + return fmt.Errorf("html: inconsistent first relationship") + } + + if len(seen) != 0 { + return fmt.Errorf("html: inconsistent forwards/backwards child list") + } + + return nil +} diff --git a/Godeps/_workspace/src/golang.org/x/net/html/parse.go b/Godeps/_workspace/src/golang.org/x/net/html/parse.go new file mode 100644 index 0000000000..be4b2bf5aa --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/parse.go @@ -0,0 +1,2094 @@ +// 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 html + +import ( + "errors" + "fmt" + "io" + "strings" + + a "golang.org/x/net/html/atom" +) + +// A parser implements the HTML5 parsing algorithm: +// https://html.spec.whatwg.org/multipage/syntax.html#tree-construction +type parser struct { + // tokenizer provides the tokens for the parser. + tokenizer *Tokenizer + // tok is the most recently read token. + tok Token + // Self-closing tags like
are treated as start tags, except that + // hasSelfClosingToken is set while they are being processed. + hasSelfClosingToken bool + // doc is the document root element. + doc *Node + // The stack of open elements (section 12.2.3.2) and active formatting + // elements (section 12.2.3.3). + oe, afe nodeStack + // Element pointers (section 12.2.3.4). + head, form *Node + // Other parsing state flags (section 12.2.3.5). + scripting, framesetOK bool + // im is the current insertion mode. + im insertionMode + // originalIM is the insertion mode to go back to after completing a text + // or inTableText insertion mode. + originalIM insertionMode + // fosterParenting is whether new elements should be inserted according to + // the foster parenting rules (section 12.2.5.3). + fosterParenting bool + // quirks is whether the parser is operating in "quirks mode." + quirks bool + // fragment is whether the parser is parsing an HTML fragment. + fragment bool + // context is the context element when parsing an HTML fragment + // (section 12.4). + context *Node +} + +func (p *parser) top() *Node { + if n := p.oe.top(); n != nil { + return n + } + return p.doc +} + +// Stop tags for use in popUntil. These come from section 12.2.3.2. +var ( + defaultScopeStopTags = map[string][]a.Atom{ + "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template}, + "math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext}, + "svg": {a.Desc, a.ForeignObject, a.Title}, + } +) + +type scope int + +const ( + defaultScope scope = iota + listItemScope + buttonScope + tableScope + tableRowScope + tableBodyScope + selectScope +) + +// popUntil pops the stack of open elements at the highest element whose tag +// is in matchTags, provided there is no higher element in the scope's stop +// tags (as defined in section 12.2.3.2). It returns whether or not there was +// such an element. If there was not, popUntil leaves the stack unchanged. +// +// For example, the set of stop tags for table scope is: "html", "table". If +// the stack was: +// ["html", "body", "font", "table", "b", "i", "u"] +// then popUntil(tableScope, "font") would return false, but +// popUntil(tableScope, "i") would return true and the stack would become: +// ["html", "body", "font", "table", "b"] +// +// If an element's tag is in both the stop tags and matchTags, then the stack +// will be popped and the function returns true (provided, of course, there was +// no higher element in the stack that was also in the stop tags). For example, +// popUntil(tableScope, "table") returns true and leaves: +// ["html", "body", "font"] +func (p *parser) popUntil(s scope, matchTags ...a.Atom) bool { + if i := p.indexOfElementInScope(s, matchTags...); i != -1 { + p.oe = p.oe[:i] + return true + } + return false +} + +// indexOfElementInScope returns the index in p.oe of the highest element whose +// tag is in matchTags that is in scope. If no matching element is in scope, it +// returns -1. +func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int { + for i := len(p.oe) - 1; i >= 0; i-- { + tagAtom := p.oe[i].DataAtom + if p.oe[i].Namespace == "" { + for _, t := range matchTags { + if t == tagAtom { + return i + } + } + switch s { + case defaultScope: + // No-op. + case listItemScope: + if tagAtom == a.Ol || tagAtom == a.Ul { + return -1 + } + case buttonScope: + if tagAtom == a.Button { + return -1 + } + case tableScope: + if tagAtom == a.Html || tagAtom == a.Table { + return -1 + } + case selectScope: + if tagAtom != a.Optgroup && tagAtom != a.Option { + return -1 + } + default: + panic("unreachable") + } + } + switch s { + case defaultScope, listItemScope, buttonScope: + for _, t := range defaultScopeStopTags[p.oe[i].Namespace] { + if t == tagAtom { + return -1 + } + } + } + } + return -1 +} + +// elementInScope is like popUntil, except that it doesn't modify the stack of +// open elements. +func (p *parser) elementInScope(s scope, matchTags ...a.Atom) bool { + return p.indexOfElementInScope(s, matchTags...) != -1 +} + +// clearStackToContext pops elements off the stack of open elements until a +// scope-defined element is found. +func (p *parser) clearStackToContext(s scope) { + for i := len(p.oe) - 1; i >= 0; i-- { + tagAtom := p.oe[i].DataAtom + switch s { + case tableScope: + if tagAtom == a.Html || tagAtom == a.Table { + p.oe = p.oe[:i+1] + return + } + case tableRowScope: + if tagAtom == a.Html || tagAtom == a.Tr { + p.oe = p.oe[:i+1] + return + } + case tableBodyScope: + if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead { + p.oe = p.oe[:i+1] + return + } + default: + panic("unreachable") + } + } +} + +// generateImpliedEndTags pops nodes off the stack of open elements as long as +// the top node has a tag name of dd, dt, li, option, optgroup, p, rp, or rt. +// If exceptions are specified, nodes with that name will not be popped off. +func (p *parser) generateImpliedEndTags(exceptions ...string) { + var i int +loop: + for i = len(p.oe) - 1; i >= 0; i-- { + n := p.oe[i] + if n.Type == ElementNode { + switch n.DataAtom { + case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt: + for _, except := range exceptions { + if n.Data == except { + break loop + } + } + continue + } + } + break + } + + p.oe = p.oe[:i+1] +} + +// addChild adds a child node n to the top element, and pushes n onto the stack +// of open elements if it is an element node. +func (p *parser) addChild(n *Node) { + if p.shouldFosterParent() { + p.fosterParent(n) + } else { + p.top().AppendChild(n) + } + + if n.Type == ElementNode { + p.oe = append(p.oe, n) + } +} + +// shouldFosterParent returns whether the next node to be added should be +// foster parented. +func (p *parser) shouldFosterParent() bool { + if p.fosterParenting { + switch p.top().DataAtom { + case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr: + return true + } + } + return false +} + +// fosterParent adds a child node according to the foster parenting rules. +// Section 12.2.5.3, "foster parenting". +func (p *parser) fosterParent(n *Node) { + var table, parent, prev *Node + var i int + for i = len(p.oe) - 1; i >= 0; i-- { + if p.oe[i].DataAtom == a.Table { + table = p.oe[i] + break + } + } + + if table == nil { + // The foster parent is the html element. + parent = p.oe[0] + } else { + parent = table.Parent + } + if parent == nil { + parent = p.oe[i-1] + } + + if table != nil { + prev = table.PrevSibling + } else { + prev = parent.LastChild + } + if prev != nil && prev.Type == TextNode && n.Type == TextNode { + prev.Data += n.Data + return + } + + parent.InsertBefore(n, table) +} + +// addText adds text to the preceding node if it is a text node, or else it +// calls addChild with a new text node. +func (p *parser) addText(text string) { + if text == "" { + return + } + + if p.shouldFosterParent() { + p.fosterParent(&Node{ + Type: TextNode, + Data: text, + }) + return + } + + t := p.top() + if n := t.LastChild; n != nil && n.Type == TextNode { + n.Data += text + return + } + p.addChild(&Node{ + Type: TextNode, + Data: text, + }) +} + +// addElement adds a child element based on the current token. +func (p *parser) addElement() { + p.addChild(&Node{ + Type: ElementNode, + DataAtom: p.tok.DataAtom, + Data: p.tok.Data, + Attr: p.tok.Attr, + }) +} + +// Section 12.2.3.3. +func (p *parser) addFormattingElement() { + tagAtom, attr := p.tok.DataAtom, p.tok.Attr + p.addElement() + + // Implement the Noah's Ark clause, but with three per family instead of two. + identicalElements := 0 +findIdenticalElements: + for i := len(p.afe) - 1; i >= 0; i-- { + n := p.afe[i] + if n.Type == scopeMarkerNode { + break + } + if n.Type != ElementNode { + continue + } + if n.Namespace != "" { + continue + } + if n.DataAtom != tagAtom { + continue + } + if len(n.Attr) != len(attr) { + continue + } + compareAttributes: + for _, t0 := range n.Attr { + for _, t1 := range attr { + if t0.Key == t1.Key && t0.Namespace == t1.Namespace && t0.Val == t1.Val { + // Found a match for this attribute, continue with the next attribute. + continue compareAttributes + } + } + // If we get here, there is no attribute that matches a. + // Therefore the element is not identical to the new one. + continue findIdenticalElements + } + + identicalElements++ + if identicalElements >= 3 { + p.afe.remove(n) + } + } + + p.afe = append(p.afe, p.top()) +} + +// Section 12.2.3.3. +func (p *parser) clearActiveFormattingElements() { + for { + n := p.afe.pop() + if len(p.afe) == 0 || n.Type == scopeMarkerNode { + return + } + } +} + +// Section 12.2.3.3. +func (p *parser) reconstructActiveFormattingElements() { + n := p.afe.top() + if n == nil { + return + } + if n.Type == scopeMarkerNode || p.oe.index(n) != -1 { + return + } + i := len(p.afe) - 1 + for n.Type != scopeMarkerNode && p.oe.index(n) == -1 { + if i == 0 { + i = -1 + break + } + i-- + n = p.afe[i] + } + for { + i++ + clone := p.afe[i].clone() + p.addChild(clone) + p.afe[i] = clone + if i == len(p.afe)-1 { + break + } + } +} + +// Section 12.2.4. +func (p *parser) acknowledgeSelfClosingTag() { + p.hasSelfClosingToken = false +} + +// An insertion mode (section 12.2.3.1) is the state transition function from +// a particular state in the HTML5 parser's state machine. It updates the +// parser's fields depending on parser.tok (where ErrorToken means EOF). +// It returns whether the token was consumed. +type insertionMode func(*parser) bool + +// setOriginalIM sets the insertion mode to return to after completing a text or +// inTableText insertion mode. +// Section 12.2.3.1, "using the rules for". +func (p *parser) setOriginalIM() { + if p.originalIM != nil { + panic("html: bad parser state: originalIM was set twice") + } + p.originalIM = p.im +} + +// Section 12.2.3.1, "reset the insertion mode". +func (p *parser) resetInsertionMode() { + for i := len(p.oe) - 1; i >= 0; i-- { + n := p.oe[i] + if i == 0 && p.context != nil { + n = p.context + } + + switch n.DataAtom { + case a.Select: + p.im = inSelectIM + case a.Td, a.Th: + p.im = inCellIM + case a.Tr: + p.im = inRowIM + case a.Tbody, a.Thead, a.Tfoot: + p.im = inTableBodyIM + case a.Caption: + p.im = inCaptionIM + case a.Colgroup: + p.im = inColumnGroupIM + case a.Table: + p.im = inTableIM + case a.Head: + p.im = inBodyIM + case a.Body: + p.im = inBodyIM + case a.Frameset: + p.im = inFramesetIM + case a.Html: + p.im = beforeHeadIM + default: + continue + } + return + } + p.im = inBodyIM +} + +const whitespace = " \t\r\n\f" + +// Section 12.2.5.4.1. +func initialIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } + case CommentToken: + p.doc.AppendChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + n, quirks := parseDoctype(p.tok.Data) + p.doc.AppendChild(n) + p.quirks = quirks + p.im = beforeHTMLIM + return true + } + p.quirks = true + p.im = beforeHTMLIM + return false +} + +// Section 12.2.5.4.2. +func beforeHTMLIM(p *parser) bool { + switch p.tok.Type { + case DoctypeToken: + // Ignore the token. + return true + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } + case StartTagToken: + if p.tok.DataAtom == a.Html { + p.addElement() + p.im = beforeHeadIM + return true + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Head, a.Body, a.Html, a.Br: + p.parseImpliedToken(StartTagToken, a.Html, a.Html.String()) + return false + default: + // Ignore the token. + return true + } + case CommentToken: + p.doc.AppendChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + } + p.parseImpliedToken(StartTagToken, a.Html, a.Html.String()) + return false +} + +// Section 12.2.5.4.3. +func beforeHeadIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } + case StartTagToken: + switch p.tok.DataAtom { + case a.Head: + p.addElement() + p.head = p.top() + p.im = inHeadIM + return true + case a.Html: + return inBodyIM(p) + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Head, a.Body, a.Html, a.Br: + p.parseImpliedToken(StartTagToken, a.Head, a.Head.String()) + return false + default: + // Ignore the token. + return true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + // Ignore the token. + return true + } + + p.parseImpliedToken(StartTagToken, a.Head, a.Head.String()) + return false +} + +// Section 12.2.5.4.4. +func inHeadIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + s := strings.TrimLeft(p.tok.Data, whitespace) + if len(s) < len(p.tok.Data) { + // Add the initial whitespace to the current node. + p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) + if s == "" { + return true + } + p.tok.Data = s + } + case StartTagToken: + switch p.tok.DataAtom { + case a.Html: + return inBodyIM(p) + case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta: + p.addElement() + p.oe.pop() + p.acknowledgeSelfClosingTag() + return true + case a.Script, a.Title, a.Noscript, a.Noframes, a.Style: + p.addElement() + p.setOriginalIM() + p.im = textIM + return true + case a.Head: + // Ignore the token. + return true + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Head: + n := p.oe.pop() + if n.DataAtom != a.Head { + panic("html: bad parser state: element not found, in the in-head insertion mode") + } + p.im = afterHeadIM + return true + case a.Body, a.Html, a.Br: + p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) + return false + default: + // Ignore the token. + return true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + // Ignore the token. + return true + } + + p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) + return false +} + +// Section 12.2.5.4.6. +func afterHeadIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + s := strings.TrimLeft(p.tok.Data, whitespace) + if len(s) < len(p.tok.Data) { + // Add the initial whitespace to the current node. + p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) + if s == "" { + return true + } + p.tok.Data = s + } + case StartTagToken: + switch p.tok.DataAtom { + case a.Html: + return inBodyIM(p) + case a.Body: + p.addElement() + p.framesetOK = false + p.im = inBodyIM + return true + case a.Frameset: + p.addElement() + p.im = inFramesetIM + return true + case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title: + p.oe = append(p.oe, p.head) + defer p.oe.remove(p.head) + return inHeadIM(p) + case a.Head: + // Ignore the token. + return true + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Body, a.Html, a.Br: + // Drop down to creating an implied tag. + default: + // Ignore the token. + return true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + // Ignore the token. + return true + } + + p.parseImpliedToken(StartTagToken, a.Body, a.Body.String()) + p.framesetOK = true + return false +} + +// copyAttributes copies attributes of src not found on dst to dst. +func copyAttributes(dst *Node, src Token) { + if len(src.Attr) == 0 { + return + } + attr := map[string]string{} + for _, t := range dst.Attr { + attr[t.Key] = t.Val + } + for _, t := range src.Attr { + if _, ok := attr[t.Key]; !ok { + dst.Attr = append(dst.Attr, t) + attr[t.Key] = t.Val + } + } +} + +// Section 12.2.5.4.7. +func inBodyIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + d := p.tok.Data + switch n := p.oe.top(); n.DataAtom { + case a.Pre, a.Listing: + if n.FirstChild == nil { + // Ignore a newline at the start of a
 block.
+				if d != "" && d[0] == '\r' {
+					d = d[1:]
+				}
+				if d != "" && d[0] == '\n' {
+					d = d[1:]
+				}
+			}
+		}
+		d = strings.Replace(d, "\x00", "", -1)
+		if d == "" {
+			return true
+		}
+		p.reconstructActiveFormattingElements()
+		p.addText(d)
+		if p.framesetOK && strings.TrimLeft(d, whitespace) != "" {
+			// There were non-whitespace characters inserted.
+			p.framesetOK = false
+		}
+	case StartTagToken:
+		switch p.tok.DataAtom {
+		case a.Html:
+			copyAttributes(p.oe[0], p.tok)
+		case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
+			return inHeadIM(p)
+		case a.Body:
+			if len(p.oe) >= 2 {
+				body := p.oe[1]
+				if body.Type == ElementNode && body.DataAtom == a.Body {
+					p.framesetOK = false
+					copyAttributes(body, p.tok)
+				}
+			}
+		case a.Frameset:
+			if !p.framesetOK || len(p.oe) < 2 || p.oe[1].DataAtom != a.Body {
+				// Ignore the token.
+				return true
+			}
+			body := p.oe[1]
+			if body.Parent != nil {
+				body.Parent.RemoveChild(body)
+			}
+			p.oe = p.oe[:1]
+			p.addElement()
+			p.im = inFramesetIM
+			return true
+		case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Menu, a.Nav, a.Ol, a.P, a.Section, a.Summary, a.Ul:
+			p.popUntil(buttonScope, a.P)
+			p.addElement()
+		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
+			p.popUntil(buttonScope, a.P)
+			switch n := p.top(); n.DataAtom {
+			case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
+				p.oe.pop()
+			}
+			p.addElement()
+		case a.Pre, a.Listing:
+			p.popUntil(buttonScope, a.P)
+			p.addElement()
+			// The newline, if any, will be dealt with by the TextToken case.
+			p.framesetOK = false
+		case a.Form:
+			if p.form == nil {
+				p.popUntil(buttonScope, a.P)
+				p.addElement()
+				p.form = p.top()
+			}
+		case a.Li:
+			p.framesetOK = false
+			for i := len(p.oe) - 1; i >= 0; i-- {
+				node := p.oe[i]
+				switch node.DataAtom {
+				case a.Li:
+					p.oe = p.oe[:i]
+				case a.Address, a.Div, a.P:
+					continue
+				default:
+					if !isSpecialElement(node) {
+						continue
+					}
+				}
+				break
+			}
+			p.popUntil(buttonScope, a.P)
+			p.addElement()
+		case a.Dd, a.Dt:
+			p.framesetOK = false
+			for i := len(p.oe) - 1; i >= 0; i-- {
+				node := p.oe[i]
+				switch node.DataAtom {
+				case a.Dd, a.Dt:
+					p.oe = p.oe[:i]
+				case a.Address, a.Div, a.P:
+					continue
+				default:
+					if !isSpecialElement(node) {
+						continue
+					}
+				}
+				break
+			}
+			p.popUntil(buttonScope, a.P)
+			p.addElement()
+		case a.Plaintext:
+			p.popUntil(buttonScope, a.P)
+			p.addElement()
+		case a.Button:
+			p.popUntil(defaultScope, a.Button)
+			p.reconstructActiveFormattingElements()
+			p.addElement()
+			p.framesetOK = false
+		case a.A:
+			for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- {
+				if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A {
+					p.inBodyEndTagFormatting(a.A)
+					p.oe.remove(n)
+					p.afe.remove(n)
+					break
+				}
+			}
+			p.reconstructActiveFormattingElements()
+			p.addFormattingElement()
+		case a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
+			p.reconstructActiveFormattingElements()
+			p.addFormattingElement()
+		case a.Nobr:
+			p.reconstructActiveFormattingElements()
+			if p.elementInScope(defaultScope, a.Nobr) {
+				p.inBodyEndTagFormatting(a.Nobr)
+				p.reconstructActiveFormattingElements()
+			}
+			p.addFormattingElement()
+		case a.Applet, a.Marquee, a.Object:
+			p.reconstructActiveFormattingElements()
+			p.addElement()
+			p.afe = append(p.afe, &scopeMarker)
+			p.framesetOK = false
+		case a.Table:
+			if !p.quirks {
+				p.popUntil(buttonScope, a.P)
+			}
+			p.addElement()
+			p.framesetOK = false
+			p.im = inTableIM
+			return true
+		case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr:
+			p.reconstructActiveFormattingElements()
+			p.addElement()
+			p.oe.pop()
+			p.acknowledgeSelfClosingTag()
+			if p.tok.DataAtom == a.Input {
+				for _, t := range p.tok.Attr {
+					if t.Key == "type" {
+						if strings.ToLower(t.Val) == "hidden" {
+							// Skip setting framesetOK = false
+							return true
+						}
+					}
+				}
+			}
+			p.framesetOK = false
+		case a.Param, a.Source, a.Track:
+			p.addElement()
+			p.oe.pop()
+			p.acknowledgeSelfClosingTag()
+		case a.Hr:
+			p.popUntil(buttonScope, a.P)
+			p.addElement()
+			p.oe.pop()
+			p.acknowledgeSelfClosingTag()
+			p.framesetOK = false
+		case a.Image:
+			p.tok.DataAtom = a.Img
+			p.tok.Data = a.Img.String()
+			return false
+		case a.Isindex:
+			if p.form != nil {
+				// Ignore the token.
+				return true
+			}
+			action := ""
+			prompt := "This is a searchable index. Enter search keywords: "
+			attr := []Attribute{{Key: "name", Val: "isindex"}}
+			for _, t := range p.tok.Attr {
+				switch t.Key {
+				case "action":
+					action = t.Val
+				case "name":
+					// Ignore the attribute.
+				case "prompt":
+					prompt = t.Val
+				default:
+					attr = append(attr, t)
+				}
+			}
+			p.acknowledgeSelfClosingTag()
+			p.popUntil(buttonScope, a.P)
+			p.parseImpliedToken(StartTagToken, a.Form, a.Form.String())
+			if action != "" {
+				p.form.Attr = []Attribute{{Key: "action", Val: action}}
+			}
+			p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
+			p.parseImpliedToken(StartTagToken, a.Label, a.Label.String())
+			p.addText(prompt)
+			p.addChild(&Node{
+				Type:     ElementNode,
+				DataAtom: a.Input,
+				Data:     a.Input.String(),
+				Attr:     attr,
+			})
+			p.oe.pop()
+			p.parseImpliedToken(EndTagToken, a.Label, a.Label.String())
+			p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
+			p.parseImpliedToken(EndTagToken, a.Form, a.Form.String())
+		case a.Textarea:
+			p.addElement()
+			p.setOriginalIM()
+			p.framesetOK = false
+			p.im = textIM
+		case a.Xmp:
+			p.popUntil(buttonScope, a.P)
+			p.reconstructActiveFormattingElements()
+			p.framesetOK = false
+			p.addElement()
+			p.setOriginalIM()
+			p.im = textIM
+		case a.Iframe:
+			p.framesetOK = false
+			p.addElement()
+			p.setOriginalIM()
+			p.im = textIM
+		case a.Noembed, a.Noscript:
+			p.addElement()
+			p.setOriginalIM()
+			p.im = textIM
+		case a.Select:
+			p.reconstructActiveFormattingElements()
+			p.addElement()
+			p.framesetOK = false
+			p.im = inSelectIM
+			return true
+		case a.Optgroup, a.Option:
+			if p.top().DataAtom == a.Option {
+				p.oe.pop()
+			}
+			p.reconstructActiveFormattingElements()
+			p.addElement()
+		case a.Rp, a.Rt:
+			if p.elementInScope(defaultScope, a.Ruby) {
+				p.generateImpliedEndTags()
+			}
+			p.addElement()
+		case a.Math, a.Svg:
+			p.reconstructActiveFormattingElements()
+			if p.tok.DataAtom == a.Math {
+				adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
+			} else {
+				adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
+			}
+			adjustForeignAttributes(p.tok.Attr)
+			p.addElement()
+			p.top().Namespace = p.tok.Data
+			if p.hasSelfClosingToken {
+				p.oe.pop()
+				p.acknowledgeSelfClosingTag()
+			}
+			return true
+		case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
+			// Ignore the token.
+		default:
+			p.reconstructActiveFormattingElements()
+			p.addElement()
+		}
+	case EndTagToken:
+		switch p.tok.DataAtom {
+		case a.Body:
+			if p.elementInScope(defaultScope, a.Body) {
+				p.im = afterBodyIM
+			}
+		case a.Html:
+			if p.elementInScope(defaultScope, a.Body) {
+				p.parseImpliedToken(EndTagToken, a.Body, a.Body.String())
+				return false
+			}
+			return true
+		case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
+			p.popUntil(defaultScope, p.tok.DataAtom)
+		case a.Form:
+			node := p.form
+			p.form = nil
+			i := p.indexOfElementInScope(defaultScope, a.Form)
+			if node == nil || i == -1 || p.oe[i] != node {
+				// Ignore the token.
+				return true
+			}
+			p.generateImpliedEndTags()
+			p.oe.remove(node)
+		case a.P:
+			if !p.elementInScope(buttonScope, a.P) {
+				p.parseImpliedToken(StartTagToken, a.P, a.P.String())
+			}
+			p.popUntil(buttonScope, a.P)
+		case a.Li:
+			p.popUntil(listItemScope, a.Li)
+		case a.Dd, a.Dt:
+			p.popUntil(defaultScope, p.tok.DataAtom)
+		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
+			p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6)
+		case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
+			p.inBodyEndTagFormatting(p.tok.DataAtom)
+		case a.Applet, a.Marquee, a.Object:
+			if p.popUntil(defaultScope, p.tok.DataAtom) {
+				p.clearActiveFormattingElements()
+			}
+		case a.Br:
+			p.tok.Type = StartTagToken
+			return false
+		default:
+			p.inBodyEndTagOther(p.tok.DataAtom)
+		}
+	case CommentToken:
+		p.addChild(&Node{
+			Type: CommentNode,
+			Data: p.tok.Data,
+		})
+	}
+
+	return true
+}
+
+func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
+	// This is the "adoption agency" algorithm, described at
+	// https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency
+
+	// TODO: this is a fairly literal line-by-line translation of that algorithm.
+	// Once the code successfully parses the comprehensive test suite, we should
+	// refactor this code to be more idiomatic.
+
+	// Steps 1-4. The outer loop.
+	for i := 0; i < 8; i++ {
+		// Step 5. Find the formatting element.
+		var formattingElement *Node
+		for j := len(p.afe) - 1; j >= 0; j-- {
+			if p.afe[j].Type == scopeMarkerNode {
+				break
+			}
+			if p.afe[j].DataAtom == tagAtom {
+				formattingElement = p.afe[j]
+				break
+			}
+		}
+		if formattingElement == nil {
+			p.inBodyEndTagOther(tagAtom)
+			return
+		}
+		feIndex := p.oe.index(formattingElement)
+		if feIndex == -1 {
+			p.afe.remove(formattingElement)
+			return
+		}
+		if !p.elementInScope(defaultScope, tagAtom) {
+			// Ignore the tag.
+			return
+		}
+
+		// Steps 9-10. Find the furthest block.
+		var furthestBlock *Node
+		for _, e := range p.oe[feIndex:] {
+			if isSpecialElement(e) {
+				furthestBlock = e
+				break
+			}
+		}
+		if furthestBlock == nil {
+			e := p.oe.pop()
+			for e != formattingElement {
+				e = p.oe.pop()
+			}
+			p.afe.remove(e)
+			return
+		}
+
+		// Steps 11-12. Find the common ancestor and bookmark node.
+		commonAncestor := p.oe[feIndex-1]
+		bookmark := p.afe.index(formattingElement)
+
+		// Step 13. The inner loop. Find the lastNode to reparent.
+		lastNode := furthestBlock
+		node := furthestBlock
+		x := p.oe.index(node)
+		// Steps 13.1-13.2
+		for j := 0; j < 3; j++ {
+			// Step 13.3.
+			x--
+			node = p.oe[x]
+			// Step 13.4 - 13.5.
+			if p.afe.index(node) == -1 {
+				p.oe.remove(node)
+				continue
+			}
+			// Step 13.6.
+			if node == formattingElement {
+				break
+			}
+			// Step 13.7.
+			clone := node.clone()
+			p.afe[p.afe.index(node)] = clone
+			p.oe[p.oe.index(node)] = clone
+			node = clone
+			// Step 13.8.
+			if lastNode == furthestBlock {
+				bookmark = p.afe.index(node) + 1
+			}
+			// Step 13.9.
+			if lastNode.Parent != nil {
+				lastNode.Parent.RemoveChild(lastNode)
+			}
+			node.AppendChild(lastNode)
+			// Step 13.10.
+			lastNode = node
+		}
+
+		// Step 14. Reparent lastNode to the common ancestor,
+		// or for misnested table nodes, to the foster parent.
+		if lastNode.Parent != nil {
+			lastNode.Parent.RemoveChild(lastNode)
+		}
+		switch commonAncestor.DataAtom {
+		case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
+			p.fosterParent(lastNode)
+		default:
+			commonAncestor.AppendChild(lastNode)
+		}
+
+		// Steps 15-17. Reparent nodes from the furthest block's children
+		// to a clone of the formatting element.
+		clone := formattingElement.clone()
+		reparentChildren(clone, furthestBlock)
+		furthestBlock.AppendChild(clone)
+
+		// Step 18. Fix up the list of active formatting elements.
+		if oldLoc := p.afe.index(formattingElement); oldLoc != -1 && oldLoc < bookmark {
+			// Move the bookmark with the rest of the list.
+			bookmark--
+		}
+		p.afe.remove(formattingElement)
+		p.afe.insert(bookmark, clone)
+
+		// Step 19. Fix up the stack of open elements.
+		p.oe.remove(formattingElement)
+		p.oe.insert(p.oe.index(furthestBlock)+1, clone)
+	}
+}
+
+// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
+// "Any other end tag" handling from 12.2.5.5 The rules for parsing tokens in foreign content
+// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
+func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
+	for i := len(p.oe) - 1; i >= 0; i-- {
+		if p.oe[i].DataAtom == tagAtom {
+			p.oe = p.oe[:i]
+			break
+		}
+		if isSpecialElement(p.oe[i]) {
+			break
+		}
+	}
+}
+
+// Section 12.2.5.4.8.
+func textIM(p *parser) bool {
+	switch p.tok.Type {
+	case ErrorToken:
+		p.oe.pop()
+	case TextToken:
+		d := p.tok.Data
+		if n := p.oe.top(); n.DataAtom == a.Textarea && n.FirstChild == nil {
+			// Ignore a newline at the start of a -->
+#errors
+#document
+| 
+|   
+|   
+|     -->
+#errors
+#document
+| 
+|   
+|   
+|     
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| 
+|   
+|   
+|     
+#errors
+Line: 1 Col: 9 Unexpected end tag (strong). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end tag (strong) after the (implied) root element.
+Line: 1 Col: 13 Unexpected end tag (b) after the (implied) root element.
+Line: 1 Col: 18 Unexpected end tag (em) after the (implied) root element.
+Line: 1 Col: 22 Unexpected end tag (i) after the (implied) root element.
+Line: 1 Col: 26 Unexpected end tag (u) after the (implied) root element.
+Line: 1 Col: 35 Unexpected end tag (strike) after the (implied) root element.
+Line: 1 Col: 39 Unexpected end tag (s) after the (implied) root element.
+Line: 1 Col: 47 Unexpected end tag (blink) after the (implied) root element.
+Line: 1 Col: 52 Unexpected end tag (tt) after the (implied) root element.
+Line: 1 Col: 58 Unexpected end tag (pre) after the (implied) root element.
+Line: 1 Col: 64 Unexpected end tag (big) after the (implied) root element.
+Line: 1 Col: 72 Unexpected end tag (small) after the (implied) root element.
+Line: 1 Col: 79 Unexpected end tag (font) after the (implied) root element.
+Line: 1 Col: 88 Unexpected end tag (select) after the (implied) root element.
+Line: 1 Col: 93 Unexpected end tag (h1) after the (implied) root element.
+Line: 1 Col: 98 Unexpected end tag (h2) after the (implied) root element.
+Line: 1 Col: 103 Unexpected end tag (h3) after the (implied) root element.
+Line: 1 Col: 108 Unexpected end tag (h4) after the (implied) root element.
+Line: 1 Col: 113 Unexpected end tag (h5) after the (implied) root element.
+Line: 1 Col: 118 Unexpected end tag (h6) after the (implied) root element.
+Line: 1 Col: 125 Unexpected end tag (body) after the (implied) root element.
+Line: 1 Col: 130 Unexpected end tag (br). Treated as br element.
+Line: 1 Col: 134 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 140 This element (img) has no end tag.
+Line: 1 Col: 148 Unexpected end tag (title). Ignored.
+Line: 1 Col: 155 Unexpected end tag (span). Ignored.
+Line: 1 Col: 163 Unexpected end tag (style). Ignored.
+Line: 1 Col: 172 Unexpected end tag (script). Ignored.
+Line: 1 Col: 180 Unexpected end tag (table). Ignored.
+Line: 1 Col: 185 Unexpected end tag (th). Ignored.
+Line: 1 Col: 190 Unexpected end tag (td). Ignored.
+Line: 1 Col: 195 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 203 This element (frame) has no end tag.
+Line: 1 Col: 210 This element (area) has no end tag.
+Line: 1 Col: 217 Unexpected end tag (link). Ignored.
+Line: 1 Col: 225 This element (param) has no end tag.
+Line: 1 Col: 230 This element (hr) has no end tag.
+Line: 1 Col: 238 This element (input) has no end tag.
+Line: 1 Col: 244 Unexpected end tag (col). Ignored.
+Line: 1 Col: 251 Unexpected end tag (base). Ignored.
+Line: 1 Col: 258 Unexpected end tag (meta). Ignored.
+Line: 1 Col: 269 This element (basefont) has no end tag.
+Line: 1 Col: 279 This element (bgsound) has no end tag.
+Line: 1 Col: 287 This element (embed) has no end tag.
+Line: 1 Col: 296 This element (spacer) has no end tag.
+Line: 1 Col: 300 Unexpected end tag (p). Ignored.
+Line: 1 Col: 305 End tag (dd) seen too early. Expected other end tag.
+Line: 1 Col: 310 End tag (dt) seen too early. Expected other end tag.
+Line: 1 Col: 320 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 331 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 339 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 347 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 355 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 365 End tag (address) seen too early. Expected other end tag.
+Line: 1 Col: 378 End tag (blockquote) seen too early. Expected other end tag.
+Line: 1 Col: 387 End tag (center) seen too early. Expected other end tag.
+Line: 1 Col: 393 Unexpected end tag (dir). Ignored.
+Line: 1 Col: 399 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 404 End tag (dl) seen too early. Expected other end tag.
+Line: 1 Col: 415 End tag (fieldset) seen too early. Expected other end tag.
+Line: 1 Col: 425 End tag (listing) seen too early. Expected other end tag.
+Line: 1 Col: 432 End tag (menu) seen too early. Expected other end tag.
+Line: 1 Col: 437 End tag (ol) seen too early. Expected other end tag.
+Line: 1 Col: 442 End tag (ul) seen too early. Expected other end tag.
+Line: 1 Col: 447 End tag (li) seen too early. Expected other end tag.
+Line: 1 Col: 454 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 460 This element (wbr) has no end tag.
+Line: 1 Col: 476 End tag (button) seen too early. Expected other end tag.
+Line: 1 Col: 486 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 495 End tag (object) seen too early. Expected other end tag.
+Line: 1 Col: 513 Unexpected end tag (html). Ignored.
+Line: 1 Col: 513 Unexpected end tag (frameset). Ignored.
+Line: 1 Col: 520 Unexpected end tag (head). Ignored.
+Line: 1 Col: 529 Unexpected end tag (iframe). Ignored.
+Line: 1 Col: 537 This element (image) has no end tag.
+Line: 1 Col: 547 This element (isindex) has no end tag.
+Line: 1 Col: 557 Unexpected end tag (noembed). Ignored.
+Line: 1 Col: 568 Unexpected end tag (noframes). Ignored.
+Line: 1 Col: 579 Unexpected end tag (noscript). Ignored.
+Line: 1 Col: 590 Unexpected end tag (optgroup). Ignored.
+Line: 1 Col: 599 Unexpected end tag (option). Ignored.
+Line: 1 Col: 611 Unexpected end tag (plaintext). Ignored.
+Line: 1 Col: 622 Unexpected end tag (textarea). Ignored.
+#document
+| 
+|   
+|   
+|     
+|

+ +#data +

+#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end tag (strong) in table context caused voodoo mode. +Line: 1 Col: 20 End tag (strong) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 24 Unexpected end tag (b) in table context caused voodoo mode. +Line: 1 Col: 24 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 29 Unexpected end tag (em) in table context caused voodoo mode. +Line: 1 Col: 29 End tag (em) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 33 Unexpected end tag (i) in table context caused voodoo mode. +Line: 1 Col: 33 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 37 Unexpected end tag (u) in table context caused voodoo mode. +Line: 1 Col: 37 End tag (u) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 46 Unexpected end tag (strike) in table context caused voodoo mode. +Line: 1 Col: 46 End tag (strike) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 50 Unexpected end tag (s) in table context caused voodoo mode. +Line: 1 Col: 50 End tag (s) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 58 Unexpected end tag (blink) in table context caused voodoo mode. +Line: 1 Col: 58 Unexpected end tag (blink). Ignored. +Line: 1 Col: 63 Unexpected end tag (tt) in table context caused voodoo mode. +Line: 1 Col: 63 End tag (tt) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 69 Unexpected end tag (pre) in table context caused voodoo mode. +Line: 1 Col: 69 End tag (pre) seen too early. Expected other end tag. +Line: 1 Col: 75 Unexpected end tag (big) in table context caused voodoo mode. +Line: 1 Col: 75 End tag (big) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 83 Unexpected end tag (small) in table context caused voodoo mode. +Line: 1 Col: 83 End tag (small) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 90 Unexpected end tag (font) in table context caused voodoo mode. +Line: 1 Col: 90 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 99 Unexpected end tag (select) in table context caused voodoo mode. +Line: 1 Col: 99 Unexpected end tag (select). Ignored. +Line: 1 Col: 104 Unexpected end tag (h1) in table context caused voodoo mode. +Line: 1 Col: 104 End tag (h1) seen too early. Expected other end tag. +Line: 1 Col: 109 Unexpected end tag (h2) in table context caused voodoo mode. +Line: 1 Col: 109 End tag (h2) seen too early. Expected other end tag. +Line: 1 Col: 114 Unexpected end tag (h3) in table context caused voodoo mode. +Line: 1 Col: 114 End tag (h3) seen too early. Expected other end tag. +Line: 1 Col: 119 Unexpected end tag (h4) in table context caused voodoo mode. +Line: 1 Col: 119 End tag (h4) seen too early. Expected other end tag. +Line: 1 Col: 124 Unexpected end tag (h5) in table context caused voodoo mode. +Line: 1 Col: 124 End tag (h5) seen too early. Expected other end tag. +Line: 1 Col: 129 Unexpected end tag (h6) in table context caused voodoo mode. +Line: 1 Col: 129 End tag (h6) seen too early. Expected other end tag. +Line: 1 Col: 136 Unexpected end tag (body) in the table row phase. Ignored. +Line: 1 Col: 141 Unexpected end tag (br) in table context caused voodoo mode. +Line: 1 Col: 141 Unexpected end tag (br). Treated as br element. +Line: 1 Col: 145 Unexpected end tag (a) in table context caused voodoo mode. +Line: 1 Col: 145 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 151 Unexpected end tag (img) in table context caused voodoo mode. +Line: 1 Col: 151 This element (img) has no end tag. +Line: 1 Col: 159 Unexpected end tag (title) in table context caused voodoo mode. +Line: 1 Col: 159 Unexpected end tag (title). Ignored. +Line: 1 Col: 166 Unexpected end tag (span) in table context caused voodoo mode. +Line: 1 Col: 166 Unexpected end tag (span). Ignored. +Line: 1 Col: 174 Unexpected end tag (style) in table context caused voodoo mode. +Line: 1 Col: 174 Unexpected end tag (style). Ignored. +Line: 1 Col: 183 Unexpected end tag (script) in table context caused voodoo mode. +Line: 1 Col: 183 Unexpected end tag (script). Ignored. +Line: 1 Col: 196 Unexpected end tag (th). Ignored. +Line: 1 Col: 201 Unexpected end tag (td). Ignored. +Line: 1 Col: 206 Unexpected end tag (tr). Ignored. +Line: 1 Col: 214 This element (frame) has no end tag. +Line: 1 Col: 221 This element (area) has no end tag. +Line: 1 Col: 228 Unexpected end tag (link). Ignored. +Line: 1 Col: 236 This element (param) has no end tag. +Line: 1 Col: 241 This element (hr) has no end tag. +Line: 1 Col: 249 This element (input) has no end tag. +Line: 1 Col: 255 Unexpected end tag (col). Ignored. +Line: 1 Col: 262 Unexpected end tag (base). Ignored. +Line: 1 Col: 269 Unexpected end tag (meta). Ignored. +Line: 1 Col: 280 This element (basefont) has no end tag. +Line: 1 Col: 290 This element (bgsound) has no end tag. +Line: 1 Col: 298 This element (embed) has no end tag. +Line: 1 Col: 307 This element (spacer) has no end tag. +Line: 1 Col: 311 Unexpected end tag (p). Ignored. +Line: 1 Col: 316 End tag (dd) seen too early. Expected other end tag. +Line: 1 Col: 321 End tag (dt) seen too early. Expected other end tag. +Line: 1 Col: 331 Unexpected end tag (caption). Ignored. +Line: 1 Col: 342 Unexpected end tag (colgroup). Ignored. +Line: 1 Col: 350 Unexpected end tag (tbody). Ignored. +Line: 1 Col: 358 Unexpected end tag (tfoot). Ignored. +Line: 1 Col: 366 Unexpected end tag (thead). Ignored. +Line: 1 Col: 376 End tag (address) seen too early. Expected other end tag. +Line: 1 Col: 389 End tag (blockquote) seen too early. Expected other end tag. +Line: 1 Col: 398 End tag (center) seen too early. Expected other end tag. +Line: 1 Col: 404 Unexpected end tag (dir). Ignored. +Line: 1 Col: 410 End tag (div) seen too early. Expected other end tag. +Line: 1 Col: 415 End tag (dl) seen too early. Expected other end tag. +Line: 1 Col: 426 End tag (fieldset) seen too early. Expected other end tag. +Line: 1 Col: 436 End tag (listing) seen too early. Expected other end tag. +Line: 1 Col: 443 End tag (menu) seen too early. Expected other end tag. +Line: 1 Col: 448 End tag (ol) seen too early. Expected other end tag. +Line: 1 Col: 453 End tag (ul) seen too early. Expected other end tag. +Line: 1 Col: 458 End tag (li) seen too early. Expected other end tag. +Line: 1 Col: 465 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 471 This element (wbr) has no end tag. +Line: 1 Col: 487 End tag (button) seen too early. Expected other end tag. +Line: 1 Col: 497 End tag (marquee) seen too early. Expected other end tag. +Line: 1 Col: 506 End tag (object) seen too early. Expected other end tag. +Line: 1 Col: 524 Unexpected end tag (html). Ignored. +Line: 1 Col: 524 Unexpected end tag (frameset). Ignored. +Line: 1 Col: 531 Unexpected end tag (head). Ignored. +Line: 1 Col: 540 Unexpected end tag (iframe). Ignored. +Line: 1 Col: 548 This element (image) has no end tag. +Line: 1 Col: 558 This element (isindex) has no end tag. +Line: 1 Col: 568 Unexpected end tag (noembed). Ignored. +Line: 1 Col: 579 Unexpected end tag (noframes). Ignored. +Line: 1 Col: 590 Unexpected end tag (noscript). Ignored. +Line: 1 Col: 601 Unexpected end tag (optgroup). Ignored. +Line: 1 Col: 610 Unexpected end tag (option). Ignored. +Line: 1 Col: 622 Unexpected end tag (plaintext). Ignored. +Line: 1 Col: 633 Unexpected end tag (textarea). Ignored. +#document +| +| +| +|
+| +| +| +|

+ +#data + +#errors +Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE. +Line: 1 Col: 10 Expected closing tag. Unexpected end of file. +#document +| +| +| diff --git a/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests10.dat b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests10.dat new file mode 100644 index 0000000000..4f8df86f20 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests10.dat @@ -0,0 +1,799 @@ +#data + +#errors +#document +| +| +| +| +| + +#data +a +#errors +29: Bogus comment +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| + +#data + +#errors +35: Stray “svg†start tag. +42: Stray end tag “svg†+#document +| +| +| +| +| +#errors +43: Stray “svg†start tag. +50: Stray end tag “svg†+#document +| +| +| +| +|

+#errors +34: Start tag “svg†seen in “tableâ€. +41: Stray end tag “svgâ€. +#document +| +| +| +| +| +| + +#data +
foo
+#errors +34: Start tag “svg†seen in “tableâ€. +46: Stray end tag “gâ€. +53: Stray end tag “svgâ€. +#document +| +| +| +| +| +| +| "foo" +| + +#data +
foobar
+#errors +34: Start tag “svg†seen in “tableâ€. +46: Stray end tag “gâ€. +58: Stray end tag “gâ€. +65: Stray end tag “svgâ€. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +| + +#data +
foobar
+#errors +41: Start tag “svg†seen in “tableâ€. +53: Stray end tag “gâ€. +65: Stray end tag “gâ€. +72: Stray end tag “svgâ€. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +| +| + +#data +
foobar
+#errors +45: Start tag “svg†seen in “tableâ€. +57: Stray end tag “gâ€. +69: Stray end tag “gâ€. +76: Stray end tag “svgâ€. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +| +| +| + +#data +
foobar
+#errors +#document +| +| +| +| +| +| +| +|
+| +| +| "foo" +| +| "bar" + +#data +
foobar

baz

+#errors +#document +| +| +| +| +| +| +| +|
+| +| +| "foo" +| +| "bar" +|

+| "baz" + +#data +
foobar

baz

+#errors +#document +| +| +| +| +| +|
+| +| +| "foo" +| +| "bar" +|

+| "baz" + +#data +
foobar

baz

quux +#errors +70: HTML start tag “p†in a foreign namespace context. +81: “table†closed but “caption†was still open. +#document +| +| +| +| +| +|
+| +| +| "foo" +| +| "bar" +|

+| "baz" +|

+| "quux" + +#data +
foobarbaz

quux +#errors +78: “table†closed but “caption†was still open. +78: Unclosed elements on stack. +#document +| +| +| +| +| +|
+| +| +| "foo" +| +| "bar" +| "baz" +|

+| "quux" + +#data +foobar

baz

quux +#errors +44: Start tag “svg†seen in “tableâ€. +56: Stray end tag “gâ€. +68: Stray end tag “gâ€. +71: HTML start tag “p†in a foreign namespace context. +71: Start tag “p†seen in “tableâ€. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +|

+| "baz" +| +| +|

+| "quux" + +#data +

quux +#errors +50: Stray “svg†start tag. +54: Stray “g†start tag. +62: Stray end tag “g†+66: Stray “g†start tag. +74: Stray end tag “g†+77: Stray “p†start tag. +88: “table†end tag with “select†open. +#document +| +| +| +| +| +| +| +|
+|

quux +#errors +36: Start tag “select†seen in “tableâ€. +42: Stray “svg†start tag. +46: Stray “g†start tag. +54: Stray end tag “g†+58: Stray “g†start tag. +66: Stray end tag “g†+69: Stray “p†start tag. +80: “table†end tag with “select†open. +#document +| +| +| +| +| +|

+| "quux" + +#data +foobar

baz +#errors +41: Stray “svg†start tag. +68: HTML start tag “p†in a foreign namespace context. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +|

+| "baz" + +#data +foobar

baz +#errors +34: Stray “svg†start tag. +61: HTML start tag “p†in a foreign namespace context. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +|

+| "baz" + +#data +

+#errors +31: Stray “svg†start tag. +35: Stray “g†start tag. +40: Stray end tag “g†+44: Stray “g†start tag. +49: Stray end tag “g†+52: Stray “p†start tag. +58: Stray “span†start tag. +58: End of file seen and there were open elements. +#document +| +| +| +| + +#data +

+#errors +42: Stray “svg†start tag. +46: Stray “g†start tag. +51: Stray end tag “g†+55: Stray “g†start tag. +60: Stray end tag “g†+63: Stray “p†start tag. +69: Stray “span†start tag. +#document +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| xlink:href="foo" +| +| xlink href="foo" + +#data + +#errors +#document +| +| +| +| +| xlink:href="foo" +| xml:lang="en" +| +| +| xlink href="foo" +| xml lang="en" + +#data + +#errors +#document +| +| +| +| +| xlink:href="foo" +| xml:lang="en" +| +| +| xlink href="foo" +| xml lang="en" + +#data +bar +#errors +#document +| +| +| +| +| xlink:href="foo" +| xml:lang="en" +| +| +| xlink href="foo" +| xml lang="en" +| "bar" + +#data + +#errors +#document +| +| +| +| + +#data +

a +#errors +#document +| +| +| +|
+| +| "a" + +#data +
a +#errors +#document +| +| +| +|
+| +| +| "a" + +#data +
+#errors +#document +| +| +| +|
+| +| +| + +#data +
a +#errors +#document +| +| +| +|
+| +| +| +| +| "a" + +#data +

a +#errors +#document +| +| +| +|

+| +| +| +|

+| "a" + +#data +
    a +#errors +40: HTML start tag “ul†in a foreign namespace context. +41: End of file in a foreign namespace context. +#document +| +| +| +| +| +| +|
    +| +|
      +| "a" + +#data +
        a +#errors +35: HTML start tag “ul†in a foreign namespace context. +36: End of file in a foreign namespace context. +#document +| +| +| +| +| +| +| +|
          +| "a" + +#data +

          +#errors +#document +| +| +| +| +|

          +| +| +|

          + +#data +

          +#errors +#document +| +| +| +| +|

          +| +| +|

          + +#data +

          +#errors +#document +| +| +| +|

          +| +| +| +|

          +|

          + +#data +
          +#errors +#document +| +| +| +| +| +|
          +| +|
          +| +| + +#data +
          +#errors +#document +| +| +| +| +| +| +| +|
          +|
          +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data +

+#errors +#document +| +| +| +| +|
+| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| + +#data +
+#errors +#document +| +| +| +| +| +| +| +|
+| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| diff --git a/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests11.dat b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests11.dat new file mode 100644 index 0000000000..638cde479f --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests11.dat @@ -0,0 +1,482 @@ +#data + +#errors +#document +| +| +| +| +| +| attributeName="" +| attributeType="" +| baseFrequency="" +| baseProfile="" +| calcMode="" +| clipPathUnits="" +| contentScriptType="" +| contentStyleType="" +| diffuseConstant="" +| edgeMode="" +| externalResourcesRequired="" +| filterRes="" +| filterUnits="" +| glyphRef="" +| gradientTransform="" +| gradientUnits="" +| kernelMatrix="" +| kernelUnitLength="" +| keyPoints="" +| keySplines="" +| keyTimes="" +| lengthAdjust="" +| limitingConeAngle="" +| markerHeight="" +| markerUnits="" +| markerWidth="" +| maskContentUnits="" +| maskUnits="" +| numOctaves="" +| pathLength="" +| patternContentUnits="" +| patternTransform="" +| patternUnits="" +| pointsAtX="" +| pointsAtY="" +| pointsAtZ="" +| preserveAlpha="" +| preserveAspectRatio="" +| primitiveUnits="" +| refX="" +| refY="" +| repeatCount="" +| repeatDur="" +| requiredExtensions="" +| requiredFeatures="" +| specularConstant="" +| specularExponent="" +| spreadMethod="" +| startOffset="" +| stdDeviation="" +| stitchTiles="" +| surfaceScale="" +| systemLanguage="" +| tableValues="" +| targetX="" +| targetY="" +| textLength="" +| viewBox="" +| viewTarget="" +| xChannelSelector="" +| yChannelSelector="" +| zoomAndPan="" + +#data + +#errors +#document +| +| +| +| +| +| attributeName="" +| attributeType="" +| baseFrequency="" +| baseProfile="" +| calcMode="" +| clipPathUnits="" +| contentScriptType="" +| contentStyleType="" +| diffuseConstant="" +| edgeMode="" +| externalResourcesRequired="" +| filterRes="" +| filterUnits="" +| glyphRef="" +| gradientTransform="" +| gradientUnits="" +| kernelMatrix="" +| kernelUnitLength="" +| keyPoints="" +| keySplines="" +| keyTimes="" +| lengthAdjust="" +| limitingConeAngle="" +| markerHeight="" +| markerUnits="" +| markerWidth="" +| maskContentUnits="" +| maskUnits="" +| numOctaves="" +| pathLength="" +| patternContentUnits="" +| patternTransform="" +| patternUnits="" +| pointsAtX="" +| pointsAtY="" +| pointsAtZ="" +| preserveAlpha="" +| preserveAspectRatio="" +| primitiveUnits="" +| refX="" +| refY="" +| repeatCount="" +| repeatDur="" +| requiredExtensions="" +| requiredFeatures="" +| specularConstant="" +| specularExponent="" +| spreadMethod="" +| startOffset="" +| stdDeviation="" +| stitchTiles="" +| surfaceScale="" +| systemLanguage="" +| tableValues="" +| targetX="" +| targetY="" +| textLength="" +| viewBox="" +| viewTarget="" +| xChannelSelector="" +| yChannelSelector="" +| zoomAndPan="" + +#data + +#errors +#document +| +| +| +| +| +| attributeName="" +| attributeType="" +| baseFrequency="" +| baseProfile="" +| calcMode="" +| clipPathUnits="" +| contentScriptType="" +| contentStyleType="" +| diffuseConstant="" +| edgeMode="" +| externalResourcesRequired="" +| filterRes="" +| filterUnits="" +| glyphRef="" +| gradientTransform="" +| gradientUnits="" +| kernelMatrix="" +| kernelUnitLength="" +| keyPoints="" +| keySplines="" +| keyTimes="" +| lengthAdjust="" +| limitingConeAngle="" +| markerHeight="" +| markerUnits="" +| markerWidth="" +| maskContentUnits="" +| maskUnits="" +| numOctaves="" +| pathLength="" +| patternContentUnits="" +| patternTransform="" +| patternUnits="" +| pointsAtX="" +| pointsAtY="" +| pointsAtZ="" +| preserveAlpha="" +| preserveAspectRatio="" +| primitiveUnits="" +| refX="" +| refY="" +| repeatCount="" +| repeatDur="" +| requiredExtensions="" +| requiredFeatures="" +| specularConstant="" +| specularExponent="" +| spreadMethod="" +| startOffset="" +| stdDeviation="" +| stitchTiles="" +| surfaceScale="" +| systemLanguage="" +| tableValues="" +| targetX="" +| targetY="" +| textLength="" +| viewBox="" +| viewTarget="" +| xChannelSelector="" +| yChannelSelector="" +| zoomAndPan="" + +#data + +#errors +#document +| +| +| +| +| +| attributename="" +| attributetype="" +| basefrequency="" +| baseprofile="" +| calcmode="" +| clippathunits="" +| contentscripttype="" +| contentstyletype="" +| diffuseconstant="" +| edgemode="" +| externalresourcesrequired="" +| filterres="" +| filterunits="" +| glyphref="" +| gradienttransform="" +| gradientunits="" +| kernelmatrix="" +| kernelunitlength="" +| keypoints="" +| keysplines="" +| keytimes="" +| lengthadjust="" +| limitingconeangle="" +| markerheight="" +| markerunits="" +| markerwidth="" +| maskcontentunits="" +| maskunits="" +| numoctaves="" +| pathlength="" +| patterncontentunits="" +| patterntransform="" +| patternunits="" +| pointsatx="" +| pointsaty="" +| pointsatz="" +| preservealpha="" +| preserveaspectratio="" +| primitiveunits="" +| refx="" +| refy="" +| repeatcount="" +| repeatdur="" +| requiredextensions="" +| requiredfeatures="" +| specularconstant="" +| specularexponent="" +| spreadmethod="" +| startoffset="" +| stddeviation="" +| stitchtiles="" +| surfacescale="" +| systemlanguage="" +| tablevalues="" +| targetx="" +| targety="" +| textlength="" +| viewbox="" +| viewtarget="" +| xchannelselector="" +| ychannelselector="" +| zoomandpan="" + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| diff --git a/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests12.dat b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests12.dat new file mode 100644 index 0000000000..63107d277b --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests12.dat @@ -0,0 +1,62 @@ +#data +

foobazeggs

spam

quuxbar +#errors +#document +| +| +| +| +|

+| "foo" +| +| +| +| "baz" +| +| +| +| +| "eggs" +| +| +|

+| "spam" +| +| +| +|
+| +| +| "quux" +| "bar" + +#data +foobazeggs

spam
quuxbar +#errors +#document +| +| +| +| +| "foo" +| +| +| +| "baz" +| +| +| +| +| "eggs" +| +| +|

+| "spam" +| +| +| +|
+| +| +| "quux" +| "bar" diff --git a/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests14.dat b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests14.dat new file mode 100644 index 0000000000..b8713f8858 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests14.dat @@ -0,0 +1,74 @@ +#data + +#errors +#document +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +15: Unexpected start tag html +#document +| +| +| abc:def="gh" +| +| +| + +#data + +#errors +15: Unexpected start tag html +#document +| +| +| xml:lang="bar" +| +| + +#data + +#errors +#document +| +| +| 123="456" +| +| + +#data + +#errors +#document +| +| +| 123="456" +| 789="012" +| +| + +#data + +#errors +#document +| +| +| +| +| 789="012" diff --git a/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests15.dat b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests15.dat new file mode 100644 index 0000000000..6ce1c0d166 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests15.dat @@ -0,0 +1,208 @@ +#data +

X +#errors +Line: 1 Col: 31 Unexpected end tag (p). Ignored. +Line: 1 Col: 36 Expected closing tag. Unexpected end of file. +#document +| +| +| +| +|

+| +| +| +| +| +| +| " " +|

+| "X" + +#data +

+

X +#errors +Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected end tag (p). Ignored. +Line: 2 Col: 4 Expected closing tag. Unexpected end of file. +#document +| +| +| +|

+| +| +| +| +| +| +| " +" +|

+| "X" + +#data + +#errors +Line: 1 Col: 22 Unexpected end tag (html) after the (implied) root element. +#document +| +| +| +| +| " " + +#data + +#errors +Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element. +#document +| +| +| +| +| + +#data + +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end tag (html) after the (implied) root element. +#document +| +| +| +| + +#data +X +#errors +Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element. +#document +| +| +| +| +| +| "X" + +#data +<!doctype html><table> X<meta></table> +#errors +Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 30 Unexpected start tag (meta) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " X" +| <meta> +| <table> + +#data +<!doctype html><table> x</table> +#errors +Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " x" +| <table> + +#data +<!doctype html><table> x </table> +#errors +Line: 1 Col: 25 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " x " +| <table> + +#data +<!doctype html><table><tr> x</table> +#errors +Line: 1 Col: 28 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " x" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table>X<style> <tr>x </style> </table> +#errors +Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "X" +| <table> +| <style> +| " <tr>x " +| " " + +#data +<!doctype html><div><table><a>foo</a> <tr><td>bar</td> </tr></table></div> +#errors +Line: 1 Col: 30 Unexpected start tag (a) in table context caused voodoo mode. +Line: 1 Col: 37 Unexpected end tag (a) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> +| <a> +| "foo" +| <table> +| " " +| <tbody> +| <tr> +| <td> +| "bar" +| " " + +#data +<frame></frame></frame><frameset><frame><frameset><frame></frameset><noframes></frameset><noframes> +#errors +6: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>â€. +13: Stray start tag “frameâ€. +21: Stray end tag “frameâ€. +29: Stray end tag “frameâ€. +39: “frameset†start tag after “body†already open. +105: End of file seen inside an [R]CDATA element. +105: End of file seen and there were open elements. +XXX: These errors are wrong, please fix me! +#document +| <html> +| <head> +| <frameset> +| <frame> +| <frameset> +| <frame> +| <noframes> +| "</frameset><noframes>" + +#data +<!DOCTYPE html><object></html> +#errors +1: Expected closing tag. Unexpected end of file +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <object> diff --git a/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests16.dat b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests16.dat new file mode 100644 index 0000000000..c8ef66f0e6 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests16.dat @@ -0,0 +1,2299 @@ +#data +<!doctype html><script> +#errors +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| <body> + +#data +<!doctype html><script>a +#errors +Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "a" +| <body> + +#data +<!doctype html><script>< +#errors +Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<" +| <body> + +#data +<!doctype html><script></ +#errors +Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</" +| <body> + +#data +<!doctype html><script></S +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</S" +| <body> + +#data +<!doctype html><script></SC +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SC" +| <body> + +#data +<!doctype html><script></SCR +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCR" +| <body> + +#data +<!doctype html><script></SCRI +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCRI" +| <body> + +#data +<!doctype html><script></SCRIP +#errors +Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCRIP" +| <body> + +#data +<!doctype html><script></SCRIPT +#errors +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCRIPT" +| <body> + +#data +<!doctype html><script></SCRIPT +#errors +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| <body> + +#data +<!doctype html><script></s +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</s" +| <body> + +#data +<!doctype html><script></sc +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</sc" +| <body> + +#data +<!doctype html><script></scr +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</scr" +| <body> + +#data +<!doctype html><script></scri +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</scri" +| <body> + +#data +<!doctype html><script></scrip +#errors +Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</scrip" +| <body> + +#data +<!doctype html><script></script +#errors +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</script" +| <body> + +#data +<!doctype html><script></script +#errors +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| <body> + +#data +<!doctype html><script><! +#errors +Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!" +| <body> + +#data +<!doctype html><script><!a +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!a" +| <body> + +#data +<!doctype html><script><!- +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!-" +| <body> + +#data +<!doctype html><script><!-a +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!-a" +| <body> + +#data +<!doctype html><script><!-- +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<!doctype html><script><!--a +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--a" +| <body> + +#data +<!doctype html><script><!--< +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<" +| <body> + +#data +<!doctype html><script><!--<a +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<a" +| <body> + +#data +<!doctype html><script><!--</ +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--</" +| <body> + +#data +<!doctype html><script><!--</script +#errors +Line: 1 Col: 35 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--</script" +| <body> + +#data +<!doctype html><script><!--</script +#errors +Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<!doctype html><script><!--<s +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<s" +| <body> + +#data +<!doctype html><script><!--<script +#errors +Line: 1 Col: 34 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script" +| <body> + +#data +<!doctype html><script><!--<script +#errors +Line: 1 Col: 35 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script " +| <body> + +#data +<!doctype html><script><!--<script < +#errors +Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script <" +| <body> + +#data +<!doctype html><script><!--<script <a +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script <a" +| <body> + +#data +<!doctype html><script><!--<script </ +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </" +| <body> + +#data +<!doctype html><script><!--<script </s +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </s" +| <body> + +#data +<!doctype html><script><!--<script </script +#errors +Line: 1 Col: 43 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script" +| <body> + +#data +<!doctype html><script><!--<script </scripta +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </scripta" +| <body> + +#data +<!doctype html><script><!--<script </script +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script </script> +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script>" +| <body> + +#data +<!doctype html><script><!--<script </script/ +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script/" +| <body> + +#data +<!doctype html><script><!--<script </script < +#errors +Line: 1 Col: 45 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script <" +| <body> + +#data +<!doctype html><script><!--<script </script <a +#errors +Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script <a" +| <body> + +#data +<!doctype html><script><!--<script </script </ +#errors +Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script </" +| <body> + +#data +<!doctype html><script><!--<script </script </script +#errors +Line: 1 Col: 52 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script </script" +| <body> + +#data +<!doctype html><script><!--<script </script </script +#errors +Line: 1 Col: 53 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script </script </script/ +#errors +Line: 1 Col: 53 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script </script </script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script - +#errors +Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -" +| <body> + +#data +<!doctype html><script><!--<script -a +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -a" +| <body> + +#data +<!doctype html><script><!--<script -< +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -<" +| <body> + +#data +<!doctype html><script><!--<script -- +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --" +| <body> + +#data +<!doctype html><script><!--<script --a +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --a" +| <body> + +#data +<!doctype html><script><!--<script --< +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --<" +| <body> + +#data +<!doctype html><script><!--<script --> +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script -->< +#errors +Line: 1 Col: 39 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --><" +| <body> + +#data +<!doctype html><script><!--<script --></ +#errors +Line: 1 Col: 40 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --></" +| <body> + +#data +<!doctype html><script><!--<script --></script +#errors +Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --></script" +| <body> + +#data +<!doctype html><script><!--<script --></script +#errors +Line: 1 Col: 47 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script --></script/ +#errors +Line: 1 Col: 47 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script --></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script><\/script>--></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script><\/script>-->" +| <body> + +#data +<!doctype html><script><!--<script></scr'+'ipt>--></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt>-->" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>--><!--</script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>--><!--" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>-- ></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>-- >" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>- -></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- ->" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>- - ></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- - >" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>-></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>->" +| <body> + +#data +<!doctype html><script><!--<script>--!></script>X +#errors +Line: 1 Col: 49 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script>--!></script>X" +| <body> + +#data +<!doctype html><script><!--<scr'+'ipt></script>--></script> +#errors +Line: 1 Col: 59 Unexpected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<scr'+'ipt>" +| <body> +| "-->" + +#data +<!doctype html><script><!--<script></scr'+'ipt></script>X +#errors +Line: 1 Col: 57 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt></script>X" +| <body> + +#data +<!doctype html><style><!--<style></style>--></style> +#errors +Line: 1 Col: 52 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--<style>" +| <body> +| "-->" + +#data +<!doctype html><style><!--</style>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--" +| <body> +| "X" + +#data +<!doctype html><style><!--...</style>...--></style> +#errors +Line: 1 Col: 51 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--..." +| <body> +| "...-->" + +#data +<!doctype html><style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>" +| <body> +| "X" + +#data +<!doctype html><style><!--...<style><!--...--!></style>--></style> +#errors +Line: 1 Col: 66 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--...<style><!--...--!>" +| <body> +| "-->" + +#data +<!doctype html><style><!--...</style><!-- --><style>@import ...</style> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--..." +| <!-- --> +| <style> +| "@import ..." +| <body> + +#data +<!doctype html><style>...<style><!--...</style><!-- --></style> +#errors +Line: 1 Col: 63 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "...<style><!--..." +| <!-- --> +| <body> + +#data +<!doctype html><style>...<!--[if IE]><style>...</style>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "...<!--[if IE]><style>..." +| <body> +| "X" + +#data +<!doctype html><title><!--<title>--> +#errors +Line: 1 Col: 52 Unexpected end tag (title). +#document +| +| +| +| +| "<!--<title>" +| <body> +| "-->" + +#data +<!doctype html><title></title> +#errors +#document +| +| +| +| +| "" +| + +#data +foo/title><link></head><body>X +#errors +Line: 1 Col: 52 Unexpected end of file. Expected end tag (title). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <title> +| "foo/title><link></head><body>X" +| <body> + +#data +<!doctype html><noscript><!--<noscript></noscript>--></noscript> +#errors +Line: 1 Col: 64 Unexpected end tag (noscript). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noscript> +| "<!--<noscript>" +| <body> +| "-->" + +#data +<!doctype html><noscript><!--</noscript>X<noscript>--></noscript> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noscript> +| "<!--" +| <body> +| "X" +| <noscript> +| "-->" + +#data +<!doctype html><noscript><iframe></noscript>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noscript> +| "<iframe>" +| <body> +| "X" + +#data +<!doctype html><noframes><!--<noframes></noframes>--></noframes> +#errors +Line: 1 Col: 64 Unexpected end tag (noframes). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noframes> +| "<!--<noframes>" +| <body> +| "-->" + +#data +<!doctype html><noframes><body><script><!--...</script></body></noframes></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noframes> +| "<body><script><!--...</script></body>" +| <body> + +#data +<!doctype html><textarea><!--<textarea></textarea>--></textarea> +#errors +Line: 1 Col: 64 Unexpected end tag (textarea). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "<!--<textarea>" +| "-->" + +#data +<!doctype html><textarea></textarea></textarea> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "</textarea>" + +#data +<!doctype html><textarea><</textarea> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "<" + +#data +<!doctype html><textarea>a<b</textarea> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "a<b" + +#data +<!doctype html><iframe><!--<iframe></iframe>--></iframe> +#errors +Line: 1 Col: 56 Unexpected end tag (iframe). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <iframe> +| "<!--<iframe>" +| "-->" + +#data +<!doctype html><iframe>...<!--X->...<!--/X->...</iframe> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <iframe> +| "...<!--X->...<!--/X->..." + +#data +<!doctype html><xmp><!--<xmp></xmp>--></xmp> +#errors +Line: 1 Col: 44 Unexpected end tag (xmp). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <xmp> +| "<!--<xmp>" +| "-->" + +#data +<!doctype html><noembed><!--<noembed></noembed>--></noembed> +#errors +Line: 1 Col: 60 Unexpected end tag (noembed). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <noembed> +| "<!--<noembed>" +| "-->" + +#data +<script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 8 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| <body> + +#data +<script>a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 9 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "a" +| <body> + +#data +<script>< +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 9 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<" +| <body> + +#data +<script></ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 10 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</" +| <body> + +#data +<script></S +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</S" +| <body> + +#data +<script></SC +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SC" +| <body> + +#data +<script></SCR +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCR" +| <body> + +#data +<script></SCRI +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCRI" +| <body> + +#data +<script></SCRIP +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 15 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCRIP" +| <body> + +#data +<script></SCRIPT +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCRIPT" +| <body> + +#data +<script></SCRIPT +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 17 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| <body> + +#data +<script></s +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</s" +| <body> + +#data +<script></sc +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</sc" +| <body> + +#data +<script></scr +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</scr" +| <body> + +#data +<script></scri +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</scri" +| <body> + +#data +<script></scrip +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 15 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</scrip" +| <body> + +#data +<script></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</script" +| <body> + +#data +<script></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 17 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| <body> + +#data +<script><! +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 10 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!" +| <body> + +#data +<script><!a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!a" +| <body> + +#data +<script><!- +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!-" +| <body> + +#data +<script><!-a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!-a" +| <body> + +#data +<script><!-- +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<script><!--a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--a" +| <body> + +#data +<script><!--< +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<" +| <body> + +#data +<script><!--<a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<a" +| <body> + +#data +<script><!--</ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--</" +| <body> + +#data +<script><!--</script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--</script" +| <body> + +#data +<script><!--</script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<script><!--<s +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<s" +| <body> + +#data +<script><!--<script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 19 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script" +| <body> + +#data +<script><!--<script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script " +| <body> + +#data +<script><!--<script < +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script <" +| <body> + +#data +<script><!--<script <a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script <a" +| <body> + +#data +<script><!--<script </ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </" +| <body> + +#data +<script><!--<script </s +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </s" +| <body> + +#data +<script><!--<script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script" +| <body> + +#data +<script><!--<script </scripta +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </scripta" +| <body> + +#data +<script><!--<script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script </script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script>" +| <body> + +#data +<script><!--<script </script/ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script/" +| <body> + +#data +<script><!--<script </script < +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script <" +| <body> + +#data +<script><!--<script </script <a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script <a" +| <body> + +#data +<script><!--<script </script </ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script </" +| <body> + +#data +<script><!--<script </script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script </script" +| <body> + +#data +<script><!--<script </script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script </script </script/ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script </script </script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script - +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -" +| <body> + +#data +<script><!--<script -a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -a" +| <body> + +#data +<script><!--<script -- +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --" +| <body> + +#data +<script><!--<script --a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --a" +| <body> + +#data +<script><!--<script --> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script -->< +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --><" +| <body> + +#data +<script><!--<script --></ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --></" +| <body> + +#data +<script><!--<script --></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --></script" +| <body> + +#data +<script><!--<script --></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script --></script/ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script --></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script><\/script>--></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script><\/script>-->" +| <body> + +#data +<script><!--<script></scr'+'ipt>--></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt>-->" +| <body> + +#data +<script><!--<script></script><script></script></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>" +| <body> + +#data +<script><!--<script></script><script></script>--><!--</script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>--><!--" +| <body> + +#data +<script><!--<script></script><script></script>-- ></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>-- >" +| <body> + +#data +<script><!--<script></script><script></script>- -></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- ->" +| <body> + +#data +<script><!--<script></script><script></script>- - ></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- - >" +| <body> + +#data +<script><!--<script></script><script></script>-></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>->" +| <body> + +#data +<script><!--<script>--!></script>X +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 34 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script>--!></script>X" +| <body> + +#data +<script><!--<scr'+'ipt></script>--></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 44 Unexpected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<scr'+'ipt>" +| <body> +| "-->" + +#data +<script><!--<script></scr'+'ipt></script>X +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 42 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt></script>X" +| <body> + +#data +<style><!--<style></style>--></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 37 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "<!--<style>" +| <body> +| "-->" + +#data +<style><!--</style>X +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "<!--" +| <body> +| "X" + +#data +<style><!--...</style>...--></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 36 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "<!--..." +| <body> +| "...-->" + +#data +<style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>" +| <body> +| "X" + +#data +<style><!--...<style><!--...--!></style>--></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 51 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "<!--...<style><!--...--!>" +| <body> +| "-->" + +#data +<style><!--...</style><!-- --><style>@import ...</style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "<!--..." +| <!-- --> +| <style> +| "@import ..." +| <body> + +#data +<style>...<style><!--...</style><!-- --></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 48 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "...<style><!--..." +| <!-- --> +| <body> + +#data +<style>...<!--[if IE]><style>...</style>X +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "...<!--[if IE]><style>..." +| <body> +| "X" + +#data +<title><!--<title>--> +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +Line: 1 Col: 37 Unexpected end tag (title). +#document +| +| +| +| "<!--<title>" +| <body> +| "-->" + +#data +<title></title> +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +#document +| +| +| +| "" +| + +#data +foo/title><link></head><body>X +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +Line: 1 Col: 37 Unexpected end of file. Expected end tag (title). +#document +| <html> +| <head> +| <title> +| "foo/title><link></head><body>X" +| <body> + +#data +<noscript><!--<noscript></noscript>--></noscript> +#errors +Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. +Line: 1 Col: 49 Unexpected end tag (noscript). +#document +| <html> +| <head> +| <noscript> +| "<!--<noscript>" +| <body> +| "-->" + +#data +<noscript><!--</noscript>X<noscript>--></noscript> +#errors +Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. +#document +| <html> +| <head> +| <noscript> +| "<!--" +| <body> +| "X" +| <noscript> +| "-->" + +#data +<noscript><iframe></noscript>X +#errors +Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. +#document +| <html> +| <head> +| <noscript> +| "<iframe>" +| <body> +| "X" + +#data +<noframes><!--<noframes></noframes>--></noframes> +#errors +Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE. +Line: 1 Col: 49 Unexpected end tag (noframes). +#document +| <html> +| <head> +| <noframes> +| "<!--<noframes>" +| <body> +| "-->" + +#data +<noframes><body><script><!--...</script></body></noframes></html> +#errors +Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE. +#document +| <html> +| <head> +| <noframes> +| "<body><script><!--...</script></body>" +| <body> + +#data +<textarea><!--<textarea></textarea>--></textarea> +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +Line: 1 Col: 49 Unexpected end tag (textarea). +#document +| <html> +| <head> +| <body> +| <textarea> +| "<!--<textarea>" +| "-->" + +#data +<textarea></textarea></textarea> +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <textarea> +| "</textarea>" + +#data +<iframe><!--<iframe></iframe>--></iframe> +#errors +Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE. +Line: 1 Col: 41 Unexpected end tag (iframe). +#document +| <html> +| <head> +| <body> +| <iframe> +| "<!--<iframe>" +| "-->" + +#data +<iframe>...<!--X->...<!--/X->...</iframe> +#errors +Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <iframe> +| "...<!--X->...<!--/X->..." + +#data +<xmp><!--<xmp></xmp>--></xmp> +#errors +Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end tag (xmp). +#document +| <html> +| <head> +| <body> +| <xmp> +| "<!--<xmp>" +| "-->" + +#data +<noembed><!--<noembed></noembed>--></noembed> +#errors +Line: 1 Col: 9 Unexpected start tag (noembed). Expected DOCTYPE. +Line: 1 Col: 45 Unexpected end tag (noembed). +#document +| <html> +| <head> +| <body> +| <noembed> +| "<!--<noembed>" +| "-->" + +#data +<!doctype html><table> + +#errors +Line 2 Col 0 Unexpected end of file. Expected table content. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| " +" + +#data +<!doctype html><table><td><span><font></span><span> +#errors +Line 1 Col 26 Unexpected table cell start tag (td) in the table body phase. +Line 1 Col 45 Unexpected end tag (span). +Line 1 Col 51 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <span> +| <font> +| <font> +| <span> + +#data +<!doctype html><form><table></form><form></table></form> +#errors +35: Stray end tag “formâ€. +41: Start tag “form†seen in “tableâ€. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <table> +| <form> diff --git a/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests17.dat b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests17.dat new file mode 100644 index 0000000000..7b555f888d --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests17.dat @@ -0,0 +1,153 @@ +#data +<!doctype html><table><tbody><select><tr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><tr><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <table> +| <tbody> +| <tr> +| <td> + +#data +<!doctype html><table><tr><td><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <select> +| <td> + +#data +<!doctype html><table><tr><th><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <th> +| <select> +| <td> + +#data +<!doctype html><table><caption><select><tr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <select> +| <tbody> +| <tr> + +#data +<!doctype html><select><tr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><th> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><tbody> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><thead> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><tfoot> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><caption> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><table><tr></table>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| "a" diff --git a/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests18.dat b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests18.dat new file mode 100644 index 0000000000..680e1f068a --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests18.dat @@ -0,0 +1,269 @@ +#data +<!doctype html><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" + +#data +<!doctype html><table><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> + +#data +<!doctype html><table><tbody><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> +| <tbody> + +#data +<!doctype html><table><tbody><tr><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><tbody><tr><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><td><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <plaintext> +| "</plaintext>" + +#data +<!doctype html><table><caption><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <plaintext> +| "</plaintext>" + +#data +<!doctype html><table><tr><style></script></style>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "abc" +| <table> +| <tbody> +| <tr> +| <style> +| "</script>" + +#data +<!doctype html><table><tr><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "abc" +| <table> +| <tbody> +| <tr> +| <script> +| "</style>" + +#data +<!doctype html><table><caption><style></script></style>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <style> +| "</script>" +| "abc" + +#data +<!doctype html><table><td><style></script></style>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <style> +| "</script>" +| "abc" + +#data +<!doctype html><select><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <script> +| "</style>" +| "abc" + +#data +<!doctype html><table><select><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <script> +| "</style>" +| "abc" +| <table> + +#data +<!doctype html><table><tr><select><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <script> +| "</style>" +| "abc" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><frameset></frameset><noframes>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" + +#data +<!doctype html><frameset></frameset><noframes>abc</noframes><!--abc--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" +| <!-- abc --> + +#data +<!doctype html><frameset></frameset></html><noframes>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" + +#data +<!doctype html><frameset></frameset></html><noframes>abc</noframes><!--abc--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" +| <!-- abc --> + +#data +<!doctype html><table><tr></tbody><tfoot> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <tfoot> + +#data +<!doctype html><table><td><svg></svg>abc<td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <svg svg> +| "abc" +| <td> diff --git a/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests19.dat b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests19.dat new file mode 100644 index 0000000000..0d62f5a5b0 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests19.dat @@ -0,0 +1,1237 @@ +#data +<!doctype html><math><mn DefinitionUrl="foo"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math mn> +| definitionURL="foo" + +#data +<!doctype html><html></p><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <!-- foo --> +| <head> +| <body> + +#data +<!doctype html><head></head></p><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <!-- foo --> +| <body> + +#data +<!doctype html><body><p><pre> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <pre> + +#data +<!doctype html><body><p><listing> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <listing> + +#data +<!doctype html><p><plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <plaintext> + +#data +<!doctype html><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <h1> + +#data +<!doctype html><form><isindex> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> + +#data +<!doctype html><isindex action="POST"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| action="POST" +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| <hr> + +#data +<!doctype html><isindex prompt="this is isindex"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "this is isindex" +| <input> +| name="isindex" +| <hr> + +#data +<!doctype html><isindex type="hidden"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| type="hidden" +| <hr> + +#data +<!doctype html><isindex name="foo"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| <hr> + +#data +<!doctype html><ruby><p><rp> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <p> +| <rp> + +#data +<!doctype html><ruby><div><span><rp> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <span> +| <rp> + +#data +<!doctype html><ruby><div><p><rp> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <p> +| <rp> + +#data +<!doctype html><ruby><p><rt> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <p> +| <rt> + +#data +<!doctype html><ruby><div><span><rt> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <span> +| <rt> + +#data +<!doctype html><ruby><div><p><rt> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <p> +| <rt> + +#data +<!doctype html><math/><foo> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <foo> + +#data +<!doctype html><svg/><foo> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <foo> + +#data +<!doctype html><div></body><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> +| <!-- foo --> + +#data +<!doctype html><h1><div><h3><span></h1>foo +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <h1> +| <div> +| <h3> +| <span> +| "foo" + +#data +<!doctype html><p></h3>foo +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| "foo" + +#data +<!doctype html><h3><li>abc</h2>foo +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <h3> +| <li> +| "abc" +| "foo" + +#data +<!doctype html><table>abc<!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "abc" +| <table> +| <!-- foo --> + +#data +<!doctype html><table> <!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| " " +| <!-- foo --> + +#data +<!doctype html><table> b <!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " b " +| <table> +| <!-- foo --> + +#data +<!doctype html><select><option><option> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> +| <option> + +#data +<!doctype html><select><option></optgroup> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> + +#data +<!doctype html><select><option></optgroup> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> + +#data +<!doctype html><p><math><mi><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mi> +| <p> +| <h1> + +#data +<!doctype html><p><math><mo><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mo> +| <p> +| <h1> + +#data +<!doctype html><p><math><mn><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mn> +| <p> +| <h1> + +#data +<!doctype html><p><math><ms><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math ms> +| <p> +| <h1> + +#data +<!doctype html><p><math><mtext><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mtext> +| <p> +| <h1> + +#data +<!doctype html><frameset></noframes> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><html c=d><body></html><html a=b> +#errors +#document +| <!DOCTYPE html> +| <html> +| a="b" +| c="d" +| <head> +| <body> + +#data +<!doctype html><html c=d><frameset></frameset></html><html a=b> +#errors +#document +| <!DOCTYPE html> +| <html> +| a="b" +| c="d" +| <head> +| <frameset> + +#data +<!doctype html><html><frameset></frameset></html><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <!-- foo --> + +#data +<!doctype html><html><frameset></frameset></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| " " + +#data +<!doctype html><html><frameset></frameset></html>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><html><frameset></frameset></html><p> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><html><frameset></frameset></html></p> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<html><frameset></frameset></html><!doctype html> +#errors +#document +| <html> +| <head> +| <frameset> + +#data +<!doctype html><body><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +<!doctype html><p><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><p>a<frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| "a" + +#data +<!doctype html><p> <frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><pre><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <pre> + +#data +<!doctype html><listing><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <listing> + +#data +<!doctype html><li><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <li> + +#data +<!doctype html><dd><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <dd> + +#data +<!doctype html><dt><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <dt> + +#data +<!doctype html><button><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <button> + +#data +<!doctype html><applet><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <applet> + +#data +<!doctype html><marquee><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <marquee> + +#data +<!doctype html><object><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <object> + +#data +<!doctype html><table><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> + +#data +<!doctype html><area><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <area> + +#data +<!doctype html><basefont><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <basefont> +| <frameset> + +#data +<!doctype html><bgsound><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <bgsound> +| <frameset> + +#data +<!doctype html><br><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <br> + +#data +<!doctype html><embed><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <embed> + +#data +<!doctype html><img><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <img> + +#data +<!doctype html><input><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <input> + +#data +<!doctype html><keygen><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <keygen> + +#data +<!doctype html><wbr><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <wbr> + +#data +<!doctype html><hr><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <hr> + +#data +<!doctype html><textarea></textarea><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> + +#data +<!doctype html><xmp></xmp><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <xmp> + +#data +<!doctype html><iframe></iframe><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <iframe> + +#data +<!doctype html><select></select><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><svg></svg><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><math></math><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><svg><foreignObject><div> <frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><svg>a</svg><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| "a" + +#data +<!doctype html><svg> </svg><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<html>aaa<frameset></frameset> +#errors +#document +| <html> +| <head> +| <body> +| "aaa" + +#data +<html> a <frameset></frameset> +#errors +#document +| <html> +| <head> +| <body> +| "a " + +#data +<!doctype html><div><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><div><body><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> + +#data +<!doctype html><p><math></p>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| "a" + +#data +<!doctype html><p><math><mn><span></p>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mn> +| <span> +| <p> +| "a" + +#data +<!doctype html><math></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> + +#data +<!doctype html><meta charset="ascii"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <meta> +| charset="ascii" +| <body> + +#data +<!doctype html><meta http-equiv="content-type" content="text/html;charset=ascii"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <meta> +| content="text/html;charset=ascii" +| http-equiv="content-type" +| <body> + +#data +<!doctype html><head><!--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--><meta charset="utf8"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <!-- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --> +| <meta> +| charset="utf8" +| <body> + +#data +<!doctype html><html a=b><head></head><html c=d> +#errors +#document +| <!DOCTYPE html> +| <html> +| a="b" +| c="d" +| <head> +| <body> + +#data +<!doctype html><image/> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <img> + +#data +<!doctype html>a<i>b<table>c<b>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "a" +| <i> +| "bc" +| <b> +| "de" +| "f" +| <table> + +#data +<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <b> +| <i> +| "c" +| <a> +| "d" +| <a> +| "e" +| <a> +| "f" +| <table> + +#data +<!doctype html><i>a<b>b<div>c<a>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <b> +| <i> +| "c" +| <a> +| "d" +| <a> +| "e" +| <a> +| "f" + +#data +<!doctype html><table><i>a<b>b<div>c</i> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <i> +| "c" +| <table> + +#data +<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <b> +| <i> +| "c" +| <a> +| "d" +| <a> +| "e" +| <a> +| "f" +| <table> + +#data +<!doctype html><table><i>a<div>b<tr>c<b>d</i>e +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <div> +| "b" +| <i> +| "c" +| <b> +| "d" +| <b> +| "e" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><td><table><i>a<div>b<b>c</i>d +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <i> +| "a" +| <div> +| <i> +| "b" +| <b> +| "c" +| <b> +| "d" +| <table> + +#data +<!doctype html><body><bgsound> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <bgsound> + +#data +<!doctype html><body><basefont> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <basefont> + +#data +<!doctype html><a><b></a><basefont> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <a> +| <b> +| <basefont> + +#data +<!doctype html><a><b></a><bgsound> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <a> +| <b> +| <bgsound> + +#data +<!doctype html><figcaption><article></figcaption>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <figcaption> +| <article> +| "a" + +#data +<!doctype html><summary><article></summary>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <summary> +| <article> +| "a" + +#data +<!doctype html><p><a><plaintext>b +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <a> +| <plaintext> +| <a> +| "b" + +#data +<!DOCTYPE html><div>a<a></div>b<p>c</p>d +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> +| "a" +| <a> +| <a> +| "b" +| <p> +| "c" +| "d" diff --git a/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests2.dat b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests2.dat new file mode 100644 index 0000000000..60d8592216 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/html/testdata/webkit/tests2.dat @@ -0,0 +1,763 @@ +#data +<!DOCTYPE html>Test +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "Test" + +#data +<textarea>test</div>test +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +Line: 1 Col: 24 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <textarea> +| "test</div>test" + +#data +<table><td> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 11 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> + +#data +<table><td>test</tbody></table> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| "test" + +#data +<frame>test +#errors +Line: 1 Col: 7 Unexpected start tag (frame). Expected DOCTYPE. +Line: 1 Col: 7 Unexpected start tag frame. Ignored. +#document +| <html> +| <head> +| <body> +| "test" + +#data +<!DOCTYPE html><frameset>test +#errors +Line: 1 Col: 29 Unepxected characters in the frameset phase. Characters ignored. +Line: 1 Col: 29 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!DOCTYPE html><frameset><!DOCTYPE html> +#errors +Line: 1 Col: 40 Unexpected DOCTYPE. Ignored. +Line: 1 Col: 40 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!DOCTYPE html><font><p><b>test</font> +#errors +Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <font> +| <p> +| <font> +| <b> +| "test" + +#data +<!DOCTYPE html><dt><div><dd> +#errors +Line: 1 Col: 28 Missing end tag (div, dt). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <dt> +| <div> +| <dd> + +#data +<script></x +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</x" +| <body> + +#data +<table><plaintext><td> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 18 Unexpected start tag (plaintext) in table context caused voodoo mode. +Line: 1 Col: 22 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| <plaintext> +| "<td>" +| <table> + +#data +<plaintext></plaintext> +#errors +Line: 1 Col: 11 Unexpected start tag (plaintext). Expected DOCTYPE. +Line: 1 Col: 23 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" + +#data +<!DOCTYPE html><table><tr>TEST +#errors +Line: 1 Col: 30 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 30 Unexpected end of file. Expected table content. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "TEST" +| <table> +| <tbody> +| <tr> + +#data +<!DOCTYPE html><body t1=1><body t2=2><body t3=3 t4=4> +#errors +Line: 1 Col: 37 Unexpected start tag (body). +Line: 1 Col: 53 Unexpected start tag (body). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| t1="1" +| t2="2" +| t3="3" +| t4="4" + +#data +</b test +#errors +Line: 1 Col: 8 Unexpected end of file in attribute name. +Line: 1 Col: 8 End tag contains unexpected attributes. +Line: 1 Col: 8 Unexpected end tag (b). Expected DOCTYPE. +Line: 1 Col: 8 Unexpected end tag (b) after the (implied) root element. +#document +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html></b test<b &=&>X +#errors +Line: 1 Col: 32 Named entity didn't end with ';'. +Line: 1 Col: 33 End tag contains unexpected attributes. +Line: 1 Col: 33 Unexpected end tag (b) after the (implied) root element. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "X" + +#data +<!doctypehtml><scrIPt type=text/x-foobar;baz>X</SCRipt +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +Line: 1 Col: 54 Unexpected end of file in the tag name. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| type="text/x-foobar;baz" +| "X</SCRipt" +| <body> + +#data +& +#errors +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&" + +#data +&# +#errors +Line: 1 Col: 1 Numeric entity expected. Got end of file instead. +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&#" + +#data +&#X +#errors +Line: 1 Col: 3 Numeric entity expected but none found. +Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&#X" + +#data +&#x +#errors +Line: 1 Col: 3 Numeric entity expected but none found. +Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&#x" + +#data +- +#errors +Line: 1 Col: 4 Numeric entity didn't end with ';'. +Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "-" + +#data +&x-test +#errors +Line: 1 Col: 1 Named entity expected. Got none. +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&x-test" + +#data +<!doctypehtml><p><li> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <li> + +#data +<!doctypehtml><p><dt> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <dt> + +#data +<!doctypehtml><p><dd> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <dd> + +#data +<!doctypehtml><p><form> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +Line: 1 Col: 23 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <form> + +#data +<!DOCTYPE html><p></P>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| "X" + +#data +& +#errors +Line: 1 Col: 4 Named entity didn't end with ';'. +Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&" + +#data +&AMp; +#errors +Line: 1 Col: 1 Named entity expected. Got none. +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&AMp;" + +#data +<!DOCTYPE html><html><head></head><body><thisISasillyTESTelementNameToMakeSureCrazyTagNamesArePARSEDcorrectLY> +#errors +Line: 1 Col: 110 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <thisisasillytestelementnametomakesurecrazytagnamesareparsedcorrectly> + +#data +<!DOCTYPE html>X</body>X +#errors +Line: 1 Col: 24 Unexpected non-space characters in the after body phase. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "XX" + +#data +<!DOCTYPE html><!-- X +#errors +Line: 1 Col: 21 Unexpected end of file in comment. +#document +| <!DOCTYPE html> +| <!-- X --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><table><caption>test TEST</caption><td>test +#errors +Line: 1 Col: 54 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 58 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| "test TEST" +| <tbody> +| <tr> +| <td> +| "test" + +#data +<!DOCTYPE html><select><option><optgroup> +#errors +Line: 1 Col: 41 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> +| <optgroup> + +#data +<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option> +#errors +Line: 1 Col: 68 Unexpected select start tag in the select phase treated as select end tag. +Line: 1 Col: 76 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <optgroup> +| <option> +| <option> +| <option> + +#data +<!DOCTYPE html><select><optgroup><option><optgroup> +#errors +Line: 1 Col: 51 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <optgroup> +| <option> +| <optgroup> + +#data +<!DOCTYPE html><datalist><option>foo</datalist>bar +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <datalist> +| <option> +| "foo" +| "bar" + +#data +<!DOCTYPE html><font><input><input></font> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <font> +| <input> +| <input> + +#data +<!DOCTYPE html><!-- XXX - XXX --> +#errors +#document +| <!DOCTYPE html> +| <!-- XXX - XXX --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><!-- XXX - XXX +#errors +Line: 1 Col: 29 Unexpected end of file in comment (-) +#document +| <!DOCTYPE html> +| <!-- XXX - XXX --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><!-- XXX - XXX - XXX --> +#errors +#document +| <!DOCTYPE html> +| <!-- XXX - XXX - XXX --> +| <html> +| <head> +| <body> + +#data +<isindex test=x name=x> +#errors +Line: 1 Col: 23 Unexpected start tag (isindex). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected start tag isindex. Don't use it! +#document +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| test="x" +| <hr> + +#data +test +test +#errors +Line: 2 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "test +test" + +#data +<!DOCTYPE html><body><title>test</body> +#errors +#document +| +| +| +| +| +| "test</body>" + +#data +<!DOCTYPE html><body><title>X +#errors +#document +| +| +| +| +| +| "X" +| <meta> +| name="z" +| <link> +| rel="foo" +| <style> +| " +x { content:"</style" } " + +#data +<!DOCTYPE html><select><optgroup></optgroup></select> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <optgroup> + +#data + + +#errors +Line: 2 Col: 1 Unexpected End of file. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html> <html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><script> +</script> <title>x +#errors +#document +| +| +| +| +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected start tag (script) that can be in head. Moved. +#document +| +| +| +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +Line: 1 Col: 28 Unexpected start tag (style) that can be in head. Moved. +#document +| +| +| +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +#document +| +| +| +| +| "x" +| x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (style). +#document +| +| +| --> x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| +| +| x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| +| +| x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| +| +| x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| +| +|

+#errors +#document +| +| +| +| +| +| ddd +#errors +#document +| +| +| +#errors +#document +| +| +| +| +|
  • +| +| ", + "
  • 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