From 5e6032702cf5bfd352d17dd67ac7fd4297336cfe Mon Sep 17 00:00:00 2001 From: Greg Melton Date: Wed, 22 Feb 2012 15:23:42 -0800 Subject: [PATCH] initial commit for 0.0.0 --- LICENSE | 19 + index.js | 1 + lib/casio.js | 995 +++ node_modules/.bin/nodeunit | 1 + node_modules/async/.gitmodules | 9 + node_modules/async/LICENSE | 19 + node_modules/async/Makefile | 21 + node_modules/async/README.md | 1022 +++ node_modules/async/deps/nodeunit.css | 70 + node_modules/async/deps/nodeunit.js | 1966 +++++ node_modules/async/dist/async.min.js | 1 + node_modules/async/index.js | 3 + node_modules/async/lib/async.js | 701 ++ node_modules/async/nodelint.cfg | 4 + node_modules/async/package.json | 16 + node_modules/async/test/.swp | Bin 0 -> 12288 bytes node_modules/async/test/test-async.js | 1625 ++++ node_modules/async/test/test.html | 24 + node_modules/cassandra-client/.jslint.conf | 4 + node_modules/cassandra-client/.npmignore | 9 + node_modules/cassandra-client/CHANGES | 56 + node_modules/cassandra-client/LICENSE.txt | 203 + .../LICENSE_buffer_ieee754.txt | 30 + node_modules/cassandra-client/README.md | 162 + node_modules/cassandra-client/gary.js | 55 + node_modules/cassandra-client/lib/bigint.js | 1256 ++++ node_modules/cassandra-client/lib/decoder.js | 225 + node_modules/cassandra-client/lib/driver.js | 806 ++ .../lib/gen-nodejs/Cassandra.js | 6686 +++++++++++++++++ .../lib/gen-nodejs/cassandra_types.js | 3270 ++++++++ node_modules/cassandra-client/lib/system.js | 228 + node_modules/cassandra-client/lib/uuid.js | 117 + .../cassandra-client/node-cassandra-client.js | 19 + .../node_modules/.bin/whiskey | 1 + .../node_modules/async/.gitmodules | 9 + .../node_modules/async/LICENSE | 19 + .../node_modules/async/Makefile | 21 + .../node_modules/async/README.md | 1022 +++ .../node_modules/async/deps/nodeunit.css | 70 + .../node_modules/async/deps/nodeunit.js | 1966 +++++ .../node_modules/async/dist/async.min.js | 1 + .../node_modules/async/index.js | 3 + .../node_modules/async/lib/async.js | 701 ++ .../node_modules/async/nodelint.cfg | 4 + .../node_modules/async/package.json | 16 + .../node_modules/async/test/.swp | Bin 0 -> 12288 bytes .../node_modules/async/test/test-async.js | 1625 ++++ .../node_modules/async/test/test.html | 24 + .../node_modules/node-uuid/.npmignore | 2 + .../node_modules/node-uuid/LICENSE.md | 3 + .../node_modules/node-uuid/README.md | 199 + .../node-uuid/benchmark/README.md | 53 + .../node-uuid/benchmark/bench.gnu | 174 + .../node_modules/node-uuid/benchmark/bench.sh | 34 + .../node-uuid/benchmark/benchmark-native.c | 34 + .../node-uuid/benchmark/benchmark.js | 84 + .../node_modules/node-uuid/package.json | 14 + .../node_modules/node-uuid/test/compare_v1.js | 63 + .../node_modules/node-uuid/test/test.html | 17 + .../node_modules/node-uuid/test/test.js | 240 + .../node_modules/node-uuid/uuid.js | 249 + .../node_modules/thrift/LICENSE | 13 + .../node_modules/thrift/NOTICE | 5 + .../node_modules/thrift/README.md | 55 + .../node_modules/thrift/examples/README.md | 29 + .../node_modules/thrift/examples/client.js | 49 + .../thrift/examples/client_multitransport.js | 40 + .../examples/gen-nodejs/BucketStoreMapping.js | 224 + .../examples/gen-nodejs/FacebookService.js | 1676 +++++ .../thrift/examples/gen-nodejs/UserStorage.js | 295 + .../gen-nodejs/bucketupdater_types.js | 127 + .../thrift/examples/gen-nodejs/fb303_types.js | 15 + .../thrift/examples/gen-nodejs/scribe.js | 206 + .../examples/gen-nodejs/scribe_types.js | 70 + .../thrift/examples/gen-nodejs/user_types.js | 80 + .../thrift/examples/scribe_client.js | 42 + .../node_modules/thrift/examples/server.js | 39 + .../thrift/examples/server_multitransport.js | 28 + .../node_modules/thrift/examples/user.thrift | 27 + .../thrift/lib/thrift/binary_parser.js | 274 + .../thrift/lib/thrift/connection.js | 130 + .../node_modules/thrift/lib/thrift/index.js | 26 + .../thrift/lib/thrift/protocol.js | 337 + .../node_modules/thrift/lib/thrift/server.js | 59 + .../node_modules/thrift/lib/thrift/thrift.js | 140 + .../thrift/lib/thrift/transport.js | 240 + .../node_modules/thrift/package.json | 27 + .../node_modules/whiskey/.npmignore | 4 + .../node_modules/whiskey/CHANGES.md | 194 + .../node_modules/whiskey/LICENSE | 203 + .../node_modules/whiskey/Makefile | 9 + .../node_modules/whiskey/PROCESS_RUNNER.md | 107 + .../node_modules/whiskey/README.md | 199 + .../whiskey/assets/Makefile.magic | 22 + .../whiskey/assets/coverage_html.js | 372 + .../whiskey/assets/jquery-1.4.3.min.js | 166 + .../whiskey/assets/jquery.hotkeys.js | 99 + .../whiskey/assets/jquery.isonscreen.js | 53 + .../whiskey/assets/jquery.tablesorter.min.js | 2 + .../whiskey/assets/keybd_closed.png | Bin 0 -> 264 bytes .../whiskey/assets/keybd_open.png | Bin 0 -> 267 bytes .../node_modules/whiskey/assets/style.css | 275 + .../node_modules/whiskey/assets/whiskey.magic | 97 + .../whiskey/assets/whiskey_source.magic | 83 + .../node_modules/whiskey/bin/whiskey | 53 + .../whiskey/bin/whiskey-process-runner | 34 + .../example/custom-assert-functions.js | 9 + .../whiskey/example/dependencies.json | 27 + .../node_modules/whiskey/example/init-test.js | 27 + .../whiskey/example/init-timeout.js | 19 + .../node_modules/whiskey/example/init.js | 27 + .../node_modules/whiskey/example/some-file.js | 39 + .../whiskey/example/test-chdir.js | 22 + .../example/test-custom-assert-functions.js | 8 + .../example/test-custom-assert-methods.js | 64 + .../whiskey/example/test-failure.js | 26 + .../example/test-getFilePathAndPattern.js | 37 + .../whiskey/example/test-init-function.js | 28 + .../whiskey/example/test-jscoverage.js | 24 + .../whiskey/example/test-leaks.js | 55 + .../whiskey/example/test-no-test-functions.js | 1 + .../test-print-stdout-stderr-timeout.js | 27 + .../whiskey/example/test-scope-leaks.js | 33 + .../example/test-setup-and-teardown.js | 62 + .../whiskey/example/test-setup-fail.js | 31 + .../whiskey/example/test-setup-timeout.js | 24 + .../whiskey/example/test-skipped.js | 30 + ...tdout-and-stderr-is-captured-on-timeout.js | 23 + ...succeeded-tests-are-reported-on-timeout.js | 24 + .../example/test-success-with-coverage.js | 22 + .../whiskey/example/test-success.js | 37 + .../whiskey/example/test-teardown-timeout.js | 24 + .../example/test-timeout-after-finish.js | 23 + .../whiskey/example/test-timeout-blocking.js | 23 + .../whiskey/example/test-timeout.js | 40 + .../whiskey/example/test-uncaught.js | 46 + .../whiskey/example/timeout-throws.js | 13 + .../node_modules/whiskey/index.js | 19 + .../extern/long-stack-traces/README.md | 75 + .../extern/long-stack-traces/examples.html | 51 + .../extern/long-stack-traces/examples.js | 58 + .../lib-cov/extern/long-stack-traces/index.js | 9 + .../lib/long-stack-traces.js | 381 + .../extern/long-stack-traces/package.json | 13 + .../whiskey/lib-cov/extern/optparse/README.md | 161 + .../whiskey/lib-cov/extern/optparse/TODO | 1 + .../optparse/examples/browser-test.html | 75 + .../extern/optparse/examples/nodejs-test.js | 115 + .../lib-cov/extern/optparse/lib/optparse.js | 606 ++ .../lib-cov/extern/optparse/package.json | 8 + .../whiskey/lib-cov/extern/optparse/seed.yml | 5 + .../node_modules/whiskey/lib/assert.js | 348 + .../node_modules/whiskey/lib/common.js | 546 ++ .../node_modules/whiskey/lib/constants.js | 154 + .../node_modules/whiskey/lib/coverage.js | 225 + .../node_modules/whiskey/lib/debugger.js | 77 + .../node_modules/whiskey/lib/errors.js | 42 + .../whiskey/lib/extern/_debugger.js | 1178 +++ .../lib/extern/long-stack-traces/README.md | 75 + .../extern/long-stack-traces/examples.html | 51 + .../lib/extern/long-stack-traces/examples.js | 30 + .../lib/extern/long-stack-traces/index.js | 1 + .../lib/long-stack-traces.js | 206 + .../lib/extern/long-stack-traces/package.json | 13 + .../whiskey/lib/extern/optparse/README.md | 161 + .../whiskey/lib/extern/optparse/TODO | 1 + .../optparse/examples/browser-test.html | 75 + .../extern/optparse/examples/nodejs-test.js | 90 + .../lib/extern/optparse/lib/optparse.js | 309 + .../whiskey/lib/extern/optparse/package.json | 8 + .../whiskey/lib/extern/optparse/seed.yml | 5 + .../node_modules/whiskey/lib/gen_makefile.js | 41 + .../node_modules/whiskey/lib/parser.js | 115 + .../whiskey/lib/process_runner/run.js | 81 + .../whiskey/lib/process_runner/runner.js | 473 ++ .../whiskey/lib/reporters/coverage/base.js | 32 + .../whiskey/lib/reporters/coverage/cli.js | 80 + .../whiskey/lib/reporters/coverage/html.js | 180 + .../whiskey/lib/reporters/coverage/json.js | 52 + .../whiskey/lib/reporters/index.js | 81 + .../whiskey/lib/reporters/scope-leaks/base.js | 40 + .../whiskey/lib/reporters/scope-leaks/cli.js | 83 + .../whiskey/lib/reporters/test/base.js | 53 + .../whiskey/lib/reporters/test/cli.js | 195 + .../whiskey/lib/reporters/test/tap.js | 158 + .../node_modules/whiskey/lib/run.js | 552 ++ .../node_modules/whiskey/lib/run_test_file.js | 108 + .../node_modules/whiskey/lib/scopeleaks.js | 41 + .../node_modules/whiskey/lib/util.js | 310 + .../whiskey/node_modules/gex/README.md | 84 + .../whiskey/node_modules/gex/lib/gex.js | 82 + .../gex/node_modules/underscore/.npmignore | 3 + .../gex/node_modules/underscore/LICENSE | 22 + .../gex/node_modules/underscore/README.md | 19 + .../gex/node_modules/underscore/index.html | 1975 +++++ .../gex/node_modules/underscore/index.js | 1 + .../gex/node_modules/underscore/package.json | 10 + .../underscore/raw/underscore.psd | Bin 0 -> 215540 bytes .../node_modules/underscore/underscore-min.js | 31 + .../gex/node_modules/underscore/underscore.js | 999 +++ .../whiskey/node_modules/gex/package.json | 22 + .../whiskey/node_modules/logmagic/LICENSE | 202 + .../whiskey/node_modules/logmagic/NOTICE | 5 + .../whiskey/node_modules/logmagic/README.md | 44 + .../node_modules/logmagic/lib/graylog.js | 103 + .../node_modules/logmagic/lib/logmagic.js | 269 + .../node_modules/logmagic/package.json | 18 + .../node_modules/logmagic/tests/bench.js | 13 + .../whiskey/node_modules/logmagic/tests/t.js | 28 + .../node_modules/magic-templates/.npmignore | 1 + .../node_modules/magic-templates/README.md | 82 + .../node_modules/magic-templates/context.js | 125 + .../magic-templates/exceptions.js | 20 + .../magic-templates/extensions.js | 113 + .../node_modules/magic-templates/index.js | 37 + .../node_modules/magic-templates/package.json | 18 + .../magic-templates/tags/block.js | 24 + .../magic-templates/tags/extends.js | 53 + .../node_modules/magic-templates/tags/for.js | 97 + .../node_modules/magic-templates/tags/if.js | 146 + .../magic-templates/tags/include.js | 61 + .../magic-templates/tags/index.js | 6 + .../node_modules/magic-templates/template.js | 43 + .../magic-templates/templateproto.js | 239 + .../magic-templates/tests/base.html | 10 + .../magic-templates/tests/forloop.js | 21 + .../magic-templates/tests/included.html | 4 + .../magic-templates/tests/page.html | 34 + .../node_modules/magic-templates/tests/run.js | 78 + .../magic-templates/tests/run2.js | 54 + .../magic-templates/tests/test.html | 2 + .../magic-templates/tests/test_forloop.html | 29 + .../node_modules/magic-templates/tokens.js | 204 + .../whiskey/node_modules/rimraf/README.md | 3 + .../whiskey/node_modules/rimraf/package.json | 8 + .../whiskey/node_modules/rimraf/rimraf.js | 81 + .../whiskey/node_modules/rimraf/test/run.sh | 10 + .../whiskey/node_modules/rimraf/test/setup.sh | 47 + .../node_modules/rimraf/test/test-async.js | 5 + .../node_modules/rimraf/test/test-sync.js | 3 + .../whiskey/node_modules/simplesets/README.md | 104 + .../node_modules/simplesets/examples/hello.js | 35 + .../node_modules/simplesets/lib/simplesets.js | 321 + .../node_modules/simplesets/package.json | 11 + .../node_modules/simplesets/test/testsets.js | 180 + .../whiskey/node_modules/sprintf/README.md | 14 + .../node_modules/sprintf/lib/sprintf.js | 189 + .../whiskey/node_modules/sprintf/package.json | 14 + .../whiskey/node_modules/terminal/.lvimrc | 3 + .../whiskey/node_modules/terminal/.npmignore | 3 + .../whiskey/node_modules/terminal/Makefile | 11 + .../whiskey/node_modules/terminal/index.js | 30 + .../node_modules/terminal/lib/spinner.js | 210 + .../node_modules/terminal/lib/terminal.js | 468 ++ .../node_modules/terminal/package.json | 34 + .../terminal/tests/test-terminal.js | 215 + .../node_modules/whiskey/package.json | 41 + .../node_modules/whiskey/test/run.sh | 265 + node_modules/cassandra-client/package.json | 39 + node_modules/cassandra-client/test/cass.sh | 13 + node_modules/cassandra-client/test/cass2.sh | 13 + node_modules/cassandra-client/test/cass3.sh | 13 + .../test/conf/cassandra-env.sh | 194 + .../cassandra-client/test/conf/cassandra.yaml | 47 + .../test/conf/log4j-server.properties | 31 + .../test/conf2/cassandra-env.sh | 194 + .../test/conf2/cassandra.yaml | 47 + .../test/conf2/log4j-server.properties | 31 + .../test/conf3/cassandra-env.sh | 194 + .../test/conf3/cassandra.yaml | 47 + .../test/conf3/log4j-server.properties | 31 + .../cassandra-client/test/dependencies.json | 13 + .../cassandra-client/test/test_decoder.js | 257 + .../cassandra-client/test/test_driver.js | 1119 +++ .../cassandra-client/test/test_uuid.js | 105 + node_modules/cassandra-client/test/util.js | 23 + node_modules/nodeunit/.npmignore | 3 + node_modules/nodeunit/CONTRIBUTORS.md | 68 + node_modules/nodeunit/LICENSE | 19 + node_modules/nodeunit/Makefile | 177 + node_modules/nodeunit/README.md | 443 ++ node_modules/nodeunit/bin/nodeunit | 133 + node_modules/nodeunit/bin/nodeunit.json | 10 + node_modules/nodeunit/browser | 1 + node_modules/nodeunit/deps/async.js | 623 ++ node_modules/nodeunit/deps/console.log.js | 55 + node_modules/nodeunit/deps/ejs/History.md | 70 + node_modules/nodeunit/deps/ejs/Makefile | 20 + node_modules/nodeunit/deps/ejs/Readme.md | 152 + node_modules/nodeunit/deps/ejs/benchmark.js | 14 + node_modules/nodeunit/deps/ejs/ejs.js | 531 ++ node_modules/nodeunit/deps/ejs/ejs.min.js | 2 + .../nodeunit/deps/ejs/examples/client.html | 5 + .../nodeunit/deps/ejs/examples/list.ejs | 7 + .../nodeunit/deps/ejs/examples/list.js | 16 + node_modules/nodeunit/deps/ejs/index.js | 2 + node_modules/nodeunit/deps/ejs/lib/ejs.js | 251 + node_modules/nodeunit/deps/ejs/lib/filters.js | 198 + node_modules/nodeunit/deps/ejs/lib/utils.js | 23 + node_modules/nodeunit/deps/ejs/package.json | 11 + .../nodeunit/deps/ejs/support/compile.js | 173 + .../nodeunit/deps/ejs/test/ejs.test.js | 269 + node_modules/nodeunit/deps/json2.js | 481 ++ .../nodeunit/dist/nodeunit/bin/nodeunit | 125 + .../nodeunit/dist/nodeunit/bin/nodeunit.json | 10 + .../nodeunit/dist/nodeunit/deps/async.js | 623 ++ .../dist/nodeunit/deps/console.log.js | 55 + .../nodeunit/dist/nodeunit/deps/ejs.js | 125 + .../nodeunit/dist/nodeunit/deps/json2.js | 481 ++ node_modules/nodeunit/dist/nodeunit/index.js | 3 + node_modules/nodeunit/dist/nodeunit/lib/.swp | Bin 0 -> 12288 bytes .../nodeunit/dist/nodeunit/lib/assert.js | 327 + .../nodeunit/dist/nodeunit/lib/core.js | 316 + .../nodeunit/dist/nodeunit/lib/nodeunit.js | 104 + .../dist/nodeunit/lib/reporters/browser.js | 121 + .../dist/nodeunit/lib/reporters/default.js | 130 + .../dist/nodeunit/lib/reporters/eclipse.js | 104 + .../dist/nodeunit/lib/reporters/html.js | 109 + .../dist/nodeunit/lib/reporters/index.js | 14 + .../dist/nodeunit/lib/reporters/junit.js | 183 + .../dist/nodeunit/lib/reporters/machineout.js | 111 + .../dist/nodeunit/lib/reporters/minimal.js | 120 + .../dist/nodeunit/lib/reporters/nested.js | 213 + .../nodeunit/lib/reporters/skip_passed.js | 107 + .../dist/nodeunit/lib/reporters/tap.js | 65 + .../dist/nodeunit/lib/reporters/verbose.js | 122 + .../nodeunit/dist/nodeunit/lib/track.js | 48 + .../nodeunit/dist/nodeunit/lib/types.js | 189 + .../nodeunit/dist/nodeunit/lib/utils.js | 209 + .../nodeunit/dist/nodeunit/package.json | 65 + .../dist/nodeunit/share/junit.xml.ejs | 19 + .../nodeunit/dist/nodeunit/share/license.js | 11 + .../nodeunit/dist/nodeunit/share/nodeunit.css | 70 + node_modules/nodeunit/doc/nodeunit.md | 60 + .../nodeunit/examples/browser/nodeunit.js | 2034 +++++ .../nodeunit/examples/browser/suite1.js | 12 + .../nodeunit/examples/browser/suite2.js | 13 + .../nodeunit/examples/browser/suite3.js | 7 + .../nodeunit/examples/browser/test.html | 18 + .../nested/nested_reporter_test.unit.js | 94 + node_modules/nodeunit/img/example_fail.png | Bin 0 -> 38642 bytes .../nodeunit/img/example_machineout.png | Bin 0 -> 422136 bytes node_modules/nodeunit/img/example_pass.png | Bin 0 -> 14133 bytes node_modules/nodeunit/index.js | 3 + node_modules/nodeunit/lib/assert.js | 354 + node_modules/nodeunit/lib/core.js | 318 + node_modules/nodeunit/lib/nodeunit.js | 104 + .../nodeunit/lib/reporters/browser.js | 121 + .../nodeunit/lib/reporters/default.js | 131 + .../nodeunit/lib/reporters/eclipse.js | 104 + node_modules/nodeunit/lib/reporters/html.js | 110 + node_modules/nodeunit/lib/reporters/index.js | 14 + node_modules/nodeunit/lib/reporters/junit.js | 180 + .../nodeunit/lib/reporters/machineout.js | 112 + .../nodeunit/lib/reporters/minimal.js | 121 + node_modules/nodeunit/lib/reporters/nested.js | 214 + .../nodeunit/lib/reporters/skip_passed.js | 108 + node_modules/nodeunit/lib/reporters/tap.js | 65 + .../nodeunit/lib/reporters/verbose.js | 123 + node_modules/nodeunit/lib/track.js | 48 + node_modules/nodeunit/lib/types.js | 189 + node_modules/nodeunit/lib/utils.js | 203 + node_modules/nodeunit/man1/nodeunit.1 | 95 + .../nodeunit/node_modules/tap-assert/AUTHORS | 2 + .../nodeunit/node_modules/tap-assert/LICENSE | 23 + .../node_modules/tap-assert/README.md | 3 + .../node_modules/tap-assert/assert.js | 396 + .../node_modules/tap-assert/package.json | 29 + .../node_modules/tap-producer/README.md | 4 + .../node_modules/inherits/README.md | 51 + .../node_modules/inherits/inherits.js | 29 + .../node_modules/inherits/package.json | 7 + .../node_modules/tap-results/README.md | 2 + .../node_modules/tap-results/package.json | 11 + .../node_modules/tap-results/results.js | 68 + .../tap-producer/node_modules/yamlish/LICENSE | 19 + .../node_modules/yamlish/README.md | 20 + .../node_modules/yamlish/package.json | 9 + .../node_modules/yamlish/yamlish.js | 260 + .../node_modules/tap-producer/package.json | 12 + .../node_modules/tap-producer/tap-producer.js | 113 + node_modules/nodeunit/nodelint.cfg | 7 + node_modules/nodeunit/package.json | 67 + node_modules/nodeunit/share/junit.xml.ejs | 19 + node_modules/nodeunit/share/license.js | 11 + node_modules/nodeunit/share/nodeunit.css | 70 + node_modules/nodeunit/test.js | 8 + .../fixtures/coffee/mock_coffee_module.coffee | 4 + .../test/fixtures/dir/mock_module3.js | 1 + .../test/fixtures/dir/mock_module4.js | 1 + .../nodeunit/test/fixtures/mock_module1.js | 1 + .../nodeunit/test/fixtures/mock_module2.js | 1 + .../nodeunit/test/fixtures/raw_jscode1.js | 3 + .../nodeunit/test/fixtures/raw_jscode2.js | 3 + .../nodeunit/test/fixtures/raw_jscode3.js | 1 + node_modules/nodeunit/test/test-base.js | 239 + .../nodeunit/test/test-bettererrors.js | 71 + .../nodeunit/test/test-failing-callbacks.js | 114 + node_modules/nodeunit/test/test-httputil.js | 55 + node_modules/nodeunit/test/test-runfiles.js | 214 + node_modules/nodeunit/test/test-runmodule.js | 177 + node_modules/nodeunit/test/test-runtest.js | 46 + node_modules/nodeunit/test/test-sandbox.js | 31 + .../nodeunit/test/test-testcase-legacy.js | 257 + node_modules/nodeunit/test/test-testcase.js | 256 + node_modules/nodeunit/test/test.html | 28 + node_modules/underscore/.npmignore | 3 + node_modules/underscore/LICENSE | 22 + node_modules/underscore/README.md | 19 + node_modules/underscore/index.html | 1975 +++++ node_modules/underscore/index.js | 1 + node_modules/underscore/package.json | 10 + node_modules/underscore/raw/underscore.psd | Bin 0 -> 215540 bytes node_modules/underscore/underscore-min.js | 31 + node_modules/underscore/underscore.js | 999 +++ package.json | 28 + test/keyspaces/casio.cql | 29 + test/model/index.js | 3 + test/model/user.js | 79 + test/model/vote.js | 33 + test/rebuild.js | 143 + test/test-casio.js | 241 + test/testsuite.sh | 4 + 423 files changed, 70639 insertions(+) create mode 100644 LICENSE create mode 100644 index.js create mode 100644 lib/casio.js create mode 120000 node_modules/.bin/nodeunit create mode 100644 node_modules/async/.gitmodules create mode 100644 node_modules/async/LICENSE create mode 100644 node_modules/async/Makefile create mode 100644 node_modules/async/README.md create mode 100644 node_modules/async/deps/nodeunit.css create mode 100644 node_modules/async/deps/nodeunit.js create mode 100644 node_modules/async/dist/async.min.js create mode 100644 node_modules/async/index.js create mode 100644 node_modules/async/lib/async.js create mode 100644 node_modules/async/nodelint.cfg create mode 100644 node_modules/async/package.json create mode 100644 node_modules/async/test/.swp create mode 100644 node_modules/async/test/test-async.js create mode 100644 node_modules/async/test/test.html create mode 100644 node_modules/cassandra-client/.jslint.conf create mode 100644 node_modules/cassandra-client/.npmignore create mode 100644 node_modules/cassandra-client/CHANGES create mode 100644 node_modules/cassandra-client/LICENSE.txt create mode 100644 node_modules/cassandra-client/LICENSE_buffer_ieee754.txt create mode 100644 node_modules/cassandra-client/README.md create mode 100644 node_modules/cassandra-client/gary.js create mode 100644 node_modules/cassandra-client/lib/bigint.js create mode 100644 node_modules/cassandra-client/lib/decoder.js create mode 100644 node_modules/cassandra-client/lib/driver.js create mode 100644 node_modules/cassandra-client/lib/gen-nodejs/Cassandra.js create mode 100644 node_modules/cassandra-client/lib/gen-nodejs/cassandra_types.js create mode 100644 node_modules/cassandra-client/lib/system.js create mode 100644 node_modules/cassandra-client/lib/uuid.js create mode 100644 node_modules/cassandra-client/node-cassandra-client.js create mode 120000 node_modules/cassandra-client/node_modules/.bin/whiskey create mode 100644 node_modules/cassandra-client/node_modules/async/.gitmodules create mode 100644 node_modules/cassandra-client/node_modules/async/LICENSE create mode 100644 node_modules/cassandra-client/node_modules/async/Makefile create mode 100644 node_modules/cassandra-client/node_modules/async/README.md create mode 100644 node_modules/cassandra-client/node_modules/async/deps/nodeunit.css create mode 100644 node_modules/cassandra-client/node_modules/async/deps/nodeunit.js create mode 100644 node_modules/cassandra-client/node_modules/async/dist/async.min.js create mode 100644 node_modules/cassandra-client/node_modules/async/index.js create mode 100644 node_modules/cassandra-client/node_modules/async/lib/async.js create mode 100644 node_modules/cassandra-client/node_modules/async/nodelint.cfg create mode 100644 node_modules/cassandra-client/node_modules/async/package.json create mode 100644 node_modules/cassandra-client/node_modules/async/test/.swp create mode 100644 node_modules/cassandra-client/node_modules/async/test/test-async.js create mode 100644 node_modules/cassandra-client/node_modules/async/test/test.html create mode 100644 node_modules/cassandra-client/node_modules/node-uuid/.npmignore create mode 100644 node_modules/cassandra-client/node_modules/node-uuid/LICENSE.md create mode 100644 node_modules/cassandra-client/node_modules/node-uuid/README.md create mode 100644 node_modules/cassandra-client/node_modules/node-uuid/benchmark/README.md create mode 100644 node_modules/cassandra-client/node_modules/node-uuid/benchmark/bench.gnu create mode 100755 node_modules/cassandra-client/node_modules/node-uuid/benchmark/bench.sh create mode 100644 node_modules/cassandra-client/node_modules/node-uuid/benchmark/benchmark-native.c create mode 100644 node_modules/cassandra-client/node_modules/node-uuid/benchmark/benchmark.js create mode 100644 node_modules/cassandra-client/node_modules/node-uuid/package.json create mode 100644 node_modules/cassandra-client/node_modules/node-uuid/test/compare_v1.js create mode 100644 node_modules/cassandra-client/node_modules/node-uuid/test/test.html create mode 100644 node_modules/cassandra-client/node_modules/node-uuid/test/test.js create mode 100644 node_modules/cassandra-client/node_modules/node-uuid/uuid.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/LICENSE create mode 100644 node_modules/cassandra-client/node_modules/thrift/NOTICE create mode 100644 node_modules/cassandra-client/node_modules/thrift/README.md create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/README.md create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/client.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/client_multitransport.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/gen-nodejs/BucketStoreMapping.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/gen-nodejs/FacebookService.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/gen-nodejs/UserStorage.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/gen-nodejs/bucketupdater_types.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/gen-nodejs/fb303_types.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/gen-nodejs/scribe.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/gen-nodejs/scribe_types.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/gen-nodejs/user_types.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/scribe_client.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/server.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/server_multitransport.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/examples/user.thrift create mode 100644 node_modules/cassandra-client/node_modules/thrift/lib/thrift/binary_parser.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/lib/thrift/connection.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/lib/thrift/index.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/lib/thrift/protocol.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/lib/thrift/server.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/lib/thrift/thrift.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/lib/thrift/transport.js create mode 100644 node_modules/cassandra-client/node_modules/thrift/package.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/.npmignore create mode 100644 node_modules/cassandra-client/node_modules/whiskey/CHANGES.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/LICENSE create mode 100644 node_modules/cassandra-client/node_modules/whiskey/Makefile create mode 100644 node_modules/cassandra-client/node_modules/whiskey/PROCESS_RUNNER.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/README.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/assets/Makefile.magic create mode 100644 node_modules/cassandra-client/node_modules/whiskey/assets/coverage_html.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/assets/jquery-1.4.3.min.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/assets/jquery.hotkeys.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/assets/jquery.isonscreen.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/assets/jquery.tablesorter.min.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/assets/keybd_closed.png create mode 100644 node_modules/cassandra-client/node_modules/whiskey/assets/keybd_open.png create mode 100644 node_modules/cassandra-client/node_modules/whiskey/assets/style.css create mode 100644 node_modules/cassandra-client/node_modules/whiskey/assets/whiskey.magic create mode 100644 node_modules/cassandra-client/node_modules/whiskey/assets/whiskey_source.magic create mode 100755 node_modules/cassandra-client/node_modules/whiskey/bin/whiskey create mode 100755 node_modules/cassandra-client/node_modules/whiskey/bin/whiskey-process-runner create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/custom-assert-functions.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/dependencies.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/init-test.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/init-timeout.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/init.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/some-file.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-chdir.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-custom-assert-functions.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-custom-assert-methods.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-failure.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-getFilePathAndPattern.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-init-function.js create mode 100755 node_modules/cassandra-client/node_modules/whiskey/example/test-jscoverage.js create mode 100755 node_modules/cassandra-client/node_modules/whiskey/example/test-leaks.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-no-test-functions.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-print-stdout-stderr-timeout.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-scope-leaks.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-setup-and-teardown.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-setup-fail.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-setup-timeout.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-skipped.js create mode 100755 node_modules/cassandra-client/node_modules/whiskey/example/test-stdout-and-stderr-is-captured-on-timeout.js create mode 100755 node_modules/cassandra-client/node_modules/whiskey/example/test-succeeded-tests-are-reported-on-timeout.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-success-with-coverage.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-success.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-teardown-timeout.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-timeout-after-finish.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-timeout-blocking.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-timeout.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/test-uncaught.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/example/timeout-throws.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/index.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/README.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/examples.html create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/examples.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/index.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/lib/long-stack-traces.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/package.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/README.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/TODO create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/examples/browser-test.html create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/examples/nodejs-test.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/lib/optparse.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/package.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/seed.yml create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/assert.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/common.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/constants.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/coverage.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/debugger.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/errors.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/extern/_debugger.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/README.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/examples.html create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/examples.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/index.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/lib/long-stack-traces.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/package.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/README.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/TODO create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/examples/browser-test.html create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/examples/nodejs-test.js create mode 100755 node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/lib/optparse.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/package.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/seed.yml create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/gen_makefile.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/parser.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/process_runner/run.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/process_runner/runner.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/base.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/cli.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/html.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/json.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/reporters/index.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/reporters/scope-leaks/base.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/reporters/scope-leaks/cli.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/reporters/test/base.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/reporters/test/cli.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/reporters/test/tap.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/run.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/run_test_file.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/scopeleaks.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/lib/util.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/README.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/lib/gex.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/.npmignore create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/LICENSE create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/README.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/index.html create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/index.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/package.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/raw/underscore.psd create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/underscore-min.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/underscore.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/package.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/LICENSE create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/NOTICE create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/README.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/lib/graylog.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/lib/logmagic.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/package.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/tests/bench.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/tests/t.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/.npmignore create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/README.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/context.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/exceptions.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/extensions.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/index.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/package.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/block.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/extends.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/for.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/if.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/include.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/index.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/template.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/templateproto.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/base.html create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/forloop.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/included.html create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/page.html create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/run.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/run2.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/test.html create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/test_forloop.html create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tokens.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/README.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/package.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/rimraf.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/run.sh create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/setup.sh create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/test-async.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/test-sync.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/README.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/examples/hello.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/lib/simplesets.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/package.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/test/testsets.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/sprintf/README.md create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/sprintf/lib/sprintf.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/sprintf/package.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/.lvimrc create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/.npmignore create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/Makefile create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/index.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/lib/spinner.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/lib/terminal.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/package.json create mode 100644 node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/tests/test-terminal.js create mode 100644 node_modules/cassandra-client/node_modules/whiskey/package.json create mode 100755 node_modules/cassandra-client/node_modules/whiskey/test/run.sh create mode 100644 node_modules/cassandra-client/package.json create mode 100755 node_modules/cassandra-client/test/cass.sh create mode 100755 node_modules/cassandra-client/test/cass2.sh create mode 100755 node_modules/cassandra-client/test/cass3.sh create mode 100644 node_modules/cassandra-client/test/conf/cassandra-env.sh create mode 100644 node_modules/cassandra-client/test/conf/cassandra.yaml create mode 100644 node_modules/cassandra-client/test/conf/log4j-server.properties create mode 100644 node_modules/cassandra-client/test/conf2/cassandra-env.sh create mode 100644 node_modules/cassandra-client/test/conf2/cassandra.yaml create mode 100644 node_modules/cassandra-client/test/conf2/log4j-server.properties create mode 100644 node_modules/cassandra-client/test/conf3/cassandra-env.sh create mode 100644 node_modules/cassandra-client/test/conf3/cassandra.yaml create mode 100644 node_modules/cassandra-client/test/conf3/log4j-server.properties create mode 100644 node_modules/cassandra-client/test/dependencies.json create mode 100644 node_modules/cassandra-client/test/test_decoder.js create mode 100644 node_modules/cassandra-client/test/test_driver.js create mode 100644 node_modules/cassandra-client/test/test_uuid.js create mode 100644 node_modules/cassandra-client/test/util.js create mode 100644 node_modules/nodeunit/.npmignore create mode 100644 node_modules/nodeunit/CONTRIBUTORS.md create mode 100644 node_modules/nodeunit/LICENSE create mode 100644 node_modules/nodeunit/Makefile create mode 100644 node_modules/nodeunit/README.md create mode 100755 node_modules/nodeunit/bin/nodeunit create mode 100644 node_modules/nodeunit/bin/nodeunit.json create mode 120000 node_modules/nodeunit/browser create mode 100644 node_modules/nodeunit/deps/async.js create mode 100644 node_modules/nodeunit/deps/console.log.js create mode 100644 node_modules/nodeunit/deps/ejs/History.md create mode 100644 node_modules/nodeunit/deps/ejs/Makefile create mode 100644 node_modules/nodeunit/deps/ejs/Readme.md create mode 100644 node_modules/nodeunit/deps/ejs/benchmark.js create mode 100644 node_modules/nodeunit/deps/ejs/ejs.js create mode 100644 node_modules/nodeunit/deps/ejs/ejs.min.js create mode 100644 node_modules/nodeunit/deps/ejs/examples/client.html create mode 100644 node_modules/nodeunit/deps/ejs/examples/list.ejs create mode 100644 node_modules/nodeunit/deps/ejs/examples/list.js create mode 100644 node_modules/nodeunit/deps/ejs/index.js create mode 100644 node_modules/nodeunit/deps/ejs/lib/ejs.js create mode 100644 node_modules/nodeunit/deps/ejs/lib/filters.js create mode 100644 node_modules/nodeunit/deps/ejs/lib/utils.js create mode 100644 node_modules/nodeunit/deps/ejs/package.json create mode 100644 node_modules/nodeunit/deps/ejs/support/compile.js create mode 100644 node_modules/nodeunit/deps/ejs/test/ejs.test.js create mode 100644 node_modules/nodeunit/deps/json2.js create mode 100755 node_modules/nodeunit/dist/nodeunit/bin/nodeunit create mode 100644 node_modules/nodeunit/dist/nodeunit/bin/nodeunit.json create mode 100644 node_modules/nodeunit/dist/nodeunit/deps/async.js create mode 100644 node_modules/nodeunit/dist/nodeunit/deps/console.log.js create mode 100644 node_modules/nodeunit/dist/nodeunit/deps/ejs.js create mode 100644 node_modules/nodeunit/dist/nodeunit/deps/json2.js create mode 100644 node_modules/nodeunit/dist/nodeunit/index.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/.swp create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/assert.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/core.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/nodeunit.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/reporters/browser.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/reporters/default.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/reporters/eclipse.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/reporters/html.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/reporters/index.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/reporters/junit.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/reporters/machineout.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/reporters/minimal.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/reporters/nested.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/reporters/skip_passed.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/reporters/tap.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/reporters/verbose.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/track.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/types.js create mode 100644 node_modules/nodeunit/dist/nodeunit/lib/utils.js create mode 100644 node_modules/nodeunit/dist/nodeunit/package.json create mode 100644 node_modules/nodeunit/dist/nodeunit/share/junit.xml.ejs create mode 100644 node_modules/nodeunit/dist/nodeunit/share/license.js create mode 100644 node_modules/nodeunit/dist/nodeunit/share/nodeunit.css create mode 100644 node_modules/nodeunit/doc/nodeunit.md create mode 100644 node_modules/nodeunit/examples/browser/nodeunit.js create mode 100644 node_modules/nodeunit/examples/browser/suite1.js create mode 100644 node_modules/nodeunit/examples/browser/suite2.js create mode 100644 node_modules/nodeunit/examples/browser/suite3.js create mode 100644 node_modules/nodeunit/examples/browser/test.html create mode 100644 node_modules/nodeunit/examples/nested/nested_reporter_test.unit.js create mode 100644 node_modules/nodeunit/img/example_fail.png create mode 100644 node_modules/nodeunit/img/example_machineout.png create mode 100644 node_modules/nodeunit/img/example_pass.png create mode 100644 node_modules/nodeunit/index.js create mode 100644 node_modules/nodeunit/lib/assert.js create mode 100644 node_modules/nodeunit/lib/core.js create mode 100644 node_modules/nodeunit/lib/nodeunit.js create mode 100644 node_modules/nodeunit/lib/reporters/browser.js create mode 100644 node_modules/nodeunit/lib/reporters/default.js create mode 100644 node_modules/nodeunit/lib/reporters/eclipse.js create mode 100644 node_modules/nodeunit/lib/reporters/html.js create mode 100644 node_modules/nodeunit/lib/reporters/index.js create mode 100644 node_modules/nodeunit/lib/reporters/junit.js create mode 100644 node_modules/nodeunit/lib/reporters/machineout.js create mode 100644 node_modules/nodeunit/lib/reporters/minimal.js create mode 100644 node_modules/nodeunit/lib/reporters/nested.js create mode 100644 node_modules/nodeunit/lib/reporters/skip_passed.js create mode 100644 node_modules/nodeunit/lib/reporters/tap.js create mode 100644 node_modules/nodeunit/lib/reporters/verbose.js create mode 100644 node_modules/nodeunit/lib/track.js create mode 100644 node_modules/nodeunit/lib/types.js create mode 100644 node_modules/nodeunit/lib/utils.js create mode 100644 node_modules/nodeunit/man1/nodeunit.1 create mode 100644 node_modules/nodeunit/node_modules/tap-assert/AUTHORS create mode 100644 node_modules/nodeunit/node_modules/tap-assert/LICENSE create mode 100644 node_modules/nodeunit/node_modules/tap-assert/README.md create mode 100644 node_modules/nodeunit/node_modules/tap-assert/assert.js create mode 100644 node_modules/nodeunit/node_modules/tap-assert/package.json create mode 100644 node_modules/nodeunit/node_modules/tap-producer/README.md create mode 100644 node_modules/nodeunit/node_modules/tap-producer/node_modules/inherits/README.md create mode 100644 node_modules/nodeunit/node_modules/tap-producer/node_modules/inherits/inherits.js create mode 100644 node_modules/nodeunit/node_modules/tap-producer/node_modules/inherits/package.json create mode 100644 node_modules/nodeunit/node_modules/tap-producer/node_modules/tap-results/README.md create mode 100644 node_modules/nodeunit/node_modules/tap-producer/node_modules/tap-results/package.json create mode 100644 node_modules/nodeunit/node_modules/tap-producer/node_modules/tap-results/results.js create mode 100644 node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/LICENSE create mode 100644 node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/README.md create mode 100644 node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/package.json create mode 100644 node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/yamlish.js create mode 100644 node_modules/nodeunit/node_modules/tap-producer/package.json create mode 100644 node_modules/nodeunit/node_modules/tap-producer/tap-producer.js create mode 100644 node_modules/nodeunit/nodelint.cfg create mode 100644 node_modules/nodeunit/package.json create mode 100644 node_modules/nodeunit/share/junit.xml.ejs create mode 100644 node_modules/nodeunit/share/license.js create mode 100644 node_modules/nodeunit/share/nodeunit.css create mode 100644 node_modules/nodeunit/test.js create mode 100644 node_modules/nodeunit/test/fixtures/coffee/mock_coffee_module.coffee create mode 100644 node_modules/nodeunit/test/fixtures/dir/mock_module3.js create mode 100644 node_modules/nodeunit/test/fixtures/dir/mock_module4.js create mode 100644 node_modules/nodeunit/test/fixtures/mock_module1.js create mode 100644 node_modules/nodeunit/test/fixtures/mock_module2.js create mode 100644 node_modules/nodeunit/test/fixtures/raw_jscode1.js create mode 100644 node_modules/nodeunit/test/fixtures/raw_jscode2.js create mode 100644 node_modules/nodeunit/test/fixtures/raw_jscode3.js create mode 100644 node_modules/nodeunit/test/test-base.js create mode 100644 node_modules/nodeunit/test/test-bettererrors.js create mode 100644 node_modules/nodeunit/test/test-failing-callbacks.js create mode 100644 node_modules/nodeunit/test/test-httputil.js create mode 100644 node_modules/nodeunit/test/test-runfiles.js create mode 100644 node_modules/nodeunit/test/test-runmodule.js create mode 100644 node_modules/nodeunit/test/test-runtest.js create mode 100644 node_modules/nodeunit/test/test-sandbox.js create mode 100644 node_modules/nodeunit/test/test-testcase-legacy.js create mode 100644 node_modules/nodeunit/test/test-testcase.js create mode 100644 node_modules/nodeunit/test/test.html create mode 100644 node_modules/underscore/.npmignore create mode 100644 node_modules/underscore/LICENSE create mode 100644 node_modules/underscore/README.md create mode 100644 node_modules/underscore/index.html create mode 100644 node_modules/underscore/index.js create mode 100644 node_modules/underscore/package.json create mode 100644 node_modules/underscore/raw/underscore.psd create mode 100644 node_modules/underscore/underscore-min.js create mode 100644 node_modules/underscore/underscore.js create mode 100644 package.json create mode 100644 test/keyspaces/casio.cql create mode 100644 test/model/index.js create mode 100644 test/model/user.js create mode 100644 test/model/vote.js create mode 100644 test/rebuild.js create mode 100644 test/test-casio.js create mode 100755 test/testsuite.sh diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0c1b6ff --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 Greg Melton + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..eeb338c --- /dev/null +++ b/index.js @@ -0,0 +1 @@ +module.exports = require("./lib/casio"); \ No newline at end of file diff --git a/lib/casio.js b/lib/casio.js new file mode 100644 index 0000000..8419d29 --- /dev/null +++ b/lib/casio.js @@ -0,0 +1,995 @@ +var util = require('util'); +var Buffer = require('buffer').Buffer; + +var _ = require('underscore'); +var async = require('async'); +var Cassandra = require('cassandra-client'); + +/* +todo: + +Column Family Validation Types: + x - Text + x - Counter (support counter column types) + +- Model.property + x - String + x - Date + x - Number + x - Boolean + x - BigInts + x - convert bigint using parseInt(num, 0) + (this essentially makes it a Int32) + + - Object (has one) + - List (has many) + +x - Model.find + x - override returned class + +x - Model.prototype.get + x - cql select statement gen + x - override returned class + +x - Model.prototype.create + x - cql insert statement gen + +- Model.prototype.update + x - cql update statement gen + +- Model.prototype.delete + - cql delete statement gen + +*/ + + + + +/* +-- CQL Type Description +-- ascii US-ASCII character string +-- bigint 64-bit signed long +-- blob Arbitrary hexadecimal bytes (no validation) +-- boolean true or false +-- counter Distributed counter value (64-bit long) +-- decimal Variable-precision decimal +-- double 64-bit IEEE-754 floating point +-- float 32-bit IEEE-754 floating point +-- int 32-bit signed integer +-- text UTF-8 encoded string +-- timestamp Date plus time, encoded as 8 bytes since epoch +-- uuid Type 1 or type 4 UUID +-- varchar UTF-8 encoded string +-- varint Arbitrary-precision integer + + +ZERO +ONE +QUORUM +ALL +DCQUORUM +DCQUORUMSYNC +*/ + + +var Casio = module.exports.Casio = { + _models:{}, + types:{ + BigInteger: Cassandra.BigInteger + } +}; + +Casio.register = function(model){ + this._models[model.prototype._name] = model +}; + +Casio.model = function(name, opts){ + + // set up our default Model options + _.defaults(opts, { + + host: '127.0.0.1', + port: 9160, + + + // todo: partion this different for reads vs writes + // see => http://wiki.apache.org/cassandra/API + consistency:{ + select:'ONE', + insert:'ONE', + update:'ONE', + delete:'ONE' + } + }); + + var Model = function(attrs) { + // console.log(attrs) + + // cache the attrs so we can check + // for dirty values on upate... + this._props = {}; + + // seed defaults and copy attrs; + var colDef; + for (var p in this._schema){ + colDef = this._schema[p]; + this[p] = colDef.default; + this._props[p] = colDef.default; + + // now update the instance with this property value + if (attrs[p] !== undefined) { + var val = attrs[p]; + + switch(colDef.type){ + case Boolean: + // coming from cassandra client these will be string buffers + if (Buffer.isBuffer(val)) { + val = (val[0] == 0) ? false : true; + // just-in-case someone sets a boolean with a 0 or 1 + } else if(val.constructor === Number) { + if (val < 0 && val > 1) { + throw new Error('Tried setting a boolean with a value other then 0 or 1') + } + val = (val[0] == 0) ? false : true; + } + break; + case Casio.types.BigInteger: + // todo: figure what to with BigInteger values here... + val = parseInt(val.toString(), 0); + break + default: + break; + } + this[p] = val; + } + } + return this; + } + /** + * + * + **/ + Model.connect = function(callback){ + var self = this; + this.prototype._client = new Cassandra.Connection(this.prototype._options); + this.prototype._client.connect(function(err){ + self.prototype._clientConnected = true; + callback(err) + }); + } + + /** + Model.primary - Return the primary key column; + + **/ + Model.primary = function(){ + + if (this.prototype._primary) { + return this.prototype._primary; + } + + var prop; + for (var p in this.prototype._schema) { + prop = this.prototype._schema[p]; + if (prop.primary) break; + } + // set this for later; + this.prototype._primary = p; + return p + } + + /** + Model.property - define a prop with name as type with these options + + @p - The name of the property to define + @type - String, Number, Date, etc. + @opts - options for this property type + **/ + Model.property = function(p, type, opts){ + opts = opts || {}; + opts.type = type; + + if (opts.default===undefined){ + switch(opts.type){ + case String: + case Number: + case Object: + default: + _default = null; + break + } + opts.default = _default; + } + this.prototype._schema[p] = opts; + } + + /** + Model.classMethods - Extend class methods + @methods - object of methods + **/ + Model.classMethods = function(methods){ + // _.extend(this, methods) + for (var name in methods){ + if (this[name] !== undefined){ + throw new Error('Falied to extend Model.classMethod. ' + + this.prototype._name + '#' + name + '() already exists.'); + } + this[name] = methods[name]; + } + + } + + /** + Model.instanceMethods - Extend methods as instance methods + @methods - object of methods + **/ + Model.instanceMethods = function(methods){ + for (var name in methods){ + if (this.prototype[name] !== undefined){ + throw new Error('Falied to extend Model.instanceMethod. ' + + this.prototype._name + '#' + name + '() already exists.'); + } + this.prototype[name] = methods[name]; + } + } + + /** + Model.find - return a list of models + @args { + // the columns to select for each row + columns:'*' || ['c1', 'c2', 'c3'], + + // where clause to perform + where: ['key=:key', {key:'somthing'}] + + // optional shallow class to instanitate rows as + as: ClassName + } + @callback + + **/ + Model.find = function(args, callback){ + // console.log(args) + + var q = new CQL('find'); + if (args.columns !== undefined){ + if (typeof(args.columns)==='string'){ + args.columns = [args.columns]; + } + } else { + args.columns = ['*']; + } + q.select(args.columns); + q.from(this.prototype._name); + + if (args.where !== undefined){ + if (args.where instanceof Array){ + var clause = args.where[0]; + var bind = (args.where.length > 1) ? args.where[1] : {}; + q.where(clause, bind); + } + } + if (args.start !== undefined) { + q.first(args.start); + } + if (args.limit !== undefined) { + q.limit(args.limit); + } + + q.consistency(this.prototype._options.consistency.select); + + var s = q.statement(); + this.cql(s, [], function(err, results){ + if (err) return callback(err, null); + var model, models=[]; + + _.each(results, function(item){ + var props = item.colHash; + props.key = item.key; + + // instantiate the model... + if (args.as === undefined){ + model = new Model(props); + model.shadow(); + + } else { + model = new args.as(props); + } + models.push(model); + }) + callback(null, models) + }); + } + + /** + Model.get + Return a single instance of a model. + By default, the model is instantiated... + as the model type this was called from + + @args = key + -or- + @args = { + columns:['*'] // defaults to all. + optional csv or list of specific column names to return + } + @callback - [err, results] + **/ + Model.get = function(args, callback){ + + var primary = this.primary(); + if (typeof(args) !== 'object'){ + // we should a string here... + args = { + where:[primary + '=:key', {key:args}] + } + } else { + // do we have a where clause? + if (args.where === undefined){ + if (args[primary] === undefined) { + return callback(new Error('Missing key in get args object')); + } + args.where = [primary + '=:key', {key:args[primary]}]; + } + } + if (args.columns !== undefined){ + if (typeof(args.columns)==='string'){ + args.columns = [args.columns]; + } + } else { + args.columns = ['*']; + } + + var q = new CQL('get'); + q.select(args.columns); + q.from(this.prototype._name); + + if (args.where !== undefined){ + if (args.where instanceof Array){ + var clause = args.where[0]; + var bind = (args.where.length > 1) ? args.where[1] : {}; + q.where(clause, bind); + } + } + var statement = q.statement(); + // console.log(statement); + this.cql(statement, [], function(err, results) { + if (err) return callback(err, null); + var model; + if (results.length) { + var first = results[0]; + var props = first.colHash; + props.key = first.key; + + // instantiate model + if (args.as === undefined){ + model = new Model(props); + model.shadow(); + + } else { + // we're being told to not instantiate + // these props as new Model(); + // instead as... + model = new args.as(props); + } + + } + callback(null, model); + }); + + }; + + /** + Model.createIndicies - create indicies on all defined properties + @callback + **/ + Model.createIndicies = function(callback) { + // loop over all schema properties and determine which ones are 'indexed' + var prop, statements = []; + for (var p in this.prototype._schema){ + prop = this.prototype._schema[p]; + if (prop.index !== undefined && prop.index) { + console.log('create index for this column:', p) + + var q = new CQL('create index for ' + this.prototype._name + '.' + p); + q.createIndex(this.prototype._name, p); + // statements.push(q.statement()); + + this.cql(q.statement(), [], function(err, results){ + if (err) return console.log(err); + if (results) console.log(results); + }) + + } + } + } + + + /** + Model.incr - increment a key.column counter this many times + @key - the key we want to work on + @col - the column counter + @i - the incr value (+/- ok); defaults to +1 + @callback + **/ + Model.incr = function(key, col, i, callback) { + var primary = this.primary(); + var cb = function(err, results){}; + if (i===undefined){ + callback = cb; + i = 1; + } else if (typeof(i) === 'function'){ + callback = i; + i = 1; + } + // make sure we have a callback + if (callback===undefined){ + callback=cb; + } + var q = new CQL('incr counter'); + + q.update(this.prototype._name); + + // set consitency... + q.consistency(this.prototype._options.consistency.update) + + // todo: set ttl... + + // set timestamp... + q.timestamp(new Date().getTime()); + + var counter = {}; counter[col] = i; + q.counter(counter); + q.where(primary + '=:key', {key:key}) + + var qry = q.statement(); + this.cql(qry, [], function(err, results){ + if (err) return callback(err, null); + callback(null, results); + }) + } + + /** + Model.decr - decremente a key.column counter this many times + This is just a pass wrapper for Model.incr and negates the i value + before calling it... + + @key - the key we want to work on + @col - the column counter + @i - the incr value (+ num only); defaults to -1 + @callback + **/ + Model.decr = function(key, col, i, callback) { + if (i===undefined){ + callback = function(err, results){} + i = 1; + } else if (typeof(i) === 'function'){ + callback = i; + i = 1; + } + this.incr(key, col, -(i), callback); + } + + + /** + * + * + **/ + Model.cql = function(qry, args, callback) { + + if (typeof args === 'function'){ + callback = args + args = []; + } + console.log(qry) + this.prototype._client.execute(qry, args, callback) + } + + Model.prototype = { + _name:null, + _client:null, + _clientConnected:null, + _primary:null, + _schema:{}, + _options:{}, + }; + Model.prototype._name = name; + Model.prototype._options = opts; + + + /** + Model.prototype.shadow - take all the properties and sync model._props values + + **/ + Model.prototype.shadow = function(){ + for (var p in this._schema){ + this._props[p] = this[p]; + } + } + + /** + * + * + **/ + Model.prototype.update = function(callback){ + // determine all dirty properties... + + // create query plan to save dirty properties + + // set updated_at property + + // update _props with new changes... + }; + + /** + Model.prototype.create - Create the model... + + todo: determine how to handle 'default' values + + @callback + **/ + Model.prototype.create = function(callback){ + var q = new CQL('create'); + q.insert(this._name); + + // make sure we have a key... + // if not set a uuid + if (this.key === undefined){ + this.key = new Cassandra.UUID().toString(); + } + + var hasCreatedAt=false; + var hasUpdatedAt=false; + var args = {}, + val, + colDef; + for(var p in this._schema){ + + colDef = this._schema[p] + val = this[p]; + + + // set created_at + if(!hasCreatedAt && p.replace(/_/g,'').toLowerCase() === 'createdat'){ + hasCreatedAt=true; + var dt = new Date(); + this[p] = dt; + val = dt.getTime(); + + } + // set updated_at + else if(!hasUpdatedAt && p.replace(/_/g,'').toLowerCase() === 'updatedat'){ + hasUpdatedAt=true; + var dt = new Date(); + this[p] = dt; + val = dt.getTime(); + } + // make sure we convert all Date values to a timestamp + else if (colDef.type === Date){ + // 1. check to make sure this[p] is a Date + if (val.constructor === Date){ + val = val.getTime(); + } + } else if (colDef.type === Boolean){ + // convert boolean to int; + // if (val.constructor === Boolean){ + // val = (val) ? 1 : 0; + // } + } + + // todo: need to determine how to handle null values + args[p] = val; + + } + // set set args... + q.set(args); + + // set consitency... + q.consistency(this._options.consistency.update) + + // todo: set ttl... + + // set timestamp... + q.timestamp(new Date().getTime()); + + var statement = q.statement(); + console.log(statement); + + + var self = this; + this._client.execute(statement, [], function(err, results){ + if (err) return callback(err); + + // copy all saved props into _props + for (var p in self._schema){ + self._props[p] = self[p] + } + + + callback(null, {created: true}); + }) + }; + + /** + * create or update + * + **/ + Model.prototype.save = function(callback){ + // check to see if this item has a primary key... + // if yes and its null, create a uuid of some kind, and call update. + // if yes and its not null, call update + }; + + /** + * + * + **/ + Model.prototype.delete = function(callback){ + + }; + + /** + Model.prototype.incr - wrapper for Model.incr + + **/ + Model.prototype.incr = function(col, i, callback){ + Model.incr(this[Model.primary()], col, i, callback) + }; + + /** + Model.prototype.decr - wrapper for Model.incr + + **/ + Model.prototype.decr = function(col, i, callback){ + Model.decr(this[Model.primary()], col, i, callback) + }; + + this.register(Model); + + return Model; +} + + + + + + +function quote(s){ + if (typeof(s) === 'string') { + if (s.indexOf("\\'") == -1){ + s = s.replace(/'/g, "\\'"); + } + s = "'" + s + "'"; + } else if (s instanceof Array) { + var temp = []; + _.each(s, function(v){ + temp.push(quote(v)); + }) + s = temp.join(', '); + } + + return s; +} + +var CQL = function(name){ + this.name = name; +} + +CQL.prototype = { + _name:null, + _cmd:null, + _first:null, + _limit:null, + _reversed:null, + _cf:null, + _col:null, + _cols:null, + _consistency:null, + _where:null, + _set:null, + _ttl:null, + _timestamp:null, + _indexName:null, + _counter:null, +} + +CQL.prototype.first = function(num){ + this._first = num; +} +CQL.prototype.limit = function(num){ + this._limit = num; +} +CQL.prototype.reversed = function(b){ + this._reversed = b; +} + +CQL.prototype.from = function(cf){ + this._cf = cf; +} + +CQL.prototype.set = function(args){ + this._set = args; +} + +CQL.prototype.counter = function(args){ + this._counter = args; +} + +CQL.prototype.ttl = function(num){ + this._ttl = num; +} + +CQL.prototype.timestamp = function(num){ + this._timestamp = num; +} + +CQL.prototype.consistency = function(s){ + /* + ZERO + ONE + QUORUM + ALL + DCQUORUM + DCQUORUMSYNC + */ + + this._consistency = s; +} + +CQL.prototype.where = function(s, args){ + if (args !== undefined){ + var v + for (var p in args){ + v = args[p]; + s = s.replace(new RegExp(':' + p), quote(v)) + } + } + this._where = s; +} + +CQL.prototype.select = function(cols){ + this._cmd = 'SELECT'; + if (cols instanceof String){ + cols = [cols]; + } + this._cols = cols; +} + +CQL.prototype.update = function(cf){ + this._cmd = 'UPDATE'; + this._cf = cf; +} + +CQL.prototype.insert = function(cf){ + this._cmd = 'INSERT'; + this._cf = cf; +} + +CQL.prototype.delete = function(cf){ + this._cmd = 'DELETE'; + this._cf = cf; +} + +CQL.prototype.createIndex = function(cf, col){ + this._cmd = 'CREATE INDEX'; + this._indexName = cf + '_' + col; + this._cf = cf; + this._col = col; +} + + +CQL.prototype.count = function(){ + +} + +CQL.prototype.statement = function(){ + var cql = [] + var cmd = this._cmd; + + cql.push(cmd); + + if (cmd === 'SELECT') { + // SELECT [FIRST N] [REVERSED] ",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"], +area:[1,"",""],_default:[0,"",""]};O.optgroup=O.option;O.tbody=O.tfoot=O.colgroup=O.caption=O.thead;O.th=O.td;if(!c.support.htmlSerialize)O._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==A)return this.empty().append((this[0]&&this[0].ownerDocument||u).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this, +d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})}, +unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a= +c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*")); +c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(xa,"").replace(cb,'="$1">').replace($, +"")],e)[0]}else return this.cloneNode(true)});if(a===true){la(this,b);la(this.find("*"),b.find("*"))}return b},html:function(a){if(a===A)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(xa,""):null;else if(typeof a==="string"&&!Aa.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!O[(za.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ya,"<$1>");try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?l.cloneNode(true):l)}k.length&&c.each(k,Ka)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:u;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===u&&!Aa.test(a[0])&&(c.support.checkClone|| +!Ba.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h= +d.length;f0?this.clone(true):this).get();c(d[f])[b](k);e=e.concat(k)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||u;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||u;for(var f=[],h=0,k;(k=a[h])!=null;h++){if(typeof k==="number")k+="";if(k){if(typeof k==="string"&&!bb.test(k))k=b.createTextNode(k);else if(typeof k==="string"){k=k.replace(ya,"<$1>");var l=(za.exec(k)||["",""])[1].toLowerCase(),n=O[l]||O._default, +s=n[0],v=b.createElement("div");for(v.innerHTML=n[1]+k+n[2];s--;)v=v.lastChild;if(!c.support.tbody){s=ab.test(k);l=l==="table"&&!s?v.firstChild&&v.firstChild.childNodes:n[1]===""&&!s?v.childNodes:[];for(n=l.length-1;n>=0;--n)c.nodeName(l[n],"tbody")&&!l[n].childNodes.length&&l[n].parentNode.removeChild(l[n])}!c.support.leadingWhitespace&&$.test(k)&&v.insertBefore(b.createTextNode($.exec(k)[0]),v.firstChild);k=v.childNodes}if(k.nodeType)f.push(k);else f=c.merge(f,k)}}if(d)for(h=0;f[h];h++)if(e&& +c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script"))));d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,k=0,l;(l=a[k])!=null;k++)if(!(l.nodeName&&c.noData[l.nodeName.toLowerCase()]))if(d=l[c.expando]){if((b=e[d])&&b.events)for(var n in b.events)f[n]? +c.event.remove(l,n):c.removeEvent(l,n,b.handle);if(h)delete l[c.expando];else l.removeAttribute&&l.removeAttribute(c.expando);delete e[d]}}});var Ca=/alpha\([^)]*\)/i,db=/opacity=([^)]*)/,eb=/-([a-z])/ig,fb=/([A-Z])/g,Da=/^-?\d+(?:px)?$/i,gb=/^-?\d/,hb={position:"absolute",visibility:"hidden",display:"block"},La=["Left","Right"],Ma=["Top","Bottom"],W,ib=u.defaultView&&u.defaultView.getComputedStyle,jb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===A)return this; +return c.access(this,a,b,true,function(d,e,f){return f!==A?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),k=a.style,l=c.cssHooks[h];b=c.cssProps[h]|| +h;if(d!==A){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!l||!("set"in l)||(d=l.set(a,d))!==A)try{k[b]=d}catch(n){}}}else{if(l&&"get"in l&&(f=l.get(a,false,e))!==A)return f;return k[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==A)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]= +e[f]},camelCase:function(a){return a.replace(eb,jb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=ma(d,b,f);else c.swap(d,hb,function(){h=ma(d,b,f)});return h+"px"}},set:function(d,e){if(Da.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return db.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"": +b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f=d.filter||"";d.filter=Ca.test(f)?f.replace(Ca,e):d.filter+" "+e}};if(ib)W=function(a,b,d){var e;d=d.replace(fb,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return A;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};else if(u.documentElement.currentStyle)W=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b], +h=a.style;if(!Da.test(f)&&gb.test(f)){d=h.left;e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f};if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var kb=c.now(),lb=/)<[^<]*)*<\/script>/gi, +mb=/^(?:select|textarea)/i,nb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ob=/^(?:GET|HEAD|DELETE)$/,Na=/\[\]$/,T=/\=\?(&|$)/,ia=/\?/,pb=/([?&])_=[^&]*/,qb=/^(\w+:)?\/\/([^\/?#]+)/,rb=/%20/g,sb=/#.*$/,Ea=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ea)return Ea.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d= +b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(k,l){if(l==="success"||l==="notmodified")h.html(f?c("
").append(k.responseText.replace(lb,"")).find(f):k.responseText);d&&h.each(d,[k.responseText,l,k])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&& +!this.disabled&&(this.checked||mb.test(this.nodeName)||nb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})}, +getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html", +script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),k=ob.test(h);b.url=b.url.replace(sb,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ia.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data|| +!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+kb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var l=E[d];E[d]=function(m){f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);if(c.isFunction(l))l(m);else{E[d]=A;try{delete E[d]}catch(p){}}v&&v.removeChild(B)}}if(b.dataType==="script"&&b.cache===null)b.cache= +false;if(b.cache===false&&h==="GET"){var n=c.now(),s=b.url.replace(pb,"$1_="+n);b.url=s+(s===b.url?(ia.test(b.url)?"&":"?")+"_="+n:"")}if(b.data&&h==="GET")b.url+=(ia.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");n=(n=qb.exec(b.url))&&(n[1]&&n[1]!==location.protocol||n[2]!==location.host);if(b.dataType==="script"&&h==="GET"&&n){var v=u.getElementsByTagName("head")[0]||u.documentElement,B=u.createElement("script");if(b.scriptCharset)B.charset=b.scriptCharset;B.src= +b.url;if(!d){var D=false;B.onload=B.onreadystatechange=function(){if(!D&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){D=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);B.onload=B.onreadystatechange=null;v&&B.parentNode&&v.removeChild(B)}}}v.insertBefore(B,v.firstChild);return A}var H=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!k||a&&a.contentType)w.setRequestHeader("Content-Type", +b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}n||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(G){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&& +c.triggerGlobal(b,"ajaxSend",[w,b]);var M=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){H||c.handleComplete(b,w,e,f);H=true;if(w)w.onreadystatechange=c.noop}else if(!H&&w&&(w.readyState===4||m==="timeout")){H=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d|| +c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&g.call&&g.call(w);M("abort")}}catch(j){}b.async&&b.timeout>0&&setTimeout(function(){w&&!H&&M("timeout")},b.timeout);try{w.send(k||b.data==null?null:b.data)}catch(o){c.handleError(b,w,null,o);c.handleComplete(b,w,e,f)}b.async||M();return w}},param:function(a,b){var d=[],e=function(h,k){k=c.isFunction(k)?k():k;d[d.length]=encodeURIComponent(h)+ +"="+encodeURIComponent(k)};if(b===A)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)ca(f,a[f],b,e);return d.join("&").replace(rb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess",[b,a])},handleComplete:function(a, +b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),e=a.getResponseHeader("Etag"); +if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}});if(E.ActiveXObject)c.ajaxSettings.xhr= +function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var da={},tb=/^(?:toggle|show|hide)$/,ub=/^([+\-]=)?([\d+.\-]+)(.*)$/,aa,na=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show",3),a,b,d);else{a= +0;for(b=this.length;a=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b, +d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a* +Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(h){return f.step(h)} +this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;var f=this;a=c.fx;e.elem=this.elem;if(e()&&c.timers.push(e)&&!aa)aa=setInterval(a.tick,a.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true; +this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(l,n){f.style["overflow"+n]=h.overflow[l]})}this.options.hide&&c(this.elem).hide();if(this.options.hide|| +this.options.show)for(var k in this.options.curAnim)c.style(this.elem,k,this.options.orig[k]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a= +c.timers,b=0;b-1;e={};var s={};if(n)s=f.position();k=n?s.top:parseInt(k,10)||0;l=n?s.left:parseInt(l,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+k;if(b.left!=null)e.left=b.left-h.left+l;"using"in b?b.using.call(a, +e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Fa.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||u.body;a&&!Fa.test(a.nodeName)&& +c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==A)return this.each(function(){if(h=ea(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=ea(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase(); +c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(h){var k=c(this);k[d](e.call(this,h,k[d]()))});return c.isWindow(f)?f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b]:f.nodeType===9?Math.max(f.documentElement["client"+ +b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]):e===A?parseFloat(c.css(f,d)):this.css(d,typeof e==="string"?e:e+"px")}})})(window); diff --git a/node_modules/cassandra-client/node_modules/whiskey/assets/jquery.hotkeys.js b/node_modules/cassandra-client/node_modules/whiskey/assets/jquery.hotkeys.js new file mode 100644 index 0000000..09b21e0 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/assets/jquery.hotkeys.js @@ -0,0 +1,99 @@ +/* + * jQuery Hotkeys Plugin + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * + * Based upon the plugin by Tzury Bar Yochay: + * http://github.com/tzuryby/hotkeys + * + * Original idea by: + * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/ +*/ + +(function(jQuery){ + + jQuery.hotkeys = { + version: "0.8", + + specialKeys: { + 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause", + 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home", + 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del", + 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7", + 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/", + 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8", + 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta" + }, + + shiftNums: { + "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&", + "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<", + ".": ">", "/": "?", "\\": "|" + } + }; + + function keyHandler( handleObj ) { + // Only care when a possible input has been specified + if ( typeof handleObj.data !== "string" ) { + return; + } + + var origHandler = handleObj.handler, + keys = handleObj.data.toLowerCase().split(" "); + + handleObj.handler = function( event ) { + // Don't fire in text-accepting inputs that we didn't directly bind to + if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) || + event.target.type === "text") ) { + return; + } + + // Keypress represents characters, not special keys + var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ], + character = String.fromCharCode( event.which ).toLowerCase(), + key, modif = "", possible = {}; + + // check combinations (alt|ctrl|shift+anything) + if ( event.altKey && special !== "alt" ) { + modif += "alt+"; + } + + if ( event.ctrlKey && special !== "ctrl" ) { + modif += "ctrl+"; + } + + // TODO: Need to make sure this works consistently across platforms + if ( event.metaKey && !event.ctrlKey && special !== "meta" ) { + modif += "meta+"; + } + + if ( event.shiftKey && special !== "shift" ) { + modif += "shift+"; + } + + if ( special ) { + possible[ modif + special ] = true; + + } else { + possible[ modif + character ] = true; + possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true; + + // "$" can be triggered as "Shift+4" or "Shift+$" or just "$" + if ( modif === "shift+" ) { + possible[ jQuery.hotkeys.shiftNums[ character ] ] = true; + } + } + + for ( var i = 0, l = keys.length; i < l; i++ ) { + if ( possible[ keys[i] ] ) { + return origHandler.apply( this, arguments ); + } + } + }; + } + + jQuery.each([ "keydown", "keyup", "keypress" ], function() { + jQuery.event.special[ this ] = { add: keyHandler }; + }); + +})( jQuery ); diff --git a/node_modules/cassandra-client/node_modules/whiskey/assets/jquery.isonscreen.js b/node_modules/cassandra-client/node_modules/whiskey/assets/jquery.isonscreen.js new file mode 100644 index 0000000..0182ebd --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/assets/jquery.isonscreen.js @@ -0,0 +1,53 @@ +/* Copyright (c) 2010 + * @author Laurence Wheway + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * + * @version 1.2.0 + */ +(function($) { + jQuery.extend({ + isOnScreen: function(box, container) { + //ensure numbers come in as intgers (not strings) and remove 'px' is it's there + for(var i in box){box[i] = parseFloat(box[i])}; + for(var i in container){container[i] = parseFloat(container[i])}; + + if(!container){ + container = { + left: $(window).scrollLeft(), + top: $(window).scrollTop(), + width: $(window).width(), + height: $(window).height() + } + } + + if( box.left+box.width-container.left > 0 && + box.left < container.width+container.left && + box.top+box.height-container.top > 0 && + box.top < container.height+container.top + ) return true; + return false; + } + }) + + + jQuery.fn.isOnScreen = function (container) { + for(var i in container){container[i] = parseFloat(container[i])}; + + if(!container){ + container = { + left: $(window).scrollLeft(), + top: $(window).scrollTop(), + width: $(window).width(), + height: $(window).height() + } + } + + if( $(this).offset().left+$(this).width()-container.left > 0 && + $(this).offset().left < container.width+container.left && + $(this).offset().top+$(this).height()-container.top > 0 && + $(this).offset().top < container.height+container.top + ) return true; + return false; + } +})(jQuery); diff --git a/node_modules/cassandra-client/node_modules/whiskey/assets/jquery.tablesorter.min.js b/node_modules/cassandra-client/node_modules/whiskey/assets/jquery.tablesorter.min.js new file mode 100644 index 0000000..64c7007 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/assets/jquery.tablesorter.min.js @@ -0,0 +1,2 @@ + +(function($){$.extend({tablesorter:new function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'.',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}var rows=table.tBodies[0].rows;if(table.tBodies[0].rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('
').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;ib)?1:0));};function sortTextDesc(a,b){return((ba)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){$this.trigger("sortStart");var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){var $cell=$(this);var i=this.column;this.order=this.count++%2;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;iD6{MWQjEnx?oJHr&dIz4a@dl*-CY>| zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfZ8lau9@bl*u7(4JIy_w*Lo808 zo$Afkpupp@{Fv_bobxQ#pD>iB3oNa1d9=pM`D99*FvsH{pKJfpB1-4UD;=6}F=+gKX>Gx9b=!>PY1_pdfo@{(boFyt=akR{ E04sl8JOBUy literal 0 HcmV?d00001 diff --git a/node_modules/cassandra-client/node_modules/whiskey/assets/keybd_open.png b/node_modules/cassandra-client/node_modules/whiskey/assets/keybd_open.png new file mode 100644 index 0000000000000000000000000000000000000000..a77961db5424cfff43a63d399972ee85fc0dfdb1 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0vp^%0SG+!3HE>D6{MWQjEnx?oJHr&dIz4a@dl*-CY>| zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfZ8lau9%kc-1xY}mZci7-5R21$ zCp+>TR^VYdE*ieC^FGV{Cyeh_21=Rotz3KNq=!VmdK II;Vst00jnQH~;_u literal 0 HcmV?d00001 diff --git a/node_modules/cassandra-client/node_modules/whiskey/assets/style.css b/node_modules/cassandra-client/node_modules/whiskey/assets/style.css new file mode 100644 index 0000000..c40357b --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/assets/style.css @@ -0,0 +1,275 @@ +/* CSS styles for Coverage. */ +/* Page-wide styles */ +html, body, h1, h2, h3, p, td, th { + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-weight: inherit; + font-style: inherit; + font-size: 100%; + font-family: inherit; + vertical-align: baseline; + } + +/* Set baseline grid to 16 pt. */ +body { + font-family: georgia, serif; + font-size: 1em; + } + +html>body { + font-size: 16px; + } + +/* Set base font size to 12/16 */ +p { + font-size: .75em; /* 12/16 */ + line-height: 1.3333em; /* 16/12 */ + } + +table { + border-collapse: collapse; + } + +a.nav { + text-decoration: none; + color: inherit; + } +a.nav:hover { + text-decoration: underline; + color: inherit; + } + +/* Page structure */ +#header { + background: #f8f8f8; + width: 100%; + border-bottom: 1px solid #eee; + } + +#source { + padding: 1em; + font-family: "courier new", monospace; + } + +#indexfile #footer { + margin: 1em 3em; + } + +#pyfile #footer { + margin: 1em 1em; + } + +#footer .content { + padding: 0; + font-size: 85%; + font-family: verdana, sans-serif; + color: #666666; + font-style: italic; + } + +#index { + margin: 1em 0 0 3em; + } + +/* Header styles */ +#header .content { + padding: 1em 3em; + } + +h1 { + font-size: 1.25em; +} + +h2.stats { + margin-top: .5em; + font-size: 1em; +} +.stats span { + border: 1px solid; + padding: .1em .25em; + margin: 0 .1em; + cursor: pointer; + border-color: #999 #ccc #ccc #999; +} +.stats span.hide_run, .stats span.hide_exc, +.stats span.hide_mis, .stats span.hide_par, +.stats span.par.hide_run.hide_par { + border-color: #ccc #999 #999 #ccc; +} +.stats span.par.hide_run { + border-color: #999 #ccc #ccc #999; +} + +/* Help panel */ +#keyboard_icon { + float: right; + cursor: pointer; +} + +.help_panel { + position: absolute; + background: #ffc; + padding: .5em; + border: 1px solid #883; + display: none; +} + +#indexfile .help_panel { + width: 20em; height: 4em; +} + +#pyfile .help_panel { + width: 16em; height: 8em; +} + +.help_panel .legend { + font-style: italic; + margin-bottom: 1em; +} + +#panel_icon { + float: right; + cursor: pointer; +} + +.keyhelp { + margin: .75em; +} + +.keyhelp .key { + border: 1px solid black; + border-color: #888 #333 #333 #888; + padding: .1em .35em; + font-family: monospace; + font-weight: bold; + background: #eee; +} + +/* Source file styles */ +.linenos p { + text-align: right; + margin: 0; + padding: 0 .5em; + color: #999999; + font-family: verdana, sans-serif; + font-size: .625em; /* 10/16 */ + line-height: 1.6em; /* 16/10 */ + } +.linenos p.highlight { + background: #ffdd00; + } +.linenos p a { + text-decoration: none; + color: #999999; + } +.linenos p a:hover { + text-decoration: underline; + color: #999999; + } + +td.text { + width: 100%; + } +.text p { + margin: 0; + padding: 0 0 0 .5em; + border-left: 2px solid #ffffff; + white-space: nowrap; + } + +.text p.mis { + background: #ffdddd; + border-left: 2px solid #ff0000; + } +.text p.run, .text p.run.hide_par { + background: #ddffdd; + border-left: 2px solid #00ff00; + } +.text p.exc { + background: #eeeeee; + border-left: 2px solid #808080; + } +.text p.par, .text p.par.hide_run { + background: #ffffaa; + border-left: 2px solid #eeee99; + } +.text p.hide_run, .text p.hide_exc, .text p.hide_mis, .text p.hide_par, +.text p.hide_run.hide_par { + background: inherit; + } + +.text span.annotate { + font-family: georgia; + font-style: italic; + color: #666; + float: right; + padding-right: .5em; + } +.text p.hide_par span.annotate { + display: none; + } + +/* Syntax coloring */ +.text .com { + color: green; + font-style: italic; + line-height: 1px; + } +.text .key { + font-weight: bold; + line-height: 1px; + } +.text .str { + color: #000080; + } + +/* index styles */ +#index td, #index th { + text-align: right; + width: 5em; + padding: .25em .5em; + border-bottom: 1px solid #eee; + } +#index th { + font-style: italic; + color: #333; + border-bottom: 1px solid #ccc; + cursor: pointer; + } +#index th:hover { + background: #eee; + border-bottom: 1px solid #999; + } +#index td.left, #index th.left { + padding-left: 0; + } +#index td.right, #index th.right { + padding-right: 0; + } +#index th.headerSortDown, #index th.headerSortUp { + border-bottom: 1px solid #000; + } +#index td.name, #index th.name { + text-align: left; + width: auto; + } +#index td.name a { + text-decoration: none; + color: #000; + } +#index td.name a:hover { + text-decoration: underline; + color: #000; + } +#index tr.total { + } +#index tr.total td { + font-weight: bold; + border-top: 1px solid #ccc; + border-bottom: none; + } +#index tr.file:hover { + background: #eeeeee; + } diff --git a/node_modules/cassandra-client/node_modules/whiskey/assets/whiskey.magic b/node_modules/cassandra-client/node_modules/whiskey/assets/whiskey.magic new file mode 100644 index 0000000..8c62fd4 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/assets/whiskey.magic @@ -0,0 +1,97 @@ + + + + + Coverage report + + + + + + + + + + + +
+ +

Hot-keys on this page

+
+

+ n + s + m + {% if arcs %} + b + p + {% endif %} + c   change column sorting +

+
+
+ +
+
+ + {# The title='' attr doesn't work in Safari. #} + + + + + {% if arcs %} + + + {% endif %} + + + + {# HTML syntax requires thead, tfoot, tbody #} + + + + + + {% if arcs %} + + + {% endif %} + + + + + {% for file in cov.files %} + + + + + {% if arcs %} + + + {% endif %} + + + {% endfor %} + +
Modulestatementsmissingbranchespartialcoverage
Total{{cov.totalHits}}{{cov.totalMisses}}{{totals.n_branches}}{{totals.n_missing_branches}}{{cov.coverage}}%
{{file.name}}{{file.totalHits}}{{file.totalMisses}}{{file.nums.n_branches}}{{file.nums.n_missing_branches}}{{file.coverage}}%
+ + + + + diff --git a/node_modules/cassandra-client/node_modules/whiskey/assets/whiskey_source.magic b/node_modules/cassandra-client/node_modules/whiskey/assets/whiskey_source.magic new file mode 100644 index 0000000..8ae696b --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/assets/whiskey_source.magic @@ -0,0 +1,83 @@ + + + + + {# IE8 rounds line-height incorrectly, and adding this emulateIE7 line makes it right! #} + {# http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/7684445e-f080-4d8f-8529-132763348e21 #} + + Coverage for {{name}}: {{cov.coverage}}% + + + + + + + + + + + +
+ +

Hot-keys on this page

+
+

+ r + m   toggle line displays +

+

+ j + k   next/prev highlighted chunk +

+

+ 0   (zero) top of page +

+

+ 1   (one) first highlighted chunk +

+
+
+ +
+ + + + + +
+ {% for line in markup %} +

{{line.number}}

+ {% endfor %} +
+ {% for line in markup %} +

{% if line.annotate %}{{line.annotate}}{% endif %}{{line.source}} 

+ {% endfor %} +
+
+ + + + + diff --git a/node_modules/cassandra-client/node_modules/whiskey/bin/whiskey b/node_modules/cassandra-client/node_modules/whiskey/bin/whiskey new file mode 100755 index 0000000..a117eff --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/bin/whiskey @@ -0,0 +1,53 @@ +#!/usr/bin/env node +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var path = require('path'); + +var logmagic = require('logmagic'); + +var cwd = process.cwd(); +var argv = process.argv; +var whiskey = require('../index'); +var run = require('../lib/run'); +var argvLen = argv.length; + +if (argvLen >= 3) { + if (argv[2].indexOf('-') !== 0) { + argv.splice(2, 0, '--tests'); + } +} + +logmagic.route('whiskey.process_runner.*', logmagic.INFO, 'process_runner'); +whiskey.run(cwd, argv); + +process.on('uncaughtException', function(err) { + console.log(err.message); + + if (err.stack) { + console.log(err.stack); + } + + run.exitCode = 1; + + if (run.processRunner) { + run.processRunner.stop(process.exit.bind(null, 1)); + } + else { + process.exit(1); + } +}); diff --git a/node_modules/cassandra-client/node_modules/whiskey/bin/whiskey-process-runner b/node_modules/cassandra-client/node_modules/whiskey/bin/whiskey-process-runner new file mode 100755 index 0000000..4b8544b --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/bin/whiskey-process-runner @@ -0,0 +1,34 @@ +#!/usr/bin/env node +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var logmagic = require('logmagic'); + +var run = require('./../lib/process_runner/run').run; + +logmagic.route('whiskey.process_runner.*', logmagic.INFO, 'process_runner'); +run(process.argv); + +process.on('uncaughtException', function(err) { + console.log(err.message); + + if (err.stack) { + console.log(err.stack); + } + + process.exit(1); +}); diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/custom-assert-functions.js b/node_modules/cassandra-client/node_modules/whiskey/example/custom-assert-functions.js new file mode 100644 index 0000000..11cd878 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/custom-assert-functions.js @@ -0,0 +1,9 @@ +function assertThrow() { + throw new Error('Assert thrown'); +} + +function assertNoop() { +} + +exports.assertThrow = assertThrow; +exports.assertNoop = assertNoop; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/dependencies.json b/node_modules/cassandra-client/node_modules/whiskey/example/dependencies.json new file mode 100644 index 0000000..95a9212 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/dependencies.json @@ -0,0 +1,27 @@ +{ + "cassandra": { + "cmd": ["/usr/local/bin/cassandra/", "-f"], + "cwd": ["__dirname", ".."], + "log_file": "cassandra.log", + "wait_for": "socket", + "wait_for_options": { + "host": "127.0.0.1", + "port": "1234" + }, + "timeout": 6000, + "depends": [] + }, + + "api_server": { + "cmd": ["bin/api-server"], + "depends": ["cassandra"] + }, + + "celery": { + "cmd": ["celeryd", "-w", "5"], + "wait_for": "stdout", + "wait_for_options": { + "string": "Celery has been started..." + } + } +} diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/init-test.js b/node_modules/cassandra-client/node_modules/whiskey/example/init-test.js new file mode 100644 index 0000000..46f03f0 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/init-test.js @@ -0,0 +1,27 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var path = require('path'); +var fs = require('fs'); + +var dirPath = path.join(process.cwd(), 'example/test-123456'); + +exports['init'] = function(callback) { + fs.rmdir(dirPath, function(err) { + callback(); + }); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/init-timeout.js b/node_modules/cassandra-client/node_modules/whiskey/example/init-timeout.js new file mode 100644 index 0000000..8bf660a --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/init-timeout.js @@ -0,0 +1,19 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +exports['init'] = function(callback) { +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/init.js b/node_modules/cassandra-client/node_modules/whiskey/example/init.js new file mode 100644 index 0000000..e56015c --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/init.js @@ -0,0 +1,27 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var path = require('path'); +var fs = require('fs'); + +var dirPath = path.join(process.cwd(), 'example/test-123456'); + +exports['init'] = function(callback) { + fs.mkdir(dirPath, 0655, function(err) { + callback(); + }); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/some-file.js b/node_modules/cassandra-client/node_modules/whiskey/example/some-file.js new file mode 100644 index 0000000..97925ac --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/some-file.js @@ -0,0 +1,39 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var throwException = function() { + throw new Error('failure!'); +}; + +var throwNestedFunctions = function() { + var function1 = function(callback) { + var function2 = function(callback) { + var function3 = function(callback) { + throw new Error('woho, failure!'); + }; + + function3(callback); + }; + + function2(callback); + }; + + function1(function() {}); +}; + +exports.throwException = throwException; +exports.throwNestedFunctions = throwNestedFunctions; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-chdir.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-chdir.js new file mode 100644 index 0000000..6d9c3e3 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-chdir.js @@ -0,0 +1,22 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + * + */ + +exports['test_chdir'] = function(test, assert) { + assert.ok(process.cwd().indexOf('example') !== -1); + test.finish(); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-custom-assert-functions.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-custom-assert-functions.js new file mode 100644 index 0000000..4879fe1 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-custom-assert-functions.js @@ -0,0 +1,8 @@ +exports['test_assertThrow'] = function(test, assert) { + assert.assertThrow(); +}; + +exports['test_assertNoop'] = function(test, assert) { + assert.assertNoop(); + test.finish(); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-custom-assert-methods.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-custom-assert-methods.js new file mode 100644 index 0000000..302097e --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-custom-assert-methods.js @@ -0,0 +1,64 @@ +var http = require('http'); + +var async = require('async'); + +exports['test_assert.response'] = function(test, assert) { + var server = http.createServer(function (req, res) { + if (req.method === 'GET') { + res.writeHead(200, {'Content-Type': 'text/plain'}); + } + else { + res.writeHead(404, {'Content-Type': 'text/plain'}); + } + + res.end('hello world'); + }); + + async.series([ + function testGet(callback) { + var req = { + 'url': '/test', + 'method': 'get' + }; + + assert.response(server, req, function(res) { + assert.equal(res.statusCode, 200); + assert.equal(res.body, 'hello world'); + callback(); + }); + }, + + function testPost(callback) { + var req = { + 'url': '/test', + 'method': 'post' + }; + + assert.response(server, req, function(res) { + assert.equal(res.statusCode, 404); + assert.equal(res.body, 'hello world'); + callback(); + }); + } + ], + + function(err) { + assert.ifError(err); + test.finish(); + }); +}; + +exports['test_other_custom_asserts_functions'] = function(test, assert) { + assert.isNull(null); + assert.isNotNull(1); + assert.isNotNull(false); + assert.isNotNull(0); + assert.isNotNull(-1); + assert.isDefined(1); + assert.type('a', 'string'); + assert.type(function() {}, 'function'); + assert.includes([1,2,3], 2); + assert.length([1,2,3], 3); + + test.finish(); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-failure.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-failure.js new file mode 100644 index 0000000..d184454 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-failure.js @@ -0,0 +1,26 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +exports['test_false_is_not_equal_true'] = function(test, assert) { + assert.ok(false); + test.finish(); +}; + +exports['test_one_is_not_equal_two'] = function(test, assert) { + assert.equal(1, 2); + test.finish(); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-getFilePathAndPattern.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-getFilePathAndPattern.js new file mode 100644 index 0000000..6c116ef --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-getFilePathAndPattern.js @@ -0,0 +1,37 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var common = require('../lib/common'); + +exports['test_getTestFilePathAndPattern'] = function(test, assert) { + var i, len, item; + var data = [ + [ 'foo.js', [ 'foo.js', '*' ] ], + [ '/bar/foo.js', [ '/bar/foo.js', '*' ] ], + [ 'example.foo.', [ 'example/foo.js', '*'] ], + [ 'example.foo.bar*', [ 'example/foo.js', 'bar*'] ], + [ 'a.b?e*', [ 'a.js', 'b?e*'] ], + + ]; + + for (i = 0, len = data.length; i < len; i++) { + item = data[i]; + assert.deepEqual(common.getTestFilePathAndPattern(item[0]), item[1]); + } + + test.finish(); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-init-function.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-init-function.js new file mode 100644 index 0000000..7a90a6a --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-init-function.js @@ -0,0 +1,28 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var path = require('path'); +var fs = require('fs'); + +var dirPath = path.join(process.cwd(), 'example/test-123456'); + +exports['test_folder_exists'] = function(test, assert) { + fs.mkdir(dirPath, 0655, function(err) { + assert.ifError(err); + test.finish(); + }); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-jscoverage.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-jscoverage.js new file mode 100755 index 0000000..1152f3a --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-jscoverage.js @@ -0,0 +1,24 @@ +#!/usr/bin/env node + +var assert = require('../lib/assert').getAssertModule(); +var exec = require('child_process').exec; + +var sprintf = require('sprintf').sprintf; + +var cwd = process.cwd(); + +exec(sprintf('%s/bin/whiskey --tests %s/example/test-success-with-coverage.js --timeout 6000 --coverage --coverage-reporter cli', cwd, cwd), + function(err, stdout, stderr) { + try { + assert.match(stdout, /test coverage/i); + assert.match(stdout, /coverage\.js/); + assert.match(stdout, /loc/i); + assert.match(stdout, /sloc/i); + assert.match(stdout, /missed/i); + } + catch (err2) { + process.exit(5); + } + + process.exit(0); +}); diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-leaks.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-leaks.js new file mode 100755 index 0000000..77d6902 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-leaks.js @@ -0,0 +1,55 @@ +#!/usr/bin/env node + +var assert = require('../lib/assert').getAssertModule(); +var exec = require('child_process').exec; + +var sprintf = require('sprintf').sprintf; +var async = require('async'); + +var cwd = process.cwd(); +var cmd1 = sprintf('%s/bin/whiskey --tests %s/example/test-scope-leaks.js ' + + '--sequential --scope-leaks --timeout 2000', cwd, cwd); + +var cmd2 = sprintf('%s/bin/whiskey --tests %s/example/test-scope-leaks.js ' + + '--concurrency 100 --scope-leaks --timeout 2000', cwd, cwd); + +async.series([ + function testSequentialMode(callback) { + exec(cmd1, function(err, stdout, stderr) { + try { + assert.match(stdout, /leaked variables/i); + assert.match(stdout, /test_scope_leaks_on_success: a, b, c[^,]/i); + assert.match(stdout, /test_scope_leaks_on_failure: d[^,]/i); + } + catch (err2) { + callback(err2); + return; + } + + callback(); + }); + }, + + function testParallelMode(callback) { + exec(cmd2, function(err, stdout, stderr) { + try { + assert.match(stdout, /leaked variables/i); + assert.match(stdout, /test-scope-leaks\.js:/i); + } + catch (err2) { + callback(err2); + return; + } + + callback(); + }); + }], + + function(err) { + if (err) { + process.exit(3); + } + else { + process.exit(0); + } + }); diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-no-test-functions.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-no-test-functions.js new file mode 100644 index 0000000..841eeab --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-no-test-functions.js @@ -0,0 +1 @@ +exports['some_function'] = function() {}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-print-stdout-stderr-timeout.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-print-stdout-stderr-timeout.js new file mode 100644 index 0000000..24e222c --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-print-stdout-stderr-timeout.js @@ -0,0 +1,27 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +exports['test_print_stdout_and_stderr_timeout'] = function(test, assert) { + console.log('this is stdout 1'); + console.error('this is stderr 1'); + process.stdout.write('this is stdout 2'); + process.stderr.write('this is stderr 2'); + + setTimeout(function() { + test.finish(); + }, 500000); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-scope-leaks.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-scope-leaks.js new file mode 100644 index 0000000..75f2a66 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-scope-leaks.js @@ -0,0 +1,33 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +exports['test_scope_leaks_on_success'] = function(test, assert) { + a = 1; + b = 2 + c = 3; + + assert.ok(true); + test.finish(); +}; + +exports['test_scope_leaks_on_failure'] = function(test, assert) { + d = 4; + assert.ok(false); + e = 5; + + test.finish(); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-setup-and-teardown.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-setup-and-teardown.js new file mode 100644 index 0000000..850ce5c --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-setup-and-teardown.js @@ -0,0 +1,62 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var i = 0; +var called = false; +var n = 0; + +exports['not_called'] = function(test, assert) { + assert.ok(false); + test.finish(); +}; + +exports['setUp'] = function(test, assert) { + i = 9; + called = true; + n++; + test.finish(); +}; + +exports['test_indexOf'] = function(test, assert) { + assert.ok(called); + assert.equal('test'.indexOf('test'), 0); + setTimeout(function() { + n++; + test.finish(); + }, 50); +}; + +exports['test_throw'] = function(test, assert) { + assert.ok(called); + + try { + throw new Error('test'); + } + catch (err) { + assert.ok(err); + } + + n++; + test.finish(); +}; + +exports['tearDown'] = function(test, assert) { + assert.ok(called); + assert.equal(n, 3); + + test.finish(); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-setup-fail.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-setup-fail.js new file mode 100644 index 0000000..c45e11e --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-setup-fail.js @@ -0,0 +1,31 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +exports['setUp'] = function(test, assert) { + assert.ok(false); + test.finish(); +}; + +exports['test_1'] = function(test, assert) { + assert.ok(false); + test.finish(); +}; + +exports['test_2'] = function(test, assert) { + assert.ok(false); + test.finish(); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-setup-timeout.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-setup-timeout.js new file mode 100644 index 0000000..c843bfa --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-setup-timeout.js @@ -0,0 +1,24 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +exports['setUp'] = function(test, assert) { +}; + +exports['test_one_equals_two'] = function(test, assert) { + assert.equal(1, 2); + test.finish(); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-skipped.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-skipped.js new file mode 100644 index 0000000..279adc6 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-skipped.js @@ -0,0 +1,30 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +exports['test_skip1'] = function(test, assert) { + test.skip("some reason blah"); + assert.ok(false); +}; + +exports['test_skip2'] = function(test, assert) { + assert.ok(true); + + setTimeout(function() { + test.skip(); + assert.equal(1, 3); + }, 10); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-stdout-and-stderr-is-captured-on-timeout.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-stdout-and-stderr-is-captured-on-timeout.js new file mode 100755 index 0000000..51567cc --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-stdout-and-stderr-is-captured-on-timeout.js @@ -0,0 +1,23 @@ +#!/usr/bin/env node + +var assert = require('../lib/assert').getAssertModule(); +var exec = require('child_process').exec; + +var sprintf = require('sprintf').sprintf; + +var cwd = process.cwd(); + +exec(sprintf('%s/bin/whiskey --tests %s/example/test-print-stdout-stderr-timeout.js --timeout 1000', cwd, cwd), + function(err, stdout, stderr) { + try { + assert.match(stdout, /this is stdout 1/); + assert.match(stdout, /this is stdout 2/); + assert.match(stdout, /this is stderr 1/); + assert.match(stdout, /this is stderr 2/); + } + catch (err2) { + process.exit(5); + } + + process.exit(0); +}); diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-succeeded-tests-are-reported-on-timeout.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-succeeded-tests-are-reported-on-timeout.js new file mode 100755 index 0000000..b72e7b8 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-succeeded-tests-are-reported-on-timeout.js @@ -0,0 +1,24 @@ +#!/usr/bin/env node + +var assert = require('../lib/assert').getAssertModule(); +var exec = require('child_process').exec; + +var sprintf = require('sprintf').sprintf; + +var cwd = process.cwd(); + +exec(sprintf('%s/bin/whiskey --tests %s/example/test-timeout.js --timeout 1000', cwd, cwd), + function(err, stdout, stderr) { + try { + assert.match(stdout, /test_success_1/); + assert.match(stdout, /test_success_2/); + assert.match(stdout, /test_success_3/); + assert.match(stdout, /timeout/i); + } + catch (err2) { + process.exit(4); + } + + process.exit(0); + }); + diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-success-with-coverage.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-success-with-coverage.js new file mode 100644 index 0000000..24477f6 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-success-with-coverage.js @@ -0,0 +1,22 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +exports['test_coverage_file_coverage'] = function(test, assert) { + require('coverage'); + assert.ok(true); + test.finish(); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-success.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-success.js new file mode 100644 index 0000000..1cf08f4 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-success.js @@ -0,0 +1,37 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var n = 0; + +exports['test_true_equals_true'] = function(test, assert) { + assert.ok(true); + + setTimeout(function() { + n++; + test.finish(); + }, 100); +}; + +exports['test_two_plus_two_equals_four'] = function(done, assert) { + assert.equal(2 + 2, 4); + done(); +}; + +exports['tearDown'] = function(test, assert) { + assert.ok(n === 1); + test.finish(); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-teardown-timeout.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-teardown-timeout.js new file mode 100644 index 0000000..3f11911 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-teardown-timeout.js @@ -0,0 +1,24 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +exports['test_one_equals_two'] = function(test, assert) { + assert.equal(1, 2); + test.finish(); +}; + +exports['tearDown'] = function(test, assert) { +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-timeout-after-finish.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-timeout-after-finish.js new file mode 100644 index 0000000..8037a83 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-timeout-after-finish.js @@ -0,0 +1,23 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +exports['test_timeout_after_finish'] = function(test, assert) { + test.finish(); + setTimeout(function() { + assert.ok(false); + }, 50000); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-timeout-blocking.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-timeout-blocking.js new file mode 100644 index 0000000..ba5a767 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-timeout-blocking.js @@ -0,0 +1,23 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +exports['test_test_timeout_non_blocking'] = function(test, assert) { + var i = 0; + while (i < 1000000); + + assert.ok(true); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-timeout.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-timeout.js new file mode 100644 index 0000000..c427236 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-timeout.js @@ -0,0 +1,40 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. +*/ + +exports['test_success_1'] = function(test, assert) { + assert.ok(true); + test.finish(); +}; + +exports['test_success_2'] = function(test, assert) { + assert.ok(true); + test.finish(); +}; + +exports['test_success_3'] = function(test, assert) { + assert.ok(true); + test.finish(); +}; + +exports['test_test_timeout_non_blocking'] = function(test, assert) { + setTimeout(function() { + assert.ok(true); + test.finish(); + }, 50000); + + assert.ok(true); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/test-uncaught.js b/node_modules/cassandra-client/node_modules/whiskey/example/test-uncaught.js new file mode 100644 index 0000000..eab43c0 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/test-uncaught.js @@ -0,0 +1,46 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. +*/ + +var someFile = require('./some-file'); + +exports['test_uncaught_exception'] = function(test, assert) { + throw new Error('Testing uncaught exception'); + // Line bellow won't be reached + test.finish(); +}; + +exports['test_uncaught_exception_2'] = function(test, assert) { + someFile.throwException(); + // Line bellow won't be reached + test.finish(); +}; + +exports['test_unknown_method'] = function(test, assert) { + someFile.unknownMethod(); + // Line bellow won't be reached + test.finish(); +}; + +exports['test_uncaught_nested_functions'] = function(test, assert) { + someFile.throwNestedFunctions(); + // Line bellow won't be reached + test.finish(); +}; + +exports['test1_require_throws'] = function(test, assert) { + require('timeout-throws.js'); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/example/timeout-throws.js b/node_modules/cassandra-client/node_modules/whiskey/example/timeout-throws.js new file mode 100644 index 0000000..0f46f04 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/example/timeout-throws.js @@ -0,0 +1,13 @@ +function initSecondTimeout(tag) { + setTimeout(function secondTimeout() { + throw new Error(tag); + }, 100); +} + +function onload() { + setTimeout(function firstTimeout() { + initSecondTimeout("timeout"); + }, 100); +} + +onload(); diff --git a/node_modules/cassandra-client/node_modules/whiskey/index.js b/node_modules/cassandra-client/node_modules/whiskey/index.js new file mode 100644 index 0000000..47fcfe6 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/index.js @@ -0,0 +1,19 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +exports.run = require('./lib/run.js').run; +exports.installCoverageHandler = require('./lib/coverage').installCoverageHandler; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/README.md b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/README.md new file mode 100644 index 0000000..d449504 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/README.md @@ -0,0 +1,75 @@ +Long Stacktraces +================ + +Long stacktraces for V8 implemented in user-land JavaScript. Supports Chrome/Chromium and Node.js. + +Background +---------- + +A common problem when debugging event-driven JavaScript is stack traces are limited to a single "event", so it's difficult to trace the code path that caused an error. + +A contrived example (taken from the PDF referenced below): + + function f() { + throw new Error('foo'); + } + + setTimeout(f, Math.random()*1000); + setTimeout(f, Math.random()*1000); + +Which one throws the first error? + +Node.js intended to fix this problem with a solution called "Long Stacktraces": http://nodejs.org/illuminati0.pdf + +But what if we wanted something like this in the browser? It turns out V8 already has everything needed to implement this in user-land JavaScript (although in a slightly hacky way). + +V8 has a [stack trace API](http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi) that allows custom formatting of textual stack trace representations. By wrapping any function that registers an asynchronous event callback (e.x. `setTimeout` and `addEventListener` in the browser) we can store the stack trace at the time of callback registration, and later append it to stack traces. This also works for multiple levels of events (a timeout or event registered within a timeout or event, etc). + +Usage +----- + +For Node.js install using `npm install long-stack-traces`. + +Simply include the "long-stack-traces.js" via a script tag or other method before any event listener or timeout registrations. In Node.js call `require("long-stack-traces")`. + +Stack traces from example above: + + Uncaught Error: foo + at f (index.html:24:23) + ---------------------------------------- + at setTimeout + at onload (index.html:28:40) + Uncaught Error: foo + at f (index.html:24:23) + ---------------------------------------- + at setTimeout + at onload (index.html:27:40) + +Note one was from the timeout on line 27, the other on line 28. Events' stack traces are divided by a line of dashes. + +See examples.html for more examples, and run `node examples.js` for a Node.js example. + +Supported APIs +-------------- + +Currently supports the following APIs: + +### Chromium ### +* `setTimeout` +* `setInterval` +* `addEventListener` +* `XMLHttpRequest.onreadystatechange` (stack actually recorded upon `send()`) + +### Node.js ### +* `setTimeout` +* `setInterval` +* `EventEmitter.addListener` +* `EventEmitter.on` +* All APIs that use `EventEmitter` + +TODO +---- + +* Gracefully degrade in non-V8 environments. +* Figure out what's up with these stack frames when throwing an exception from an input's event handler: + \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/examples.html b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/examples.html new file mode 100644 index 0000000..6b6adc6 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/examples.html @@ -0,0 +1,51 @@ + + + + + + + + + + + + + diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/examples.js b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/examples.js new file mode 100644 index 0000000..1f690e0 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/examples.js @@ -0,0 +1,58 @@ +/* automatically generated by JSCoverage - do not edit */ +if (typeof _$jscoverage === 'undefined') _$jscoverage = {}; +if (! _$jscoverage['extern/long-stack-traces/examples.js']) { + _$jscoverage['extern/long-stack-traces/examples.js'] = []; + _$jscoverage['extern/long-stack-traces/examples.js'][1] = 0; + _$jscoverage['extern/long-stack-traces/examples.js'][3] = 0; + _$jscoverage['extern/long-stack-traces/examples.js'][5] = 0; + _$jscoverage['extern/long-stack-traces/examples.js'][6] = 0; + _$jscoverage['extern/long-stack-traces/examples.js'][7] = 0; + _$jscoverage['extern/long-stack-traces/examples.js'][11] = 0; + _$jscoverage['extern/long-stack-traces/examples.js'][18] = 0; + _$jscoverage['extern/long-stack-traces/examples.js'][19] = 0; + _$jscoverage['extern/long-stack-traces/examples.js'][22] = 0; + _$jscoverage['extern/long-stack-traces/examples.js'][23] = 0; + _$jscoverage['extern/long-stack-traces/examples.js'][24] = 0; + _$jscoverage['extern/long-stack-traces/examples.js'][28] = 0; + _$jscoverage['extern/long-stack-traces/examples.js'][30] = 0; +} +_$jscoverage['extern/long-stack-traces/examples.js'][1]++; +require("./index"); +_$jscoverage['extern/long-stack-traces/examples.js'][3]++; +var fs = require("fs"); +_$jscoverage['extern/long-stack-traces/examples.js'][5]++; +function initSecondTimeout(tag) { + _$jscoverage['extern/long-stack-traces/examples.js'][6]++; + setTimeout((function secondTimeout() { + _$jscoverage['extern/long-stack-traces/examples.js'][7]++; + throw new Error(tag); +}), 1000); +} +_$jscoverage['extern/long-stack-traces/examples.js'][11]++; +function onload() { + _$jscoverage['extern/long-stack-traces/examples.js'][18]++; + setTimeout((function firstTimeout() { + _$jscoverage['extern/long-stack-traces/examples.js'][19]++; + initSecondTimeout("timeout"); +}), 1000); + _$jscoverage['extern/long-stack-traces/examples.js'][22]++; + fs.readFile("README.md", "utf8", (function (err, data) { + _$jscoverage['extern/long-stack-traces/examples.js'][23]++; + if (err) { + _$jscoverage['extern/long-stack-traces/examples.js'][23]++; + throw err; + } + _$jscoverage['extern/long-stack-traces/examples.js'][24]++; + initSecondTimeout("readFile"); +})); +} +_$jscoverage['extern/long-stack-traces/examples.js'][28]++; +onload(); +_$jscoverage['extern/long-stack-traces/examples.js'][30]++; +process.on("uncaughtException", (function (e) { + _$jscoverage['extern/long-stack-traces/examples.js'][30]++; + console.log("wa"); + _$jscoverage['extern/long-stack-traces/examples.js'][30]++; + console.log(e.stack); +})); +_$jscoverage['extern/long-stack-traces/examples.js'].source = ["require(\"./index\");","","var fs = require(\"fs\");","","function initSecondTimeout(tag) {"," setTimeout(function secondTimeout() {"," throw new Error(tag);"," }, 1000);","}","","function onload() {"," // function f() {"," // throw new Error('foo');"," // }"," // setTimeout(f, Math.random()*1000);"," // setTimeout(f, Math.random()*1000);",""," setTimeout(function firstTimeout() {"," initSecondTimeout(\"timeout\");"," }, 1000);",""," fs.readFile('README.md', 'utf8', function (err, data) {"," if (err) throw err;"," initSecondTimeout(\"readFile\");"," });","}","","onload();","","process.on('uncaughtException', function(e) { console.log('wa');console.log(e.stack)})"]; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/index.js b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/index.js new file mode 100644 index 0000000..9ec5245 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/index.js @@ -0,0 +1,9 @@ +/* automatically generated by JSCoverage - do not edit */ +if (typeof _$jscoverage === 'undefined') _$jscoverage = {}; +if (! _$jscoverage['extern/long-stack-traces/index.js']) { + _$jscoverage['extern/long-stack-traces/index.js'] = []; + _$jscoverage['extern/long-stack-traces/index.js'][1] = 0; +} +_$jscoverage['extern/long-stack-traces/index.js'][1]++; +exports = require("./lib/long-stack-traces"); +_$jscoverage['extern/long-stack-traces/index.js'].source = ["exports = require('./lib/long-stack-traces')"]; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/lib/long-stack-traces.js b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/lib/long-stack-traces.js new file mode 100644 index 0000000..ba7a002 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/lib/long-stack-traces.js @@ -0,0 +1,381 @@ +/* automatically generated by JSCoverage - do not edit */ +if (typeof _$jscoverage === 'undefined') _$jscoverage = {}; +if (! _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js']) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'] = []; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][1] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][2] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][4] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][6] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][7] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][8] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][11] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][12] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][13] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][14] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][15] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][16] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][17] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][18] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][21] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][25] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][28] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][29] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][33] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][34] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][35] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][36] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][38] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][39] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][43] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][46] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][48] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][50] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][52] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][56] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][57] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][62] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][64] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][65] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][66] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][67] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][73] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][74] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][75] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][77] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][78] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][79] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][83] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][88] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][89] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][90] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][92] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][96] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][125] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][126] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][127] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][128] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][130] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][131] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][133] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][136] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][137] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][138] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][139] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][140] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][142] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][143] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][146] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][149] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][151] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][154] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][155] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][156] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][157] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][158] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][159] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][161] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][162] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][163] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][164] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][165] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][166] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][167] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][168] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][169] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][174] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][175] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][177] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][178] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][179] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][180] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][181] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][182] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][183] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][184] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][185] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][186] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][187] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][188] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][191] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][193] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][194] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][195] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][196] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][198] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][199] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][201] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][202] = 0; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][204] = 0; +} +_$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][1]++; +(function (LST) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][2]++; + LST.rethrow = false; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][4]++; + var currentTraceError = null; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][6]++; + var filename = new Error().stack.split("\n")[1].match(/^ at ((?:\w+:\/\/)?[^:]+)/)[1]; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][7]++; + function filterInternalFrames(frames) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][8]++; + return frames.split("\n").filter((function (frame) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][8]++; + return frame.indexOf(filename) < 0; +})).join("\n"); +} + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][11]++; + Error.prepareStackTrace = (function (error, structuredStackTrace) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][12]++; + if (! error.__cachedTrace) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][13]++; + error.__cachedTrace = filterInternalFrames(FormatStackTrace(error, structuredStackTrace)); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][14]++; + if (! has.call(error, "__previous")) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][15]++; + var previous = currentTraceError; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][16]++; + while (previous) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][17]++; + var previousTrace = previous.stack; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][18]++; + error.__cachedTrace += "\n----------------------------------------\n" + " at " + previous.__location + "\n" + previousTrace.substring(previousTrace.indexOf("\n") + 1); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][21]++; + previous = previous.__previous; +} + } + } + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][25]++; + return error.__cachedTrace; +}); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][28]++; + var slice = Array.prototype.slice; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][29]++; + var has = Object.prototype.hasOwnProperty; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][33]++; + function wrapRegistrationFunction(object, property, callbackArg) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][34]++; + if (typeof object[property] !== "function") { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][35]++; + console.error("(long-stack-traces) Object", object, "does not contain function", property); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][36]++; + return; + } + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][38]++; + if (! has.call(object, property)) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][39]++; + console.warn("(long-stack-traces) Object", object, "does not directly contain function", property); + } + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][43]++; + var sourcePosition = (object.constructor.name || Object.prototype.toString.call(object)) + "." + property; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][46]++; + var fn = object[property]; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][48]++; + object[property] = (function () { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][50]++; + arguments[callbackArg] = makeWrappedCallback(arguments[callbackArg], sourcePosition); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][52]++; + return fn.apply(this, arguments); +}); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][56]++; + if (object[property] === fn) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][57]++; + console.warn("(long-stack-traces) Couldn't replace ", property, "on", object); + } +} + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][62]++; + function makeWrappedCallback(callback, frameLocation) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][64]++; + var traceError = new Error(); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][65]++; + traceError.__location = frameLocation; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][66]++; + traceError.__previous = currentTraceError; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][67]++; + return (function () { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][73]++; + currentTraceError = traceError; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][74]++; + try { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][75]++; + return callback.apply(this, arguments); + } + catch (e) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][77]++; + var stack = e.stack; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][78]++; + e.stack = stack; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][79]++; + throw e; + } + finally { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][83]++; + currentTraceError = null; + } +}); +} + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][88]++; + var global = (function () { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][88]++; + return this; +})(); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][89]++; + wrapRegistrationFunction(global, "setTimeout", 0); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][90]++; + wrapRegistrationFunction(global, "setInterval", 0); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][92]++; + var EventEmitter = require("events").EventEmitter; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][96]++; + wrapRegistrationFunction(process, "nextTick", 0); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][125]++; + function FormatStackTrace(error, frames) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][126]++; + var lines = []; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][127]++; + try { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][128]++; + lines.push(error.toString()); + } + catch (e) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][130]++; + try { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][131]++; + lines.push(""); + } + catch (ee) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][133]++; + lines.push(""); + } + } + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][136]++; + for (var i = 0; i < frames.length; i++) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][137]++; + var frame = frames[i]; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][138]++; + var line; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][139]++; + try { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][140]++; + line = FormatSourcePosition(frame); + } + catch (e) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][142]++; + try { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][143]++; + line = ""; + } + catch (ee) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][146]++; + line = ""; + } + } + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][149]++; + lines.push(" at " + line); +} + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][151]++; + return lines.join("\n"); +} + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][154]++; + function FormatSourcePosition(frame) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][155]++; + var fileLocation = ""; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][156]++; + if (frame.isNative()) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][157]++; + fileLocation = "native"; + } + else { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][158]++; + if (frame.isEval()) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][159]++; + fileLocation = "eval at " + frame.getEvalOrigin(); + } + else { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][161]++; + var fileName = frame.getFileName(); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][162]++; + if (fileName) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][163]++; + fileLocation += fileName; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][164]++; + var lineNumber = frame.getLineNumber(); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][165]++; + if (lineNumber != null) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][166]++; + fileLocation += ":" + lineNumber; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][167]++; + var columnNumber = frame.getColumnNumber(); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][168]++; + if (columnNumber) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][169]++; + fileLocation += ":" + columnNumber; + } + } + } + } + } + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][174]++; + if (! fileLocation) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][175]++; + fileLocation = "unknown source"; + } + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][177]++; + var line = ""; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][178]++; + var functionName = frame.getFunction().name; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][179]++; + var addPrefix = true; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][180]++; + var isConstructor = frame.isConstructor(); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][181]++; + var isMethodCall = ! (frame.isToplevel() || isConstructor); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][182]++; + if (isMethodCall) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][183]++; + var methodName = frame.getMethodName(); + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][184]++; + line += frame.getTypeName() + "."; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][185]++; + if (functionName) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][186]++; + line += functionName; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][187]++; + if (methodName && (methodName != functionName)) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][188]++; + line += " [as " + methodName + "]"; + } + } + else { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][191]++; + line += methodName || ""; + } + } + else { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][193]++; + if (isConstructor) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][194]++; + line += "new " + (functionName || ""); + } + else { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][195]++; + if (functionName) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][196]++; + line += functionName; + } + else { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][198]++; + line += fileLocation; + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][199]++; + addPrefix = false; + } + } + } + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][201]++; + if (addPrefix) { + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][202]++; + line += " (" + fileLocation + ")"; + } + _$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'][204]++; + return line; +} +})(typeof exports !== "undefined"? exports: {}); +_$jscoverage['extern/long-stack-traces/lib/long-stack-traces.js'].source = ["(function(LST) {"," LST.rethrow = false;",""," var currentTraceError = null;",""," var filename = new Error().stack.split(\"\\n\")[1].match(/^ at ((?:\\w+:\\/\\/)?[^:]+)/)[1];"," function filterInternalFrames(frames) {"," return frames.split(\"\\n\").filter(function(frame) { return frame.indexOf(filename) < 0; }).join(\"\\n\");"," }",""," Error.prepareStackTrace = function(error, structuredStackTrace) {"," if (!error.__cachedTrace) {"," error.__cachedTrace = filterInternalFrames(FormatStackTrace(error, structuredStackTrace));"," if (!has.call(error, \"__previous\")) {"," var previous = currentTraceError;"," while (previous) {"," var previousTrace = previous.stack;"," error.__cachedTrace += \"\\n----------------------------------------\\n\" +"," \" at \" + previous.__location + \"\\n\" +"," previousTrace.substring(previousTrace.indexOf(\"\\n\") + 1);"," previous = previous.__previous;"," }"," }"," }"," return error.__cachedTrace;"," }",""," var slice = Array.prototype.slice;"," var has = Object.prototype.hasOwnProperty;",""," // Takes an object, a property name for the callback function to wrap, and an argument position"," // and overwrites the function with a wrapper that captures the stack at the time of callback registration"," function wrapRegistrationFunction(object, property, callbackArg) {"," if (typeof object[property] !== \"function\") {"," console.error(\"(long-stack-traces) Object\", object, \"does not contain function\", property);"," return;"," }"," if (!has.call(object, property)) {"," console.warn(\"(long-stack-traces) Object\", object, \"does not directly contain function\", property);"," }",""," // TODO: better source position detection"," var sourcePosition = (object.constructor.name || Object.prototype.toString.call(object)) + \".\" + property;",""," // capture the original registration function"," var fn = object[property];"," // overwrite it with a wrapped registration function that modifies the supplied callback argument"," object[property] = function() {"," // replace the callback argument with a wrapped version that captured the current stack trace"," arguments[callbackArg] = makeWrappedCallback(arguments[callbackArg], sourcePosition);"," // call the original registration function with the modified arguments"," return fn.apply(this, arguments);"," }",""," // check that the registration function was indeed overwritten"," if (object[property] === fn)"," console.warn(\"(long-stack-traces) Couldn't replace \", property, \"on\", object);"," }",""," // Takes a callback function and name, and captures a stack trace, returning a new callback that restores the stack frame"," // This function adds a single function call overhead during callback registration vs. inlining it in wrapRegistationFunction"," function makeWrappedCallback(callback, frameLocation) {"," // add a fake stack frame. we can't get a real one since we aren't inside the original function"," var traceError = new Error();"," traceError.__location = frameLocation;"," traceError.__previous = currentTraceError;"," return function() {"," // if (currentTraceError) {"," // FIXME: This shouldn't normally happen, but it often does. Do we actually need a stack instead?"," // console.warn(\"(long-stack-traces) Internal Error: currentTrace already set.\");"," // }"," // restore the trace"," currentTraceError = traceError;"," try {"," return callback.apply(this, arguments);"," } catch (e) {"," var stack = e.stack;"," e.stack = stack;"," throw e;"," } finally {"," // clear the trace so we can check that none is set above."," // TODO: could we remove this for slightly better performace?"," currentTraceError = null;"," }"," }"," }",""," var global = (function() { return this; })();"," wrapRegistrationFunction(global, \"setTimeout\", 0);"," wrapRegistrationFunction(global, \"setInterval\", 0);",""," var EventEmitter = require('events').EventEmitter;"," //wrapRegistrationFunction(EventEmitter.prototype, \"addListener\", 1);"," //wrapRegistrationFunction(EventEmitter.prototype, \"on\", 1);",""," wrapRegistrationFunction(process, \"nextTick\", 0);",""," // Copyright 2006-2008 the V8 project 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.",""," function FormatStackTrace(error, frames) {"," var lines = [];"," try {"," lines.push(error.toString());"," } catch (e) {"," try {"," lines.push(\"<error: \" + e + \">\");"," } catch (ee) {"," lines.push(\"<error>\");"," }"," }"," for (var i = 0; i < frames.length; i++) {"," var frame = frames[i];"," var line;"," try {"," line = FormatSourcePosition(frame);"," } catch (e) {"," try {"," line = \"<error: \" + e + \">\";"," } catch (ee) {"," // Any code that reaches this point is seriously nasty!"," line = \"<error>\";"," }"," }"," lines.push(\" at \" + line);"," }"," return lines.join(\"\\n\");"," }",""," function FormatSourcePosition(frame) {"," var fileLocation = \"\";"," if (frame.isNative()) {"," fileLocation = \"native\";"," } else if (frame.isEval()) {"," fileLocation = \"eval at \" + frame.getEvalOrigin();"," } else {"," var fileName = frame.getFileName();"," if (fileName) {"," fileLocation += fileName;"," var lineNumber = frame.getLineNumber();"," if (lineNumber != null) {"," fileLocation += \":\" + lineNumber;"," var columnNumber = frame.getColumnNumber();"," if (columnNumber) {"," fileLocation += \":\" + columnNumber;"," }"," }"," }"," }"," if (!fileLocation) {"," fileLocation = \"unknown source\";"," }"," var line = \"\";"," var functionName = frame.getFunction().name;"," var addPrefix = true;"," var isConstructor = frame.isConstructor();"," var isMethodCall = !(frame.isToplevel() || isConstructor);"," if (isMethodCall) {"," var methodName = frame.getMethodName();"," line += frame.getTypeName() + \".\";"," if (functionName) {"," line += functionName;"," if (methodName && (methodName != functionName)) {"," line += \" [as \" + methodName + \"]\";"," }"," } else {"," line += methodName || \"<anonymous>\";"," }"," } else if (isConstructor) {"," line += \"new \" + (functionName || \"<anonymous>\");"," } else if (functionName) {"," line += functionName;"," } else {"," line += fileLocation;"," addPrefix = false;"," }"," if (addPrefix) {"," line += \" (\" + fileLocation + \")\";"," }"," return line;"," }","})(typeof exports !== \"undefined\" ? exports : {});"]; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/package.json b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/package.json new file mode 100644 index 0000000..7c36b03 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/long-stack-traces/package.json @@ -0,0 +1,13 @@ +{ + "name": "long-stack-traces", + "description": "Long stacktraces for V8 implemented in user-land JavaScript.", + "version": "0.1.1", + "author": "Tom Robinson (http://tlrobinson.net/)", + "main" : "./lib/long-stack-traces", + "directories": { + "lib": "./lib" + }, + "engines": { + "node": "*" + } +} \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/README.md b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/README.md new file mode 100644 index 0000000..d08ccf1 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/README.md @@ -0,0 +1,161 @@ +optparse-js +=========== + +Optparse-js is a command line option parser for Javascript. It's slightly based on Ruby's implementation optparse but with some differences (different languages has different needs) such as custom parsers. + +All examples in this readme is using [Node.js](http://nodejs.org/). How ever, the library works with all kinds of Javascript implementations. + + +QUICK START +----------- + +The library defines one class, the OptionParser class. The class constructor takes one single argument, a list with a set of rules. Here is a quick example: + + // Import the sys library + var sys = require('sys'); + + // Import the optparse library. + var optparse = require('optparse'); + + // Define an option called ´´help´´. We give it a quick alias named ´´-h´´ + // and a quick help text. + var switches = [ + ['-h', '--help', 'Shows help sections'] + ]; + + // Create a new OptionParser. + var parser = new optparse.OptionParser(switches); + + // Hook the help option. The callback will be executed when the OptionParser + // hits the switch ´´-h´´ or ´´--help´´. Each representatio + parser.on('help', function() { + sys.puts('Help'); + }); + + + +DEFINING RULES +-------------- +The OptionParser constructor takes an Array with rules. Each rule is represented by an array (tuple) of two or three values. A typical rule definition may look like this: + + ['-h', '--help', 'Print this help'] + + +The first value is optional, and represents an alias for the long-named switch (the second value, in this case ´´--help´´). + +The second argument is the actual rule. The rule must start with a double dash followed by a switch name (in this case ´help´). The OptionParser also supports special option arguments. Define an option argument in the rule by adding a named argument after the leading double dash and switch name (E.G '--port-number PORT_NUMBER'). The argument is then parsed to the option handler. To define an optional option argument, just add a braces around argument in the rule (E.G '--port-number [PORT_NUMBER]). The OptionParser also supports filter. More on that in in the section called ´Option Filters´. + +The third argument is an optional rule description. + + +OPTION FILTERS +-------------- +Filters is a neat feature that let you filter option arguments. The OptionParser itself as already a set of built-in common filter's. These are: + +- NUMBER, supports both decimal and hexadecimal numbers. +- DATE, filters arguments that matches YYYY-MM-DD. +- EMAIL, filters arguments that matches my@email.com. + +It's simple to use any of the filter above in your rule-set. Here is a quick example how to filter number: + + var rules = [ + ['--first-option NUMBER', 'Takes a number as argument'], + ['--second-option [NUMBER]', 'Takes an optional number as argument'] + ] + +You can add your own set of filter by calling the *parser_instance.filter* method: + + parser.filter('single_char', function(value) { + if(value.length != 1) throw "Filter mismatch."; + return value; + }); + + +OPTION PARSER +------------- +The OptionParser class has the following properties and methods: + +### string banner +An optional usage banner. This text is included when calling ´´toString´´. Default value is: "Usage: [Options]". + + +### string options_title +An optional title for the options list. This text is included when calling ´´toString´´. Default value is: "Available options:". + + +### function on(switch_or_arg_index, callback) +Add's a callback for a switch or an argument (defined by index). Switch hooks MUST be typed witout the leading ´´--´´. This example show how to hook a switch: + + parser.on('help', function(optional_argument) { + // Show help section + }); + +And this example show how to hook an argument (an option without the leading - or --): + + parser.on(0, function(opt) { + puts('The first non-switch option is:' + opt); + }); + +It's also possible to define a default handler. The default handler is called when no rule's are meet. Here is an example how to add a ´default handler´: + + parser.on(function(opt) { + puts('No handler was defined for option:' + opt); + }); + +Use the wildcard handler to build a custom ´´on´´ handler. + + parser.on('*', function(opt, value) { + puts('option=' + opt + ', value=' + value); + }); + +### function filter(name, callback) +Adds a new filter extension to the OptionParser instance. The first argument is the name of the filter (trigger). The second argument is the actual filter See the ´OPTION FILTERS´ section for more info. + +It's possible to override the default filters by passing the value "_DEFAULT" to the ´´name´´ argument. The name of the filter is automatically transformed into +upper case. + + +### function halt([callback]) +Interrupt's further parsing. This function should be called from an ´on´ -callbacks, to cancel the parsing. This can be useful when the program should ignore all other arguments (when displaying help or version information). + +The function also takes an optional callback argument. If the callback argument is specified, a ´halt´ callback will be added (instead of executing the ´halt´ command). + +Here is an example how to add an ´on_halt´ callback: + + parser.halt(function() { + puts('An option callback interupted the parser'); + }); + + +### function parse(arguments) +Start's parsing of arguments. This should be the last thing you do. + + +### function options() +Returns an Array with all defined option rules + + +### function toString() +Returns a string representation of this OptionParser instance (a formatted help section). + + +MORE EXAMPLES +------------- +See examples/nodejs-test.js and examples/browser-test-html for more info how to +use the script. + + +SUGGESTIONS +----------- +All comments in how to improve this library is very welcome. Feel free post suggestions to the [Issue tracker](http://github.com/jfd/optparse-js/issues), or even better, fork the repository to implement your own features. + + +LICENSE +------- +Released under a MIT-style license. + + +COPYRIGHT +--------- +Copyright (c) 2009 Johan Dahlberg + diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/TODO b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/TODO new file mode 100644 index 0000000..a1b6050 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/TODO @@ -0,0 +1 @@ +- Support for Argument lists (for switches) \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/examples/browser-test.html b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/examples/browser-test.html new file mode 100644 index 0000000..2d8f6d3 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/examples/browser-test.html @@ -0,0 +1,75 @@ + + + + + optparse.js example + + + + + + + \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/examples/nodejs-test.js b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/examples/nodejs-test.js new file mode 100644 index 0000000..0250026 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/examples/nodejs-test.js @@ -0,0 +1,115 @@ +/* automatically generated by JSCoverage - do not edit */ +if (typeof _$jscoverage === 'undefined') _$jscoverage = {}; +if (! _$jscoverage['extern/optparse/examples/nodejs-test.js']) { + _$jscoverage['extern/optparse/examples/nodejs-test.js'] = []; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][2] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][4] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][6] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][9] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][20] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][22] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][25] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][33] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][34] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][38] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][39] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][43] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][44] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][48] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][49] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][53] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][54] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][58] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][59] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][63] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][64] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][65] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][69] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][70] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][74] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][76] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][77] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][80] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][81] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][82] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][86] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][88] = 0; + _$jscoverage['extern/optparse/examples/nodejs-test.js'][89] = 0; +} +_$jscoverage['extern/optparse/examples/nodejs-test.js'][2]++; +require.paths.unshift(__dirname); +_$jscoverage['extern/optparse/examples/nodejs-test.js'][4]++; +var optparse = require("lib/optparse"); +_$jscoverage['extern/optparse/examples/nodejs-test.js'][6]++; +var sys = require("sys"); +_$jscoverage['extern/optparse/examples/nodejs-test.js'][9]++; +var SWITCHES = [["-i", "--include-file FILE", "Includes a file"], ["-p", "--print [MESSAGE]", "Prints an optional message on screen"], ["-d", "--debug", "Enables debug mode"], ["-H", "--help", "Shows this help section"], ["--date DATE", "A date. A date is expected E.G. 2009-01-14"], ["--number NUMBER", "A Number. Supported formats are 123, 123.123, 0xA123"], ["--other NAME", "No handler defined for this option. Will be handled by the wildcard handler."],]; +_$jscoverage['extern/optparse/examples/nodejs-test.js'][20]++; +var parser = new optparse.OptionParser(SWITCHES), print_summary = true, first_arg; +_$jscoverage['extern/optparse/examples/nodejs-test.js'][22]++; +parser.banner = "Usage: nodejs-test.js [options]"; +_$jscoverage['extern/optparse/examples/nodejs-test.js'][25]++; +var options = {debug: true, files: [], number: undefined, date: undefined}; +_$jscoverage['extern/optparse/examples/nodejs-test.js'][33]++; +parser.on(0, (function (value) { + _$jscoverage['extern/optparse/examples/nodejs-test.js'][34]++; + first_arg = value; +})); +_$jscoverage['extern/optparse/examples/nodejs-test.js'][38]++; +parser.on("include-file", (function (value) { + _$jscoverage['extern/optparse/examples/nodejs-test.js'][39]++; + options.files.push(value); +})); +_$jscoverage['extern/optparse/examples/nodejs-test.js'][43]++; +parser.on("print", (function (value) { + _$jscoverage['extern/optparse/examples/nodejs-test.js'][44]++; + sys.puts("PRINT: " + (value || "No message entered")); +})); +_$jscoverage['extern/optparse/examples/nodejs-test.js'][48]++; +parser.on("date", (function (value) { + _$jscoverage['extern/optparse/examples/nodejs-test.js'][49]++; + options.date = value; +})); +_$jscoverage['extern/optparse/examples/nodejs-test.js'][53]++; +parser.on("number", (function (value) { + _$jscoverage['extern/optparse/examples/nodejs-test.js'][54]++; + options.number = value; +})); +_$jscoverage['extern/optparse/examples/nodejs-test.js'][58]++; +parser.on("debug", (function () { + _$jscoverage['extern/optparse/examples/nodejs-test.js'][59]++; + options.debug = true; +})); +_$jscoverage['extern/optparse/examples/nodejs-test.js'][63]++; +parser.on("help", (function () { + _$jscoverage['extern/optparse/examples/nodejs-test.js'][64]++; + sys.puts(parser.toString()); + _$jscoverage['extern/optparse/examples/nodejs-test.js'][65]++; + print_summary = false; +})); +_$jscoverage['extern/optparse/examples/nodejs-test.js'][69]++; +parser.on("*", (function (opt, value) { + _$jscoverage['extern/optparse/examples/nodejs-test.js'][70]++; + sys.puts("wild handler for " + opt + ", value=" + value); +})); +_$jscoverage['extern/optparse/examples/nodejs-test.js'][74]++; +parser.parse(process.ARGV); +_$jscoverage['extern/optparse/examples/nodejs-test.js'][76]++; +if (print_summary) { + _$jscoverage['extern/optparse/examples/nodejs-test.js'][77]++; + sys.puts("First non-switch argument is: " + first_arg); + _$jscoverage['extern/optparse/examples/nodejs-test.js'][80]++; + sys.puts("No of files to include: " + options.files.length); + _$jscoverage['extern/optparse/examples/nodejs-test.js'][81]++; + for (var i = 0; i < options.files.length; i++) { + _$jscoverage['extern/optparse/examples/nodejs-test.js'][82]++; + sys.puts("File [" + (i + 1) + "]:" + options.files[i]); +} + _$jscoverage['extern/optparse/examples/nodejs-test.js'][86]++; + sys.puts("Debug mode is set to: " + options.debug); + _$jscoverage['extern/optparse/examples/nodejs-test.js'][88]++; + sys.puts("Number value is: " + options.number); + _$jscoverage['extern/optparse/examples/nodejs-test.js'][89]++; + sys.puts("Date value is: " + options.date); +} +_$jscoverage['extern/optparse/examples/nodejs-test.js'].source = ["// Import the optparse script","require.paths.unshift(__dirname); //make local paths accessible","","var optparse = require('lib/optparse');","","var sys= require('sys');","","// Define some options","var SWITCHES = ["," ['-i', '--include-file FILE', \"Includes a file\"],"," ['-p', '--print [MESSAGE]', \"Prints an optional message on screen\"],"," ['-d', '--debug', \"Enables debug mode\"],"," ['-H', '--help', \"Shows this help section\"],"," ['--date DATE', \"A date. A date is expected E.G. 2009-01-14\"],"," ['--number NUMBER', \"A Number. Supported formats are 123, 123.123, 0xA123\"],"," ['--other NAME', \"No handler defined for this option. Will be handled by the wildcard handler.\"],","];","","// Create a new OptionParser with defined switches","var parser = new optparse.OptionParser(SWITCHES), print_summary = true, "," first_arg;","parser.banner = 'Usage: nodejs-test.js [options]';","","// Internal variable to store options.","var options = {"," debug: true,"," files: [],"," number: undefined,"," date: undefined","};","","// Handle the first argument (switches excluded)","parser.on(0, function(value) {"," first_arg = value;","});","","// Handle the --include-file switch","parser.on('include-file', function(value) {"," options.files.push(value);","});","","// Handle the --print switch","parser.on('print', function(value) {"," sys.puts('PRINT: ' + (value || 'No message entered'));","});","","// Handle the --date switch","parser.on('date', function(value) {"," options.date = value;","});","","// Handle the --number switch","parser.on('number', function(value) {"," options.number = value;","});","","// Handle the --debug switch","parser.on('debug', function() {"," options.debug = true;","});","","// Handle the --help switch","parser.on('help', function() {"," sys.puts(parser.toString());"," print_summary = false;","});","","// Set a default handler","parser.on('*', function(opt, value) {"," sys.puts('wild handler for ' + opt + ', value=' + value);","});","","// Parse command line arguments","parser.parse(process.ARGV);","","if(print_summary) {"," sys.puts(\"First non-switch argument is: \" + first_arg);"," "," // Output all files that was included."," sys.puts(\"No of files to include: \" + options.files.length);"," for(var i = 0; i < options.files.length; i++) {"," sys.puts(\"File [\" + (i + 1) + \"]:\" + options.files[i]);"," }",""," // Is debug-mode enabled?"," sys.puts(\"Debug mode is set to: \" + options.debug);",""," sys.puts(\"Number value is: \" + options.number);"," sys.puts(\"Date value is: \" + options.date);","}"]; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/lib/optparse.js b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/lib/optparse.js new file mode 100644 index 0000000..047a22e --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/lib/optparse.js @@ -0,0 +1,606 @@ +/* automatically generated by JSCoverage - do not edit */ +if (typeof _$jscoverage === 'undefined') _$jscoverage = {}; +if (! _$jscoverage['extern/optparse/lib/optparse.js']) { + _$jscoverage['extern/optparse/lib/optparse.js'] = []; + _$jscoverage['extern/optparse/lib/optparse.js'][7] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][8] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][9] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][10] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][11] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][12] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][13] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][14] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][15] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][16] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][17] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][21] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][22] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][25] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][26] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][32] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][33] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][34] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][35] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][37] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][41] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][43] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][48] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][49] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][50] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][51] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][52] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][56] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][57] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][58] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][59] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][65] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][66] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][67] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][68] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][69] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][73] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][74] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][75] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][76] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][77] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][78] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][80] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][81] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][83] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][84] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][85] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][86] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][87] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][89] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][90] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][93] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][95] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][97] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][113] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][114] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][115] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][116] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][117] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][118] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][121] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][122] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][123] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][124] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][125] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][127] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][141] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][142] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][143] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][144] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][145] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][149] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][150] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][151] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][152] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][154] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][158] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][159] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][160] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][161] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][163] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][164] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][165] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][167] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][168] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][174] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][175] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][179] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][180] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][181] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][182] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][183] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][188] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][189] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][190] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][191] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][192] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][193] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][194] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][195] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][196] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][197] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][200] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][204] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][205] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][206] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][207] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][209] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][218] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][223] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][224] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][225] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][226] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][227] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][228] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][232] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][233] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][234] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][235] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][236] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][237] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][238] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][239] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][241] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][243] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][244] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][246] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][249] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][250] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][251] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][252] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][255] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][259] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][260] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][261] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][264] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][269] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][276] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][277] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][282] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][284] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][285] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][286] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][288] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][289] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][291] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][292] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][293] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][294] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][295] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][296] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][298] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][299] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][300] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][302] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][306] = 0; + _$jscoverage['extern/optparse/lib/optparse.js'][307] = 0; +} +_$jscoverage['extern/optparse/lib/optparse.js'][7]++; +var optparse = {}; +_$jscoverage['extern/optparse/lib/optparse.js'][8]++; +try { + _$jscoverage['extern/optparse/lib/optparse.js'][8]++; + optparse = exports; +} +catch (e) { +} +_$jscoverage['extern/optparse/lib/optparse.js'][8]++; +; +_$jscoverage['extern/optparse/lib/optparse.js'][9]++; +(function (self) { + _$jscoverage['extern/optparse/lib/optparse.js'][10]++; + var VERSION = "1.0.2"; + _$jscoverage['extern/optparse/lib/optparse.js'][11]++; + var LONG_SWITCH_RE = /^--\w/; + _$jscoverage['extern/optparse/lib/optparse.js'][12]++; + var SHORT_SWITCH_RE = /^-\w/; + _$jscoverage['extern/optparse/lib/optparse.js'][13]++; + var NUMBER_RE = /^(0x[A-Fa-f0-9]+)|([0-9]+\.[0-9]+)|(\d+)$/; + _$jscoverage['extern/optparse/lib/optparse.js'][14]++; + var DATE_RE = /^\d{4}-(0[0-9]|1[0,1,2])-([0,1,2][0-9]|3[0,1])$/; + _$jscoverage['extern/optparse/lib/optparse.js'][15]++; + var EMAIL_RE = /^([0-9a-zA-Z]+([_.-]?[0-9a-zA-Z]+)*@[0-9a-zA-Z]+[0-9,a-z,A-Z,.,-]*(.){1}[a-zA-Z]{2,4})+$/; + _$jscoverage['extern/optparse/lib/optparse.js'][16]++; + var EXT_RULE_RE = /(\-\-[\w_-]+)\s+([\w\[\]_-]+)|(\-\-[\w_-]+)/; + _$jscoverage['extern/optparse/lib/optparse.js'][17]++; + var ARG_OPTIONAL_RE = /\[(.+)\]/; + _$jscoverage['extern/optparse/lib/optparse.js'][21]++; + var DEFAULT_FILTER = "_DEFAULT"; + _$jscoverage['extern/optparse/lib/optparse.js'][22]++; + var PREDEFINED_FILTERS = {}; + _$jscoverage['extern/optparse/lib/optparse.js'][25]++; + function filter_text(value) { + _$jscoverage['extern/optparse/lib/optparse.js'][26]++; + return value; +} + _$jscoverage['extern/optparse/lib/optparse.js'][32]++; + function filter_number(value) { + _$jscoverage['extern/optparse/lib/optparse.js'][33]++; + var m = value.match(NUMBER_RE); + _$jscoverage['extern/optparse/lib/optparse.js'][34]++; + if (m == null) { + _$jscoverage['extern/optparse/lib/optparse.js'][34]++; + throw OptError("Expected a number representative"); + } + _$jscoverage['extern/optparse/lib/optparse.js'][35]++; + if (m[1]) { + _$jscoverage['extern/optparse/lib/optparse.js'][37]++; + return parseInt(m[1], 16); + } + else { + _$jscoverage['extern/optparse/lib/optparse.js'][41]++; + return parseFloat(m[2] || m[3]); + } +} + _$jscoverage['extern/optparse/lib/optparse.js'][43]++; + ; + _$jscoverage['extern/optparse/lib/optparse.js'][48]++; + function filter_date(value) { + _$jscoverage['extern/optparse/lib/optparse.js'][49]++; + var m = value.match(DATE_RE); + _$jscoverage['extern/optparse/lib/optparse.js'][50]++; + if (m == null) { + _$jscoverage['extern/optparse/lib/optparse.js'][50]++; + throw OptError("Expected a date representation in the \"yyyy-mm-dd\" format."); + } + _$jscoverage['extern/optparse/lib/optparse.js'][51]++; + return new Date(parseInt(m[0]), parseInt(m[1]), parseInt(m[2])); +} + _$jscoverage['extern/optparse/lib/optparse.js'][52]++; + ; + _$jscoverage['extern/optparse/lib/optparse.js'][56]++; + function filter_email(value) { + _$jscoverage['extern/optparse/lib/optparse.js'][57]++; + var m = value.match(EMAIL_RE); + _$jscoverage['extern/optparse/lib/optparse.js'][58]++; + if (m == null) { + _$jscoverage['extern/optparse/lib/optparse.js'][58]++; + throw OptError("Excpeted an email address."); + } + _$jscoverage['extern/optparse/lib/optparse.js'][59]++; + return m[1]; +} + _$jscoverage['extern/optparse/lib/optparse.js'][65]++; + PREDEFINED_FILTERS[DEFAULT_FILTER] = filter_text; + _$jscoverage['extern/optparse/lib/optparse.js'][66]++; + PREDEFINED_FILTERS.TEXT = filter_text; + _$jscoverage['extern/optparse/lib/optparse.js'][67]++; + PREDEFINED_FILTERS.NUMBER = filter_number; + _$jscoverage['extern/optparse/lib/optparse.js'][68]++; + PREDEFINED_FILTERS.DATE = filter_date; + _$jscoverage['extern/optparse/lib/optparse.js'][69]++; + PREDEFINED_FILTERS.EMAIL = filter_email; + _$jscoverage['extern/optparse/lib/optparse.js'][73]++; + function build_rules(filters, arr) { + _$jscoverage['extern/optparse/lib/optparse.js'][74]++; + var rules = []; + _$jscoverage['extern/optparse/lib/optparse.js'][75]++; + for (var i = 0; i < arr.length; i++) { + _$jscoverage['extern/optparse/lib/optparse.js'][76]++; + var r = arr[i], rule; + _$jscoverage['extern/optparse/lib/optparse.js'][77]++; + if (! contains_expr(r)) { + _$jscoverage['extern/optparse/lib/optparse.js'][77]++; + throw OptError("Rule MUST contain an option."); + } + _$jscoverage['extern/optparse/lib/optparse.js'][78]++; + switch (r.length) { + case 1: + _$jscoverage['extern/optparse/lib/optparse.js'][80]++; + rule = build_rule(filters, r[0]); + _$jscoverage['extern/optparse/lib/optparse.js'][81]++; + break; + case 2: + _$jscoverage['extern/optparse/lib/optparse.js'][83]++; + var expr = r[0].match(LONG_SWITCH_RE)? 0: 1; + _$jscoverage['extern/optparse/lib/optparse.js'][84]++; + var alias = expr == 0? -1: 0; + _$jscoverage['extern/optparse/lib/optparse.js'][85]++; + var desc = alias == -1? 1: -1; + _$jscoverage['extern/optparse/lib/optparse.js'][86]++; + rule = build_rule(filters, r[alias], r[expr], r[desc]); + _$jscoverage['extern/optparse/lib/optparse.js'][87]++; + break; + case 3: + _$jscoverage['extern/optparse/lib/optparse.js'][89]++; + rule = build_rule(filters, r[0], r[1], r[2]); + _$jscoverage['extern/optparse/lib/optparse.js'][90]++; + break; + default: + case 0: + _$jscoverage['extern/optparse/lib/optparse.js'][93]++; + continue; + } + _$jscoverage['extern/optparse/lib/optparse.js'][95]++; + rules.push(rule); +} + _$jscoverage['extern/optparse/lib/optparse.js'][97]++; + return rules; +} + _$jscoverage['extern/optparse/lib/optparse.js'][113]++; + function build_rule(filters, short, expr, desc) { + _$jscoverage['extern/optparse/lib/optparse.js'][114]++; + var optional, filter; + _$jscoverage['extern/optparse/lib/optparse.js'][115]++; + var m = expr.match(EXT_RULE_RE); + _$jscoverage['extern/optparse/lib/optparse.js'][116]++; + if (m == null) { + _$jscoverage['extern/optparse/lib/optparse.js'][116]++; + throw OptError("The switch is not well-formed."); + } + _$jscoverage['extern/optparse/lib/optparse.js'][117]++; + var long = m[1] || m[3]; + _$jscoverage['extern/optparse/lib/optparse.js'][118]++; + if (m[2] != undefined) { + _$jscoverage['extern/optparse/lib/optparse.js'][121]++; + var optional_match = m[2].match(ARG_OPTIONAL_RE); + _$jscoverage['extern/optparse/lib/optparse.js'][122]++; + var filter_name = optional_match === null? m[2]: optional_match[1]; + _$jscoverage['extern/optparse/lib/optparse.js'][123]++; + optional = optional_match !== null; + _$jscoverage['extern/optparse/lib/optparse.js'][124]++; + filter = filters[filter_name]; + _$jscoverage['extern/optparse/lib/optparse.js'][125]++; + if (filter === undefined) { + _$jscoverage['extern/optparse/lib/optparse.js'][125]++; + filter = filters[DEFAULT_FILTER]; + } + } + _$jscoverage['extern/optparse/lib/optparse.js'][127]++; + return ({name: long.substr(2), short: short, long: long, decl: expr, desc: desc, optional_arg: optional, filter: filter}); +} + _$jscoverage['extern/optparse/lib/optparse.js'][141]++; + function contains_expr(arr) { + _$jscoverage['extern/optparse/lib/optparse.js'][142]++; + if (! arr || ! arr.length) { + _$jscoverage['extern/optparse/lib/optparse.js'][142]++; + return false; + } + _$jscoverage['extern/optparse/lib/optparse.js'][143]++; + var l = arr.length; + _$jscoverage['extern/optparse/lib/optparse.js'][144]++; + while (l-- > 0) { + _$jscoverage['extern/optparse/lib/optparse.js'][144]++; + if (arr[l].match(LONG_SWITCH_RE)) { + _$jscoverage['extern/optparse/lib/optparse.js'][144]++; + return true; + } +} + _$jscoverage['extern/optparse/lib/optparse.js'][145]++; + return false; +} + _$jscoverage['extern/optparse/lib/optparse.js'][149]++; + function extend(dest, src) { + _$jscoverage['extern/optparse/lib/optparse.js'][150]++; + var result = dest; + _$jscoverage['extern/optparse/lib/optparse.js'][151]++; + for (var n in src) { + _$jscoverage['extern/optparse/lib/optparse.js'][152]++; + result[n] = src[n]; +} + _$jscoverage['extern/optparse/lib/optparse.js'][154]++; + return result; +} + _$jscoverage['extern/optparse/lib/optparse.js'][158]++; + function spaces(arg1, arg2) { + _$jscoverage['extern/optparse/lib/optparse.js'][159]++; + var l, builder = []; + _$jscoverage['extern/optparse/lib/optparse.js'][160]++; + if (arg1.constructor === Number) { + _$jscoverage['extern/optparse/lib/optparse.js'][161]++; + l = arg1; + } + else { + _$jscoverage['extern/optparse/lib/optparse.js'][163]++; + if (arg1.length == arg2) { + _$jscoverage['extern/optparse/lib/optparse.js'][163]++; + return arg1; + } + _$jscoverage['extern/optparse/lib/optparse.js'][164]++; + l = arg2 - arg1.length; + _$jscoverage['extern/optparse/lib/optparse.js'][165]++; + builder.push(arg1); + } + _$jscoverage['extern/optparse/lib/optparse.js'][167]++; + while (l-- > 0) { + _$jscoverage['extern/optparse/lib/optparse.js'][167]++; + builder.push(" "); +} + _$jscoverage['extern/optparse/lib/optparse.js'][168]++; + return builder.join(""); +} + _$jscoverage['extern/optparse/lib/optparse.js'][174]++; + function Parser(rules) { + _$jscoverage['extern/optparse/lib/optparse.js'][175]++; + return new OptionParser(rules); +} + _$jscoverage['extern/optparse/lib/optparse.js'][179]++; + function OptError(msg) { + _$jscoverage['extern/optparse/lib/optparse.js'][180]++; + return new (function () { + _$jscoverage['extern/optparse/lib/optparse.js'][181]++; + this.msg = msg; + _$jscoverage['extern/optparse/lib/optparse.js'][182]++; + this.toString = (function () { + _$jscoverage['extern/optparse/lib/optparse.js'][183]++; + return this.msg; +}); +})(); +} + _$jscoverage['extern/optparse/lib/optparse.js'][188]++; + function OptionParser(rules) { + _$jscoverage['extern/optparse/lib/optparse.js'][189]++; + this.banner = "Usage: [Options]"; + _$jscoverage['extern/optparse/lib/optparse.js'][190]++; + this.options_title = "Available options:"; + _$jscoverage['extern/optparse/lib/optparse.js'][191]++; + this._rules = rules; + _$jscoverage['extern/optparse/lib/optparse.js'][192]++; + this._halt = false; + _$jscoverage['extern/optparse/lib/optparse.js'][193]++; + this.filters = extend({}, PREDEFINED_FILTERS); + _$jscoverage['extern/optparse/lib/optparse.js'][194]++; + this.on_args = {}; + _$jscoverage['extern/optparse/lib/optparse.js'][195]++; + this.on_switches = {}; + _$jscoverage['extern/optparse/lib/optparse.js'][196]++; + this.on_halt = (function () { +}); + _$jscoverage['extern/optparse/lib/optparse.js'][197]++; + this.default_handler = (function () { +}); +} + _$jscoverage['extern/optparse/lib/optparse.js'][200]++; + OptionParser.prototype = {on: (function (value, fn) { + _$jscoverage['extern/optparse/lib/optparse.js'][204]++; + if (value.constructor === Function) { + _$jscoverage['extern/optparse/lib/optparse.js'][205]++; + this.default_handler = value; + } + else { + _$jscoverage['extern/optparse/lib/optparse.js'][206]++; + if (value.constructor === Number) { + _$jscoverage['extern/optparse/lib/optparse.js'][207]++; + this.on_args[value] = fn; + } + else { + _$jscoverage['extern/optparse/lib/optparse.js'][209]++; + this.on_switches[value] = fn; + } + } +}), filter: (function (name, fn) { + _$jscoverage['extern/optparse/lib/optparse.js'][218]++; + this.filters[name.toUpperCase()] = fn; +}), parse: (function (args) { + _$jscoverage['extern/optparse/lib/optparse.js'][223]++; + var result = [], callback; + _$jscoverage['extern/optparse/lib/optparse.js'][224]++; + var rules = build_rules(this.filters, this._rules); + _$jscoverage['extern/optparse/lib/optparse.js'][225]++; + var tokens = args.concat([]); + _$jscoverage['extern/optparse/lib/optparse.js'][226]++; + while ((token = tokens.shift()) && this._halt == false) { + _$jscoverage['extern/optparse/lib/optparse.js'][227]++; + if (token.match(LONG_SWITCH_RE) || token.match(SHORT_SWITCH_RE)) { + _$jscoverage['extern/optparse/lib/optparse.js'][228]++; + var arg = undefined; + _$jscoverage['extern/optparse/lib/optparse.js'][232]++; + for (var i = 0; i < rules.length; i++) { + _$jscoverage['extern/optparse/lib/optparse.js'][233]++; + var rule = rules[i]; + _$jscoverage['extern/optparse/lib/optparse.js'][234]++; + if (rule["long"] == token || rule["short"] == token) { + _$jscoverage['extern/optparse/lib/optparse.js'][235]++; + if (rule.filter !== undefined) { + _$jscoverage['extern/optparse/lib/optparse.js'][236]++; + arg = tokens.shift(); + _$jscoverage['extern/optparse/lib/optparse.js'][237]++; + if (! arg.match(LONG_SWITCH_RE) && ! arg.match(SHORT_SWITCH_RE)) { + _$jscoverage['extern/optparse/lib/optparse.js'][238]++; + try { + _$jscoverage['extern/optparse/lib/optparse.js'][239]++; + arg = rule.filter(arg); + } + catch (e) { + _$jscoverage['extern/optparse/lib/optparse.js'][241]++; + throw OptError(token + ": " + e.toString()); + } + } + else { + _$jscoverage['extern/optparse/lib/optparse.js'][243]++; + if (rule.optional_arg) { + _$jscoverage['extern/optparse/lib/optparse.js'][244]++; + tokens.unshift(arg); + } + else { + _$jscoverage['extern/optparse/lib/optparse.js'][246]++; + throw OptError("Expected switch argument."); + } + } + } + _$jscoverage['extern/optparse/lib/optparse.js'][249]++; + callback = this.on_switches[rule.name]; + _$jscoverage['extern/optparse/lib/optparse.js'][250]++; + if (! callback) { + _$jscoverage['extern/optparse/lib/optparse.js'][250]++; + callback = this.on_switches["*"]; + } + _$jscoverage['extern/optparse/lib/optparse.js'][251]++; + if (callback) { + _$jscoverage['extern/optparse/lib/optparse.js'][251]++; + callback.apply(this, [rule.name, arg]); + } + _$jscoverage['extern/optparse/lib/optparse.js'][252]++; + break; + } +} + _$jscoverage['extern/optparse/lib/optparse.js'][255]++; + if (i == rules.length) { + _$jscoverage['extern/optparse/lib/optparse.js'][255]++; + this.default_handler.apply(this, [token]); + } + } + else { + _$jscoverage['extern/optparse/lib/optparse.js'][259]++; + callback = this.on_args[result.length]; + _$jscoverage['extern/optparse/lib/optparse.js'][260]++; + result.push(token); + _$jscoverage['extern/optparse/lib/optparse.js'][261]++; + if (callback) { + _$jscoverage['extern/optparse/lib/optparse.js'][261]++; + callback.apply(this, [token]); + } + } +} + _$jscoverage['extern/optparse/lib/optparse.js'][264]++; + return this._halt? this.on_halt.apply(this, []): result; +}), options: (function () { + _$jscoverage['extern/optparse/lib/optparse.js'][269]++; + return build_rules(this.filters, this._rules); +}), halt: (function (fn) { + _$jscoverage['extern/optparse/lib/optparse.js'][276]++; + this._halt = fn === undefined; + _$jscoverage['extern/optparse/lib/optparse.js'][277]++; + if (fn) { + _$jscoverage['extern/optparse/lib/optparse.js'][277]++; + this.on_halt = fn; + } +}), toString: (function () { + _$jscoverage['extern/optparse/lib/optparse.js'][282]++; + var builder = [this.banner, "", this.options_title], shorts = false, longest = 0, rule; + _$jscoverage['extern/optparse/lib/optparse.js'][284]++; + var rules = build_rules(this.filters, this._rules); + _$jscoverage['extern/optparse/lib/optparse.js'][285]++; + for (var i = 0; i < rules.length; i++) { + _$jscoverage['extern/optparse/lib/optparse.js'][286]++; + rule = rules[i]; + _$jscoverage['extern/optparse/lib/optparse.js'][288]++; + if (rule["short"]) { + _$jscoverage['extern/optparse/lib/optparse.js'][288]++; + shorts = true; + } + _$jscoverage['extern/optparse/lib/optparse.js'][289]++; + if (rule.decl.length > longest) { + _$jscoverage['extern/optparse/lib/optparse.js'][289]++; + longest = rule.decl.length; + } +} + _$jscoverage['extern/optparse/lib/optparse.js'][291]++; + for (var i = 0; i < rules.length; i++) { + _$jscoverage['extern/optparse/lib/optparse.js'][292]++; + var text; + _$jscoverage['extern/optparse/lib/optparse.js'][293]++; + rule = rules[i]; + _$jscoverage['extern/optparse/lib/optparse.js'][294]++; + if (shorts) { + _$jscoverage['extern/optparse/lib/optparse.js'][295]++; + if (rule["short"]) { + _$jscoverage['extern/optparse/lib/optparse.js'][295]++; + text = spaces(2) + rule["short"] + ", "; + } + else { + _$jscoverage['extern/optparse/lib/optparse.js'][296]++; + text = spaces(6); + } + } + _$jscoverage['extern/optparse/lib/optparse.js'][298]++; + text += spaces(rule.decl, longest) + spaces(3); + _$jscoverage['extern/optparse/lib/optparse.js'][299]++; + text += rule.desc; + _$jscoverage['extern/optparse/lib/optparse.js'][300]++; + builder.push(text); +} + _$jscoverage['extern/optparse/lib/optparse.js'][302]++; + return builder.join("\n"); +})}; + _$jscoverage['extern/optparse/lib/optparse.js'][306]++; + self.VERSION = VERSION; + _$jscoverage['extern/optparse/lib/optparse.js'][307]++; + self.OptionParser = OptionParser; +})(optparse); +_$jscoverage['extern/optparse/lib/optparse.js'].source = ["// Optparse.js 1.0.2 - Option Parser for Javascript ","// ","// Copyright (c) 2009 Johan Dahlberg","// ","// See README.md for license.","// ","var optparse = {};","try{ optparse = exports } catch(e) {}; // Try to export the lib for node.js","(function(self) {","var VERSION = '1.0.2';","var LONG_SWITCH_RE = /^--\\w/;","var SHORT_SWITCH_RE = /^-\\w/;","var NUMBER_RE = /^(0x[A-Fa-f0-9]+)|([0-9]+\\.[0-9]+)|(\\d+)$/;","var DATE_RE = /^\\d{4}-(0[0-9]|1[0,1,2])-([0,1,2][0-9]|3[0,1])$/;","var EMAIL_RE = /^([0-9a-zA-Z]+([_.-]?[0-9a-zA-Z]+)*@[0-9a-zA-Z]+[0-9,a-z,A-Z,.,-]*(.){1}[a-zA-Z]{2,4})+$/;","var EXT_RULE_RE = /(\\-\\-[\\w_-]+)\\s+([\\w\\[\\]_-]+)|(\\-\\-[\\w_-]+)/;","var ARG_OPTIONAL_RE = /\\[(.+)\\]/;","","// The default switch argument filter to use, when argument name doesnt match","// any other names. ","var DEFAULT_FILTER = '_DEFAULT';","var PREDEFINED_FILTERS = {};","","// The default switch argument filter. Parses the argument as text.","function filter_text(value) {"," return value;","}","","// Switch argument filter that expects an integer, HEX or a decimal value. An ","// exception is throwed if the criteria is not matched. ","// Valid input formats are: 0xFFFFFFF, 12345 and 1234.1234","function filter_number(value) {"," var m = value.match(NUMBER_RE);"," if(m == null) throw OptError('Expected a number representative');"," if(m[1]) {"," // The number is in HEX format. Convert into a number, then return it"," return parseInt(m[1], 16);"," } else {"," // The number is in regular- or decimal form. Just run in through "," // the float caster."," return parseFloat(m[2] || m[3]);"," }","};","","// Switch argument filter that expects a Date expression. The date string MUST be","// formated as: \"yyyy-mm-dd\" An exception is throwed if the criteria is not ","// matched. An DATE object is returned on success. ","function filter_date(value) {"," var m = value.match(DATE_RE);"," if(m == null) throw OptError('Expected a date representation in the \"yyyy-mm-dd\" format.');"," return new Date(parseInt(m[0]), parseInt(m[1]), parseInt(m[2]));","};","","// Switch argument filter that expects an email address. An exception is throwed","// if the criteria doesn`t match. ","function filter_email(value) {"," var m = value.match(EMAIL_RE);"," if(m == null) throw OptError('Excpeted an email address.');"," return m[1];","}","","// Register all predefined filters. This dict is used by each OptionParser ","// instance, when parsing arguments. Custom filters can be added to the parser ","// instance by calling the \"add_filter\" -method. ","PREDEFINED_FILTERS[DEFAULT_FILTER] = filter_text;","PREDEFINED_FILTERS['TEXT'] = filter_text;","PREDEFINED_FILTERS['NUMBER'] = filter_number;","PREDEFINED_FILTERS['DATE'] = filter_date;","PREDEFINED_FILTERS['EMAIL'] = filter_email;","","// Buildes rules from a switches collection. The switches collection is defined","// when constructing a new OptionParser object. ","function build_rules(filters, arr) {"," var rules = [];"," for(var i=0; i<arr.length; i++) {"," var r = arr[i], rule"," if(!contains_expr(r)) throw OptError('Rule MUST contain an option.');"," switch(r.length) {"," case 1:"," rule = build_rule(filters, r[0]);"," break;"," case 2:"," var expr = r[0].match(LONG_SWITCH_RE) ? 0 : 1;"," var alias = expr == 0 ? -1 : 0;"," var desc = alias == -1 ? 1 : -1;"," rule = build_rule(filters, r[alias], r[expr], r[desc]);"," break;"," case 3:"," rule = build_rule(filters, r[0], r[1], r[2]);"," break;"," default:"," case 0:"," continue;"," }"," rules.push(rule)"," }"," return rules;","}","","// Builds a rule with specified expression, short style switch and help. This ","// function expects a dict with filters to work correctly. ","//","// Return format:","// name The name of the switch.","// short The short style switch","// long The long style switch","// decl The declaration expression (the input expression)","// desc The optional help section for the switch","// optional_arg Indicates that switch argument is optional","// filter The filter to use when parsing the arg. An ","// <<undefined>> value means that the switch does ","// not take anargument.","function build_rule(filters, short, expr, desc) {"," var optional, filter;"," var m = expr.match(EXT_RULE_RE);"," if(m == null) throw OptError('The switch is not well-formed.');"," var long = m[1] || m[3];"," if(m[2] != undefined) {"," // A switch argument is expected. Check if the argument is optional,"," // then find a filter that suites."," var optional_match = m[2].match(ARG_OPTIONAL_RE);"," var filter_name = optional_match === null ? m[2] : optional_match[1];"," optional = optional_match !== null;"," filter = filters[filter_name];"," if(filter === undefined) filter = filters[DEFAULT_FILTER];"," }"," return {"," name: long.substr(2), "," short: short, "," long: long,"," decl: expr,"," desc: desc, "," optional_arg: optional,"," filter: filter "," }","}","","// Loop's trough all elements of an array and check if there is valid","// options expression within. An valid option is a token that starts ","// double dashes. E.G. --my_option","function contains_expr(arr) {"," if(!arr || !arr.length) return false;"," var l = arr.length;"," while(l-- > 0) if(arr[l].match(LONG_SWITCH_RE)) return true;"," return false;","}","","// Extends destination object with members of source object","function extend(dest, src) {"," var result = dest;"," for(var n in src) {"," result[n] = src[n];"," }"," return result;","}","","// Appends spaces to match specified number of chars","function spaces(arg1, arg2) {"," var l, builder = [];"," if(arg1.constructor === Number) {"," l = arg1; "," } else {"," if(arg1.length == arg2) return arg1;"," l = arg2 - arg1.length;"," builder.push(arg1);"," }"," while(l-- > 0) builder.push(' ');"," return builder.join('');","}","","// Create a new Parser object that can be used to parse command line arguments.","//","//","function Parser(rules) {"," return new OptionParser(rules);","}","","// Creates an error object with specified error message.","function OptError(msg) {"," return new function() {"," this.msg = msg;"," this.toString = function() {"," return this.msg;"," }"," }","}","","function OptionParser(rules) {"," this.banner = 'Usage: [Options]';"," this.options_title = 'Available options:'"," this._rules = rules;"," this._halt = false;"," this.filters = extend({}, PREDEFINED_FILTERS);"," this.on_args = {};"," this.on_switches = {};"," this.on_halt = function() {};"," this.default_handler = function() {};","}","","OptionParser.prototype = {"," "," // Adds args and switchs handler."," on: function(value, fn) {"," if(value.constructor === Function ) {"," this.default_handler = value;"," } else if(value.constructor === Number) {"," this.on_args[value] = fn;"," } else {"," this.on_switches[value] = fn;"," }"," },"," "," // Adds a custom filter to the parser. It's possible to override the"," // default filter by passing the value \"_DEFAULT\" to the ´´name´´"," // argument. The name of the filter is automatically transformed into "," // upper case. "," filter: function(name, fn) {"," this.filters[name.toUpperCase()] = fn;"," },"," "," // Parses specified args. Returns remaining arguments. "," parse: function(args) {"," var result = [], callback;"," var rules = build_rules(this.filters, this._rules);"," var tokens = args.concat([]);"," while((token = tokens.shift()) && this._halt == false) {"," if(token.match(LONG_SWITCH_RE) || token.match(SHORT_SWITCH_RE)) {"," var arg = undefined;"," // The token is a long or a short switch. Get the corresponding "," // rule, filter and handle it. Pass the switch to the default "," // handler if no rule matched."," for(var i = 0; i < rules.length; i++) {"," var rule = rules[i];"," if(rule.long == token || rule.short == token) {"," if(rule.filter !== undefined) {"," arg = tokens.shift();"," if(!arg.match(LONG_SWITCH_RE) && !arg.match(SHORT_SWITCH_RE)) {"," try {"," arg = rule.filter(arg);"," } catch(e) {"," throw OptError(token + ': ' + e.toString());"," }"," } else if(rule.optional_arg) {"," tokens.unshift(arg);"," } else {"," throw OptError('Expected switch argument.');"," }"," } "," callback = this.on_switches[rule.name];"," if (!callback) callback = this.on_switches['*'];"," if(callback) callback.apply(this, [rule.name, arg]);"," break;"," } "," }"," if(i == rules.length) this.default_handler.apply(this, [token]);"," } else {"," // Did not match long or short switch. Parse the token as a "," // normal argument."," callback = this.on_args[result.length];"," result.push(token);"," if(callback) callback.apply(this, [token]);"," }"," }"," return this._halt ? this.on_halt.apply(this, []) : result;"," },"," "," // Returns an Array with all defined option rules "," options: function() {"," return build_rules(this.filters, this._rules);"," },",""," // Add an on_halt callback if argument ´´fn´´ is specified. on_switch handlers can "," // call instance.halt to abort the argument parsing. This can be useful when"," // displaying help or version information."," halt: function(fn) {"," this._halt = fn === undefined"," if(fn) this.on_halt = fn;"," },"," "," // Returns a string representation of this OptionParser instance."," toString: function() {"," var builder = [this.banner, '', this.options_title], "," shorts = false, longest = 0, rule;"," var rules = build_rules(this.filters, this._rules);"," for(var i = 0; i < rules.length; i++) {"," rule = rules[i];"," // Quick-analyze the options. "," if(rule.short) shorts = true;"," if(rule.decl.length > longest) longest = rule.decl.length;"," }"," for(var i = 0; i < rules.length; i++) {"," var text; "," rule = rules[i];"," if(shorts) {"," if(rule.short) text = spaces(2) + rule.short + ', ';"," else text = spaces(6);"," }"," text += spaces(rule.decl, longest) + spaces(3);"," text += rule.desc;"," builder.push(text);"," }"," return builder.join('\\n');"," }","}","","self.VERSION = VERSION;","self.OptionParser = OptionParser;","","})(optparse);"]; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/package.json b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/package.json new file mode 100644 index 0000000..41ec5ea --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/package.json @@ -0,0 +1,8 @@ +{ + "name": "optparse", + "author": "Johan Dahlberg", + "description": "Command-line option parser", + "keywords": ["option", "parser", "command-line", "cli", "terminal"], + "version": "1.0.1", + "main": "./lib/optparse" +} diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/seed.yml b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/seed.yml new file mode 100644 index 0000000..fd5ac11 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib-cov/extern/optparse/seed.yml @@ -0,0 +1,5 @@ +--- + name: optparse + description: Command-line option parser + tags: option parser command-line cli terminal + version: 1.0.1 diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/assert.js b/node_modules/cassandra-client/node_modules/whiskey/lib/assert.js new file mode 100644 index 0000000..5a5fe30 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/assert.js @@ -0,0 +1,348 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + * + * Many of the modifications to 'assert' that take place here are borrowed + * from the 'Expresso' test framework: + * + * + * Expresso + * Copyright(c) TJ Holowaychuk + * (MIT Licensed) + */ + +var util = require('util'); +var url = require('url'); +var http = require('http'); +var https = require('https'); + +var port = parseInt((Math.random() * (65500 - 2000) + 2000), 10); + +// Code bellow is taken from Node core +// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 +// +// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! +// +// Originally from narwhal.js (http://narwhaljs.org) +// Copyright (c) 2009 Thomas Robinson <280north.com> +// +// 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 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. + +var origAssert = require('assert'); + +var assert = {}; + + /* + * Alias deepEqual as eql for complex equality + */ + assert.eql = origAssert.deepEqual; + + /** + * Assert that `val` is null. + * + * @param {Mixed} val + * @param {String} msg + */ + assert.isNull = function(val, msg) { + assert.strictEqual(null, val, msg); + }; + + assert.ifError = function(err) { + if (err) { + if (err instanceof Error) { + Error.captureStackTrace(err, arguments.callee); + } + + throw err; + } + }; + + /** + * Assert that `val` is not null. + * + * @param {Mixed} val + * @param {String} msg + */ + assert.isNotNull = function(val, msg) { + assert.notStrictEqual(null, val, msg); + }; + + /** + * Assert that `val` is undefined. + * + * @param {Mixed} val + * @param {String} msg + */ + assert.isUndefined = function(val, msg) { + assert.strictEqual(undefined, val, msg); + }; + + /** + * Assert that `val` is not undefined. + * + * @param {Mixed} val + * @param {String} msg + */ + assert.isDefined = function(val, msg) { + assert.notStrictEqual(undefined, val, msg); + }; + + /** + * Assert that `obj` is `type`. + * + * @param {Mixed} obj + * @param {String} type + * @api public + */ + assert.type = function(obj, type, msg){ + var real = typeof obj; + msg = msg || 'typeof ' + util.inspect(obj) + ' is ' + real + ', expected ' + type; + assert.ok(type === real, msg); + }; + + /** + * Assert that `str` matches `regexp`. + * + * @param {String} str + * @param {RegExp} regexp + * @param {String} msg + */ + assert.match = function(str, regexp, msg) { + msg = msg || util.inspect(str) + ' does not match ' + util.inspect(regexp); + assert.ok(regexp.test(str), msg); + }; + + /** + * Assert that `val` is within `obj`. + * + * Examples: + * + * assert.includes('foobar', 'bar'); + * assert.includes(['foo', 'bar'], 'foo'); + * + * @param {String|Array} obj + * @param {Mixed} val + * @param {String} msg + */ + assert.includes = function(obj, val, msg) { + msg = msg || util.inspect(obj) + ' does not include ' + util.inspect(val); + assert.ok(obj.indexOf(val) >= 0, msg); + }; + + /** + * Assert length of `val` is `n`. + * + * @param {Mixed} val + * @param {Number} n + * @param {String} msg + */ + assert.length = function(val, n, msg) { + msg = msg || util.inspect(val) + ' has length of ' + val.length + ', expected ' + n; + assert.equal(n, val.length, msg); + }; + + /** + * Assert response from `server` with + * the given `req` object and `res` assertions object. + * + * @param {Server} server + * @param {Object} req + * @param {Object|Function} res + * @param {String} msg + */ + assert.response = function(server, req, res, msg){ + // Callback as third or fourth arg + var callback = typeof res === 'function' + ? res + : typeof msg === 'function' + ? msg + : function(){}; + + // Default messate to test title + if (typeof msg === 'function') msg = null; + msg = msg || assert.testTitle; + msg += '. '; + + // Pending responses + server.__pending = server.__pending || 0; + server.__pending++; + + server.listen(server.__port = port++, '127.0.0.1'); + + process.nextTick(function() { + // Issue request + var timer; + var trailer; + var method = req.method || 'GET'; + var status = res.status || res.statusCode; + var data = req.data || req.body; + var streamer = req.streamer; + var timeout = req.timeout || 0; + var headers = req.headers || {}; + + for (trailer in req.trailers) { + if (req.trailers.hasOwnProperty(trailer)) { + if (headers['Trailer']) { + headers['Trailer'] += ', ' + trailer; + } + else { + headers['Trailer'] = trailer; + } + } + } + + var urlParsed = url.parse(req.url); + var reqOptions = { + 'host': '127.0.0.1', + 'port': server.__port, + 'path': urlParsed.pathname, + 'method': method, + 'headers': headers + }; + + var reqMethod = (urlParsed.protocol === 'http:' || !urlParsed.hasOwnProperty('protocol')) ? http.request : https.request; + var request = http.request(reqOptions); + + if (req.trailers) { + request.addTrailers(req.trailers); + } + + // Timeout + if (timeout) { + timer = setTimeout(function(){ + --server.__pending || server.close(); + delete req.timeout; + assert.fail(msg + 'Request timed out after ' + timeout + 'ms.'); + }, timeout); + } + + if (data) request.write(data); + + request.addListener('response', function(response) { + response.body = ''; + response.setEncoding('utf8'); + response.addListener('data', function(chunk){ response.body += chunk; }); + response.addListener('end', function(){ + --server.__pending || server.close(); + if (timer) clearTimeout(timer); + + // Assert response body + if (res.body !== undefined) { + assert.equal( + response.body, + res.body, + msg + 'Invalid response body.\n' + + ' Expected: ' + util.inspect(res.body) + '\n' + + ' Got: ' + util.inspect(response.body) + ); + } + + // Assert response status + if (typeof status === 'number') { + assert.equal( + response.statusCode, + status, + msg + 'Invalid response status code.\n' + + ' Expected: [{' + status + '}\n' + + ' Got: {' + response.sttusCode + '}' + ); + } + + // Assert response headers + if (res.headers) { + var keys = Object.keys(res.headers); + for (var i = 0, len = keys.length; i < len; ++i) { + var name = keys[i]; + var actual = response.headers[name.toLowerCase()]; + var expected = res.headers[name]; + assert.equal( + actual, + expected, + msg + 'Invalid response header [bold]{' + name + '}.\n' + + ' Expected: {' + expected + '}\n' + + ' Got: {' + actual + '}' + ); + } + } + + callback(response); + }); + }); + + if (streamer) { + streamer(request); + } + else { + request.end(); + } + }); +}; + +function merge(obj1, obj2, ignore) { + obj1 = obj1 || assert; + ignore = ignore || []; + + for (var key in obj2) { + if (obj2.hasOwnProperty(key) && ignore.indexOf(key) === -1) { + obj1[key] = obj2[key]; + } + } +} + +function getAssertModule(test) { + assert.AssertionError = function AssertionError(options) { + origAssert.AssertionError.call(this, options); + this.test = test; + }; + + util.inherits(assert.AssertionError, origAssert.AssertionError); + + var ignore = ['AssertionError']; + for (var key in origAssert) { + if (origAssert.hasOwnProperty(key) && ignore.indexOf(key) === -1) { + assert[key] = (function(key) { + return function() { + try { + origAssert[key].apply(null, arguments); + } + catch (err) { + err.test = test; + throw err; + } + } + })(key); + } + } + + return assert; +} + +exports.getAssertModule = getAssertModule; +exports.merge = merge; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/common.js b/node_modules/cassandra-client/node_modules/whiskey/lib/common.js new file mode 100644 index 0000000..dd4e147 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/common.js @@ -0,0 +1,546 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + * + */ + +var path = require('path'); +var net = require('net'); +var util = require('util'); + +var sprintf = require('sprintf').sprintf; +var async = require('async'); +var gex = require('gex'); +var log = require('logmagic').local('whiskey.common'); + +var assert = require('./assert'); +var constants = require('./constants'); +var testUtil = require('./util'); +var coverage = require('./coverage'); +var scopeleaks = require('./scopeleaks'); + +var isValidTestFunctionName = function(name) { + return name.indexOf('test') === 0; +}; + + +// foo.bar.test.* -> [ foo/bar/test.js, '*' ] +// test. -> [ 'test.js', '*'] +// some.path.foo.test_bar* -> [ 'some/path/foo.js', 'test_bar*' ] +function getTestFilePathAndPattern(patternString) { + if (/\.js$/.test(patternString)) { + return [ patternString, '*' ]; + } + + var split = patternString.split('.'); + var len = split.length; + var testFile, basePath, testPath, pattern; + + testFile = sprintf('%s.js', split[len - 2]); + pattern = split[len - 1] || '*'; + basePath = split.splice(0, len - 2).join('/'); + testPath = path.join(basePath, testFile); + + return [ testPath, pattern ]; +} + +function SkipError(test, msg) { + this.test = test; + this.msg = msg || ''; + Error.call(this, 'skipped'); +} + +util.inherits(SkipError, Error); + +var runInitFunction = function(filePath, callback) { + var testObj; + var initModule = null; + + try { + initModule = require(filePath); + } + catch (err) { + // Invalid init file path provided + callback(); + return; + } + + if (initModule) { + if (initModule.hasOwnProperty(constants.INIT_FUNCTION_NAME)) { + try { + initModule[constants.INIT_FUNCTION_NAME](callback); + return; + } + catch (err2) { + callback(); + return; + } + } + } + + callback(); +}; + +function Test(testName, testFunction, scopeLeaks) { + this._testName = testName; + this._testFunction = testFunction; + + this._finished = false; + this._testObj = null; + this._assertObj = null; + + this._timeStart = null; + this._timeEnd = null; + this._status = null; // 'success' or 'failure' + this._err = null; // only populated if _status = 'failure' + this._skipMsg = null; + this._scopeLeaks = scopeLeaks || false; + this._leakedVariables = null; // a list of variables which leaked into + // global scope +} + +Test.prototype._getScopeSnapshot = function(scope) { + if (!this._scopeLeaks) { + return null; + } + + return scopeleaks.getSnapshot(scope); +}; + +Test.prototype._getLeakedVariables = function(scopeBefore, scopeAfter) { + if (!this._scopeLeaks) { + return null; + } + + return scopeleaks.getDifferences(scopeBefore, scopeAfter); +}; + +Test.prototype.run = function(callback) { + var self = this; + var scopeBefore, scopeAfter; + var finishCallbackCalled = false; + + function finishCallback() { + callback(self.getResultObject()); + } + + function finishFunc() { + if (finishCallbackCalled) { + // someone called .finish() twice. + log.infof('test.finish in [bold]${name}[/bold] has been called twice' + + ', possible double callback in your code!', + {'name': self._testName}); + return; + } + + if (!self._status) { + scopeAfter = self._getScopeSnapshot(global); + self._leakedVariables = self._getLeakedVariables(scopeBefore, scopeAfter); + + self._markAsSucceeded(); + } + + self._timeEnd = new Date().getTime(); + finishCallbackCalled = true; + finishCallback(); + } + + this._testObj = this._getTestObject(finishFunc); + this._assertObj = this._getAssertObject(); + + self._timeStart = new Date().getTime(); + + try { + scopeBefore = this._getScopeSnapshot(global); + this._testFunction(this._testObj, this._assertObj); + + } + catch (err) { + if (!err.hasOwnProperty('message') && err.toString && typeof err.toString === 'function') { + err.message = err.toString(); + } + + scopeAfter = this._getScopeSnapshot(global); + this._leakedVariables = this._getLeakedVariables(scopeBefore, scopeAfter); + + if (err instanceof SkipError) { + this._markAsSkipped(err.msg); + } + else { + this._markAsFailed(err); + } + + finishFunc(); + return; + } +}; + +Test.prototype._getTestObject = function(finishFunc) { + var self = this; + var testObj = function test() { + return finishFunc.apply(undefined, arguments); + }; + + function skipFunc(msg) { + throw new SkipError(self, msg); + } + + testObj.finish = finishFunc; + testObj.skip = skipFunc; + + return testObj; +}; + +Test.prototype._getAssertObject = function() { + return assert.getAssertModule(this); +}; + +Test.prototype._markAsSucceeded = function() { + this._finished = true; + this._status = 'success'; +}; + +Test.prototype._markAsFailed = function(err) { + var stack; + + if (err.hasOwnProperty('test')) { + delete err.test; + } + + if (err.stack) { + // zomg, hacky, but in a later versions of V8 it looks like stack is some + // kind of special attribute which can't be serialized. + stack = err.stack.toString(); + delete err.stack; + err.stack = stack; + } + + this._finished = true; + this._err = err; + this._status = 'failure'; +}; + +Test.prototype._markAsSkipped = function(msg) { + this._finished = true; + this._status = 'skipped'; + this._skipMsg = msg; +}; + +Test.prototype.isRunning = function() { + return !this._finished; +}; + +Test.prototype.beforeExit = function(handler) { + this._beforeExitHandler = handler; +}; + +Test.prototype.getResultObject = function() { + var resultObj = { + 'name': this._testName, + 'status': this._status, + 'error': this._err, + 'skip_msg': this._skipMsg, + 'leaked_variables': this._leakedVariables, + 'time_start': this._timeStart, + 'time_end': this._timeEnd + }; + + return resultObj; +}; + +function TestFile(filePath, options) { + this._filePath = filePath; + this._pattern = options['pattern']; + + this._socketPath = options['socket_path']; + this._fileName = path.basename(this._filePath); + this._testInitFile = options['init_file']; + this._timeout = options['timeout']; + this._concurrency = options['concurrency']; + this._scopeLeaks = options['scope_leaks']; + + this._tests = []; + this._uncaughtExceptions = []; + + this._runningTest = null; +} + +TestFile.prototype.addTest = function(test) { + this._tests.push(test); +}; + +TestFile.prototype.runTests = function(callback) { + var self = this; + var i, test, exportedFunctions, exportedFunctionsNames, errName; + var setUpFunc, tearDownFunc, setUpFuncIndex, tearDownFuncIndex; + var testName, testFunc, testsLen; + var callbackCalled = false; + var testModule = this._filePath.replace(/\.js$/, ''); + + function handleEnd() { + var resultObj; + if (callbackCalled) { + return; + } + + callbackCalled = true; + callback(); + } + + function onTestDone(test, callback) { + var resultObj = test.getResultObject(); + + self.addTest(test); + self._reportTestResult(resultObj); + callback(); + } + + async.series([ + // Obtain the connection + function(callback) { + self._getConnection(function(err, connection) { + if (err) { + callback(new Error('Unable to establish connection with the master ' + + 'process')); + return; + } + + self._connection = connection; + callback(); + }); + }, + + // if test init file is present, run init function in it + function(callback) { + if (!self._testInitFile) { + callback(); + return; + } + + runInitFunction(self._testInitFile, callback); + }, + + // Require the test file + function(callback) { + var errName; + try { + exportedFunctions = require(testModule); + } + catch (err) { + if (err.message.indexOf(testModule) !== -1 && + err.message.match(/cannot find module/i)) { + errName = 'file_does_not_exist'; + } + else { + errName = 'uncaught_exception'; + } + + test = new Test(errName, null); + test._markAsFailed(err); + self._reportTestResult(test.getResultObject()); + callback(err); + return; + } + + exportedFunctionsNames = Object.keys(exportedFunctions); + exportedFunctionsNames = exportedFunctionsNames.filter(isValidTestFunctionName); + testsLen = exportedFunctionsNames.length; + setUpFunc = exportedFunctions[constants.SETUP_FUNCTION_NAME]; + tearDownFunc = exportedFunctions[constants.TEARDOWN_FUNCTION_NAME]; + + callback(); + }, + + // if setUp function is present, run it + function(callback){ + if (!setUpFunc) { + callback(); + return; + } + + var test = new Test(constants.SETUP_FUNCTION_NAME, setUpFunc, + self._scopeLeaks); + test.run(async.apply(onTestDone, test, callback)); + }, + + // Run the tests + function(callback) { + var queue; + + if (exportedFunctionsNames.length === 0) { + callback(); + return; + } + + function taskFunc(task, _callback) { + var test = task.test; + self._runningTest = test; + test.run(async.apply(onTestDone, task.test, _callback)); + } + + function onDrain() { + callback(); + } + + queue = async.queue(taskFunc, self._concurrency); + queue.drain = onDrain; + + for (i = 0; i < testsLen; i++) { + testName = exportedFunctionsNames[i]; + testFunc = exportedFunctions[testName]; + + if (!gex(self._pattern).on(testName)) { + continue; + } + + test = new Test(testName, testFunc, self._scopeLeaks); + queue.push({'test': test}); + } + + if (queue.length() === 0) { + // No test matched the provided pattern + callback(); + } + + }, + + // if tearDown function is present, run it + function(callback) { + if (!tearDownFunc) { + callback(); + return; + } + + var test = new Test(constants.TEARDOWN_FUNCTION_NAME, tearDownFunc, + self._scopeLeaks); + test.run(async.apply(onTestDone, test, callback)); + } + ], + + function(err) { + handleEnd(); + }); +}; + +TestFile.prototype._getConnection = function(callback) { + var connection = net.createConnection(this._socketPath); + + connection.on('connect', function onConnect() { + callback(null, connection); + }); + + connection.on('error', function onError(err) { + callback(err, null); + }); +}; + +TestFile.prototype._reportTestResult = function(resultObj) { + var payload; + payload = sprintf('%s%s%s%s%s\n', constants.TEST_START_MARKER, this._filePath, + constants.DELIMITER, JSON.stringify(resultObj), + constants.TEST_END_MARKER); + this._connection.write(payload); +}; + +TestFile.prototype._reportTestCoverage = function(coverageObj) { + this._connection.write(sprintf('%s%s%s%s\n', + this._filePath, + constants.DELIMITER, + coverage.stringifyCoverage(coverageObj), + constants.COVERAGE_END_MARKER)); +}; + +TestFile.prototype._reportTestFileEnd = function() { + this._connection.end(sprintf('%s%s\n', this._filePath, + constants.TEST_FILE_END_MARKER)); +}; + +TestFile.prototype.addUncaughtException = function(err) { + var test = err.test; + + if (test) { + if (err instanceof SkipError) { + test._markAsSkipped(err.msg); + test._testObj.finish(); + } + else { + test._markAsFailed(err); + test._testObj.finish(); + } + + this.addTest(test); + } + else if (this._runningTest) { + // User did not use our assert module or uncaughtException was thrown + // somewhere in the async code. + // Check which test is still running, mark it as failed and finish it. + test = this._runningTest; + test._markAsFailed(err); + test._testObj.finish(); + this.addTest(test); + } + else { + // Can't figure out the origin, just add it to the _uncaughtExceptions + // array. + this._uncaughtExceptions.push(err); + } +}; + +TestFile.prototype.getResultObject = function(errObj) { + var i, test, result, name, uncaughtException; + var testsLen = this._tests.length; + var uncaughtExceptionsLen = this._uncaughtExceptions.length; + + var resultObj = { + 'file_path': this._filePath, + 'file_name': this._fileName, + 'error': null, + 'timeout': false, + 'stdout': '', + 'stderr': '', + 'tests': {} + }; + + if (errObj) { + resultObj.error = errObj; + return resultObj; + } + + for (i = 0; i < testsLen; i++) { + test = this._tests[i]; + result = test.getResultObject(); + resultObj.tests[result.name] = result; + } + + for (i = 0; i < uncaughtExceptionsLen; i++) { + name = sprintf('uncaught_exception_%d', i + 1); + uncaughtException = this._uncaughtExceptions[i]; + test = new Test(name, null); + test._markAsFailed(uncaughtException); + resultObj.tests[name] = test.getResultObject(); + } + + return resultObj; +}; + +function registerCustomAssertionFunctions(functions) { + assert.merge(null, functions); +} + +exports.Test = Test; +exports.TestFile = TestFile; +exports.getTestFilePathAndPattern = getTestFilePathAndPattern; + +exports.registerCustomAssertionFunctions = registerCustomAssertionFunctions; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/constants.js b/node_modules/cassandra-client/node_modules/whiskey/lib/constants.js new file mode 100644 index 0000000..3f80197 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/constants.js @@ -0,0 +1,154 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var sprintf = require('sprintf').sprintf; + +/* + * How long to wait for a test file to complete. + */ +var DEFAULT_TEST_TIMEOUT = 15 * 1000; + +var DEFAULT_CONCURRENCY = 1; + +/** + * Default reporters. + */ +var DEFAULT_TEST_REPORTER = 'cli'; +var DEFAULT_COVERAGE_REPORTER = 'cli'; +var DEFAULT_SCOPE_LEAKS_REPORTER = 'cli'; + +/** + * Program version. + */ +var VERSION = '0.6.6'; + +/** + * Path where the instrumented files are saved. + */ +var COVERAGE_PATH = 'lib-cov'; + +/** + * Default test verbosity (1 = quiet, 2 = verbose, 3 = very verbose) + */ +var DEFAULT_VERBOSITY = 2; + +var INIT_FUNCTION_NAME = 'init'; + +var TEARDOWN_FUNCTION_NAME = 'tearDown'; + +var SETUP_FUNCTION_NAME = 'setUp'; + +var DEFAULT_SOCKET_PATH = '/tmp/whiskey-parent.sock'; + +/** + * Different markers. + */ +var TEST_START_MARKER = '@-start-test-@'; +var DELIMITER = '@-delimiter-@'; +var TEST_END_MARKER = '@-end-test-@'; +var TEST_FILE_END_MARKER = '@-end-test-file-@'; +var COVERAGE_END_MARKER = '@-end-coverage-@'; + +/** + * Default switches for the option parser. + */ +var DEFAULT_OPTIONS = [ + ['-h', '--help', 'Print this help'], + ['-V', '--version', 'Print the version'] +]; + +/** + * Other options for the Whiskey option parser. + */ +var WHISKEY_OPTIONS = [ + ['-t', '--tests STRING', 'Whitespace separated list of tests to run'], + ['-ti', '--test-init-file STRING', 'An initialization file which is run before each test file'], + ['-c', '--chdir STRING', 'Directory to which each test process chdirs before running the tests'], + ['-v', '--verbosity [NUMBER]', 'Test runner verbosity'], + ['', '--failfast', 'Stop running the tests on the first failure'], + ['', '--timeout [NUMBER]', 'How long to wait (ms) for a test file to complete before timing out'], + ['', '--socket-path STRING', sprintf('A path to the unix socket used for communication. ' + + 'Defaults to %s', DEFAULT_SOCKET_PATH)], + + ['', '--concurrency [NUMBER]', sprintf('Maximum number of tests in a file which will run in ' + + 'parallel. Defaults to %s', DEFAULT_CONCURRENCY)], + ['', '--sequential', 'Run test in a file in sequential mode. This is the same as using --concurrency 1'], + + ['', '--custom-assert-module STRING', 'Absolute path to a module with custom assert methods'], + + ['', '--no-styles', 'Don\'t use colors and styles'], + + ['', '--quiet', 'Don\'t print stdout and stderr'], + ['', '--real-time', 'Print data which is sent to stdout / stderr as soon ' + + 'as it comes in'], + + ['', '--test-reporter STRING', 'Rest reporter type (cli or tap)'], + + ['', '--coverage', 'Enable test coverage'], + ['', '--coverage-file STRING', 'A file where the coverage result is stored. Only has an effect if json coverage reporter is used'], + ['', '--coverage-files STRING', 'A comma-separated list of files containing coverage data'], + ['', '--coverage-reporter STRING', 'Coverage reporter type (cli, html)'], + ['', '--coverage-dir STRING', 'Directory where the HTML coverage report is saved'], + ['', '--coverage-encoding STRING', 'Encoding which jscoverage will use when parsing files which are instrumented'], + ['', '--coverage-exclude STRING', 'Paths which won\'t be instrumented'], + ['', '--coverage-no-instrument STRING', 'Copy but don\'t instrument the path'], + ['', '--coverage-no-regen', 'Don\'t generate coverage file if lib-cov directory already exists'], + + ['', '--scope-leaks', 'Records which variables were leaked into the global ' + + 'scope.'], + ['', '--scope-leaks-reporter STRING', 'Scope leaks reporter type (cli)'], + ['-d', '--debug', 'Attach a debugger to a test process'], + ['', '--gen-makefile', 'Genarate a Makefile'], + ['', '--makefile-path STRING', 'Path where a generated Makefile is saved'], + ['', '--report-timing', 'Report test timing'], + ['', '--dependencies STRING', 'Path to the test dependencies configuration file'], + ['', '--only-essential-dependencies', 'Only start dependencies required by the tests files which are ran'] +]; + +/** + * Other options for the Process runner option parser. + */ +var PROCESS_RUNNER_OPTIONS = [ + ['-c', '--config STRING', 'Path to the dependencies.json file'], + ['-v', '--verify', 'Verify the config'], + ['-r', '--run', 'Run the processes'], + ['-n', '--names STRING', 'Comma-delimited string of the processes to run. Only applicable' + + ' if --run is used'] +]; + +exports.DEFAULT_TEST_TIMEOUT = DEFAULT_TEST_TIMEOUT; +exports.DEFAULT_CONCURRENCY = DEFAULT_CONCURRENCY; +exports.DEFAULT_TEST_REPORTER = DEFAULT_TEST_REPORTER; +exports.DEFAULT_COVERAGE_REPORTER = DEFAULT_COVERAGE_REPORTER; +exports.DEFAULT_SCOPE_LEAKS_REPORTER = DEFAULT_SCOPE_LEAKS_REPORTER; + +exports.VERSION = VERSION; +exports.COVERAGE_PATH = COVERAGE_PATH; +exports.DEFAULT_VERBOSITY = DEFAULT_VERBOSITY; +exports.INIT_FUNCTION_NAME = INIT_FUNCTION_NAME; +exports.SETUP_FUNCTION_NAME = SETUP_FUNCTION_NAME; +exports.TEARDOWN_FUNCTION_NAME = TEARDOWN_FUNCTION_NAME; +exports.DEFAULT_SOCKET_PATH = DEFAULT_SOCKET_PATH; +exports.DEFAULT_OPTIONS = DEFAULT_OPTIONS; +exports.WHISKEY_OPTIONS = WHISKEY_OPTIONS; +exports.PROCESS_RUNNER_OPTIONS = PROCESS_RUNNER_OPTIONS; + +exports.TEST_START_MARKER = TEST_START_MARKER; +exports.DELIMITER = DELIMITER; +exports.TEST_END_MARKER = TEST_END_MARKER; +exports.TEST_FILE_END_MARKER = TEST_FILE_END_MARKER; +exports.COVERAGE_END_MARKER = COVERAGE_END_MARKER; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/coverage.js b/node_modules/cassandra-client/node_modules/whiskey/lib/coverage.js new file mode 100644 index 0000000..a11af6d --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/coverage.js @@ -0,0 +1,225 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +/* + * coverage and populateCoverage are taken from expresso + * which is MIT licensed. + * Copyright(c) TJ Holowaychuk + */ + +var path = require('path'); +var fs = require('fs'); + +/* + * Convert a _$jscoverage object so it's JSON serializable + */ +function stringifyCoverage(cov) { + var i, files, file, fileObj, source; + var tmp = {}, coverageObj = {}; + + files = Object.keys(cov); + + for (i = 0; i < files.length; i++) { + file = files[i]; + fileObj = cov[file]; + source = fileObj['source']; + delete fileObj['source']; + + coverageObj[file] = { + 'lines': fileObj, + 'source': source + }; + } + + return JSON.stringify(coverageObj); +} + +/** + * Total coverage for the given file data. + * + * @param {Array} data + * @return {Type} + */ +function coverage(data, type) { + var comparisionFunc; + var n = 0; + + function isCovered(val) { + return (val > 0); + } + + function isMissed(val) { + return !isCovered(val); + } + + if (type === 'covered') { + comparisionFunc = isCovered; + } + else if (type === 'missed') { + comparisionFunc = isMissed; + } + else { + throw new Error('Invalid type: ' + type); + } + + for (var i = 0, len = data.lines.length; i < len; ++i) { + if (data.lines[i] !== null && comparisionFunc(data.lines[i])) { + ++n; + } + } + + return n; +} + +function getEmptyResultObject() { + var results = {}; + + results.LOC = 0; + results.SLOC = 0; + results.totalFiles = 0; + results.totalHits = 0; + results.totalMisses = 0; + results.coverage = 0; + results.files = {}; + + return results; +} + +/** + * @param {?Object} results Optional results object. If it's not provided it will be created. + * @param {?Object} cov coverage object. + */ +function populateCoverage(results, cov) { + var linesLen; + + results = (!results) ? getEmptyResultObject() : results; + + /* Aggregate data from all files */ + for (var testfile in cov) { + for (var name in cov[testfile]) { + var file = cov[testfile][name], file_stats; + + file_stats = results.files[name] || { + name: name, + htmlName: name.replace('.js', '.html').replace('.java', '.html').replace(/\/|\\/g, '_'), + totalHits: 0, + totalMisses: 0, + totalLines: 0, + lines: null, + source: null + }; + + if (file_stats.lines === null) { + file_stats.lines = file.lines; + } + else { + linesLen = file.lines.length; + for (var i = 0; i < linesLen; i++) { + if (file.lines[i] !== null) { + if (file_stats.lines[i] === null) { + file_stats.lines[i] = file.lines[i]; + } + else { + file_stats.lines[i] += file.lines[i]; + } + } + } + } + + if (file_stats.source === null) { + file_stats.source = file.source; + } + + results.files[name] = file_stats; + } + } + + /* Calculate statistics */ + for (var name in results.files) { + var file_stats = results.files[name]; + + // File level statistics + file_stats.totalHits = coverage(file_stats, 'covered'); + file_stats.totalMisses = coverage(file_stats, 'missed'); + file_stats.totalLines = file_stats.totalHits + file_stats.totalMisses; + file_stats.coverage = (file_stats.totalHits / file_stats.totalLines) * 100; + file_stats.coverage = (isNaN(file_stats.coverage)) ? 0 : file_stats.coverage.toFixed(2); + file_stats.LOC = file_stats.source.length; + file_stats.SLOC = file_stats.totalLines; + results.files[name] = file_stats; + + // Global statistic update + results.totalHits += file_stats.totalHits; + results.totalMisses += file_stats.totalMisses; + results.totalFiles++; + results.LOC += file_stats.LOC; + results.SLOC += file_stats.SLOC; + } + + /* Calculate covergage of tests */ + results.coverage = (results.totalHits / results.SLOC) * 100; + results.coverage = results.coverage.toFixed(2); + + return results; +} + +/** + * Read multiple coverage files and return aggregated coverage. + */ +function aggregateCoverage(files) { + var i, len, file, content, results; + var resultsObj = getEmptyResultObject(); + + for (i = 0, len = files.length; i < len; i++) { + file = files[i]; + content = JSON.parse(fs.readFileSync(file).toString()); + resultsObj = populateCoverage(resultsObj, content); + } + + return resultsObj; +} + + +function installCoverageHandler() { + var pid = process.pid; + var coverageDirectory = process.env['COVERAGE_DIRECTORY']; + var coveragePath = path.join(coverageDirectory, pid + '.json'); + + function writeCoverage() { + var coverage = {}; + + if (typeof _$jscoverage === 'object') { + coverage[pid] = JSON.parse(stringifyCoverage(_$jscoverage)); + + try { + fs.writeFileSync(coveragePath, JSON.stringify(coverage), 'utf8'); + } + catch (e) {} + } + + process.exit(); + } + + if (coverageDirectory) { + process.on('SIGUSR2', writeCoverage); + } +} + +exports.stringifyCoverage = stringifyCoverage; +exports.populateCoverage = populateCoverage; +exports.aggregateCoverage = aggregateCoverage; +exports.installCoverageHandler = installCoverageHandler; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/debugger.js b/node_modules/cassandra-client/node_modules/whiskey/lib/debugger.js new file mode 100644 index 0000000..6f2999e --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/debugger.js @@ -0,0 +1,77 @@ +var _debugger = require('./extern/_debugger'); + +var Client = _debugger.Client; +var Interface = _debugger.Interface; + +Client.prototype.setBreakpoint = function(target, line, callback) { + var req = { + command: 'setbreakpoint', + arguments: { type: 'script', + target: target, + line: line + } + }; + + this.req(req, function(res) { + if (callback) { + callback(res); + } + }); +}; + +// Connect to the existing debug server instead of spawning one +Interface.prototype.connect = function(port, delay, cb) { + var self = this; + port = port || _debugger.port; + delay = delay || 100; + + setTimeout(function() { + var client = self.client = new Client(); + client.connect(port); + + client.once('ready', function() { + if (cb) { + cb(null, client); + } + }); + + client.on('close', function() { + self.client = null; + self.killChild(); + self.term.close(); + }); + + client.on('unhandledResponse', function(res) { + console.log('\r\nunhandled res:'); + console.log(res); + }); + + client.on('error', function(err) { + console.log('error: ' + err); + }); + + client.on('break', function(res) { + self.handleBreak(res.body); + }); + }, delay); +}; + +Interface.prototype._getScript = function(scriptName) { + var scripts, script; + scripts = this.client.scripts; + + for (var key in scripts) { + if (scripts.hasOwnProperty(key)) { + script = scripts[key]; + + if (script && script.name.indexOf(scriptName) !== -1) { + return script; + } + } + } + + return false; +}; + +exports.Client = Client; +exports.Interface = Interface; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/errors.js b/node_modules/cassandra-client/node_modules/whiskey/lib/errors.js new file mode 100644 index 0000000..1e357ff --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/errors.js @@ -0,0 +1,42 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + * + */ + +var util = require('util'); + +/** + * A class which represents a test error. + * + * @param {String} errName Error name. + * @param {Error} err Original error object. + * + * @constructor + */ +function TestError(errName, err) { + this.errName = errName; + + if (err) { + this.message = err.message; + this.stack = err.stack; + this.arguments = err.arguments; + this.type = err.type; + } +} + +util.inherits(TestError, Error); + +exports.TestError = TestError; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/_debugger.js b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/_debugger.js new file mode 100644 index 0000000..f05b249 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/_debugger.js @@ -0,0 +1,1178 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +var net = require('net'); +var readline = require('readline'); +var inherits = require('util').inherits; +var spawn = require('child_process').spawn; + +exports.port = 5858; + +exports.start = function() { + if (process.argv.length < 3) { + console.error('Usage: node debug script.js'); + process.exit(1); + } + + var interface = new Interface(); + process.on('uncaughtException', function(e) { + console.error("There was an internal error in Node's debugger. " + + 'Please report this bug.'); + console.error(e.message); + console.error(e.stack); + if (interface.child) interface.child.kill(); + process.exit(1); + }); +}; + + +var args = process.argv.slice(2); +args.unshift('--debug-brk'); + + + +// +// Parser/Serializer for V8 debugger protocol +// http://code.google.com/p/v8/wiki/DebuggerProtocol +// +// Usage: +// p = new Protocol(); +// +// p.onResponse = function(res) { +// // do stuff with response from V8 +// }; +// +// socket.setEncoding('utf8'); +// socket.on('data', function(s) { +// // Pass strings into the protocol +// p.execute(s); +// }); +// +// +function Protocol() { + this._newRes(); +} +exports.Protocol = Protocol; + + +Protocol.prototype._newRes = function(raw) { + this.res = { raw: raw || '', headers: {} }; + this.state = 'headers'; + this.reqSeq = 1; + this.execute(''); +}; + + +Protocol.prototype.execute = function(d) { + var res = this.res; + res.raw += d; + + switch (this.state) { + case 'headers': + var endHeaderIndex = res.raw.indexOf('\r\n\r\n'); + + if (endHeaderIndex < 0) break; + + var lines = res.raw.slice(0, endHeaderIndex).split('\r\n'); + for (var i = 0; i < lines.length; i++) { + var kv = lines[i].split(/: +/); + res.headers[kv[0]] = kv[1]; + } + + this.contentLength = +res.headers['Content-Length']; + this.bodyStartIndex = endHeaderIndex + 4; + + this.state = 'body'; + if (res.raw.length - this.bodyStartIndex < this.contentLength) break; + // pass thru + + case 'body': + if (res.raw.length - this.bodyStartIndex >= this.contentLength) { + res.body = + res.raw.slice(this.bodyStartIndex, + this.bodyStartIndex + this.contentLength); + // JSON parse body? + res.body = res.body.length ? JSON.parse(res.body) : {}; + + // Done! + this.onResponse(res); + + this._newRes(res.raw.slice(this.bodyStartIndex + this.contentLength)); + } + break; + + default: + throw new Error('Unknown state'); + break; + } +}; + + +Protocol.prototype.serialize = function(req) { + req.type = 'request'; + req.seq = this.reqSeq++; + var json = JSON.stringify(req); + return 'Content-Length: ' + json.length + '\r\n\r\n' + json; +}; + + +var NO_FRAME = -1; + +function Client() { + net.Stream.call(this); + var protocol = this.protocol = new Protocol(this); + this._reqCallbacks = []; + var socket = this; + + this.currentFrame = NO_FRAME; + this.currentSourceLine = -1; + this.currentSource = null; + this.handles = {}; + this.scripts = {}; + + // Note that 'Protocol' requires strings instead of Buffers. + socket.setEncoding('utf8'); + socket.on('data', function(d) { + protocol.execute(d); + }); + + protocol.onResponse = this._onResponse.bind(this); +} +inherits(Client, net.Stream); +exports.Client = Client; + + +Client.prototype._addHandle = function(desc) { + if (typeof desc != 'object' || typeof desc.handle != 'number') { + return; + } + + this.handles[desc.handle] = desc; + + if (desc.type == 'script') { + this._addScript(desc); + } +}; + + +var natives = process.binding('natives'); + + +Client.prototype._addScript = function(desc) { + this.scripts[desc.id] = desc; + if (desc.name) { + desc.isNative = (desc.name.replace('.js', '') in natives) || + desc.name == 'node.js'; + } +}; + + +Client.prototype._removeScript = function(desc) { + this.scripts[desc.id] = undefined; +}; + + +Client.prototype._onResponse = function(res) { + for (var i = 0; i < this._reqCallbacks.length; i++) { + var cb = this._reqCallbacks[i]; + if (this._reqCallbacks[i].request_seq == res.body.request_seq) break; + } + + var self = this; + var handled = false; + + if (res.headers.Type == 'connect') { + // Request a list of scripts for our own storage. + self.reqScripts(); + self.emit('ready'); + handled = true; + + } else if (res.body && res.body.event == 'break') { + this.emit('break', res.body); + handled = true; + + } else if (res.body && res.body.event == 'afterCompile') { + this._addHandle(res.body.body.script); + handled = true; + + } else if (res.body && res.body.event == 'scriptCollected') { + // ??? + this._removeScript(res.body.body.script); + handled = true; + + } + + if (cb) { + this._reqCallbacks.splice(i, 1); + handled = true; + cb(res.body); + } + + if (!handled) this.emit('unhandledResponse', res.body); +}; + + +Client.prototype.req = function(req, cb) { + this.write(this.protocol.serialize(req)); + cb.request_seq = req.seq; + this._reqCallbacks.push(cb); +}; + + +Client.prototype.reqVersion = function(cb) { + this.req({ command: 'version' } , function(res) { + if (cb) cb(res.body.V8Version, res.running); + }); +}; + + +Client.prototype.reqLookup = function(refs, cb) { + var self = this; + + // TODO: We have a cache of handle's we've already seen in this.handles + // This can be used if we're careful. + var req = { + command: 'lookup', + arguments: { + handles: refs + } + }; + + this.req(req, function(res) { + if (res.success) { + for (var ref in res.body) { + if (typeof res.body[ref] == 'object') { + self._addHandle(res.body[ref]); + } + } + } + + if (cb) cb(res); + }); +}; + +// This is like reqEval, except it will look up the expression in each of the +// scopes associated with the current frame. +Client.prototype.reqEval = function(expression, cb) { + var self = this; + + if (this.currentFrame == NO_FRAME) { + // Only need to eval in global scope. + this.reqFrameEval(expression, NO_FRAME, cb); + return; + } + + // Otherwise we need to get the current frame to see which scopes it has. + this.reqBacktrace(function(bt) { + if (!bt.frames) { + // ?? + cb({}); + return; + } + + var frame = bt.frames[self.currentFrame]; + + var evalFrames = frame.scopes.map(function(s) { + if (!s) return; + var x = bt.frames[s.index]; + if (!x) return; + return x.index; + }); + + self._reqFramesEval(expression, evalFrames, cb); + }); +}; + + +// Finds the first scope in the array in which the epxression evals. +Client.prototype._reqFramesEval = function(expression, evalFrames, cb) { + if (evalFrames.length == 0) { + // Just eval in global scope. + this.reqFrameEval(expression, NO_FRAME, cb); + return; + } + + var self = this; + var i = evalFrames.shift(); + + this.reqFrameEval(expression, i, function(res) { + if (res.success) { + if (cb) cb(res); + } else { + self._reqFramesEval(expression, evalFrames, cb); + } + }); +}; + + +Client.prototype.reqFrameEval = function(expression, frame, cb) { + var self = this; + var req = { + command: 'evaluate', + arguments: { expression: expression } + }; + + if (frame == NO_FRAME) { + req.arguments.global = true; + } else { + req.arguments.frame = frame; + } + + this.req(req, function(res) { + if (res.success) { + self._addHandle(res.body); + } + if (cb) cb(res); + }); +}; + + +// reqBacktrace(cb) +// TODO: from, to, bottom +Client.prototype.reqBacktrace = function(cb) { + this.req({ command: 'backtrace' } , function(res) { + if (cb) cb(res.body); + }); +}; + + +// Returns an array of objects like this: +// +// { handle: 11, +// type: 'script', +// name: 'node.js', +// id: 14, +// lineOffset: 0, +// columnOffset: 0, +// lineCount: 562, +// sourceStart: '(function(process) {\n\n ', +// sourceLength: 15939, +// scriptType: 2, +// compilationType: 0, +// context: { ref: 10 }, +// text: 'node.js (lines: 562)' } +// +Client.prototype.reqScripts = function(cb) { + var self = this; + this.req({ command: 'scripts' } , function(res) { + for (var i = 0; i < res.body.length; i++) { + self._addHandle(res.body[i]); + } + if (cb) cb(); + }); +}; + + +Client.prototype.reqContinue = function(cb) { + this.req({ command: 'continue' }, function(res) { + if (cb) cb(res); + }); +}; + +Client.prototype.listbreakpoints = function(cb) { + this.req({ command: 'listbreakpoints' }, function(res) { + if (cb) cb(res); + }); +}; + + +Client.prototype.reqSource = function(from, to, cb) { + var req = { + command: 'source', + fromLine: from, + toLine: to + }; + + this.req(req, function(res) { + if (cb) cb(res.body); + }); +}; + + +// client.next(1, cb); +Client.prototype.step = function(action, count, cb) { + var req = { + command: 'continue', + arguments: { stepaction: action, stepcount: count } + }; + + this.req(req, function(res) { + if (cb) cb(res); + }); +}; + + +Client.prototype.mirrorObject = function(handle, cb) { + var self = this; + + if (handle.type == 'object') { + // The handle looks something like this: + // { handle: 8, + // type: 'object', + // className: 'Object', + // constructorFunction: { ref: 9 }, + // protoObject: { ref: 4 }, + // prototypeObject: { ref: 2 }, + // properties: [ { name: 'hello', propertyType: 1, ref: 10 } ], + // text: '#' } + + // For now ignore the className and constructor and prototype. + // TJ's method of object inspection would probably be good for this: + // https://groups.google.com/forum/?pli=1#!topic/nodejs-dev/4gkWBOimiOg + + var propertyRefs = handle.properties.map(function(p) { + return p.ref; + }); + + this.reqLookup(propertyRefs, function(res) { + if (!res.success) { + console.error('problem with reqLookup'); + if (cb) cb(handle); + return; + } + + var mirror; + if (handle.className == 'Array') { + mirror = []; + } else { + mirror = {}; + } + + for (var i = 0; i < handle.properties.length; i++) { + var value = res.body[handle.properties[i].ref]; + var mirrorValue; + if (value) { + mirrorValue = value.value ? value.value : value.text; + } else { + mirrorValue = '[?]'; + } + + + if (Array.isArray(mirror) && + typeof handle.properties[i].name != 'number') { + // Skip the 'length' property. + continue; + } + + mirror[handle.properties[i].name] = mirrorValue; + } + + if (cb) cb(mirror); + }); + + } else if (handle.value) { + process.nextTick(function() { + cb(handle.value); + }); + + } else { + process.nextTick(function() { + cb(handle); + }); + } +}; + + +Client.prototype.fullTrace = function(cb) { + var self = this; + + this.reqBacktrace(function(trace) { + var refs = []; + + for (var i = 0; i < trace.frames.length; i++) { + var frame = trace.frames[i]; + // looks like this: + // { type: 'frame', + // index: 0, + // receiver: { ref: 1 }, + // func: { ref: 0 }, + // script: { ref: 7 }, + // constructCall: false, + // atReturn: false, + // debuggerFrame: false, + // arguments: [], + // locals: [], + // position: 160, + // line: 7, + // column: 2, + // sourceLineText: ' debugger;', + // scopes: [ { type: 1, index: 0 }, { type: 0, index: 1 } ], + // text: '#00 blah() /home/ryan/projects/node/test-debug.js l...' } + refs.push(frame.script.ref); + refs.push(frame.func.ref); + refs.push(frame.receiver.ref); + } + + self.reqLookup(refs, function(res) { + for (var i = 0; i < trace.frames.length; i++) { + var frame = trace.frames[i]; + frame.script = res.body[frame.script.ref]; + frame.func = res.body[frame.func.ref]; + frame.receiver = res.body[frame.receiver.ref]; + } + + if (cb) cb(trace); + }); + }); +}; + + + + + + +var commands = [ + 'backtrace', + 'breakpoint', + 'continue', + 'help', + 'info breakpoints', + 'kill', + 'list', + 'next', + 'print', + 'quit', + 'run', + 'scripts', + 'step', + 'version' +]; + + +var helpMessage = 'Commands: ' + commands.join(', '); + + +function SourceUnderline(sourceText, position) { + if (!sourceText) return; + + // Create an underline with a caret pointing to the source position. If the + // source contains a tab character the underline will have a tab character in + // the same place otherwise the underline will have a space character. + var underline = ''; + for (var i = 0; i < position; i++) { + if (sourceText[i] == '\t') { + underline += '\t'; + } else { + underline += ' '; + } + } + underline += '^'; + + // Return the source line text with the underline beneath. + return sourceText + '\n' + underline; +} + + +function SourceInfo(body) { + var result = ''; + + if (body.script) { + if (body.script.name) { + result += body.script.name; + } else { + result += '[unnamed]'; + } + } + result += ':'; + result += body.sourceLine + 1; + + return result; +} + + +// This class is the readline-enabled debugger interface which is invoked on +// "node debug" +function Interface() { + var self = this; + var child; + var client; + + function complete(line) { + return self.complete(line); + } + + var term = readline.createInterface(process.stdin, process.stdout, complete); + this.term = term; + + process.on('exit', function() { + self.killChild(); + }); + + this.stdin = process.openStdin(); + + term.setPrompt('debug> '); + term.prompt(); + + this.quitting = false; + + process.on('SIGINT', function() { + self.handleSIGINT(); + }); + + term.on('SIGINT', function() { + self.handleSIGINT(); + }); + + term.on('attemptClose', function() { + self.tryQuit(); + }); + + term.on('line', function(cmd) { + // trim whitespace + cmd = cmd.replace(/^\s*/, '').replace(/\s*$/, ''); + + if (cmd.length) { + self._lastCommand = cmd; + self.handleCommand(cmd); + } else { + self.handleCommand(self._lastCommand); + } + }); +} + + +Interface.prototype.complete = function(line) { + var left; + // Match me with a command. + var matches = []; + // Remove leading whitespace + line = line.replace(/^\s*/, ''); + + for (var i = 0; i < commands.length; i++) { + if (commands[i].indexOf(line) === 0) { + matches.push(commands[i]); + } + } + + // Breakpoint script completion + if (line.indexOf('breakpoint') === 0 || line.indexOf('bp') === 0) { + var left = line.replace(/^breakpoint/, '').replace(/^bp/, '').trim(); + matches = this._completeScripts(left); + } + + return [matches, line]; +}; + +Interface.prototype._completeScripts = function(line) { + var client = this.client; + var matches = []; + + for (var id in client.scripts) { + var script = client.scripts[id]; + if (typeof script == 'object' && script.name) { + if (script.name.indexOf(line) === 0) { + matches.push(script.name); + } + } + } + + return matches; +} + + +Interface.prototype.handleSIGINT = function() { + if (this.paused) { + this.child.kill('SIGINT'); + } else { + this.tryQuit(); + } +}; + + +Interface.prototype.quit = function() { + if (this.quitting) return; + this.quitting = true; + this.killChild(); + this.term.close(); + process.exit(0); +}; + + +Interface.prototype.tryQuit = function() { + var self = this; + + if (self.child) { + self.quitQuestion(function(yes) { + if (yes) { + self.quit(); + } else { + self.term.prompt(); + } + }); + } else { + self.quit(); + } +}; + + +Interface.prototype.pause = function() { + this.paused = true; + this.stdin.pause(); + this.term.pause(); +}; + + +Interface.prototype.resume = function() { + if (!this.paused) return false; + this.paused = false; + this.stdin.resume(); + this.term.resume(); + this.term.prompt(); + return true; +}; + + +Interface.prototype.handleBreak = function(r) { + var result = ''; + if (r.breakpoints) { + result += 'breakpoint'; + if (r.breakpoints.length > 1) { + result += 's'; + } + result += ' #'; + for (var i = 0; i < r.breakpoints.length; i++) { + if (i > 0) { + result += ', #'; + } + result += r.breakpoints[i]; + } + } else { + result += 'break'; + } + result += ' in '; + result += r.invocationText; + result += ', '; + result += SourceInfo(r); + result += '\n'; + result += SourceUnderline(r.sourceLineText, r.sourceColumn); + + this.client.currentSourceLine = r.sourceLine; + this.client.currentFrame = 0; + this.client.currentScript = r.script.name; + + console.log(result); + + if (!this.resume()) this.term.prompt(); +}; + + +function intChars(n) { + // TODO dumb: + if (n < 50) { + return 2; + } else if (n < 950) { + return 3; + } else if (n < 9950) { + return 4; + } else { + return 5; + } +} + + +function leftPad(n) { + var s = n.toString(); + var nchars = intChars(n); + var nspaces = nchars - s.length; + for (var i = 0; i < nspaces; i++) { + s = ' ' + s; + } + return s; +} + + +Interface.prototype.handleCommand = function(cmd) { + var self = this; + + var client = this.client; + var term = this.term; + + if (cmd == 'quit' || cmd == 'q' || cmd == 'exit') { + self._lastCommand = null; + self.tryQuit(); + + } else if (/^r(un)?$/.test(cmd)) { + self._lastCommand = null; + if (self.child) { + self.restartQuestion(function(yes) { + if (!yes) { + self._lastCommand = null; + term.prompt(); + } else { + console.log('restarting...'); + self.killChild(); + // XXX need to wait a little bit for the restart to work? + setTimeout(function() { + self.trySpawn(); + }, 1000); + } + }); + } else { + self.trySpawn(); + } + + } else if (/^help$/.test(cmd)) { + console.log(helpMessage); + term.prompt(); + + } else if ('version' == cmd) { + if (!client) { + self.printNotConnected(); + return; + } + client.reqVersion(function(v) { + console.log(v); + term.prompt(); + }); + + } else if (/^info(\s+breakpoint)?$/.test(cmd)) { + if (!client) { + self.printNotConnected(); + return; + } + client.listbreakpoints(function(res) { + console.log(res); + term.prompt(); + }); + + + } else if ('l' == cmd || 'list' == cmd) { + if (!client) { + self.printNotConnected(); + return; + } + + var from = client.currentSourceLine - 5; + var to = client.currentSourceLine + 5; + + client.reqSource(from, to, function(res) { + var lines = res.source.split('\n'); + for (var i = 0; i < lines.length; i++) { + var lineno = res.fromLine + i + 1; + if (lineno < from || lineno > to) continue; + + if (lineno == 1) { + // The first line needs to have the module wrapper filtered out of + // it. + var wrapper = require('module').wrapper[0]; + lines[i] = lines[i].slice(wrapper.length); + } + + if (lineno == 1 + client.currentSourceLine) { + var nchars = intChars(lineno); + var pointer = ''; + for (var j = 0; j < nchars - 1; j++) { + pointer += '='; + } + pointer += '>'; + console.log(pointer + ' ' + lines[i]); + } else { + console.log(leftPad(lineno) + ' ' + lines[i]); + } + } + term.prompt(); + }); + + } else if (/^b(ack)?t(race)?$/.test(cmd)) { + if (!client) { + self.printNotConnected(); + return; + } + + client.fullTrace(function(bt) { + if (bt.totalFrames == 0) { + console.log('(empty stack)'); + } else { + var text = ''; + + var firstFrameNative = bt.frames[0].script.isNative; + for (var i = 0; i < bt.frames.length; i++) { + var frame = bt.frames[i]; + if (!firstFrameNative && frame.script.isNative) break; + + text += '#' + i + ' '; + if (frame.func.inferredName && frame.func.inferredName.length > 0) { + text += frame.func.inferredName + ' '; + } + text += require('path').basename(frame.script.name) + ':'; + text += (frame.line + 1) + ':' + (frame.column + 1); + text += '\n'; + } + + console.log(text); + } + term.prompt(); + }); + + } else if (matches = /^(breakpoint|bp)(\s.*?)? (\d+)/.exec(cmd)) { + var scriptName, script, lineNo; + if (!client) { + self.printNotConnected(); + return; + } + + if (!matches[2]) { + scriptName = this.client.currentScript; + script = this._getScript(scriptName); + } + else { + scriptName = matches[2].trim(); + script = null; + } + + lineNo = matches[3]; + + if (script && (lineNo < 1 || lineNo > script.lineCount)) { + console.log('Invalid line number (must be between 1 and ' + script.lineCount + ')'); + self.term.prompt(); + return; + } + + this.client.setBreakpoint(scriptName, lineNo, function(res) { + self.term.prompt(); + }); + } + else if (cmd == 'scripts' || cmd == 'scripts full') { + if (!client) { + self.printNotConnected(); + return; + } + self.printScripts(cmd.indexOf('full') > 0); + term.prompt(); + + } else if (/^c(ontinue)?$/.test(cmd)) { + if (!client) { + self.printNotConnected(); + return; + } + + self.pause(); + client.reqContinue(function() { + self.resume(); + }); + + } else if (/^k(ill)?$/.test(cmd)) { + if (!client) { + self.printNotConnected(); + return; + } + // kill + if (self.child) { + self.killQuestion(function(yes) { + if (yes) { + self.killChild(); + } else { + self._lastCommand = null; + } + }); + } else { + self.term.prompt(); + } + + } else if (/^n(ext)?$/.test(cmd)) { + if (!client) { + self.printNotConnected(); + return; + } + client.step('next', 1, function(res) { + // Wait for break point. (disable raw mode?) + }); + + } else if (/^s(tep)?$/.test(cmd)) { + if (!client) { + self.printNotConnected(); + return; + } + client.step('in', 1, function(res) { + // Wait for break point. (disable raw mode?) + }); + + } else if (/^p(rint)?/.test(cmd)) { + if (!client) { + self.printNotConnected(); + return; + } + var i = cmd.indexOf(' '); + if (i < 0) { + console.log('print [expression]'); + term.prompt(); + } else { + cmd = cmd.slice(i); + client.reqEval(cmd, function(res) { + if (!res.success) { + console.log(res.message); + term.prompt(); + return; + } + + client.mirrorObject(res.body, function(mirror) { + console.log(mirror); + term.prompt(); + }); + }); + } + + } else { + if (!/^\s*$/.test(cmd)) { + // If it's not all white-space print this error message. + console.log('Unknown command "%s". Try "help"', cmd); + } + term.prompt(); + } +}; + + + +Interface.prototype.yesNoQuestion = function(prompt, cb) { + var self = this; + self.resume(); + this.term.question(prompt, function(answer) { + if (/^y(es)?$/i.test(answer)) { + cb(true); + } else if (/^n(o)?$/i.test(answer)) { + cb(false); + } else { + console.log('Please answer y or n.'); + self.restartQuestion(cb); + } + }); +}; + + +Interface.prototype.restartQuestion = function(cb) { + this.yesNoQuestion('The program being debugged has been started already.\n' + + 'Start it from the beginning? (y or n) ', cb); +}; + + +Interface.prototype.killQuestion = function(cb) { + this.yesNoQuestion('Kill the program being debugged? (y or n) ', cb); +}; + + +Interface.prototype.quitQuestion = function(cb) { + this.yesNoQuestion('A debugging session is active. Quit anyway? (y or n) ', + cb); +}; + + +Interface.prototype.killChild = function() { + if (this.child) { + this.child.kill(); + this.child = null; + } + + if (this.client) { + this.client.destroy(); + this.client = null; + } + + this.resume(); +}; + + +Interface.prototype.trySpawn = function(cb) { + var self = this; + + this.killChild(); + + this.child = spawn(process.execPath, args, { customFds: [0, 1, 2] }); + + + this.pause(); + + var client = self.client = new Client(); + var connectionAttempts = 0; + + client.once('ready', function() { + process.stdout.write(' ok\r\n'); + + // since we did debug-brk, we're hitting a break point immediately + // continue before anything else. + client.reqContinue(function() { + if (cb) cb(); + }); + + client.on('close', function() { + console.log('\nprogram terminated'); + self.client = null; + self.killChild(); + if (!self.quitting) self.term.prompt(); + }); + }); + + client.on('unhandledResponse', function(res) { + console.log('\r\nunhandled res:'); + console.log(res); + self.term.prompt(); + }); + + client.on('break', function(res) { + self.handleBreak(res.body); + }); + + client.on('error', connectError); + function connectError() { + // If it's failed to connect 4 times then don't catch the next error + if (connectionAttempts >= 4) { + client.removeListener('error', connectError); + } + setTimeout(attemptConnect, 50); + } + + function attemptConnect() { + ++connectionAttempts; + process.stdout.write('.'); + client.connect(exports.port); + } + + setTimeout(function() { + process.stdout.write('connecting..'); + attemptConnect(); + }, 50); +}; + + +Interface.prototype.printNotConnected = function() { + console.log("Program not running. Try 'run'."); + this.term.prompt(); +}; + + +// argument full tells if it should display internal node scripts or not +Interface.prototype.printScripts = function(displayNatives) { + var client = this.client; + var text = ''; + for (var id in client.scripts) { + var script = client.scripts[id]; + if (typeof script == 'object' && script.name) { + if (displayNatives || + script.name == client.currentScript || + !script.isNative) { + text += script.name == client.currentScript ? '* ' : ' '; + text += require('path').basename(script.name) + ' (' + script.name + ')\n'; + } + } + } + process.stdout.write(text); +}; + +exports.Interface = Interface; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/README.md b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/README.md new file mode 100644 index 0000000..d449504 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/README.md @@ -0,0 +1,75 @@ +Long Stacktraces +================ + +Long stacktraces for V8 implemented in user-land JavaScript. Supports Chrome/Chromium and Node.js. + +Background +---------- + +A common problem when debugging event-driven JavaScript is stack traces are limited to a single "event", so it's difficult to trace the code path that caused an error. + +A contrived example (taken from the PDF referenced below): + + function f() { + throw new Error('foo'); + } + + setTimeout(f, Math.random()*1000); + setTimeout(f, Math.random()*1000); + +Which one throws the first error? + +Node.js intended to fix this problem with a solution called "Long Stacktraces": http://nodejs.org/illuminati0.pdf + +But what if we wanted something like this in the browser? It turns out V8 already has everything needed to implement this in user-land JavaScript (although in a slightly hacky way). + +V8 has a [stack trace API](http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi) that allows custom formatting of textual stack trace representations. By wrapping any function that registers an asynchronous event callback (e.x. `setTimeout` and `addEventListener` in the browser) we can store the stack trace at the time of callback registration, and later append it to stack traces. This also works for multiple levels of events (a timeout or event registered within a timeout or event, etc). + +Usage +----- + +For Node.js install using `npm install long-stack-traces`. + +Simply include the "long-stack-traces.js" via a script tag or other method before any event listener or timeout registrations. In Node.js call `require("long-stack-traces")`. + +Stack traces from example above: + + Uncaught Error: foo + at f (index.html:24:23) + ---------------------------------------- + at setTimeout + at onload (index.html:28:40) + Uncaught Error: foo + at f (index.html:24:23) + ---------------------------------------- + at setTimeout + at onload (index.html:27:40) + +Note one was from the timeout on line 27, the other on line 28. Events' stack traces are divided by a line of dashes. + +See examples.html for more examples, and run `node examples.js` for a Node.js example. + +Supported APIs +-------------- + +Currently supports the following APIs: + +### Chromium ### +* `setTimeout` +* `setInterval` +* `addEventListener` +* `XMLHttpRequest.onreadystatechange` (stack actually recorded upon `send()`) + +### Node.js ### +* `setTimeout` +* `setInterval` +* `EventEmitter.addListener` +* `EventEmitter.on` +* All APIs that use `EventEmitter` + +TODO +---- + +* Gracefully degrade in non-V8 environments. +* Figure out what's up with these stack frames when throwing an exception from an input's event handler: + \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/examples.html b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/examples.html new file mode 100644 index 0000000..6b6adc6 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/examples.html @@ -0,0 +1,51 @@ + + + + + + + + + + + + + diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/examples.js b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/examples.js new file mode 100644 index 0000000..9fb044f --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/examples.js @@ -0,0 +1,30 @@ +require("./index"); + +var fs = require("fs"); + +function initSecondTimeout(tag) { + setTimeout(function secondTimeout() { + throw new Error(tag); + }, 1000); +} + +function onload() { + // function f() { + // throw new Error('foo'); + // } + // setTimeout(f, Math.random()*1000); + // setTimeout(f, Math.random()*1000); + + setTimeout(function firstTimeout() { + initSecondTimeout("timeout"); + }, 1000); + + fs.readFile('README.md', 'utf8', function (err, data) { + if (err) throw err; + initSecondTimeout("readFile"); + }); +} + +onload(); + +process.on('uncaughtException', function(e) { console.log('wa');console.log(e.stack)}) diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/index.js b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/index.js new file mode 100644 index 0000000..7500e59 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/index.js @@ -0,0 +1 @@ +exports = require('./lib/long-stack-traces') diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/lib/long-stack-traces.js b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/lib/long-stack-traces.js new file mode 100644 index 0000000..f127297 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/lib/long-stack-traces.js @@ -0,0 +1,206 @@ +(function(LST) { + LST.rethrow = false; + + var currentTraceError = null; + + var filename = new Error().stack.split("\n")[1].match(/^ at ((?:\w+:\/\/)?[^:]+)/)[1]; + function filterInternalFrames(frames) { + return frames.split("\n").filter(function(frame) { return frame.indexOf(filename) < 0; }).join("\n"); + } + + Error.prepareStackTrace = function(error, structuredStackTrace) { + if (!error.__cachedTrace) { + error.__cachedTrace = filterInternalFrames(FormatStackTrace(error, structuredStackTrace)); + if (!has.call(error, "__previous")) { + var previous = currentTraceError; + while (previous) { + var previousTrace = previous.stack; + error.__cachedTrace += "\n----------------------------------------\n" + + " at " + previous.__location + "\n" + + previousTrace.substring(previousTrace.indexOf("\n") + 1); + previous = previous.__previous; + } + } + } + return error.__cachedTrace; + } + + var slice = Array.prototype.slice; + var has = Object.prototype.hasOwnProperty; + + // Takes an object, a property name for the callback function to wrap, and an argument position + // and overwrites the function with a wrapper that captures the stack at the time of callback registration + function wrapRegistrationFunction(object, property, callbackArg) { + if (typeof object[property] !== "function") { + console.error("(long-stack-traces) Object", object, "does not contain function", property); + return; + } + if (!has.call(object, property)) { + console.warn("(long-stack-traces) Object", object, "does not directly contain function", property); + } + + // TODO: better source position detection + var sourcePosition = (object.constructor.name || Object.prototype.toString.call(object)) + "." + property; + + // capture the original registration function + var fn = object[property]; + // overwrite it with a wrapped registration function that modifies the supplied callback argument + object[property] = function() { + // replace the callback argument with a wrapped version that captured the current stack trace + arguments[callbackArg] = makeWrappedCallback(arguments[callbackArg], sourcePosition); + // call the original registration function with the modified arguments + return fn.apply(this, arguments); + } + + // check that the registration function was indeed overwritten + if (object[property] === fn) + console.warn("(long-stack-traces) Couldn't replace ", property, "on", object); + } + + // Takes a callback function and name, and captures a stack trace, returning a new callback that restores the stack frame + // This function adds a single function call overhead during callback registration vs. inlining it in wrapRegistationFunction + function makeWrappedCallback(callback, frameLocation) { + // add a fake stack frame. we can't get a real one since we aren't inside the original function + var traceError = new Error(); + traceError.__location = frameLocation; + traceError.__previous = currentTraceError; + return function() { + // if (currentTraceError) { + // FIXME: This shouldn't normally happen, but it often does. Do we actually need a stack instead? + // console.warn("(long-stack-traces) Internal Error: currentTrace already set."); + // } + // restore the trace + currentTraceError = traceError; + try { + return callback.apply(this, arguments); + } catch (e) { + var stack = e.stack; + e.stack = stack; + throw e; + } finally { + // clear the trace so we can check that none is set above. + // TODO: could we remove this for slightly better performace? + currentTraceError = null; + } + } + } + + var global = (function() { return this; })(); + wrapRegistrationFunction(global, "setTimeout", 0); + wrapRegistrationFunction(global, "setInterval", 0); + + var EventEmitter = require('events').EventEmitter; + //wrapRegistrationFunction(EventEmitter.prototype, "addListener", 1); + //wrapRegistrationFunction(EventEmitter.prototype, "on", 1); + + wrapRegistrationFunction(process, "nextTick", 0); + + // Copyright 2006-2008 the V8 project 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. + + function FormatStackTrace(error, frames) { + var lines = []; + try { + lines.push(error.toString()); + } catch (e) { + try { + lines.push(""); + } catch (ee) { + lines.push(""); + } + } + for (var i = 0; i < frames.length; i++) { + var frame = frames[i]; + var line; + try { + line = FormatSourcePosition(frame); + } catch (e) { + try { + line = ""; + } catch (ee) { + // Any code that reaches this point is seriously nasty! + line = ""; + } + } + lines.push(" at " + line); + } + return lines.join("\n"); + } + + function FormatSourcePosition(frame) { + var fileLocation = ""; + if (frame.isNative()) { + fileLocation = "native"; + } else if (frame.isEval()) { + fileLocation = "eval at " + frame.getEvalOrigin(); + } else { + var fileName = frame.getFileName(); + if (fileName) { + fileLocation += fileName; + var lineNumber = frame.getLineNumber(); + if (lineNumber != null) { + fileLocation += ":" + lineNumber; + var columnNumber = frame.getColumnNumber(); + if (columnNumber) { + fileLocation += ":" + columnNumber; + } + } + } + } + if (!fileLocation) { + fileLocation = "unknown source"; + } + var line = ""; + var functionName = frame.getFunction().name; + var addPrefix = true; + var isConstructor = frame.isConstructor(); + var isMethodCall = !(frame.isToplevel() || isConstructor); + if (isMethodCall) { + var methodName = frame.getMethodName(); + line += frame.getTypeName() + "."; + if (functionName) { + line += functionName; + if (methodName && (methodName != functionName)) { + line += " [as " + methodName + "]"; + } + } else { + line += methodName || ""; + } + } else if (isConstructor) { + line += "new " + (functionName || ""); + } else if (functionName) { + line += functionName; + } else { + line += fileLocation; + addPrefix = false; + } + if (addPrefix) { + line += " (" + fileLocation + ")"; + } + return line; + } +})(typeof exports !== "undefined" ? exports : {}); diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/package.json b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/package.json new file mode 100644 index 0000000..7c36b03 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/long-stack-traces/package.json @@ -0,0 +1,13 @@ +{ + "name": "long-stack-traces", + "description": "Long stacktraces for V8 implemented in user-land JavaScript.", + "version": "0.1.1", + "author": "Tom Robinson (http://tlrobinson.net/)", + "main" : "./lib/long-stack-traces", + "directories": { + "lib": "./lib" + }, + "engines": { + "node": "*" + } +} \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/README.md b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/README.md new file mode 100644 index 0000000..d08ccf1 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/README.md @@ -0,0 +1,161 @@ +optparse-js +=========== + +Optparse-js is a command line option parser for Javascript. It's slightly based on Ruby's implementation optparse but with some differences (different languages has different needs) such as custom parsers. + +All examples in this readme is using [Node.js](http://nodejs.org/). How ever, the library works with all kinds of Javascript implementations. + + +QUICK START +----------- + +The library defines one class, the OptionParser class. The class constructor takes one single argument, a list with a set of rules. Here is a quick example: + + // Import the sys library + var sys = require('sys'); + + // Import the optparse library. + var optparse = require('optparse'); + + // Define an option called ´´help´´. We give it a quick alias named ´´-h´´ + // and a quick help text. + var switches = [ + ['-h', '--help', 'Shows help sections'] + ]; + + // Create a new OptionParser. + var parser = new optparse.OptionParser(switches); + + // Hook the help option. The callback will be executed when the OptionParser + // hits the switch ´´-h´´ or ´´--help´´. Each representatio + parser.on('help', function() { + sys.puts('Help'); + }); + + + +DEFINING RULES +-------------- +The OptionParser constructor takes an Array with rules. Each rule is represented by an array (tuple) of two or three values. A typical rule definition may look like this: + + ['-h', '--help', 'Print this help'] + + +The first value is optional, and represents an alias for the long-named switch (the second value, in this case ´´--help´´). + +The second argument is the actual rule. The rule must start with a double dash followed by a switch name (in this case ´help´). The OptionParser also supports special option arguments. Define an option argument in the rule by adding a named argument after the leading double dash and switch name (E.G '--port-number PORT_NUMBER'). The argument is then parsed to the option handler. To define an optional option argument, just add a braces around argument in the rule (E.G '--port-number [PORT_NUMBER]). The OptionParser also supports filter. More on that in in the section called ´Option Filters´. + +The third argument is an optional rule description. + + +OPTION FILTERS +-------------- +Filters is a neat feature that let you filter option arguments. The OptionParser itself as already a set of built-in common filter's. These are: + +- NUMBER, supports both decimal and hexadecimal numbers. +- DATE, filters arguments that matches YYYY-MM-DD. +- EMAIL, filters arguments that matches my@email.com. + +It's simple to use any of the filter above in your rule-set. Here is a quick example how to filter number: + + var rules = [ + ['--first-option NUMBER', 'Takes a number as argument'], + ['--second-option [NUMBER]', 'Takes an optional number as argument'] + ] + +You can add your own set of filter by calling the *parser_instance.filter* method: + + parser.filter('single_char', function(value) { + if(value.length != 1) throw "Filter mismatch."; + return value; + }); + + +OPTION PARSER +------------- +The OptionParser class has the following properties and methods: + +### string banner +An optional usage banner. This text is included when calling ´´toString´´. Default value is: "Usage: [Options]". + + +### string options_title +An optional title for the options list. This text is included when calling ´´toString´´. Default value is: "Available options:". + + +### function on(switch_or_arg_index, callback) +Add's a callback for a switch or an argument (defined by index). Switch hooks MUST be typed witout the leading ´´--´´. This example show how to hook a switch: + + parser.on('help', function(optional_argument) { + // Show help section + }); + +And this example show how to hook an argument (an option without the leading - or --): + + parser.on(0, function(opt) { + puts('The first non-switch option is:' + opt); + }); + +It's also possible to define a default handler. The default handler is called when no rule's are meet. Here is an example how to add a ´default handler´: + + parser.on(function(opt) { + puts('No handler was defined for option:' + opt); + }); + +Use the wildcard handler to build a custom ´´on´´ handler. + + parser.on('*', function(opt, value) { + puts('option=' + opt + ', value=' + value); + }); + +### function filter(name, callback) +Adds a new filter extension to the OptionParser instance. The first argument is the name of the filter (trigger). The second argument is the actual filter See the ´OPTION FILTERS´ section for more info. + +It's possible to override the default filters by passing the value "_DEFAULT" to the ´´name´´ argument. The name of the filter is automatically transformed into +upper case. + + +### function halt([callback]) +Interrupt's further parsing. This function should be called from an ´on´ -callbacks, to cancel the parsing. This can be useful when the program should ignore all other arguments (when displaying help or version information). + +The function also takes an optional callback argument. If the callback argument is specified, a ´halt´ callback will be added (instead of executing the ´halt´ command). + +Here is an example how to add an ´on_halt´ callback: + + parser.halt(function() { + puts('An option callback interupted the parser'); + }); + + +### function parse(arguments) +Start's parsing of arguments. This should be the last thing you do. + + +### function options() +Returns an Array with all defined option rules + + +### function toString() +Returns a string representation of this OptionParser instance (a formatted help section). + + +MORE EXAMPLES +------------- +See examples/nodejs-test.js and examples/browser-test-html for more info how to +use the script. + + +SUGGESTIONS +----------- +All comments in how to improve this library is very welcome. Feel free post suggestions to the [Issue tracker](http://github.com/jfd/optparse-js/issues), or even better, fork the repository to implement your own features. + + +LICENSE +------- +Released under a MIT-style license. + + +COPYRIGHT +--------- +Copyright (c) 2009 Johan Dahlberg + diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/TODO b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/TODO new file mode 100644 index 0000000..a1b6050 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/TODO @@ -0,0 +1 @@ +- Support for Argument lists (for switches) \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/examples/browser-test.html b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/examples/browser-test.html new file mode 100644 index 0000000..2d8f6d3 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/examples/browser-test.html @@ -0,0 +1,75 @@ + + + + + optparse.js example + + + + + + + \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/examples/nodejs-test.js b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/examples/nodejs-test.js new file mode 100644 index 0000000..7f35ed3 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/examples/nodejs-test.js @@ -0,0 +1,90 @@ +// Import the optparse script +require.paths.unshift(__dirname); //make local paths accessible + +var optparse = require('lib/optparse'); + +var sys= require('sys'); + +// Define some options +var SWITCHES = [ + ['-i', '--include-file FILE', "Includes a file"], + ['-p', '--print [MESSAGE]', "Prints an optional message on screen"], + ['-d', '--debug', "Enables debug mode"], + ['-H', '--help', "Shows this help section"], + ['--date DATE', "A date. A date is expected E.G. 2009-01-14"], + ['--number NUMBER', "A Number. Supported formats are 123, 123.123, 0xA123"], + ['--other NAME', "No handler defined for this option. Will be handled by the wildcard handler."], +]; + +// Create a new OptionParser with defined switches +var parser = new optparse.OptionParser(SWITCHES), print_summary = true, + first_arg; +parser.banner = 'Usage: nodejs-test.js [options]'; + +// Internal variable to store options. +var options = { + debug: true, + files: [], + number: undefined, + date: undefined +}; + +// Handle the first argument (switches excluded) +parser.on(0, function(value) { + first_arg = value; +}); + +// Handle the --include-file switch +parser.on('include-file', function(value) { + options.files.push(value); +}); + +// Handle the --print switch +parser.on('print', function(value) { + sys.puts('PRINT: ' + (value || 'No message entered')); +}); + +// Handle the --date switch +parser.on('date', function(value) { + options.date = value; +}); + +// Handle the --number switch +parser.on('number', function(value) { + options.number = value; +}); + +// Handle the --debug switch +parser.on('debug', function() { + options.debug = true; +}); + +// Handle the --help switch +parser.on('help', function() { + sys.puts(parser.toString()); + print_summary = false; +}); + +// Set a default handler +parser.on('*', function(opt, value) { + sys.puts('wild handler for ' + opt + ', value=' + value); +}); + +// Parse command line arguments +parser.parse(process.ARGV); + +if(print_summary) { + sys.puts("First non-switch argument is: " + first_arg); + + // Output all files that was included. + sys.puts("No of files to include: " + options.files.length); + for(var i = 0; i < options.files.length; i++) { + sys.puts("File [" + (i + 1) + "]:" + options.files[i]); + } + + // Is debug-mode enabled? + sys.puts("Debug mode is set to: " + options.debug); + + sys.puts("Number value is: " + options.number); + sys.puts("Date value is: " + options.date); +} \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/lib/optparse.js b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/lib/optparse.js new file mode 100755 index 0000000..8a8f38b --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/lib/optparse.js @@ -0,0 +1,309 @@ +// Optparse.js 1.0.2 - Option Parser for Javascript +// +// Copyright (c) 2009 Johan Dahlberg +// +// See README.md for license. +// +var optparse = {}; +try{ optparse = exports } catch(e) {}; // Try to export the lib for node.js +(function(self) { +var VERSION = '1.0.2'; +var LONG_SWITCH_RE = /^--\w/; +var SHORT_SWITCH_RE = /^-\w/; +var NUMBER_RE = /^(0x[A-Fa-f0-9]+)|([0-9]+\.[0-9]+)|(\d+)$/; +var DATE_RE = /^\d{4}-(0[0-9]|1[0,1,2])-([0,1,2][0-9]|3[0,1])$/; +var EMAIL_RE = /^([0-9a-zA-Z]+([_.-]?[0-9a-zA-Z]+)*@[0-9a-zA-Z]+[0-9,a-z,A-Z,.,-]*(.){1}[a-zA-Z]{2,4})+$/; +var EXT_RULE_RE = /(\-\-[\w_-]+)\s+([\w\[\]_-]+)|(\-\-[\w_-]+)/; +var ARG_OPTIONAL_RE = /\[(.+)\]/; + +// The default switch argument filter to use, when argument name doesnt match +// any other names. +var DEFAULT_FILTER = '_DEFAULT'; +var PREDEFINED_FILTERS = {}; + +// The default switch argument filter. Parses the argument as text. +function filter_text(value) { + return value; +} + +// Switch argument filter that expects an integer, HEX or a decimal value. An +// exception is throwed if the criteria is not matched. +// Valid input formats are: 0xFFFFFFF, 12345 and 1234.1234 +function filter_number(value) { + var m = value.match(NUMBER_RE); + if(m == null) throw OptError('Expected a number representative'); + if(m[1]) { + // The number is in HEX format. Convert into a number, then return it + return parseInt(m[1], 16); + } else { + // The number is in regular- or decimal form. Just run in through + // the float caster. + return parseFloat(m[2] || m[3]); + } +}; + +// Switch argument filter that expects a Date expression. The date string MUST be +// formated as: "yyyy-mm-dd" An exception is throwed if the criteria is not +// matched. An DATE object is returned on success. +function filter_date(value) { + var m = value.match(DATE_RE); + if(m == null) throw OptError('Expected a date representation in the "yyyy-mm-dd" format.'); + return new Date(parseInt(m[0]), parseInt(m[1]), parseInt(m[2])); +}; + +// Switch argument filter that expects an email address. An exception is throwed +// if the criteria doesn`t match. +function filter_email(value) { + var m = value.match(EMAIL_RE); + if(m == null) throw OptError('Excpeted an email address.'); + return m[1]; +} + +// Register all predefined filters. This dict is used by each OptionParser +// instance, when parsing arguments. Custom filters can be added to the parser +// instance by calling the "add_filter" -method. +PREDEFINED_FILTERS[DEFAULT_FILTER] = filter_text; +PREDEFINED_FILTERS['TEXT'] = filter_text; +PREDEFINED_FILTERS['NUMBER'] = filter_number; +PREDEFINED_FILTERS['DATE'] = filter_date; +PREDEFINED_FILTERS['EMAIL'] = filter_email; + +// Buildes rules from a switches collection. The switches collection is defined +// when constructing a new OptionParser object. +function build_rules(filters, arr) { + var rules = []; + for(var i=0; i> value means that the switch does +// not take anargument. +function build_rule(filters, short, expr, desc) { + var optional, filter; + var m = expr.match(EXT_RULE_RE); + if(m == null) throw OptError('The switch is not well-formed.'); + var long = m[1] || m[3]; + if(m[2] != undefined) { + // A switch argument is expected. Check if the argument is optional, + // then find a filter that suites. + var optional_match = m[2].match(ARG_OPTIONAL_RE); + var filter_name = optional_match === null ? m[2] : optional_match[1]; + optional = optional_match !== null; + filter = filters[filter_name]; + if(filter === undefined) filter = filters[DEFAULT_FILTER]; + } + return { + name: long.substr(2), + short: short, + long: long, + decl: expr, + desc: desc, + optional_arg: optional, + filter: filter + } +} + +// Loop's trough all elements of an array and check if there is valid +// options expression within. An valid option is a token that starts +// double dashes. E.G. --my_option +function contains_expr(arr) { + if(!arr || !arr.length) return false; + var l = arr.length; + while(l-- > 0) if(arr[l].match(LONG_SWITCH_RE)) return true; + return false; +} + +// Extends destination object with members of source object +function extend(dest, src) { + var result = dest; + for(var n in src) { + result[n] = src[n]; + } + return result; +} + +// Appends spaces to match specified number of chars +function spaces(arg1, arg2) { + var l, builder = []; + if(arg1.constructor === Number) { + l = arg1; + } else { + if(arg1.length == arg2) return arg1; + l = arg2 - arg1.length; + builder.push(arg1); + } + while(l-- > 0) builder.push(' '); + return builder.join(''); +} + +// Create a new Parser object that can be used to parse command line arguments. +// +// +function Parser(rules) { + return new OptionParser(rules); +} + +// Creates an error object with specified error message. +function OptError(msg) { + return new function() { + this.msg = msg; + this.toString = function() { + return this.msg; + } + } +} + +function OptionParser(rules) { + this.banner = 'Usage: [Options]'; + this.options_title = 'Available options:' + this._rules = rules; + this._halt = false; + this.filters = extend({}, PREDEFINED_FILTERS); + this.on_args = {}; + this.on_switches = {}; + this.on_halt = function() {}; + this.default_handler = function() {}; +} + +OptionParser.prototype = { + + // Adds args and switchs handler. + on: function(value, fn) { + if(value.constructor === Function ) { + this.default_handler = value; + } else if(value.constructor === Number) { + this.on_args[value] = fn; + } else { + this.on_switches[value] = fn; + } + }, + + // Adds a custom filter to the parser. It's possible to override the + // default filter by passing the value "_DEFAULT" to the ´´name´´ + // argument. The name of the filter is automatically transformed into + // upper case. + filter: function(name, fn) { + this.filters[name.toUpperCase()] = fn; + }, + + // Parses specified args. Returns remaining arguments. + parse: function(args) { + var result = [], callback; + var rules = build_rules(this.filters, this._rules); + var tokens = args.concat([]); + while((token = tokens.shift()) && this._halt == false) { + if(token.match(LONG_SWITCH_RE) || token.match(SHORT_SWITCH_RE)) { + var arg = undefined; + // The token is a long or a short switch. Get the corresponding + // rule, filter and handle it. Pass the switch to the default + // handler if no rule matched. + for(var i = 0; i < rules.length; i++) { + var rule = rules[i]; + if(rule.long == token || rule.short == token) { + if(rule.filter !== undefined) { + arg = tokens.shift(); + if(!arg.match(LONG_SWITCH_RE) && !arg.match(SHORT_SWITCH_RE)) { + try { + arg = rule.filter(arg); + } catch(e) { + throw OptError(token + ': ' + e.toString()); + } + } else if(rule.optional_arg) { + tokens.unshift(arg); + } else { + throw OptError('Expected switch argument.'); + } + } + callback = this.on_switches[rule.name]; + if (!callback) callback = this.on_switches['*']; + if(callback) callback.apply(this, [rule.name, arg]); + break; + } + } + if(i == rules.length) this.default_handler.apply(this, [token]); + } else { + // Did not match long or short switch. Parse the token as a + // normal argument. + callback = this.on_args[result.length]; + result.push(token); + if(callback) callback.apply(this, [token]); + } + } + return this._halt ? this.on_halt.apply(this, []) : result; + }, + + // Returns an Array with all defined option rules + options: function() { + return build_rules(this.filters, this._rules); + }, + + // Add an on_halt callback if argument ´´fn´´ is specified. on_switch handlers can + // call instance.halt to abort the argument parsing. This can be useful when + // displaying help or version information. + halt: function(fn) { + this._halt = fn === undefined + if(fn) this.on_halt = fn; + }, + + // Returns a string representation of this OptionParser instance. + toString: function() { + var builder = [this.banner, '', this.options_title], + shorts = false, longest = 0, rule; + var rules = build_rules(this.filters, this._rules); + for(var i = 0; i < rules.length; i++) { + rule = rules[i]; + // Quick-analyze the options. + if(rule.short) shorts = true; + if(rule.decl.length > longest) longest = rule.decl.length; + } + for(var i = 0; i < rules.length; i++) { + var text; + rule = rules[i]; + if(shorts) { + if(rule.short) text = spaces(2) + rule.short + ', '; + else text = spaces(6); + } + text += spaces(rule.decl, longest) + spaces(3); + text += rule.desc; + builder.push(text); + } + return builder.join('\n'); + } +} + +self.VERSION = VERSION; +self.OptionParser = OptionParser; + +})(optparse); diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/package.json b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/package.json new file mode 100644 index 0000000..41ec5ea --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/package.json @@ -0,0 +1,8 @@ +{ + "name": "optparse", + "author": "Johan Dahlberg", + "description": "Command-line option parser", + "keywords": ["option", "parser", "command-line", "cli", "terminal"], + "version": "1.0.1", + "main": "./lib/optparse" +} diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/seed.yml b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/seed.yml new file mode 100644 index 0000000..fd5ac11 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/extern/optparse/seed.yml @@ -0,0 +1,5 @@ +--- + name: optparse + description: Command-line option parser + tags: option parser command-line cli terminal + version: 1.0.1 diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/gen_makefile.js b/node_modules/cassandra-client/node_modules/whiskey/lib/gen_makefile.js new file mode 100644 index 0000000..dd96a8f --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/gen_makefile.js @@ -0,0 +1,41 @@ +var path = require('path'); +var fs = require('fs'); + +var async = require('async'); +var sprintf = require('sprintf').sprintf; +var templates = require('magic-templates'); +templates.setTemplatesDir(path.join(__dirname, '../assets/')); +templates.setDebug(false); + +/** + * Generate and write a Makefile with Whiskey related targets. + * @param {Array} testFiles Test files. + * @param {String} targetPath path where a generated Makefile is saved. + * @param {Function} callback Callback called with (err). + */ +function generateMakefile(testFiles, targetPath, callback) { + var template = new templates.Template('Makefile.magic'); + var fullPath = path.join(targetPath, 'Makefile'); + var context = { + test_files: testFiles.join(' \\\n ') + }; + + if (path.existsSync(fullPath)) { + callback(new Error(sprintf('File "%s" already exists', fullPath))); + return; + } + + async.waterfall([ + template.load.bind(template), + + function render(template, callback) { + template.render(context, callback); + }, + + function save(output, callback) { + fs.writeFile(fullPath, output.join(''), callback); + } + ], callback); +} + +exports.generateMakefile = generateMakefile; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/parser.js b/node_modules/cassandra-client/node_modules/whiskey/lib/parser.js new file mode 100644 index 0000000..26038e4 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/parser.js @@ -0,0 +1,115 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var util = require('util'); + +var optparse = require('./extern/optparse/lib/optparse'); + +var constants = require('./constants'); +var run = require('./run'); + +var halt = function(parser) { + parser.halt(parser); + parser._halted = true; + run.exitCode = 1; +}; + +var getParser = function(options) { + var switches = []; + + switches = switches.concat(constants.DEFAULT_OPTIONS); + switches = switches.concat(options); + var parser = new optparse.OptionParser(switches); + parser._options = options; + + parser.on('help', function() { + util.puts(parser.toString()); + halt(parser); + }); + + parser.on('version', function() { + util.puts(constants.VERSION); + halt(parser); + }); + + parser.on(function(opt) { + util.puts('No handler was defined for option: ' + opt); + halt(parser); + }); + + parser.on('*', function(opt, value) { + util.puts('wild handler for ' + opt + ', value=' + value); + halt(parser); + }); + + return parser; +}; + +var getParserOptionsObject = function(options) { + var i, option, split, optionName, optionType; + var optionsLen = options.length; + var optionsObj = {}; + + for (i = 0; i < optionsLen; i++) { + option = options[i][1]; + split = option.split(' '); + + optionName = split[0].replace(/\-\-/, ''); + if (split.length === 1) { + optionType = 'boolean'; + } + else { + optionType = 'value'; + } + + optionsObj[optionName] = optionType; + } + + return optionsObj; +}; + +var parseArgv = function(parser, argv) { + var optionName, optionType; + var optionsObj = getParserOptionsObject(parser._options); + var options = {}; + + function handleParserOption(optionName, optionType) { + parser.on(optionName, function(opt, value) { + if (optionType === 'boolean') { + options[optionName] = true; + } + else if (optionType === 'value') { + if (value) { + options[optionName] = value; + } + } + }); + } + + for (optionName in optionsObj) { + if (optionsObj.hasOwnProperty(optionName)) { + optionType = optionsObj[optionName]; + handleParserOption(optionName, optionType); + } + } + + parser.parse(argv); + return options; +}; + +exports.getParser = getParser; +exports.parseArgv = parseArgv; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/process_runner/run.js b/node_modules/cassandra-client/node_modules/whiskey/lib/process_runner/run.js new file mode 100644 index 0000000..c30dcca --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/process_runner/run.js @@ -0,0 +1,81 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var path = require('path'); + +var term = require('terminal'); +var sprintf = require('sprintf').sprintf; + +var constants = require('./../constants'); +var parser = require('./../parser'); +var ProcessRunner = require('./runner').ProcessRunner; + +function getRunnerInstance(configPath) { + var runner; + + try { + runner = new ProcessRunner(configPath); + } + catch (err) { + term.puts(sprintf('Failed to load config file: [bold]%s[/bold]', err.message)); + process.exit(1); + } + + return runner; +} + +function run(argv) { + var p, options, configPath, runner, names; + + p = parser.getParser(constants.PROCESS_RUNNER_OPTIONS); + p.banner = 'Usage: process-runner --config dependencies.json [--verify|--run]'; + options = parser.parseArgv(p, argv); + + configPath = options.config || path.join(process.cwd(), 'dependencies.json'); + + if (options['verify']) { + runner = getRunnerInstance(configPath); + term.puts('Config file looks OK.'); + } + else if (options['run']) { + runner = getRunnerInstance(configPath); + names = options['names'] ? options['names'].split(',') : null; + + runner.start(names, function(err) { + if (err) { + term.puts('Failed to start processes!'); + term.puts(sprintf('Error: %s', err.message)); + } + else { + term.puts('All processes started'); + } + }); + } + else if (!p._halted) { + console.log(p.banner); + } + + process.on('SIGINT', function onSigint() { + term.puts('Stopping all processes...'); + + runner.stop(function() { + term.puts('All processes stopped'); + }); + }); +} + +exports.run = run; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/process_runner/runner.js b/node_modules/cassandra-client/node_modules/whiskey/lib/process_runner/runner.js new file mode 100644 index 0000000..2a5fe2f --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/process_runner/runner.js @@ -0,0 +1,473 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var fs = require('fs'); +var path = require('path'); +var net = require('net'); +var spawn = require('child_process').spawn; + +var sprintf = require('sprintf').sprintf; +var term = require('terminal'); +var async = require('async'); +var Set = require('simplesets').Set; +var logmagic = require('logmagic'); +var log = require('logmagic').local('whiskey.process_runner.runner'); + +var util = require('../util'); + +// Set up logging +function sink(modulename, level, message, obj) { + term.puts(sprintf('[green]%s[/green]: %s', modulename, message)); +} + +logmagic.registerSink('process_runner', sink); + +var VALID_WAIT_FOR_OPTIONS = { + 'none': { + 'required_options': new Set([]), + }, + + 'stdout': { + 'required_options': new Set(['string']), + }, + + 'socket': { + 'required_options': new Set(['host', 'port']) + } +}; + +var VALID_WAIT_FOR_OPTIONS_NAMES = Object.keys(VALID_WAIT_FOR_OPTIONS); + +var DEFAULT_TIMEOUT = 10 * 1000; +var COVERAGE_KILL_DELAY = 1500; + +var SOCKET_CONNECT_TIMEOUT = 1000; +var SOCKET_CONNECT_INTERVAL = 100; + +function ProcessRunner(configPath) { + this._configPath = path.resolve(configPath); + this._config = this.verifyConfig(this._readConfigFile(configPath)); + + this._stopped = false; + this._processes = []; +} + + +ProcessRunner.prototype._readConfigFile = function(filePath) { + var config = JSON.parse(fs.readFileSync(filePath)); + return config; +}; + + +/** + * Inspect the config, make sure all the options are valid and return a cleaned + * config object. + * + * @return {Object} Cleaned config, object with which we can work. + */ +ProcessRunner.prototype.verifyConfig = function(config) { + var key, value, available = {}, waitForOptions, requiredOptions, missing, dependencies, + i, len, component, components, cleaned = {}; + + // Verify that all the specified dependencies are defined + for (key in config) { + if (config.hasOwnProperty(key)) { + value = config[key]; + available[key] = true; + + if (!value.cmd) { + throw new Error(sprintf('%s is missing "cmd" attribute!', key)); + } + + if (value.wait_for) { + if (!VALID_WAIT_FOR_OPTIONS.hasOwnProperty(value.wait_for)) { + throw new Error(sprintf('Invalid wait_for options "%s", valid' + + ' options are: %s', value.wait_for, + VALID_WAIT_FOR_OPTIONS_NAMES)); + } + + waitForOptions = new Set(Object.keys(value.wait_for_options || {})); + requiredOptions = VALID_WAIT_FOR_OPTIONS[value.wait_for].required_options; + + missing = requiredOptions.difference(waitForOptions).array(); + + if (missing.length !== 0) { + throw new Error(sprintf('Missing required option for "%s" ' + + 'wait_for. Required options are: %s', value.wait_for, + requiredOptions.array())); + } + + } + } + } + + // Verify dependencies exist + for (key in config) { + if (config.hasOwnProperty(key)) { + value = config[key]; + dependencies = value.depends || []; + + dependencies.forEach(function(name) { + if (!available.hasOwnProperty(name)) { + throw new Error(sprintf('%s is depending on "%s" which is not' + + ' defined', key, name)); + } + else if (name === key) { + throw new Error(sprintf('%s cannot depend on itself', key)); + } + }); + + cleaned[key] = {}; + cleaned[key]['name'] = key; + cleaned[key]['cmd'] = value.cmd; + cleaned[key]['log_file'] = this._getLogFilePath(key, value.log_file); + cleaned[key]['wait_for'] = value.wait_for || null; + cleaned[key]['wait_for_options'] = (value.wait_for) ? value.wait_for_options : {}; + cleaned[key]['available_for_coverage'] = value.available_for_coverage || false; + cleaned[key]['timeout'] = parseInt(value.timeout || DEFAULT_TIMEOUT, 10); + cleaned[key]['depends'] = value.depends || []; + + if (value.cwd && value.cwd.length > 0) { + components = []; + + for (i = 0, len = value.cwd.length; i < len; i++) { + component = value.cwd[i]; + + if (component === '__dirname') { + component = path.dirname(this._configPath); + } + + components.push(component); + } + + cleaned[key]['cwd'] = path.resolve(path.join.apply(path, components)); + } + else { + cleaned[key]['cwd'] = null; + } + } + } + + return cleaned; +}; + +ProcessRunner.prototype._getLogFilePath = function(name, logFile) { + var cwd = process.cwd(); + + if (logFile) { + return logFile; + } + + return path.join(cwd, sprintf('%s.log', name)); +}; + +/** + * Scan the test files and find all the dependencies. + * + * @param {Function} Callback called with (err, {Array}dependencies). + */ +ProcessRunner.prototype.findDependencies = function(testPaths, callback) { + var self = this, exportedDependencies = new Set([]), dependencies; + + async.forEach(testPaths, function(testPath, callback) { + var testModule = testPath.replace(/\.js$/, ''), exported; + + try { + exported = require(testModule); + } + catch (err) { + callback(); + return; + } + + if (exported.hasOwnProperty('dependencies')) { + exported.dependencies.forEach(function(name) { + if (!self._config.hasOwnProperty(name)) { + throw new Error(sprintf('File "%s" depends on process "%s" which does not exist', + testPath, name)); + } + + exportedDependencies.add(name); + }); + } + + callback(); + }, + + function(err) { + dependencies = exportedDependencies.array(); + callback(err, dependencies); + }); +}; + +/** + * + * @param {?Array} names Names of the dependencies to run. Defaults to all the + * dependencies specified in the config file. + * @param {Function} callback Callback called when all the processes have + * started. + */ +ProcessRunner.prototype.start = function(names, callback) { + var self = this, i, len, name, value, ops = {}, dependencies, func; + + if (typeof names === 'function') { + callback = names; + names = Object.keys(this._config); + } + else { + names = names || Object.keys(this._config); + } + + for (i = 0, len = names.length; i < len; i++) { + name = names[i]; + + if (this._config.hasOwnProperty(name)) { + value = this._config[name]; + name = value.name; + dependencies = value.depends; + + func = this._startProcess.bind(this, value); + + if (dependencies.length === 0) { + ops[name] = func; + } + else { + ops[name] = dependencies.concat([func]); + } + } + } + + async.auto(ops, function(err) { + if (err) { + self.stop(function(err2) { + err = err2 || err; + callback(err); + }); + return; + } + + callback(); + }); +}; + +/** + * Stop all the running processes. + */ +ProcessRunner.prototype.stop = function(callback) { + if (!callback) { + callback = function() {}; + } + + if (this._stopped) { + callback(); + return; + } + + this._stopped = true; + async.forEach(this._processes, this._stopProcess.bind(this), callback); +}; + + +/** + * Start a single process. + * + * @param {Object} options Options. + * @param {Function} callback Callback called when the process has been started + * with (err). + */ +ProcessRunner.prototype._startProcess = function(options, callback) { + var self = this, args = options.cmd, logFilePath = options.log_file, + waitFor = options.wait_for, waitForOptions = options.wait_for_options, obj; + + function writeToLog(stream, chunk) { + if (stream.writable) { + stream.write(chunk, 'utf8'); + } + } + + function handleTimeout(obj, callback) { + self._stopProcess(obj, function() { + callback(new Error(sprintf('Process "%s" failed to start in %s seconds.', + options.name, (options.timeout / 1000)))); + }); + } + + + if (this._stopped) { + callback(new Error('Runner has been stopped.')); + return; + } + + async.waterfall([ + function createDataStructure(callback) { + var logFileStream = fs.createWriteStream(logFilePath, {'flags': 'w', 'encoding': 'utf8'}); + + obj = { + 'name': options.name, + 'log_file_stream': logFileStream, + 'available_for_coverage': options.available_for_coverage, + 'started_at': util.getUnixTimestamp() + }; + + callback(); + }, + + function spawnProcess(callback) { + var cmd = args.splice(0, 1)[0], + spawnArgs = [cmd, args], + spawnOptions, child; + + if (options.cwd) { + spawnOptions = {'cwd': options.cwd}; + spawnArgs.push(spawnOptions); + } + + log.infof('Starting [bold]${name}[/bold] process, cmd: ' + + '[bold]${cmd}[/bold]...', {'name': options.name, + 'cmd': [cmd, args].join(' ')}); + + child = spawn.apply(null, spawnArgs); + + obj.process = child; + child.stdout.on('data', writeToLog.bind(null, obj.log_file_stream)); + child.stderr.on('data', writeToLog.bind(null, obj.log_file_stream)); + + child.on('exit', function onExit(code) { + log.debugf('Process [bold]${name}[/bold] exited with code ${code}', + {'name': options.name, 'code': code}); + }); + + self._processes.push(obj); + callback(); + }, + + function setTimeoutAndWaitFor(callback) { + var timeoutId; + + function wrappedCallback() { + clearTimeout(timeoutId); + callback(); + } + + if (!waitFor) { + callback(); + } + else if (waitFor === 'stdout' || waitFor === 'socket') { + timeoutId = setTimeout(handleTimeout.bind(null, obj, callback), + options.timeout); + + if (waitFor === 'stdout') { + self._waitForStdout(obj, waitForOptions, wrappedCallback); + } + else if (waitFor === 'socket') { + self._waitForSocket(obj, waitForOptions, wrappedCallback); + } + } + } + ], callback); +}; + +/** + * @param {Object} process Process options object. + * @param {Function} callback Callback called on completion. + */ +ProcessRunner.prototype._stopProcess = function(process, callback) { + log.infof('Stopping [bold]${name}[/bold] process...', {'name': process.name}); + + if (process.log_file_stream.writable) { + process.log_file_stream.end(''); + } + + process.process.stdout.removeAllListeners('data'); + process.process.stderr.removeAllListeners('data'); + + if (!process.available_for_coverage) { + process.process.kill('SIGTERM'); + } + else { + process.process.kill('SIGUSR2') + } + + process.killed = true; + process.stopped_at = util.getUnixTimestamp(); + callback(); +}; + +/** + * @param {Object} obj Process object. + * @param {Object} options Options object. + * @param {Function} callback Callback called when the matching string has been + * found. + */ +ProcessRunner.prototype._waitForStdout = function(obj, options, callback) { + var stdoutBuffer = ''; + + function onData(chunk) { + stdoutBuffer += chunk; + + if (stdoutBuffer.indexOf(options.string) !== -1) { + // Found matching string + process.stdout.removeListener('data', onData); + process.stderr.removeListener('data', onData); + callback(); + } + } + + obj.process.stdout.on('data', onData); + obj.process.stderr.on('data', onData); +}; + +/** + * + * @param {Object} obj Process object. + * @param {Object} options Options object. + * @param {Function} callback Callback called when the connection has been + * established. + */ +ProcessRunner.prototype._waitForSocket = function(obj, options, callback) { + callback = util.fireOnce(callback); + var host = options.host, port = options.port; + + function connect() { + if (obj.killed) { + callback(); + return; + } + + var socket = net.createConnection(port, host), timeoutId; + + timeoutId = setTimeout(function() { + setTimeout(connect, 2000); + socket.destroy(); + }, SOCKET_CONNECT_TIMEOUT); + + socket.on('connect', function(con) { + clearTimeout(timeoutId); + socket.end(); + callback(); + }); + + socket.on('error', function(err) { + clearTimeout(timeoutId); + setTimeout(connect, SOCKET_CONNECT_INTERVAL); + }); + } + + connect(); +}; + +exports.ProcessRunner = ProcessRunner; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/base.js b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/base.js new file mode 100644 index 0000000..7464c8c --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/base.js @@ -0,0 +1,32 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +function CoverageReporter(tests, options) { + this._options = options; + this._tests = tests; +} + +exports.CoverageReporter = CoverageReporter; + +CoverageReporter.prototype.handleTestFileComplete = function(filePath, coverageObj) { + throw new Error('Not implemented'); +}; + +CoverageReporter.prototype.handleTestsComplete = function() { + throw new Error('Not implemented'); +}; + diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/cli.js b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/cli.js new file mode 100644 index 0000000..62780d7 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/cli.js @@ -0,0 +1,80 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +/* + * _reportCoverage is taken from expresso + * which is MIT licensed. + * Copyright(c) TJ Holowaychuk + */ + +var util = require('util'); +var path = require('path'); +var fs = require('fs'); + +var rimraf = require('rimraf'); +var templates = require('magic-templates'); + +var constants = require('./../../constants'); +var utils = require('./../../util'); +var coverage = require('./../../coverage'); +var CoverageReporter = require('./base').CoverageReporter; + +function CliReporter(tests, options) { + CoverageReporter.call(this, tests, options); + + this._coverage = {}; +} + +CliReporter.prototype.handleTestFileComplete = function(filePath, coverageObj) { + var filename = filePath; + this._coverage[filename] = coverageObj; +}; + +CliReporter.prototype.handleTestsComplete = function(coverageObj) { + coverageObj = (!coverageObj) ? coverage.populateCoverage(null, this._coverage) : coverageObj; + this._reportCoverage(coverageObj); +}; + +CliReporter.prototype._reportCoverage = function(cov) { + util.puts(''); + util.puts('Test Coverage'); + var sep = ' +------------------------------------------+----------+------+------+--------+', + lastSep = ' +----------+------+------+--------+'; + util.puts(sep); + util.puts(' | filename | coverage | LOC | SLOC | missed |'); + util.puts(sep); + for (var name in cov.files) { + var file = cov.files[name]; + util.print(' | ' + utils.rpad(name, 40)); + util.print(' | ' + utils.lpad(file.coverage, 8)); + util.print(' | ' + utils.lpad(file.LOC, 4)); + util.print(' | ' + utils.lpad(file.SLOC, 4)); + util.print(' | ' + utils.lpad(file.totalMisses, 6)); + util.print(' |\n'); + } + util.puts(sep); + util.print(' ' + utils.rpad('', 40)); + util.print(' | ' + utils.lpad(cov.coverage, 8)); + util.print(' | ' + utils.lpad(cov.LOC, 4)); + util.print(' | ' + utils.lpad(cov.SLOC, 4)); + util.print(' | ' + utils.lpad(cov.totalMisses, 6)); + util.print(' |\n'); + util.puts(lastSep); +}; + +exports.name = 'cli'; +exports.klass = CliReporter; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/html.js b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/html.js new file mode 100644 index 0000000..e952865 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/html.js @@ -0,0 +1,180 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var util = require('util'); +var path = require('path'); +var fs = require('fs'); + +var rimraf = require('rimraf'); +var templates = require('magic-templates'); + +var constants = require('./../../constants'); +var coverage = require('./../../coverage'); +var CoverageReporter = require('./base').CoverageReporter; + +function HtmlReporter(tests, options) { + CoverageReporter.call(this, tests, options); + + if (!options['directory']) { + throw new Error('Missing coverage-directory option'); + } + + this._coverage = {}; + + this._coverageDirectory = this._options['directory']; + this._assetsDirectory = path.join(__dirname, '../../../', 'assets'); + + templates.setTemplatesDir(this._assetsDirectory); + templates.setDebug(false); +} + +HtmlReporter.prototype.handleTestFileComplete = function(filePath, coverageObj) { + var filename = filePath; + this._coverage[filename] = coverageObj; +}; + +HtmlReporter.prototype.handleTestsComplete = function(coverageObj) { + coverageObj = (!coverageObj) ? coverage.populateCoverage(null, this._coverage) : coverageObj; + this._writeCoverage(coverageObj); +}; + +HtmlReporter.prototype._writeCoverage = function(cov) { + var self = this; + + /* Remove output directory */ + rimraf(self._coverageDirectory, function(err) { + fs.mkdir(self._coverageDirectory, 0755, function() { + self._writeFile(cov); + self._writeSourceFiles(cov); + self._writeStaticFiles(self._coverageDirectory); + }); + }); +}; + +HtmlReporter.prototype._writeFile = function(cov) { + var self = this; + var template = new templates.Template('whiskey.magic'); + + var context = { + version: constants.VERSION, + coverage: cov.coverage, + cov: cov + }; + + template.load(function(err, template) { + if (err) { + // load/parse errors (invalid filename, bad template syntax) + console.log(err); + } + else { + template.render(context, function(err, output) { + if (err) { + // render errors (invalid filename in context variables, bad context variables) + console.log(err); + } + else { + fs.writeFile(path.join(self._coverageDirectory, 'index.html'), + output.join('')); + } + }); + } + }); +}; + +HtmlReporter.prototype._writeSourceFiles = function(cov) { + var self = this; + var template = new templates.Template('whiskey_source.magic'); + + template.load(function(err, template) { + if (err) { + // load/parse errors (invalid filename, bad template syntax) + console.log(err); + } + else { + for (var name in cov.files) { + var context = { + version: constants.VERSION, + name: name, + cov: cov.files[name], + markup: self._generateSourceMarkup(cov.files[name]) + }; + + template.render(context, function(err, output) { + if (err) { + // render errors (invalid filename in context variables, bad context variables) + console.log(err); + } + else { + fs.writeFile(path.join(self._coverageDirectory, + cov.files[name].htmlName), + output.join('')); + } + }); + } + } + }); +}; + +HtmlReporter.prototype._generateSourceMarkup = function(cov) { + var rv = [], _class, data, source; + + for (var i = 1, linesLen = (cov.source.length + 1); i < linesLen; i++) { + data = cov.lines[i.toString()]; + _class = 'pln'; + if (data !== null) { + if (parseInt(data, 10) > 0) { + _class = 'stm run'; + } + else if (parseInt(data, 10) === 0) { + _class = 'stm mis'; + } + } + source = cov.source[i-1]; + source = source.replace(/\s/g, ' '); + rv.push({number: i, css: _class, source: source}); + } + + return rv; +}; + +HtmlReporter.prototype._writeStaticFiles = function(dest) { + this._copyAsset('style.css', dest); + this._copyAsset('coverage_html.js', dest); + this._copyAsset('jquery-1.4.3.min.js', dest); + this._copyAsset('jquery.tablesorter.min.js', dest); + this._copyAsset('jquery.isonscreen.js', dest); + this._copyAsset('jquery.hotkeys.js', dest); + this._copyAsset('keybd_closed.png', dest); + this._copyAsset('keybd_open.png', dest); +}; + +HtmlReporter.prototype._copyAsset = function(asset, dest) { + this._copyFile(path.join(this._assetsDirectory, asset), + path.join(dest, asset)); +}; + +HtmlReporter.prototype._copyFile = function(src, dst) { + var oldFile = fs.createReadStream(src); + var newFile = fs.createWriteStream(dst); + + newFile.once('open', function(fd) { + util.pump(oldFile, newFile); + }); +}; + +exports.name = 'html'; +exports.klass = HtmlReporter; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/json.js b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/json.js new file mode 100644 index 0000000..03e06e7 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/coverage/json.js @@ -0,0 +1,52 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var path = require('path'); +var fs = require('fs'); + +var coverage = require('./../../coverage'); +var CoverageReporter = require('./base').CoverageReporter; + +function JSONReporter(tests, options) { + CoverageReporter.call(this, tests, options); + + this._coverage = {}; + this._coverageFile = this._options['file']; +} + +JSONReporter.prototype.handleTestFileComplete = function(filePath, coverageObj) { + var filename = filePath; + this._coverage[filename] = coverageObj; +}; + +JSONReporter.prototype.handleTestsComplete = function(coverageObj) { + var filePath; + var coverage = coverageObj || this._coverage; + var data = JSON.stringify(coverage); + + if (this._coverageFile.indexOf('/') === 0) { + filePath = this._coverageFile; + } + else { + filePath = path.join(process.cwd(), this._coverageFile); + } + + fs.writeFileSync(filePath, data, 'utf8'); +}; + +exports.name = 'json'; +exports.klass = JSONReporter; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/index.js b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/index.js new file mode 100644 index 0000000..87160fa --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/index.js @@ -0,0 +1,81 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var fs = require('fs'); +var path = require('path'); + +var sprintf = require('sprintf').sprintf; + +var TEST_REPORTERS = {}; +var COVERAGE_REPORTERS = {}; +var SCOPE_LEAKS_REPORTERS = {}; + +function getReporter(type, name, tests, options) { + var reporters, availableReporters; + if (type === 'test') { + reporters = TEST_REPORTERS; + } + else if (type === 'coverage') { + reporters = COVERAGE_REPORTERS; + } + else if (type === 'scope-leaks') { + reporters = SCOPE_LEAKS_REPORTERS; + } + else { + throw new Error(sprintf('Invalid reporter type: %s', type)); + } + + availableReporters = Object.keys(reporters); + + if (availableReporters.indexOf(name) === -1) { + throw new Error(sprintf('Invalid reporter: %s. Valid reporters are: %s', + name, availableReporters.join(', '))); + } + + return new reporters[name](tests, options); +} + +function discoverReporters(reporters, reportersPath) { + var i, files, file, filesLen, moduleName, exported; + var fullPath = path.join(__dirname, reportersPath); + files = fs.readdirSync(fullPath); + + filesLen = files.length; + for (i = 0; i < filesLen; i++) { + file = files[i]; + moduleName = file.replace(/\.js$/, ''); + exported = require(sprintf('./%s/%s', reportersPath, moduleName)); + + if (exported.name && exported.klass) { + reporters[exported.name] = exported.klass; + } + } +} + +if (Object.keys(TEST_REPORTERS).length === 0) { + discoverReporters(TEST_REPORTERS, 'test'); +} + +if (Object.keys(COVERAGE_REPORTERS).length === 0) { + discoverReporters(COVERAGE_REPORTERS, 'coverage'); +} + +if (Object.keys(SCOPE_LEAKS_REPORTERS).length === 0) { + discoverReporters(SCOPE_LEAKS_REPORTERS, 'scope-leaks'); +} + +exports.getReporter = getReporter; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/scope-leaks/base.js b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/scope-leaks/base.js new file mode 100644 index 0000000..3518efa --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/scope-leaks/base.js @@ -0,0 +1,40 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +function ScopeLeaksReporter(tests, options) { + this._tests = tests; + this._options = options; + + this._leakedVariables = {}; +} + +ScopeLeaksReporter.prototype.handleTestEnd = function(filePath, resultObj) { + if (!this._leakedVariables.hasOwnProperty(filePath)) { + this._leakedVariables[filePath] = {}; + } + this._leakedVariables[filePath][resultObj['name']] = resultObj['leaked_variables']; +}; + +ScopeLeaksReporter.prototype.handleTestFileComplete = function(filePath, stdout, stderr) { + throw new Error('Not implemented'); +}; + +ScopeLeaksReporter.prototype.handleTestsComplete = function(filePath, stdout, stderr) { + throw new Error('Not implemented'); +}; + +exports.ScopeLeaksReporter = ScopeLeaksReporter; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/scope-leaks/cli.js b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/scope-leaks/cli.js new file mode 100644 index 0000000..0a99426 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/scope-leaks/cli.js @@ -0,0 +1,83 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var util = require('util'); +var path = require('path'); + +var sprintf = require('sprintf').sprintf; + +var ScopeLeaksReporter = require('./base').ScopeLeaksReporter; + +function CliReporter(tests, options) { + ScopeLeaksReporter.call(this, tests, options); +} + +util.inherits(CliReporter, ScopeLeaksReporter); + +CliReporter.prototype.handleTestsComplete = function() { + this._reportLeakedVariables(); +}; + +CliReporter.prototype._reportLeakedVariables = function() { + var testFilePath, testFile, tests, test, leakedVariables, leakedVariablesTest; + + console.log(''); + console.log('\033[1mLeaked Variables\033[22m'); + console.log(''); + + for (testFilePath in this._leakedVariables) { + testFile = path.basename(testFilePath); + tests = this._leakedVariables[testFilePath]; + + if (this._options['sequential']) { + // Sequential mode was used so we can accurately report leaked variables for + // each test separately. + console.log(testFile); + + for (test in tests) { + leakedVariables = ((tests[test] && tests[test].length > 0) ? tests[test] : null); + + if (leakedVariables && leakedVariables.length > 0) { + console.log(sprintf(' %s: %s', test, leakedVariables.join(', '))); + } + else { + console.log(sprintf(' %s: no leaks detected', test)); + } + } + } + else { + leakedVariables = []; + for (test in tests) { + leakedVariablesTest = ((tests[test] && tests[test].length > 0) ? tests[test] : null); + + if (leakedVariablesTest) { + leakedVariables = leakedVariables.concat(leakedVariablesTest); + } + } + + if (leakedVariables && leakedVariables.length > 0) { + console.log(sprintf(' %s: %s', testFile, leakedVariables.join(', '))); + } + else { + console.log(sprintf(' %s: no leaks detected', testFile)); + } + } + } +}; + +exports.name = 'cli'; +exports.klass = CliReporter; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/test/base.js b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/test/base.js new file mode 100644 index 0000000..8c4ffae --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/test/base.js @@ -0,0 +1,53 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +function TestReporter(tests, options) { + this._tests = tests; + this._options = options; + + this._testResults = {}; +} + +// Called before starting the tests +TestReporter.prototype.handleTestsStart = function() { + throw new Error('Not implemented'); +}; + +TestReporter.prototype.handleTestEnd = function(filePath, resultObj) { + if (!this._testResults.hasOwnProperty(filePath)) { + this._testResults[filePath] = {}; + } + + this._testResults[filePath][resultObj['name']] = resultObj; +}; + +// Called when a new test process is spawned +TestReporter.prototype.handleTestFileStart = function(filePath) { + throw new Error('Not implemented'); +}; + +// Called when the tests for the test file complete +TestReporter.prototype.handleTestFileComplete = function(filePath, stdout, stderr) { + throw new Error('Not implemented'); +}; + +// Called at the end when all the tests complete +TestReporter.prototype.handleTestsComplete = function() { + throw new Error('Not implemented'); +}; + +exports.TestReporter = TestReporter; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/test/cli.js b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/test/cli.js new file mode 100644 index 0000000..cce0a59 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/test/cli.js @@ -0,0 +1,195 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var util = require('util'); +var path = require('path'); + +var sprintf = require('sprintf').sprintf; +var terminal = require('terminal'); + +var TestReporter = require('./base').TestReporter; +var testUtil = require('./../../util'); + +function CliReporter(tests, options) { + TestReporter.call(this, tests, options); + + this._dateStart = null; + this._dateEnd = null; + this._successes = 0; + this._failures = 0; + this._timeouts = 0; + this._skipped = 0; + + this._puts = (this._options['styles']) ? terminal.puts : terminal.putsNoStyle; +} + +util.inherits(CliReporter, TestReporter); + +CliReporter.prototype.handleTestsStart = function() { + this._dateStart = testUtil.getUnixTimestamp(); +}; + +CliReporter.prototype.handleTestFileStart = function(filePath) { + this._puts(filePath); +}; + +CliReporter.prototype.handleTestFileComplete = function(filePath, stdout, stderr) { + var tests, test, timing, key, runTime = 0, testCount = 0; + + stdout = stdout || ''; + stderr = stderr || ''; + tests = this._testResults[filePath]; + + for (key in tests) { + if (tests.hasOwnProperty(key)) { + test = tests[key]; + timing = {'start': (test.time_start || 0), 'end': (test.time_end || 0)}; + + runTime += (timing.end - timing.start); + testCount++; + + if (test.error) { + this._failures++; + this._reportFailure(test.name, test.error, timing); + } + else if (test.timeout) { + this._timeouts++; + this._reportTimeout(); + } + else if (test.status === 'skipped') { + this._skipped++; + this._reportSkipped(test.name, test.skip_msg, timing); + } + else { + this._successes++; + this._reportSuccess(test.name, timing); + } + } + } + + if (this._options['report_timing']) { + this._reportTestStatistics(testCount, runTime); + } + + if (this._failures > 0 || this._timeouts > 0) { + this._printStderr(stderr); + this._printStdout(stdout); + } + else { + if (this._options['print_stderr']) { + this._printStderr(stderr); + } + + if (this._options['print_stdout']) { + this._printStdout(stdout); + } + } +}; + +CliReporter.prototype.handleTestsComplete = function() { + this._dateEnd = testUtil.getUnixTimestamp(); + this._reportStatistics(); + + return (this._failures + this._timeouts); +}; + +CliReporter.prototype._reportTestStatistics = function(testCount, runTime) { + this._puts(''); + this._puts(sprintf('Ran %d tests in %0.3fs', testCount, (runTime / 1000))); +}; + +CliReporter.prototype._printStdout = function(stdout) { + if (stdout.length > 0) { + this._puts(''); + this._puts('[bold]Stdout[/bold]:'); + this._puts(stdout); + } +}; + +CliReporter.prototype._printStderr = function(stdout) { + if (stdout.length > 0) { + this._puts(''); + this._puts('[bold]Stderr[/bold]:'); + this._puts(stdout); + } +}; + +CliReporter.prototype._getTestNameWithTiming = function(testName, timing) { + var str; + + if (!this._options['report_timing']) { + return testName; + } + + return sprintf('%s (took %0.3fs)', testName, ((timing.end - timing.start) / 1000)); +}; + +CliReporter.prototype._reportSuccess = function(testName, timing) { + testName = this._getTestNameWithTiming(testName, timing); + this._puts(sprintf(' %s [green][OK][/green]', + testUtil.addCharacters(testName, 74, ' '))); +}; + +CliReporter.prototype._reportFailure = function(testName, error, timing) { + testName = this._getTestNameWithTiming(testName, timing); + var errMsg = (error.stack) ? error.stack : error.message; + this._puts(sprintf(' %s [red][FAIL][/red]', + testUtil.addCharacters(testName, 72, ' '))); + this._puts(''); + this._puts('[bold]Exception[/bold]'); + this._puts(errMsg); + this._puts(''); +}; + +CliReporter.prototype._reportTimeout = function() { + this._puts(sprintf(' %s [cyan][TIMEOUT][/cyan]', + testUtil.addCharacters('timeout', 69, ' '))); +}; + +CliReporter.prototype._reportSkipped = function(testName, msg, timing) { + msg = msg || ''; + testName = (msg) ? sprintf('%s (%s)', testName, msg) : testName; + this._puts(sprintf(' %s [grey][SKIPPED][/grey]', + testUtil.addCharacters(testName, 69, ' '))); +}; + +CliReporter.prototype._reportStatistics = function() { + var runTime = (this._dateEnd - this._dateStart); + var successes = this._successes; + var failures = this._failures; + var timeouts = this._timeouts; + var skipped = this._skipped; + + this._puts(testUtil.addCharacters('', 81, '-')); + this._puts(sprintf('Ran %d tests in %0.3fs', (successes + failures), runTime)); + this._puts(''); + this._puts(sprintf('Successes: %s', successes)); + this._puts(sprintf('Failures: %s', failures)); + this._puts(sprintf('Timeouts: %s', timeouts)); + this._puts(sprintf('Skipped: %s', skipped)); + this._puts(''); + + if (failures === 0 && timeouts === 0) { + this._puts('[green]PASSED[/green]'); + } + else { + this._puts('[red]FAILED[/red]'); + } +}; + +exports.name = 'cli'; +exports.klass = CliReporter; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/test/tap.js b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/test/tap.js new file mode 100644 index 0000000..7983036 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/reporters/test/tap.js @@ -0,0 +1,158 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. +*/ + +var util = require('util'); +var path = require('path'); + +var sprintf = require('sprintf').sprintf; + +var TestReporter = require('./base').TestReporter; +var testUtil = require('./../../util'); + +function TapReporter(tests, options) { + TestReporter.call(this, tests, options); + + this._tempResults = {}; + this._successes = 0; + this._failures = 0; + this._timeouts = 0; +} + +util.inherits(TapReporter, TestReporter); + +TapReporter.prototype.handleTestsStart = function() { +}; + +TapReporter.prototype.handleTestFileStart = function(filePath) { +}; + +TapReporter.prototype.handleTestFileComplete = function(filePath, + stdout, stderr) { + var tests, test, key; + var fileName = path.basename(filePath); + + stdout = stdout || ''; + stderr = stderr || ''; + tests = this._testResults[filePath]; + + for (key in tests) { + if (tests.hasOwnProperty(key)) { + test = tests[key]; + + if (test.error) { + this._addFailure(fileName, test.name); + } + else if (test.timeout) { + this._addTimeout(fileName, 'timeout'); + } + else if (test.status === 'skipped') { + continue; + } + else { + this._addSuccess(fileName, test.name); + } + } + } + /*if (error) { + // Test file does not exist or an exception was thrown before the tests were + // even run + this._addFailure(fileName, error.name); + return; + }*/ +}; + +TapReporter.prototype.handleTestsComplete = function() { + this._reportResults(); + + return this._failures + this._timeouts; +}; + +TapReporter.prototype._addSuccess = function(testFile, testName) { + this._successes++; + this._addResult(testFile, testName, 'success'); +}; + +TapReporter.prototype._addFailure = function(testFile, testName) { + this._failures++; + this._addResult(testFile, testName, 'failure'); +}; + +TapReporter.prototype._addTimeout = function(testFile, testName) { + this._timeouts++; + this._addResult(testFile, testName, 'timeout'); +}; + +TapReporter.prototype._addResult = function(testFile, testName, testStatus) { + if (!this._tempResults.hasOwnProperty(testFile)) { + this._tempResults[testFile] = {}; + } + + this._tempResults[testFile][testName] = { + 'file': testFile, + 'name': testName, + 'status': testStatus + }; +}; + +TapReporter.prototype._reportResults = function() { + var self = this; + var startNum, i, files, file, filesLen, testsLen, tests, test, testResult, testNum; + files = Object.keys(this._tempResults); + filesLen = files.length; + + function getFileTestLen(file) { + return Object.keys(self._tempResults[file]).length; + } + + testsLen = files.map(getFileTestLen).reduce(function (a, b) { return a + b; }); + + if (testsLen === 0) { + startNum = 0; + } + else { + startNum = 1; + } + + console.log(' %d..%d', startNum, testsLen); + + testNum = 0; + for (i = 0; i < filesLen; i++) { + file = files[i]; + tests = this._tempResults[file]; + + for (test in tests) { + if (tests.hasOwnProperty(test)) { + testNum++; + testResult = tests[test]; + + if (testResult.status === 'success') { + console.log(' ok %d - %s: %s', testNum, testResult.file, testResult.name); + } + else if (testResult.status === 'failure') { + console.log(' not ok %d - %s: %s', testNum, testResult.file, testResult.name); + } + else if (testResult.status === 'timeout') { + console.log(' not ok %d - %s: %s (timeout)', testNum, testResult.file, + testResult.name); + } + } + } + } +}; + +exports.name = 'tap'; +exports.klass = TapReporter; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/run.js b/node_modules/cassandra-client/node_modules/whiskey/lib/run.js new file mode 100644 index 0000000..23ac8ef --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/run.js @@ -0,0 +1,552 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var util = require('util'); +var fs = require('fs'); +var path = require('path'); +var net = require('net'); +var spawn = require('child_process').spawn; +var exec = require('child_process').exec; +var execSync = require('child_process').execSync; + +var sprintf = require('sprintf').sprintf; +var async = require('async'); +var logmagic = require('logmagic'); + +var constants = require('./constants'); +var parser = require('./parser'); +var common = require('./common'); +var testUtil = require('./util'); +var coverage = require('./coverage'); +var getReporter = require('./reporters/index').getReporter; +var generateMakefile = require('./gen_makefile').generateMakefile; +var _debugger = require('./debugger'); +var DebuggerInterface = _debugger.Interface; +var ProcessRunner = require('./process_runner/runner').ProcessRunner; + +exports.exitCode = 0; +exports.processRunner = null; + +function TestRunner(options) { + var testReporter, coverageReporter, scopeLeaksReporter, + testReporterOptions, coverageReporterOptions, scopeLeaksReporterOptions, + defaultSocketPath; + + defaultSocketPath = sprintf('%s-%s', constants.DEFAULT_SOCKET_PATH, + Math.random() * 10000); + this._tests = options['tests']; + this._dependencies = options['dependencies'] || null; + this._onlyEssential = options['only-essential'] || false; + this._socketPath = options['socket-path'] || defaultSocketPath; + this._coverage = options['coverage']; + this._scopeLeaks = options['scope-leaks']; + this._verbosity = options['verbosity'] || constants.DEFAULT_VERBOSITY; + this._failfast = options['failfast'] || false; + this._realTime = options['real-time'] || false; + this._debug = options['debug']; + + testReporter = options['test-reporter'] || constants.DEFAULT_TEST_REPORTER; + testReporterOptions = { + 'print_stdout': options['print-stdout'], + 'print_stderr': options['print-stderr'], + 'styles': (options['no-styles'] ? false : true), + 'report_timing': options['report-timing'] + }; + + this._testReporter = getReporter('test', testReporter, this._tests, + testReporterOptions); + + if (this._coverage) { + coverageReporter = options['coverage-reporter'] || constants.DEFAULT_COVERAGE_REPORTER; + coverageReporterOptions = { + 'directory': options['coverage-dir'], + 'file': options['coverage-file'] + }; + + this._coverageReporter = getReporter('coverage', + coverageReporter, + this._tests, + coverageReporterOptions); + } + else { + this._coverageReporter = null; + } + + if (this._scopeLeaks) { + scopeLeaksReporter = options['scope-leaks-reporter'] || constants.DEFAULT_SCOPE_LEAKS_REPORTER; + scopeLeaksReporterOptions = { + 'sequential': (options['concurrency'] === 1 || options['sequential']) + }; + this._scopeLeaksReporter = getReporter('scope-leaks', scopeLeaksReporter, + this._tests, + scopeLeaksReporterOptions); + } + else { + this._scopeLeaksReporter = null; + } + + this._server = null; + this._processRunner = null; + this._testFilesData = {}; + + this._completed = false; + this._forceStopped = false; + this._completedTests = []; +} + +TestRunner.prototype.runTests = function(testInitFile, chdir, + customAssertModule, + timeout, + concurrency, failFast) { + var self = this, ops = []; + timeout = timeout || constants.DEFAULT_TEST_TIMEOUT; + + function handleChildTimeout(child, filePath) { + var resultObj, testFile; + + if (!child.killed) { + testFile = self._testFilesData[filePath]; + + resultObj = { + 'tests': [], + 'timeout': true + }; + + child.kill('SIGTERM'); + self._handleTestResult(filePath, resultObj); + } + + if (self._failfast) { + self.forceStop(); + } + } + + function onBound() { + self._testReporter.handleTestsStart(); + + async.forEachSeries(self._tests, function(filePath, callback) { + var result, pattern, cwd, child, timeoutId, testFileData; + + if (self._completed || self._forceStopped) { + callback(new Error('Runner has been stopped')); + return; + } + + cwd = process.cwd(); + result = common.getTestFilePathAndPattern(filePath); + filePath = result[0]; + pattern = result[1]; + filePath = (filePath.charAt(0) !== '/') ? path.join(cwd, filePath) : filePath; + child = self._spawnTestProcess(filePath, testInitFile, chdir, + customAssertModule, timeout, + concurrency, pattern); + + if (!self._debug) { + timeoutId = setTimeout(function() { + handleChildTimeout(child, filePath, callback); + }, timeout); + } + + self._testFilesData[filePath] = { + 'child': child, + 'callback': callback, + 'timeout_id': timeoutId, + 'stdout': '', + 'stderr': '' + }; + + testFileData = self._testFilesData[filePath]; + + child.stdout.on('data', function(chunk) { + if (self._realTime) { + process.stdout.write(chunk.toString()); + } + else { + testFileData['stdout'] += chunk; + } + }); + + child.stderr.on('data', function(chunk) { + if (self._realTime) { + process.stderr.write(chunk.toString()); + } + else { + testFileData['stderr'] += chunk; + } + }); + + child.on('exit', function() { + clearTimeout(timeoutId); + self._handleTestFileEnd(filePath); + delete self._testFilesData[filePath]; + }); + }, + + function(err) { + self._handleTestsCompleted(); + }); + } + + function startServer(callback) { + self._startServer(self._handleConnection.bind(self), + onBound); + } + + function createRunner(callback) { + self._processRunner = new ProcessRunner(self._dependencies); + exports.processRunner = self._processRunner; + callback(null, null); + } + + function findDependenciesToRun(_, callback) { + var cwd = process.cwd(); + var testPaths = self._tests.map(function(testPath) { + testPath = common.getTestFilePathAndPattern(testPath)[0]; + testPath = (testPath.charAt(0) !== '/') ? path.join(cwd, testPath) : testPath; + return testPath; + }); + + self._processRunner.findDependencies(testPaths, callback); + } + + function startDependencies(dependencies, callback) { + self._processRunner.start(dependencies, callback); + } + + if (self._dependencies) { + ops.push(createRunner); + + if (self._onlyEssential) { + ops.push(findDependenciesToRun); + } + + ops.push(startDependencies); + } + + ops.push(startServer); + + async.waterfall(ops, function(err) { + if (err) { + throw err; + } + }); +}; + +TestRunner.prototype._spawnTestProcess = function(filePath, + testInitFile, + chdir, + customAssertModule, + timeout, + concurrency, + pattern) { + var cwd = process.cwd(); + var libCovDir = (this._coverage) ? path.join(cwd, 'lib-cov') : null; + var runFilePath = path.join(__dirname, 'run_test_file.js'); + var port = parseInt((Math.random() * (65000 - 2000) + 2000), 10); + var args = []; + + if (this._debug) { + args.push('--debug-brk=' + port); + } + + args = args.concat([runFilePath, filePath, this._socketPath, cwd, libCovDir, + this._scopeLeaks, chdir, customAssertModule, testInitFile, + timeout, concurrency, pattern]); + this._testReporter.handleTestFileStart(filePath); + var child = spawn(process.execPath, args); + + if (this._debug) { + var debuggerInterface = new DebuggerInterface(); + debuggerInterface.connect(port, 400, function(err, client) { + // Skip the breakpoint set by debug-brk + client.reqContinue(); + }); + } + + return child; +}; + +TestRunner.prototype._addCompletedTest = function(filePath) { + this._completedTests.push(filePath); +}; + +TestRunner.prototype._handleTestsCompleted = function() { + var statusCode; + + if (!this._completed || this._forceStopped) { + this._completed = true; + this._stopServer(); + + statusCode = this._testReporter.handleTestsComplete(); + + if (this._scopeLeaks) { + this._scopeLeaksReporter.handleTestsComplete(); + } + + if (this._coverage) { + this._coverageReporter.handleTestsComplete(); + } + + exports.exitCode = statusCode; + + if (this._processRunner) { + this._processRunner.stop(); + } + + if (this._debug) { + process.exit(); + } + } +}; + +TestRunner.prototype._handleTestResult = function(filePath, resultObj) { + this._testReporter.handleTestEnd(filePath, resultObj); + + if (this._scopeLeaks) { + this._scopeLeaksReporter.handleTestEnd(filePath, resultObj); + } + + if (this._failfast && resultObj['status'] === 'failure') { + this.forceStop(); + } +}; + +TestRunner.prototype._handleTestCoverageResult = function(filePath, coverageData) { + var coverageObj = JSON.parse(coverageData); + this._coverageReporter.handleTestFileComplete(filePath, coverageObj); +}; + +TestRunner.prototype._handleTestFileEnd = function(filePath) { + var testData, coverageData, resultObj, coverageObj, split, testFile; + var stdout = ''; + var stderr = ''; + + testFile = this._testFilesData[filePath]; + if (testFile) { + stdout = testFile['stdout']; + stderr = testFile['stderr']; + } + + this._testReporter.handleTestFileComplete(filePath, stdout, stderr); + this._addCompletedTest(filePath); + + if (testFile) { + testFile['callback'](); + } +}; + +TestRunner.prototype._handleConnection = function(connection) { + var self = this; + var data = ''; + var lineProcessor = new testUtil.LineProcessor(); + var dataString, endMarkIndex, testFile, testFileCallback, testFileTimeoutId; + + function onLine(line) { + var result, filePath, end, resultObj; + result = testUtil.parseResultLine(line); + end = result[0]; + filePath = result[1]; + resultObj = result[2]; + + if (end) { + return; + } + + if (resultObj.hasOwnProperty('coverage')) { + self._handleTestCoverageResult(filePath, resultObj['coverage']); + } + else { + self._handleTestResult(filePath, resultObj); + } + } + + lineProcessor.on('line', onLine); + + function onData(chunk) { + lineProcessor.appendData(chunk); + data += chunk; + } + + connection.on('data', onData); +}; + +TestRunner.prototype._startServer = function(connectionHandler, + onBound) { + this._server = net.createServer(connectionHandler); + this._server.listen(this._socketPath, onBound); +}; + +TestRunner.prototype.forceStop = function() { + var testFile, testFileData, child, timeoutId; + + this._forceStopped = true; + for (testFile in this._testFilesData) { + if (this._testFilesData.hasOwnProperty(testFile)) { + testFileData = this._testFilesData[testFile]; + child = testFileData['child']; + timeoutId = testFileData['timeout_id']; + clearTimeout(timeoutId); + child.kill('SIGTERM'); + } + } +}; + +TestRunner.prototype._stopServer = function() { + if (this._server) { + this._server.close(); + this._server = null; + } +}; + +function run(cwd, argv) { + var customAssertModule, exportedFunctions; + var runner, testReporter, coverageArgs; + var socketPath, concurrency, scopeLeaks, runnerArgs; + + if ((argv === undefined) && (cwd instanceof Array)) { + argv = cwd; + } + + var p = parser.getParser(constants.WHISKEY_OPTIONS); + p.banner = 'Usage: whiskey [options] --tests "files"'; + var options = parser.parseArgv(p, argv); + + if (options['coverage-files']) { + var coverageReporter = options['coverage-reporter'] || constants.DEFAULT_COVERAGE_REPORTER; + var coverageReporterOptions = { + 'directory': options['coverage-dir'], + 'file': options['coverage-file'] + }; + + this._coverageReporter = getReporter('coverage', + coverageReporter, + [], + coverageReporterOptions); + var coverageObj = coverage.aggregateCoverage(options['coverage-files'].split(',')); + this._coverageReporter.handleTestsComplete(coverageObj); + } + else if (options.tests && options.tests.length > 0) { + options.tests = options.tests.split(' '); + + if (options['debug'] && options.tests.length > 1) { + throw new Error('--debug option can currently only be used with a single test file'); + } + else if (options['gen-makefile'] && options['makefile-path']) { + generateMakefile(options.tests, options['makefile-path'], function(err) { + if (err) { + throw err; + } + + util.puts(sprintf('Makefile has been saved in %s.', options['makefile-path'])); + }); + + return; + } + + customAssertModule = options['custom-assert-module']; + if (customAssertModule) { + customAssertModule = (customAssertModule.charAt(0) !== '/') ? path.join(cwd, customAssertModule) : customAssertModule; + + if (path.existsSync(customAssertModule)) { + customAssertModule = customAssertModule.replace(/$\.js/, ''); + } + else { + customAssertModule = null; + } + } + + concurrency = options['sequential'] ? 1 : options['concurrency']; + concurrency = concurrency || constants.DEFAULT_CONCURRENCY; + scopeLeaks = options['scope-leaks']; + + options['print-stdout'] = (options['quiet']) ? false : true; + options['print-stderr'] = (options['quiet']) ? false : true; + + if (options['quiet']) { + logmagic.registerSink('null', function nullLogger() {}); + logmagic.route('__root__', logmagic.INFO, 'null'); + } + + runner = new TestRunner(options); + runnerArgs = [options['test-init-file'], options['chdir'], + customAssertModule, options['timeout'], + concurrency, options['fail-fast']]; + + + if (options['coverage']) { + var nodePath = process.env['NODE_PATH']; + + if (!nodePath || nodePath.indexOf('lib-cov') === -1) { + throw new Error('lib-cov is not in NODE_PATH. NODE_PATH environment variable' + + ' must contain lib-cov path for the coverage to work.'); + } + + coverageArgs = ['jscoverage']; + + if (options['coverage-encoding']) { + coverageArgs.push(sprintf('--encoding=%s', options['coverage-encoding'])); + } + + if (options['coverage-exclude']) { + coverageArgs.push(sprintf('--exclude=%s', options['coverage-exclude'])); + } + + if (options['coverage-no-instrument']) { + coverageArgs.push(sprintf('--no-instrument=%s', options['coverage-no-instrument'])); + } + + coverageArgs.push(sprintf('lib %s', constants.COVERAGE_PATH)); + coverageArgs = coverageArgs.join(' '); + + if (!path.existsSync(path.join(process.cwd(), constants.COVERAGE_PATH)) || !options['coverage-no-regen']) { + exec(sprintf('rm -fr %s ; %s', constants.COVERAGE_PATH, coverageArgs), function(err) { + if (err) { + if (err.message.match(/jscoverage: not found/i)) { + err = new Error('jscoverage binary not found. To use test coverage ' + + ' you need to install node-jscoverag binary - ' + + 'https://github.com/visionmedia/node-jscoverage'); + } + + throw err; + } + + runner.runTests.apply(runner, runnerArgs); + }); + } + else { + runner.runTests.apply(runner, runnerArgs); + } + } + else { + runner.runTests.apply(runner, runnerArgs); + } + + } + else if (!p._halted) { + console.log(p.banner); + } + + process.on('SIGINT', function onSigint() { + runner.forceStop(); + }); + + process.on('exit', function() { + process.reallyExit(exports.exitCode); + }); +} + +exports.run = run; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/run_test_file.js b/node_modules/cassandra-client/node_modules/whiskey/lib/run_test_file.js new file mode 100644 index 0000000..e2f5c06 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/run_test_file.js @@ -0,0 +1,108 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var path = require('path'); + +var sprintf = require('sprintf').sprintf; + +var common = require('./common'); +var testUtil = require('./util'); +var coverage = require('./coverage'); +var constants = require('./constants'); + +var ARGUMENTS = { + 'test_path': { + 'pos': 2 + }, + 'socket_path': { + 'pos': 3 + }, + 'cwd': { + 'pos': 4 + }, + 'lib_cov_dir': { + 'pos': 5 + }, + 'scope_leaks': { + 'pos': 6 + }, + 'chdir': { + 'pos': 7 + }, + 'custom_assert_module': { + 'pos': 8 + }, + 'init_file': { + 'pos': 9 + }, + 'timeout': { + 'pos': 10, + 'type': 'number' + }, + 'concurrency': { + 'pos': 11, + 'type': 'pos' + }, + 'pattern': { + 'pos': 12 + }, +}; + +if (process.argv.length < 6) { + console.log('No enough argumentes provided'); + process.exit(1); +} + +var args = testUtil.parseArguments(ARGUMENTS, process.argv); + +var testPath = args['test_path']; +var socketPath = args['socket_path']; +var cwd = args['cwd']; +var libCovDir = args['lib_cov_dir']; +var scopeLeaks = args['scope_leaks']; +var chdir = args['chdir']; +var customAssertModule = args['custom_assert_module']; +var testInitFile = args['init_file']; +var timeout = args['timeout']; +var concurrency = args['concurrency']; +var pattern = args['pattern']; + +if (customAssertModule) { + var exportedFunctions = require(customAssertModule.replace(/$\.js/, '')); + common.registerCustomAssertionFunctions(exportedFunctions); +} + +if (chdir && path.existsSync(chdir)) { + process.chdir(chdir); +} + +var options = { 'cwd': cwd, 'socket_path': socketPath, + 'init_file': testInitFile, 'timeout': timeout, + 'concurrency': concurrency, 'scope_leaks': scopeLeaks, + 'pattern': pattern}; +var testFile = new common.TestFile(testPath, options); +testFile.runTests(function onTestFileEnd() { + if (libCovDir && typeof _$jscoverage === 'object') { + testFile._reportTestCoverage(_$jscoverage); + } + + testFile._reportTestFileEnd(); +}); + +process.on('uncaughtException', function(err) { + testFile.addUncaughtException(err); +}); diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/scopeleaks.js b/node_modules/cassandra-client/node_modules/whiskey/lib/scopeleaks.js new file mode 100644 index 0000000..631a086 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/scopeleaks.js @@ -0,0 +1,41 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +function getSnapshot(scope) { + var snapshot = {}; + + for (var item in scope) { + snapshot[item] = true; + } + + return snapshot; +} + +function getDifferences(scopeSnapshot1, scopeSnapshot2) { + var diff = []; + + for (var item in scopeSnapshot2) { + if (scopeSnapshot1[item] === undefined) { + diff.push(item); + } + } + + return diff; +} + +exports.getSnapshot = getSnapshot; +exports.getDifferences = getDifferences; diff --git a/node_modules/cassandra-client/node_modules/whiskey/lib/util.js b/node_modules/cassandra-client/node_modules/whiskey/lib/util.js new file mode 100644 index 0000000..751e68b --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/lib/util.js @@ -0,0 +1,310 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +/* + * lpad and rpad are taken from expresso + * which is MIT licensed. + * Copyright(c) TJ Holowaychuk + */ + +var util = require('util'); +var fs = require('fs'); +var path = require('path'); +var EventEmitter = require('events').EventEmitter; + +var sprintf = require('sprintf').sprintf; +var async = require('async'); + +var constants = require('./constants'); +var errors = require('./errors'); + +var printMsg = function(msg, verbosity, minVerbosity) { + if (verbosity >= minVerbosity) { + util.puts(msg); + } +}; + +var isNullOrUndefined = function(value) { + if (value === null || ((typeof value === 'string') && value === 'null') || + value === undefined || ((typeof value === 'string') && + value === 'undefined')) { + return true; + } + + return false; +}; + +/** + * Call a function and ignore any error thrown. + * + * @param {Function} func Function to call. + * @param {Object} context Context in which the function is called. + * @param {Array} Function argument + * @param {Function} callback Optional callback which is called at the end. + */ +var callIgnoringError = function(func, context, args, callback) { + try { + func.apply(context, args); + } + catch (err) {} + + if (callback) { + callback(); + } +}; + +/** + * Return Unix timestamp. + * + * @return {Number} Unix timestamp. + */ +var getUnixTimestamp = function() { + return (new Date().getTime() / 1000); +}; + +var addCharacters = function(string, width, character) { + var width_ = width || 80; + var character_ = character || ' '; + var stringLen = string.length; + var left = (width_ - stringLen); + + if (left <= 0) { + return string; + } + + while (left--) { + string += character_; + } + + return string; +}; + +/** + * Pad the given string to the maximum width provided. + * + * @param {String} str + * @param {Number} width + * @return {String} + */ +function lpad(str, width) { + str = String(str); + var n = width - str.length; + if (n < 1) return str; + while (n--) str = ' ' + str; + return str; +} + +/** + * Pad the given string to the maximum width provided. + * + * @param {String} str + * @param {Number} width + * @return {String} + */ +function rpad(str, width) { + str = String(str); + var n = width - str.length; + if (n < 1) return str; + while (n--) str = str + ' '; + return str; +} + +function LineProcessor(initialData) { + this._buffer = initialData || ''; +} + +util.inherits(LineProcessor, EventEmitter); + +LineProcessor.prototype.appendData = function(data) { + this._buffer += data; + this._processData(); +}; + +LineProcessor.prototype._processData = function() { + var newLineMarkerIndex, line; + + newLineMarkerIndex = this._buffer.indexOf('\n'); + while (newLineMarkerIndex !== -1) { + line = this._buffer.substring(0, newLineMarkerIndex); + this._buffer = this._buffer.substring(newLineMarkerIndex + 1); + newLineMarkerIndex = this._buffer.indexOf('\n'); + + this.emit('line', line); + } +}; + +function parseResultLine(line) { + // Returns a triple (end, fileName, resultObj) + var startMarkerIndex, endMarkerIndex, testFileEndMarkerIndex; + var coverageEndMarker, split, fileName, resultObj; + + testFileEndMarkerIndex = line.indexOf(constants.TEST_FILE_END_MARKER); + coverageEndMarker = line.indexOf(constants.COVERAGE_END_MARKER); + startMarkerIndex = line.indexOf(constants.TEST_START_MARKER); + endMarkerIndex = line.indexOf(constants.TEST_END_MARKER); + + if (testFileEndMarkerIndex !== -1) { + // end marker + fileName = line.substring(0, testFileEndMarkerIndex); + return [ true, fileName, null ]; + } + else if (coverageEndMarker !== -1) { + // coverage result + split = line.split(constants.DELIMITER); + resultObj = { + 'coverage': split[1].replace(constants.COVERAGE_END_MARKER, '') + }; + + return [ false, split[0], resultObj ]; + } + else { + // test result + line = line.replace(constants.TEST_START_MARKER, '') + .replace(constants.TEST_END_MARKER, ''); + split = line.split(constants.DELIMITER); + resultObj = JSON.parse(split[1]); + + return [ null, split[0], resultObj ]; + } +} + +function isTestFile(filePath) { + var exportedValues, key, value; + + try { + exportedValues = require(filePath); + } + catch (err) { + return false; + } + + for (key in exportedValues) { + if (exportedValues.hasOwnProperty(key)) { + value = exportedValues[key]; + if (key.indexOf('test') === 0 && (typeof value === 'function')) { + return true; + } + } + } + + return false; +} + +/** + * Get files in a directory which match the provided name pattern. + * Note: This function recurses into sub-directories. + * + * @param {String} directory Directory to search. + * @param {String} matchPattern File name match pattern. + * @param {Object} options Optional options object. + * @param {Function} callback Callback called with (err, matchingFilePaths). + */ +function getMatchingFiles(directory, matchPattern, options, callback) { + options = options || {}; + var matchedFiles = [], + recurse = options.recurse || false; + + fs.readdir(directory, function(err, files) { + if (err) { + callback(null, matchedFiles); + return; + } + + async.forEach(files, function(file, callback) { + var filePath = path.join(directory, file); + fs.stat(filePath, function(err, stats) { + if (err) { + callback(); + } + else if (stats.isDirectory() && recurse) { + getMatchingFiles(filePath, matchPattern, options, callback); + } + else if (matchPattern.test(file)) { + matchedFiles.push(filePath); + callback(); + } + else { + callback(); + } + }); + }, + + function(err) { + callback(err, matchedFiles); + }); + }); +}; + +function findTestFiles(basePath, callback) { + getMatchingFiles(basePath, /\.js/, {'recurse': true}, callback); +} + +function parseArguments(rules, args) { + var key, value, rule; + var result = {}; + + for (key in rules) { + if (rules.hasOwnProperty(key)) { + rule = rules[key]; + value = args[rule['pos']]; + + if (isNullOrUndefined(value)) { + value = null; + } + else if (rule['type'] === 'number') { + value = parseInt(value, 10); + } + + result[key] = value; + } + } + + return result; +} + +/** + * Wrap a function so that the original function will only be called once, + * regardless of how many times the wrapper is called. + * @param {Function} fn The to wrap. + * @return {Function} A function which will call fn the first time it is called. + */ +function fireOnce(fn) { + var fired = false; + return function wrapped() { + if (!fired) { + fired = true; + fn.apply(null, arguments); + } + }; +}; + + +exports.printMsg = printMsg; +exports.isNullOrUndefined = isNullOrUndefined; + +exports.getUnixTimestamp = getUnixTimestamp; +exports.addCharacters = addCharacters; + +exports.rpad = rpad; +exports.lpad = lpad; + +exports.LineProcessor = LineProcessor; +exports.parseResultLine = parseResultLine; +exports.getMatchingFiles = getMatchingFiles; +exports.findTestFiles = findTestFiles; +exports.parseArguments = parseArguments; +exports.fireOnce = fireOnce; diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/README.md b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/README.md new file mode 100644 index 0000000..bf67c9c --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/README.md @@ -0,0 +1,84 @@ +# gex + +If you're using this library, feel free to contact me on twitter if you have any questions! :) [@rjrodger](http://twitter.com/rjrodger) + +Current Version: 0.0.1 + +Tested on: node 0.4.1 + +Glob expressions for JavaScript + +*"When regular expressions are just too hard!"* + +Match glob expressions using * and ? against any JavaScript data type. +The character * means match anything of any length, the character ? means match exactly one of any character, +and all other characters match themselves. + + var gex = require('gex') + + gex('a*').on( 'abc' ) // returns 'abc' + gex('a*c').on( 'abbbc' ) // returns 'abbbc' + gex('a?c').on( 'abc' ) // returns 'abc' + +You can also match against objects and arrays: + + gex('a*').on( ['ab','zz','ac'] ) // returns ['ab','ac'] + gex('a*').on( {ab:1,zz:2,ac:3} ) // returns {ab:1,ac:3} + +One of the most useful things you can do with this library is quick +assertions in unit tests. For example if your objects contain dates, +randomly generated unique identifiers, or other data irrelevant for +testing, `gex` can help you ignore them when you use `JSON.stringify`: + + var entity = {created: new Date().getTime(), name:'foo' } + assert.ok( gex('{"created":*,"name":"foo"}').on( JSON.stringify(entity) ) ) + +If you need to use globbing on files, here's how apply a glob to a list of files in a folder: + + var fs = require('fs') + fs.readdir('.',function(err,files){ + var pngs = gex('*.png').on(files) + }) + +And that's it! + + +## Installation + + npm install gex + +And in your code: + + var gex = require('gex') + +Or clone the git repository: + git clone git://github.com/rjrodger/gex.git + + +This library depends on the excellent underscore module: [underscore](https://github.com/documentcloud/underscore) + + +## Usage + +The `gex` object is a function that takes a single argument, the glob +expression. This returns a `Gex` object that has only one function +itself: `on`. The `on` function accepts any JavaScript data type, and operates as follows: + + * strings, numbers, booleans, dates, regexes: converted to string form for matching, returned as themselves + * arrays: return a new array with all the elements that matched. Elements are not modified, but are converted to strings for matching. Does not recurse into elements. + * objects: return a new object with with all the property *names* that matched. Values are copied by reference. + * null, NAN, undefined: never match anything + +## Testing + +The unit tests use [expresso](https://github.com/visionmedia/expresso) + + npm install expresso + +The tests are in test/gex.test.js + + +## Hacking around with real time charts + +![](http://chartaca.com/point/adb6995d-b4b3-4edf-8892-a6d1a2324831/s.gif) +[Chartaca Hit Chart](http://chartaca.com/adb6995d-b4b3-4edf-8892-a6d1a2324831) diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/lib/gex.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/lib/gex.js new file mode 100644 index 0000000..8d6dbf1 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/lib/gex.js @@ -0,0 +1,82 @@ + +var _ = require('underscore') + + +function Gex(gexexp) { + var self = this + + var gexstr = ''+gexexp + if( _.isNull(gexexp) + || _.isNaN(gexexp) + || _.isUndefined(gexexp) ) { + gexstr = '' + } + + gexstr = gexstr.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + gexstr = gexstr.replace(/\\\*/g,'.*') + gexstr = gexstr.replace(/\\\?/g,'.') + gexstr = '^'+gexstr+'$' + + var re = new RegExp(gexstr) + + + function dodgy(obj) { + return ( _.isNull(obj) + || _.isNaN(obj) + || _.isUndefined(obj) ) + } + + self.on = function(obj) { + if( _.isString(obj) + || _.isNumber(obj) + || _.isBoolean(obj) + || _.isDate(obj) + || _.isRegExp(obj) + ) + { + return (!!re.exec(''+obj)) ? obj : null + } + + else if( _.isArray(obj) + || _.isArguments(obj) + ) { + var out = [] + for( var i = 0; i < obj.length; i++ ) { + if( !dodgy(obj[i]) && !!re.exec(''+obj[i]) ) { + out.push(obj[i]) + } + } + return out + } + + else if( dodgy(obj) ) { + return null + } + + else if( 'object' == typeof(obj) ) { + var out = {} + for( var p in obj ) { + if( obj.hasOwnProperty(p) ) { + if( !!re.exec(p) ) { + out[p] = obj[p] + } + } + } + return out + } + + else { + return null + } + } +} + + +function gex(gexexp) { + var gex = new Gex(gexexp) + return gex +} +gex.Gex = Gex + + +module.exports = gex \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/.npmignore b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/.npmignore new file mode 100644 index 0000000..2ce2684 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/.npmignore @@ -0,0 +1,3 @@ +test/ +Rakefile +docs/ \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/LICENSE b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/LICENSE new file mode 100644 index 0000000..61d28c0 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2009-2012 Jeremy Ashkenas, DocumentCloud + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/README.md b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/README.md new file mode 100644 index 0000000..a6564a2 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/README.md @@ -0,0 +1,19 @@ + __ + /\ \ __ + __ __ ___ \_\ \ __ _ __ ____ ___ ___ _ __ __ /\_\ ____ + /\ \/\ \ /' _ `\ /'_ \ /'__`\/\ __\/ ,__\ / ___\ / __`\/\ __\/'__`\ \/\ \ /',__\ + \ \ \_\ \/\ \/\ \/\ \ \ \/\ __/\ \ \//\__, `\/\ \__//\ \ \ \ \ \//\ __/ __ \ \ \/\__, `\ + \ \____/\ \_\ \_\ \___,_\ \____\\ \_\\/\____/\ \____\ \____/\ \_\\ \____\/\_\ _\ \ \/\____/ + \/___/ \/_/\/_/\/__,_ /\/____/ \/_/ \/___/ \/____/\/___/ \/_/ \/____/\/_//\ \_\ \/___/ + \ \____/ + \/___/ + +Underscore.js is a utility-belt library for JavaScript that provides +support for the usual functional suspects (each, map, reduce, filter...) +without extending any core JavaScript objects. + +For Docs, License, Tests, and pre-packed downloads, see: +http://documentcloud.github.com/underscore/ + +Many thanks to our contributors: +https://github.com/documentcloud/underscore/contributors diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/index.html b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/index.html new file mode 100644 index 0000000..52c9671 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/index.html @@ -0,0 +1,1975 @@ + + + + + + Underscore.js + + + + + + +
+ +

+ Underscore.js +

+ +

+ Underscore is a + utility-belt library for JavaScript that provides a lot of the + functional programming support that you would expect in + Prototype.js + (or Ruby), + but without extending any of the built-in JavaScript objects. It's the + tie to go along with jQuery's tux, + and Backbone.js's suspenders. +

+ +

+ Underscore provides 60-odd functions that support both the usual + functional suspects: map, select, invoke — + as well as more specialized helpers: function binding, javascript + templating, deep equality testing, and so on. It delegates to built-in + functions, if present, so modern browsers will use the + native implementations of forEach, map, reduce, + filter, every, some and indexOf. +

+ +

+ A complete Test & Benchmark Suite + is included for your perusal. +

+ +

+ You may also read through the annotated source code. +

+ +

+ The project is + hosted on GitHub. + You can report bugs and discuss features on the + issues page, + on Freenode in the #documentcloud channel, + or send tweets to @documentcloud. +

+ +

+ Underscore is an open-source component of DocumentCloud. +

+ +

Downloads (Right-click, and use "Save As")

+ + + + + + + + + + +
Development Version (1.3.1)34kb, Uncompressed with Comments
Production Version (1.3.1)< 4kb, Minified and Gzipped
+ +
Upgrade warning: version 1.3.0 removes AMD (RequireJS) support.
+ +
+ +

Collection Functions (Arrays or Objects)

+ +

+ each_.each(list, iterator, [context]) + Alias: forEach +
+ Iterates over a list of elements, yielding each in turn to an iterator + function. The iterator is bound to the context object, if one is + passed. Each invocation of iterator is called with three arguments: + (element, index, list). If list is a JavaScript object, iterator's + arguments will be (value, key, list). Delegates to the native + forEach function if it exists. +

+
+_.each([1, 2, 3], function(num){ alert(num); });
+=> alerts each number in turn...
+_.each({one : 1, two : 2, three : 3}, function(num, key){ alert(num); });
+=> alerts each number in turn...
+ +

+ map_.map(list, iterator, [context]) + Alias: collect +
+ Produces a new array of values by mapping each value in list + through a transformation function (iterator). If the native map method + exists, it will be used instead. If list is a JavaScript object, + iterator's arguments will be (value, key, list). +

+
+_.map([1, 2, 3], function(num){ return num * 3; });
+=> [3, 6, 9]
+_.map({one : 1, two : 2, three : 3}, function(num, key){ return num * 3; });
+=> [3, 6, 9]
+ +

+ reduce_.reduce(list, iterator, memo, [context]) + Aliases: inject, foldl +
+ Also known as inject and foldl, reduce boils down a + list of values into a single value. Memo is the initial state + of the reduction, and each successive step of it should be returned by + iterator. +

+
+var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
+=> 6
+
+ +

+ reduceRight_.reduceRight(list, iterator, memo, [context]) + Alias: foldr +
+ The right-associative version of reduce. Delegates to the + JavaScript 1.8 version of reduceRight, if it exists. Foldr + is not as useful in JavaScript as it would be in a language with lazy + evaluation. +

+
+var list = [[0, 1], [2, 3], [4, 5]];
+var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
+=> [4, 5, 2, 3, 0, 1]
+
+ +

+ find_.find(list, iterator, [context]) + Alias: detect +
+ Looks through each value in the list, returning the first one that + passes a truth test (iterator). The function returns as + soon as it finds an acceptable element, and doesn't traverse the + entire list. +

+
+var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
+=> 2
+
+ +

+ filter_.filter(list, iterator, [context]) + Alias: select +
+ Looks through each value in the list, returning an array of all + the values that pass a truth test (iterator). Delegates to the + native filter method, if it exists. +

+
+var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
+=> [2, 4, 6]
+
+ +

+ reject_.reject(list, iterator, [context]) +
+ Returns the values in list without the elements that the truth + test (iterator) passes. The opposite of filter. +

+
+var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
+=> [1, 3, 5]
+
+ +

+ all_.all(list, iterator, [context]) + Alias: every +
+ Returns true if all of the values in the list pass the iterator + truth test. Delegates to the native method every, if present. +

+
+_.all([true, 1, null, 'yes'], _.identity);
+=> false
+
+ +

+ any_.any(list, [iterator], [context]) + Alias: some +
+ Returns true if any of the values in the list pass the + iterator truth test. Short-circuits and stops traversing the list + if a true element is found. Delegates to the native method some, + if present. +

+
+_.any([null, 0, 'yes', false]);
+=> true
+
+ +

+ include_.include(list, value) + Alias: contains +
+ Returns true if the value is present in the list, using + === to test equality. Uses indexOf internally, if list + is an Array. +

+
+_.include([1, 2, 3], 3);
+=> true
+
+ +

+ invoke_.invoke(list, methodName, [*arguments]) +
+ Calls the method named by methodName on each value in the list. + Any extra arguments passed to invoke will be forwarded on to the + method invocation. +

+
+_.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
+=> [[1, 5, 7], [1, 2, 3]]
+
+ +

+ pluck_.pluck(list, propertyName) +
+ A convenient version of what is perhaps the most common use-case for + map: extracting a list of property values. +

+
+var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
+_.pluck(stooges, 'name');
+=> ["moe", "larry", "curly"]
+
+ +

+ max_.max(list, [iterator], [context]) +
+ Returns the maximum value in list. If iterator is passed, + it will be used on each value to generate the criterion by which the + value is ranked. +

+
+var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
+_.max(stooges, function(stooge){ return stooge.age; });
+=> {name : 'curly', age : 60};
+
+ +

+ min_.min(list, [iterator], [context]) +
+ Returns the minimum value in list. If iterator is passed, + it will be used on each value to generate the criterion by which the + value is ranked. +

+
+var numbers = [10, 5, 100, 2, 1000];
+_.min(numbers);
+=> 2
+
+ +

+ sortBy_.sortBy(list, iterator, [context]) +
+ Returns a sorted copy of list, ranked in ascending order by the + results of running each value through iterator. +

+
+_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
+=> [5, 4, 6, 3, 1, 2]
+
+ +

+ groupBy_.groupBy(list, iterator) +
+ Splits a collection into sets, grouped by the result of running each + value through iterator. If iterator is a string instead of + a function, groups by the property named by iterator on each of + the values. +

+
+_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });
+=> {1: [1.3], 2: [2.1, 2.4]}
+
+_.groupBy(['one', 'two', 'three'], 'length');
+=> {3: ["one", "two"], 5: ["three"]}
+
+ +

+ sortedIndex_.sortedIndex(list, value, [iterator]) +
+ Uses a binary search to determine the index at which the value + should be inserted into the list in order to maintain the list's + sorted order. If an iterator is passed, it will be used to compute + the sort ranking of each value. +

+
+_.sortedIndex([10, 20, 30, 40, 50], 35);
+=> 3
+
+ +

+ shuffle_.shuffle(list) +
+ Returns a shuffled copy of the list, using a version of the + Fisher-Yates shuffle. +

+
+_.shuffle([1, 2, 3, 4, 5, 6]);
+=> [4, 1, 6, 3, 5, 2]
+
+ +

+ toArray_.toArray(list) +
+ Converts the list (anything that can be iterated over), into a + real Array. Useful for transmuting the arguments object. +

+
+(function(){ return _.toArray(arguments).slice(0); })(1, 2, 3);
+=> [1, 2, 3]
+
+ +

+ size_.size(list) +
+ Return the number of values in the list. +

+
+_.size({one : 1, two : 2, three : 3});
+=> 3
+
+ +

Array Functions

+ +

+ Note: All array functions will also work on the arguments object. +

+ +

+ first_.first(array, [n]) + Alias: head +
+ Returns the first element of an array. Passing n will + return the first n elements of the array. +

+
+_.first([5, 4, 3, 2, 1]);
+=> 5
+
+ +

+ initial_.initial(array, [n]) +
+ Returns everything but the last entry of the array. Especially useful on + the arguments object. Pass n to exclude the last n elements + from the result. +

+
+_.initial([5, 4, 3, 2, 1]);
+=> [5, 4, 3, 2]
+
+ +

+ last_.last(array, [n]) +
+ Returns the last element of an array. Passing n will return + the last n elements of the array. +

+
+_.last([5, 4, 3, 2, 1]);
+=> 1
+
+ +

+ rest_.rest(array, [index]) + Alias: tail +
+ Returns the rest of the elements in an array. Pass an index + to return the values of the array from that index onward. +

+
+_.rest([5, 4, 3, 2, 1]);
+=> [4, 3, 2, 1]
+
+ +

+ compact_.compact(array) +
+ Returns a copy of the array with all falsy values removed. + In JavaScript, false, null, 0, "", + undefined and NaN are all falsy. +

+
+_.compact([0, 1, false, 2, '', 3]);
+=> [1, 2, 3]
+
+ +

+ flatten_.flatten(array, [shallow]) +
+ Flattens a nested array (the nesting can be to any depth). If you + pass shallow, the array will only be flattened a single level. +

+
+_.flatten([1, [2], [3, [[4]]]]);
+=> [1, 2, 3, 4];
+
+_.flatten([1, [2], [3, [[4]]]], true);
+=> [1, 2, 3, [[4]]];
+
+ +

+ without_.without(array, [*values]) +
+ Returns a copy of the array with all instances of the values + removed. === is used for the equality test. +

+
+_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
+=> [2, 3, 4]
+
+ +

+ union_.union(*arrays) +
+ Computes the union of the passed-in arrays: the list of unique items, + in order, that are present in one or more of the arrays. +

+
+_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
+=> [1, 2, 3, 101, 10]
+
+ +

+ intersection_.intersection(*arrays) +
+ Computes the list of values that are the intersection of all the arrays. + Each value in the result is present in each of the arrays. +

+
+_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
+=> [1, 2]
+
+ +

+ difference_.difference(array, *others) +
+ Similar to without, but returns the values from array that + are not present in the other arrays. +

+
+_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
+=> [1, 3, 4]
+
+ +

+ uniq_.uniq(array, [isSorted], [iterator]) + Alias: unique +
+ Produces a duplicate-free version of the array, using === to test + object equality. If you know in advance that the array is sorted, + passing true for isSorted will run a much faster algorithm. + If you want to compute unique items based on a transformation, pass an + iterator function. +

+
+_.uniq([1, 2, 1, 3, 1, 4]);
+=> [1, 2, 3, 4]
+
+ +

+ zip_.zip(*arrays) +
+ Merges together the values of each of the arrays with the + values at the corresponding position. Useful when you have separate + data sources that are coordinated through matching array indexes. + If you're working with a matrix of nested arrays, zip.apply + can transpose the matrix in a similar fashion. +

+
+_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
+=> [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]
+
+ +

+ indexOf_.indexOf(array, value, [isSorted]) +
+ Returns the index at which value can be found in the array, + or -1 if value is not present in the array. Uses the native + indexOf function unless it's missing. If you're working with a + large array, and you know that the array is already sorted, pass true + for isSorted to use a faster binary search. +

+
+_.indexOf([1, 2, 3], 2);
+=> 1
+
+ +

+ lastIndexOf_.lastIndexOf(array, value) +
+ Returns the index of the last occurrence of value in the array, + or -1 if value is not present. Uses the native lastIndexOf + function if possible. +

+
+_.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
+=> 4
+
+ +

+ range_.range([start], stop, [step]) +
+ A function to create flexibly-numbered lists of integers, handy for + each and map loops. start, if omitted, defaults + to 0; step defaults to 1. Returns a list of integers + from start to stop, incremented (or decremented) by step, + exclusive. +

+
+_.range(10);
+=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+_.range(1, 11);
+=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+_.range(0, 30, 5);
+=> [0, 5, 10, 15, 20, 25]
+_.range(0, -10, -1);
+=> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
+_.range(0);
+=> []
+
+ +

Function (uh, ahem) Functions

+ +

+ bind_.bind(function, object, [*arguments]) +
+ Bind a function to an object, meaning that whenever + the function is called, the value of this will be the object. + Optionally, bind arguments to the function to pre-fill them, + also known as partial application. +

+
+var func = function(greeting){ return greeting + ': ' + this.name };
+func = _.bind(func, {name : 'moe'}, 'hi');
+func();
+=> 'hi: moe'
+
+ +

+ bindAll_.bindAll(object, [*methodNames]) +
+ Binds a number of methods on the object, specified by + methodNames, to be run in the context of that object whenever they + are invoked. Very handy for binding functions that are going to be used + as event handlers, which would otherwise be invoked with a fairly useless + this. If no methodNames are provided, all of the object's + function properties will be bound to it. +

+
+var buttonView = {
+  label   : 'underscore',
+  onClick : function(){ alert('clicked: ' + this.label); },
+  onHover : function(){ console.log('hovering: ' + this.label); }
+};
+_.bindAll(buttonView);
+jQuery('#underscore_button').bind('click', buttonView.onClick);
+=> When the button is clicked, this.label will have the correct value...
+
+ +

+ memoize_.memoize(function, [hashFunction]) +
+ Memoizes a given function by caching the computed result. Useful + for speeding up slow-running computations. If passed an optional + hashFunction, it will be used to compute the hash key for storing + the result, based on the arguments to the original function. The default + hashFunction just uses the first argument to the memoized function + as the key. +

+
+var fibonacci = _.memoize(function(n) {
+  return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
+});
+
+ +

+ delay_.delay(function, wait, [*arguments]) +
+ Much like setTimeout, invokes function after wait + milliseconds. If you pass the optional arguments, they will be + forwarded on to the function when it is invoked. +

+
+var log = _.bind(console.log, console);
+_.delay(log, 1000, 'logged later');
+=> 'logged later' // Appears after one second.
+
+ +

+ defer_.defer(function) +
+ Defers invoking the function until the current call stack has cleared, + similar to using setTimeout with a delay of 0. Useful for performing + expensive computations or HTML rendering in chunks without blocking the UI thread + from updating. +

+
+_.defer(function(){ alert('deferred'); });
+// Returns from the function before the alert runs.
+
+ +

+ throttle_.throttle(function, wait) +
+ Creates and returns a new, throttled version of the passed function, + that, when invoked repeatedly, will only actually call the original function + at most once per every wait + milliseconds. Useful for rate-limiting events that occur faster than you + can keep up with. +

+
+var throttled = _.throttle(updatePosition, 100);
+$(window).scroll(throttled);
+
+ +

+ debounce_.debounce(function, wait) +
+ Creates and returns a new debounced version of the passed function that + will postpone its execution until after + wait milliseconds have elapsed since the last time it + was invoked. Useful for implementing behavior that should only happen + after the input has stopped arriving. For example: rendering a + preview of a Markdown comment, recalculating a layout after the window + has stopped being resized, and so on. +

+
+var lazyLayout = _.debounce(calculateLayout, 300);
+$(window).resize(lazyLayout);
+
+ +

+ once_.once(function) +
+ Creates a version of the function that can only be called one time. + Repeated calls to the modified function will have no effect, returning + the value from the original call. Useful for initialization functions, + instead of having to set a boolean flag and then check it later. +

+
+var initialize = _.once(createApplication);
+initialize();
+initialize();
+// Application is only created once.
+
+ +

+ after_.after(count, function) +
+ Creates a version of the function that will only be run after first + being called count times. Useful for grouping asynchronous responses, + where you want to be sure that all the async calls have finished, before + proceeding. +

+
+var renderNotes = _.after(notes.length, render);
+_.each(notes, function(note) {
+  note.asyncSave({success: renderNotes}); 
+});
+// renderNotes is run once, after all notes have saved.
+
+ +

+ wrap_.wrap(function, wrapper) +
+ Wraps the first function inside of the wrapper function, + passing it as the first argument. This allows the wrapper to + execute code before and after the function runs, adjust the arguments, + and execute it conditionally. +

+
+var hello = function(name) { return "hello: " + name; };
+hello = _.wrap(hello, function(func) {
+  return "before, " + func("moe") + ", after";
+});
+hello();
+=> 'before, hello: moe, after'
+
+ +

+ compose_.compose(*functions) +
+ Returns the composition of a list of functions, where each function + consumes the return value of the function that follows. In math terms, + composing the functions f(), g(), and h() produces + f(g(h())). +

+
+var greet    = function(name){ return "hi: " + name; };
+var exclaim  = function(statement){ return statement + "!"; };
+var welcome = _.compose(exclaim, greet);
+welcome('moe');
+=> 'hi: moe!'
+
+ +

Object Functions

+ +

+ keys_.keys(object) +
+ Retrieve all the names of the object's properties. +

+
+_.keys({one : 1, two : 2, three : 3});
+=> ["one", "two", "three"]
+
+ +

+ values_.values(object) +
+ Return all of the values of the object's properties. +

+
+_.values({one : 1, two : 2, three : 3});
+=> [1, 2, 3]
+
+ +

+ functions_.functions(object) + Alias: methods +
+ Returns a sorted list of the names of every method in an object — + that is to say, the name of every function property of the object. +

+
+_.functions(_);
+=> ["all", "any", "bind", "bindAll", "clone", "compact", "compose" ...
+
+ +

+ extend_.extend(destination, *sources) +
+ Copy all of the properties in the source objects over to the + destination object. It's in-order, so the last source will override + properties of the same name in previous arguments. +

+
+_.extend({name : 'moe'}, {age : 50});
+=> {name : 'moe', age : 50}
+
+ +

+ defaults_.defaults(object, *defaults) +
+ Fill in missing properties in object with default values from the + defaults objects. As soon as the property is filled, further defaults + will have no effect. +

+
+var iceCream = {flavor : "chocolate"};
+_.defaults(iceCream, {flavor : "vanilla", sprinkles : "lots"});
+=> {flavor : "chocolate", sprinkles : "lots"}
+
+ +

+ clone_.clone(object) +
+ Create a shallow-copied clone of the object. Any nested objects + or arrays will be copied by reference, not duplicated. +

+
+_.clone({name : 'moe'});
+=> {name : 'moe'};
+
+ +

+ tap_.tap(object, interceptor) +
+ Invokes interceptor with the object, and then returns object. + The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain. +

+
+_.chain([1,2,3,200])
+  .filter(function(num) { return num % 2 == 0; })
+  .tap(console.log)
+  .map(function(num) { return num * num })
+  .value();
+=> [2, 200]
+=> [4, 40000]
+
+ +

+ has_.has(object, key) +
+ Does the object contain the given key? Identical to + object.hasOwnProperty(key), but uses a safe reference to the + hasOwnProperty function, in case it's been + overridden accidentally. +

+
+_.has({a: 1, b: 2, c: 3}, "b");
+=> true
+
+ +

+ isEqual_.isEqual(object, other) +
+ Performs an optimized deep comparison between the two objects, to determine + if they should be considered equal. +

+
+var moe   = {name : 'moe', luckyNumbers : [13, 27, 34]};
+var clone = {name : 'moe', luckyNumbers : [13, 27, 34]};
+moe == clone;
+=> false
+_.isEqual(moe, clone);
+=> true
+
+ +

+ isEmpty_.isEmpty(object) +
+ Returns true if object contains no values. +

+
+_.isEmpty([1, 2, 3]);
+=> false
+_.isEmpty({});
+=> true
+
+ +

+ isElement_.isElement(object) +
+ Returns true if object is a DOM element. +

+
+_.isElement(jQuery('body')[0]);
+=> true
+
+ +

+ isArray_.isArray(object) +
+ Returns true if object is an Array. +

+
+(function(){ return _.isArray(arguments); })();
+=> false
+_.isArray([1,2,3]);
+=> true
+
+ +

+ isArguments_.isArguments(object) +
+ Returns true if object is an Arguments object. +

+
+(function(){ return _.isArguments(arguments); })(1, 2, 3);
+=> true
+_.isArguments([1,2,3]);
+=> false
+
+ +

+ isFunction_.isFunction(object) +
+ Returns true if object is a Function. +

+
+_.isFunction(alert);
+=> true
+
+ +

+ isString_.isString(object) +
+ Returns true if object is a String. +

+
+_.isString("moe");
+=> true
+
+ +

+ isNumber_.isNumber(object) +
+ Returns true if object is a Number (including NaN). +

+
+_.isNumber(8.4 * 5);
+=> true
+
+ +

+ isBoolean_.isBoolean(object) +
+ Returns true if object is either true or false. +

+
+_.isBoolean(null);
+=> false
+
+ +

+ isDate_.isDate(object) +
+ Returns true if object is a Date. +

+
+_.isDate(new Date());
+=> true
+
+ +

+ isRegExp_.isRegExp(object) +
+ Returns true if object is a RegExp. +

+
+_.isRegExp(/moe/);
+=> true
+
+ +

+ isNaN_.isNaN(object) +
+ Returns true if object is NaN.
Note: this is not + the same as the native isNaN function, which will also return + true if the variable is undefined. +

+
+_.isNaN(NaN);
+=> true
+isNaN(undefined);
+=> true
+_.isNaN(undefined);
+=> false
+
+ +

+ isNull_.isNull(object) +
+ Returns true if the value of object is null. +

+
+_.isNull(null);
+=> true
+_.isNull(undefined);
+=> false
+
+ +

+ isUndefined_.isUndefined(variable) +
+ Returns true if variable is undefined. +

+
+_.isUndefined(window.missingVariable);
+=> true
+
+ +

Utility Functions

+ +

+ noConflict_.noConflict() +
+ Give control of the "_" variable back to its previous owner. Returns + a reference to the Underscore object. +

+
+var underscore = _.noConflict();
+ +

+ identity_.identity(value) +
+ Returns the same value that is used as the argument. In math: + f(x) = x
+ This function looks useless, but is used throughout Underscore as + a default iterator. +

+
+var moe = {name : 'moe'};
+moe === _.identity(moe);
+=> true
+ +

+ times_.times(n, iterator) +
+ Invokes the given iterator function n times. +

+
+_(3).times(function(){ genie.grantWish(); });
+ +

+ mixin_.mixin(object) +
+ Allows you to extend Underscore with your own utility functions. Pass + a hash of {name: function} definitions to have your functions + added to the Underscore object, as well as the OOP wrapper. +

+
+_.mixin({
+  capitalize : function(string) {
+    return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase();
+  }
+});
+_("fabio").capitalize();
+=> "Fabio"
+
+ +

+ uniqueId_.uniqueId([prefix]) +
+ Generate a globally-unique id for client-side models or DOM elements + that need one. If prefix is passed, the id will be appended to it. +

+
+_.uniqueId('contact_');
+=> 'contact_104'
+ +

+ escape_.escape(string) +
+ Escapes a string for insertion into HTML, replacing + &, <, >, ", ', and / characters. +

+
+_.escape('Curly, Larry & Moe');
+=> "Curly, Larry &amp; Moe"
+ +

+ template_.template(templateString, [context]) +
+ Compiles JavaScript templates into functions that can be evaluated + for rendering. Useful for rendering complicated bits of HTML from JSON + data sources. Template functions can both interpolate variables, using
+ <%= … %>, as well as execute arbitrary JavaScript code, with + <% … %>. If you wish to interpolate a value, and have + it be HTML-escaped, use <%- … %> When you evaluate a template function, pass in a + context object that has properties corresponding to the template's free + variables. If you're writing a one-off, you can pass the context + object as the second parameter to template in order to render + immediately instead of returning a template function. +

+
+var compiled = _.template("hello: <%= name %>");
+compiled({name : 'moe'});
+=> "hello: moe"
+
+var list = "<% _.each(people, function(name) { %> <li><%= name %></li> <% }); %>";
+_.template(list, {people : ['moe', 'curly', 'larry']});
+=> "<li>moe</li><li>curly</li><li>larry</li>"
+
+var template = _.template("<b><%- value %></b>");
+template({value : '<script>'});
+=> "<b>&lt;script&gt;</b>"
+ +

+ You can also use print from within JavaScript code. This is + sometimes more convenient than using <%= ... %>. +

+ +
+var compiled = _.template("<% print('Hello ' + epithet); %>");
+compiled({epithet: "stooge"});
+=> "Hello stooge."
+ +

+ If ERB-style delimiters aren't your cup of tea, you can change Underscore's + template settings to use different symbols to set off interpolated code. + Define an interpolate regex to match expressions that should be + interpolated verbatim, an escape regex to match expressions that should + be inserted after being HTML escaped, and an evaluate regex to match + expressions that should be evaluated without insertion into the resulting + string. You may define or omit any combination of the three. + For example, to perform + Mustache.js + style templating: +

+ +
+_.templateSettings = {
+  interpolate : /\{\{(.+?)\}\}/g
+};
+
+var template = _.template("Hello {{ name }}!");
+template({name : "Mustache"});
+=> "Hello Mustache!"
+ + +

Chaining

+ +

+ You can use Underscore in either an object-oriented or a functional style, + depending on your preference. The following two lines of code are + identical ways to double a list of numbers. +

+ +
+_.map([1, 2, 3], function(n){ return n * 2; });
+_([1, 2, 3]).map(function(n){ return n * 2; });
+ +

+ Using the object-oriented style allows you to chain together methods. Calling + chain on a wrapped object will cause all future method calls to + return wrapped objects as well. When you've finished the computation, + use value to retrieve the final value. Here's an example of chaining + together a map/flatten/reduce, in order to get the word count of + every word in a song. +

+ +
+var lyrics = [
+  {line : 1, words : "I'm a lumberjack and I'm okay"},
+  {line : 2, words : "I sleep all night and I work all day"},
+  {line : 3, words : "He's a lumberjack and he's okay"},
+  {line : 4, words : "He sleeps all night and he works all day"}
+];
+
+_.chain(lyrics)
+  .map(function(line) { return line.words.split(' '); })
+  .flatten()
+  .reduce(function(counts, word) {
+    counts[word] = (counts[word] || 0) + 1;
+    return counts;
+}, {}).value();
+
+=> {lumberjack : 2, all : 4, night : 2 ... }
+ +

+ In addition, the + Array prototype's methods + are proxied through the chained Underscore object, so you can slip a + reverse or a push into your chain, and continue to + modify the array. +

+ +

+ chain_.chain(obj) +
+ Returns a wrapped object. Calling methods on this object will continue + to return wrapped objects until value is used. +

+
+var stooges = [{name : 'curly', age : 25}, {name : 'moe', age : 21}, {name : 'larry', age : 23}];
+var youngest = _.chain(stooges)
+  .sortBy(function(stooge){ return stooge.age; })
+  .map(function(stooge){ return stooge.name + ' is ' + stooge.age; })
+  .first()
+  .value();
+=> "moe is 21"
+
+ +

+ value_(obj).value() +
+ Extracts the value of a wrapped object. +

+
+_([1, 2, 3]).value();
+=> [1, 2, 3]
+
+ + + +

+ Underscore.lua, + a Lua port of the functions that are applicable in both languages. + Includes OOP-wrapping and chaining. + The source is + available on GitHub. +

+ +

+ Underscore.php, + a PHP port of the functions that are applicable in both languages. + Includes OOP-wrapping and chaining. + The source is + available on GitHub. +

+ +

+ Underscore-perl, + a Perl port of many of the Underscore.js functions, + aimed at on Perl hashes and arrays, also + available on GitHub. +

+ +

+ Underscore.string, + an Underscore extension that adds functions for string-manipulation: + trim, startsWith, contains, capitalize, + reverse, sprintf, and more. +

+ +

+ Ruby's Enumerable module. +

+ +

+ Prototype.js, which provides + JavaScript with collection functions in the manner closest to Ruby's Enumerable. +

+ +

+ Oliver Steele's + Functional JavaScript, + which includes comprehensive higher-order function support as well as string lambdas. +

+ +

+ Michael Aufreiter's Data.js, + a data manipulation + persistence library for JavaScript. +

+ +

+ Python's itertools. +

+ +

Change Log

+ +

+ 1.3.1Jan. 23, 2012
+

    +
  • + Added an _.has function, as a safer way to use hasOwnProperty. +
  • +
  • + Added _.collect as an alias for _.map. Smalltalkers, rejoice. +
  • +
  • + Reverted an old change so that _.extend will correctly copy + over keys with undefined values again. +
  • +
  • + Bugfix to stop escaping slashes within interpolations in _.template. +
  • +
+

+ +

+ 1.3.0Jan. 11, 2012
+

    +
  • + Removed AMD (RequireJS) support from Underscore. If you'd like to use + Underscore with RequireJS, you can load it as a normal script, wrap + or patch your copy, or download a forked version. +
  • +
+

+ +

+ 1.2.4Jan. 4, 2012
+

    +
  • + You now can (and probably should) write _.chain(list) + instead of _(list).chain(). +
  • +
  • + Fix for escaped characters in Underscore templates, and for supporting + customizations of _.templateSettings that only define one or + two of the required regexes. +
  • +
  • + Fix for passing an array as the first argument to an _.wrap'd function. +
  • +
  • + Improved compatibility with ClojureScript, which adds a call + function to String.prototype. +
  • +
+

+ +

+ 1.2.3Dec. 7, 2011
+

    +
  • + Dynamic scope is now preserved for compiled _.template functions, + so you can use the value of this if you like. +
  • +
  • + Sparse array support of _.indexOf, _.lastIndexOf. +
  • +
  • + Both _.reduce and _.reduceRight can now be passed an + explicitly undefined value. (There's no reason why you'd + want to do this.) +
  • +
+

+ +

+ 1.2.2Nov. 14, 2011
+

    +
  • + Continued tweaks to _.isEqual semantics. Now JS primitives are + considered equivalent to their wrapped versions, and arrays are compared + by their numeric properties only (#351). +
  • +
  • + _.escape no longer tries to be smart about not double-escaping + already-escaped HTML entities. Now it just escapes regardless (#350). +
  • +
  • + In _.template, you may now leave semicolons out of evaluated + statements if you wish: <% }) %> (#369). +
  • +
  • + _.after(callback, 0) will now trigger the callback immediately, + making "after" easier to use with asynchronous APIs (#366). +
  • +
+

+ +

+ 1.2.1Oct. 24, 2011
+

    +
  • + Several important bug fixes for _.isEqual, which should now + do better on mutated Arrays, and on non-Array objects with + length properties. (#329) +
  • +
  • + jrburke contributed Underscore exporting for AMD module loaders, + and tonylukasavage for Appcelerator Titanium. + (#335, #338) +
  • +
  • + You can now _.groupBy(list, 'property') as a shortcut for + grouping values by a particular common property. +
  • +
  • + _.throttle'd functions now fire immediately upon invocation, + and are rate-limited thereafter (#170, #266). +
  • +
  • + Most of the _.is[Type] checks no longer ducktype. +
  • +
  • + The _.bind function now also works on constructors, a-la + ES5 ... but you would never want to use _.bind on a + constructor function. +
  • +
  • + _.clone no longer wraps non-object types in Objects. +
  • +
  • + _.find and _.filter are now the preferred names for + _.detect and _.select. +
  • +
+

+ +

+ 1.2.0Oct. 5, 2011
+

    +
  • + The _.isEqual function now + supports true deep equality comparisons, with checks for cyclic structures, + thanks to Kit Cambridge. +
  • +
  • + Underscore templates now support HTML escaping interpolations, using + <%- ... %> syntax. +
  • +
  • + Ryan Tenney contributed _.shuffle, which uses a modified + Fisher-Yates to give you a shuffled copy of an array. +
  • +
  • + _.uniq can now be passed an optional iterator, to determine by + what criteria an object should be considered unique. +
  • +
  • + _.last now takes an optional argument which will return the last + N elements of the list. +
  • +
  • + A new _.initial function was added, as a mirror of _.rest, + which returns all the initial values of a list (except the last N). +
  • +
+

+ +

+ 1.1.7July 13, 2011
+ Added _.groupBy, which aggregates a collection into groups of like items. + Added _.union and _.difference, to complement the + (re-named) _.intersection. + Various improvements for support of sparse arrays. + _.toArray now returns a clone, if directly passed an array. + _.functions now also returns the names of functions that are present + in the prototype chain. +

+ +

+ 1.1.6April 18, 2011
+ Added _.after, which will return a function that only runs after + first being called a specified number of times. + _.invoke can now take a direct function reference. + _.every now requires an iterator function to be passed, which + mirrors the ECMA5 API. + _.extend no longer copies keys when the value is undefined. + _.bind now errors when trying to bind an undefined value. +

+ +

+ 1.1.5Mar 20, 2011
+ Added an _.defaults function, for use merging together JS objects + representing default options. + Added an _.once function, for manufacturing functions that should + only ever execute a single time. + _.bind now delegates to the native ECMAScript 5 version, + where available. + _.keys now throws an error when used on non-Object values, as in + ECMAScript 5. + Fixed a bug with _.keys when used over sparse arrays. +

+ +

+ 1.1.4Jan 9, 2011
+ Improved compliance with ES5's Array methods when passing null + as a value. _.wrap now correctly sets this for the + wrapped function. _.indexOf now takes an optional flag for + finding the insertion index in an array that is guaranteed to already + be sorted. Avoiding the use of .callee, to allow _.isArray + to work properly in ES5's strict mode. +

+ +

+ 1.1.3Dec 1, 2010
+ In CommonJS, Underscore may now be required with just:
+ var _ = require("underscore"). + Added _.throttle and _.debounce functions. + Removed _.breakLoop, in favor of an ECMA5-style un-break-able + each implementation — this removes the try/catch, and you'll now have + better stack traces for exceptions that are thrown within an Underscore iterator. + Improved the isType family of functions for better interoperability + with Internet Explorer host objects. + _.template now correctly escapes backslashes in templates. + Improved _.reduce compatibility with the ECMA5 version: + if you don't pass an initial value, the first item in the collection is used. + _.each no longer returns the iterated collection, for improved + consistency with ES5's forEach. +

+ +

+ 1.1.2
+ Fixed _.contains, which was mistakenly pointing at + _.intersect instead of _.include, like it should + have been. Added _.unique as an alias for _.uniq. +

+ +

+ 1.1.1
+ Improved the speed of _.template, and its handling of multiline + interpolations. Ryan Tenney contributed optimizations to many Underscore + functions. An annotated version of the source code is now available. +

+ +

+ 1.1.0
+ The method signature of _.reduce has been changed to match + the ECMAScript 5 signature, instead of the Ruby/Prototype.js version. + This is a backwards-incompatible change. _.template may now be + called with no arguments, and preserves whitespace. _.contains + is a new alias for _.include. +

+ +

+ 1.0.4
+ Andri Möll contributed the _.memoize + function, which can be used to speed up expensive repeated computations + by caching the results. +

+ +

+ 1.0.3
+ Patch that makes _.isEqual return false if any property + of the compared object has a NaN value. Technically the correct + thing to do, but of questionable semantics. Watch out for NaN comparisons. +

+ +

+ 1.0.2
+ Fixes _.isArguments in recent versions of Opera, which have + arguments objects as real Arrays. +

+ +

+ 1.0.1
+ Bugfix for _.isEqual, when comparing two objects with the same + number of undefined keys, but with different names. +

+ +

+ 1.0.0
+ Things have been stable for many months now, so Underscore is now + considered to be out of beta, at 1.0. Improvements since 0.6 + include _.isBoolean, and the ability to have _.extend + take multiple source objects. +

+ +

+ 0.6.0
+ Major release. Incorporates a number of + Mile Frawley's refactors for + safer duck-typing on collection functions, and cleaner internals. A new + _.mixin method that allows you to extend Underscore with utility + functions of your own. Added _.times, which works the same as in + Ruby or Prototype.js. Native support for ECMAScript 5's Array.isArray, + and Object.keys. +

+ +

+ 0.5.8
+ Fixed Underscore's collection functions to work on + NodeLists and + HTMLCollections + once more, thanks to + Justin Tulloss. +

+ +

+ 0.5.7
+ A safer implementation of _.isArguments, and a + faster _.isNumber,
thanks to + Jed Schmidt. +

+ +

+ 0.5.6
+ Customizable delimiters for _.template, contributed by + Noah Sloan. +

+ +

+ 0.5.5
+ Fix for a bug in MobileSafari's OOP-wrapper, with the arguments object. +

+ +

+ 0.5.4
+ Fix for multiple single quotes within a template string for + _.template. See: + Rick Strahl's blog post. +

+ +

+ 0.5.2
+ New implementations of isArray, isDate, isFunction, + isNumber, isRegExp, and isString, thanks to + a suggestion from + Robert Kieffer. + Instead of doing Object#toString + comparisons, they now check for expected properties, which is less safe, + but more than an order of magnitude faster. Most other Underscore + functions saw minor speed improvements as a result. + Evgeniy Dolzhenko + contributed _.tap, + similar to Ruby 1.9's, + which is handy for injecting side effects (like logging) into chained calls. +

+ +

+ 0.5.1
+ Added an _.isArguments function. Lots of little safety checks + and optimizations contributed by + Noah Sloan and + Andri Möll. +

+ +

+ 0.5.0
+ [API Changes] _.bindAll now takes the context object as + its first parameter. If no method names are passed, all of the context + object's methods are bound to it, enabling chaining and easier binding. + _.functions now takes a single argument and returns the names + of its Function properties. Calling _.functions(_) will get you + the previous behavior. + Added _.isRegExp so that isEqual can now test for RegExp equality. + All of the "is" functions have been shrunk down into a single definition. + Karl Guertin contributed patches. +

+ +

+ 0.4.7
+ Added isDate, isNaN, and isNull, for completeness. + Optimizations for isEqual when checking equality between Arrays + or Dates. _.keys is now 25%–2X faster (depending on your + browser) which speeds up the functions that rely on it, such as _.each. +

+ +

+ 0.4.6
+ Added the range function, a port of the + Python + function of the same name, for generating flexibly-numbered lists + of integers. Original patch contributed by + Kirill Ishanov. +

+ +

+ 0.4.5
+ Added rest for Arrays and arguments objects, and aliased + first as head, and rest as tail, + thanks to Luke Sutton's patches. + Added tests ensuring that all Underscore Array functions also work on + arguments objects. +

+ +

+ 0.4.4
+ Added isString, and isNumber, for consistency. Fixed + _.isEqual(NaN, NaN) to return true (which is debatable). +

+ +

+ 0.4.3
+ Started using the native StopIteration object in browsers that support it. + Fixed Underscore setup for CommonJS environments. +

+ +

+ 0.4.2
+ Renamed the unwrapping function to value, for clarity. +

+ +

+ 0.4.1
+ Chained Underscore objects now support the Array prototype methods, so + that you can perform the full range of operations on a wrapped array + without having to break your chain. Added a breakLoop method + to break in the middle of any Underscore iteration. Added an + isEmpty function that works on arrays and objects. +

+ +

+ 0.4.0
+ All Underscore functions can now be called in an object-oriented style, + like so: _([1, 2, 3]).map(...);. Original patch provided by + Marc-André Cournoyer. + Wrapped objects can be chained through multiple + method invocations. A functions method + was added, providing a sorted list of all the functions in Underscore. +

+ +

+ 0.3.3
+ Added the JavaScript 1.8 function reduceRight. Aliased it + as foldr, and aliased reduce as foldl. +

+ +

+ 0.3.2
+ Now runs on stock Rhino + interpreters with: load("underscore.js"). + Added identity as a utility function. +

+ +

+ 0.3.1
+ All iterators are now passed in the original collection as their third + argument, the same as JavaScript 1.6's forEach. Iterating over + objects is now called with (value, key, collection), for details + see _.each. +

+ +

+ 0.3.0
+ Added Dmitry Baranovskiy's + comprehensive optimizations, merged in + Kris Kowal's patches to make Underscore + CommonJS and + Narwhal compliant. +

+ +

+ 0.2.0
+ Added compose and lastIndexOf, renamed inject to + reduce, added aliases for inject, filter, + every, some, and forEach. +

+ +

+ 0.1.1
+ Added noConflict, so that the "Underscore" object can be assigned to + other variables. +

+ +

+ 0.1.0
+ Initial release of Underscore.js. +

+ +

+ + A DocumentCloud Project + +

+ +
+ +
+ + + + + + diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/index.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/index.js new file mode 100644 index 0000000..2cf0ca5 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/index.js @@ -0,0 +1 @@ +module.exports = require('./underscore'); diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/package.json b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/package.json new file mode 100644 index 0000000..4a2e3ca --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/package.json @@ -0,0 +1,10 @@ +{ + "name" : "underscore", + "description" : "JavaScript's functional programming helper library.", + "homepage" : "http://documentcloud.github.com/underscore/", + "keywords" : ["util", "functional", "server", "client", "browser"], + "author" : "Jeremy Ashkenas ", + "repository" : {"type": "git", "url": "git://github.com/documentcloud/underscore.git"}, + "main" : "underscore.js", + "version" : "1.3.1" +} diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/raw/underscore.psd b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/raw/underscore.psd new file mode 100644 index 0000000000000000000000000000000000000000..73ad2d7c8eebce69b4f46f31c0a1a8c2d523bc0d GIT binary patch literal 215540 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 literal 0 HcmV?d00001 diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/underscore-min.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/underscore-min.js new file mode 100644 index 0000000..5b55f32 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/underscore-min.js @@ -0,0 +1,31 @@ +// Underscore.js 1.3.1 +// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore +(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source== +c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c, +h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each= +b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e2;a== +null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect= +function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e= +e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck= +function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;bd?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a, +c,d){d||(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}}; +b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments, +1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)}; +b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"}; +b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a), +function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+ +u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]= +function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain= +true;return this};m.prototype.value=function(){return this._wrapped}}).call(this); diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/underscore.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/underscore.js new file mode 100644 index 0000000..208d4cd --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/node_modules/underscore/underscore.js @@ -0,0 +1,999 @@ +// Underscore.js 1.3.1 +// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore + +(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `global` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Establish the object that gets returned to break out of a loop iteration. + var breaker = {}; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var slice = ArrayProto.slice, + unshift = ArrayProto.unshift, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeForEach = ArrayProto.forEach, + nativeMap = ArrayProto.map, + nativeReduce = ArrayProto.reduce, + nativeReduceRight = ArrayProto.reduceRight, + nativeFilter = ArrayProto.filter, + nativeEvery = ArrayProto.every, + nativeSome = ArrayProto.some, + nativeIndexOf = ArrayProto.indexOf, + nativeLastIndexOf = ArrayProto.lastIndexOf, + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { return new wrapper(obj); }; + + // Export the Underscore object for **Node.js**, with + // backwards-compatibility for the old `require()` API. If we're in + // the browser, add `_` as a global object via a string identifier, + // for Closure Compiler "advanced" mode. + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else { + root['_'] = _; + } + + // Current version. + _.VERSION = '1.3.1'; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles objects with the built-in `forEach`, arrays, and raw objects. + // Delegates to **ECMAScript 5**'s native `forEach` if available. + var each = _.each = _.forEach = function(obj, iterator, context) { + if (obj == null) return; + if (nativeForEach && obj.forEach === nativeForEach) { + obj.forEach(iterator, context); + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; + } + } else { + for (var key in obj) { + if (_.has(obj, key)) { + if (iterator.call(context, obj[key], key, obj) === breaker) return; + } + } + } + }; + + // Return the results of applying the iterator to each element. + // Delegates to **ECMAScript 5**'s native `map` if available. + _.map = _.collect = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); + each(obj, function(value, index, list) { + results[results.length] = iterator.call(context, value, index, list); + }); + if (obj.length === +obj.length) results.length = obj.length; + return results; + }; + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. + _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduce && obj.reduce === nativeReduce) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); + } + each(obj, function(value, index, list) { + if (!initial) { + memo = value; + initial = true; + } else { + memo = iterator.call(context, memo, value, index, list); + } + }); + if (!initial) throw new TypeError('Reduce of empty array with no initial value'); + return memo; + }; + + // The right-associative version of reduce, also known as `foldr`. + // Delegates to **ECMAScript 5**'s native `reduceRight` if available. + _.reduceRight = _.foldr = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); + } + var reversed = _.toArray(obj).reverse(); + if (context && !initial) iterator = _.bind(iterator, context); + return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator); + }; + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, iterator, context) { + var result; + any(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) { + result = value; + return true; + } + }); + return result; + }; + + // Return all the elements that pass a truth test. + // Delegates to **ECMAScript 5**'s native `filter` if available. + // Aliased as `select`. + _.filter = _.select = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); + each(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + each(obj, function(value, index, list) { + if (!iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Determine whether all of the elements match a truth test. + // Delegates to **ECMAScript 5**'s native `every` if available. + // Aliased as `all`. + _.every = _.all = function(obj, iterator, context) { + var result = true; + if (obj == null) return result; + if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); + each(obj, function(value, index, list) { + if (!(result = result && iterator.call(context, value, index, list))) return breaker; + }); + return result; + }; + + // Determine if at least one element in the object matches a truth test. + // Delegates to **ECMAScript 5**'s native `some` if available. + // Aliased as `any`. + var any = _.some = _.any = function(obj, iterator, context) { + iterator || (iterator = _.identity); + var result = false; + if (obj == null) return result; + if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); + each(obj, function(value, index, list) { + if (result || (result = iterator.call(context, value, index, list))) return breaker; + }); + return !!result; + }; + + // Determine if a given value is included in the array or object using `===`. + // Aliased as `contains`. + _.include = _.contains = function(obj, target) { + var found = false; + if (obj == null) return found; + if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; + found = any(obj, function(value) { + return value === target; + }); + return found; + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + return _.map(obj, function(value) { + return (_.isFunction(method) ? method || value : value[method]).apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, function(value){ return value[key]; }); + }; + + // Return the maximum element or (element-based computation). + _.max = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); + if (!iterator && _.isEmpty(obj)) return -Infinity; + var result = {computed : -Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed >= result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj); + if (!iterator && _.isEmpty(obj)) return Infinity; + var result = {computed : Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed < result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Shuffle an array. + _.shuffle = function(obj) { + var shuffled = [], rand; + each(obj, function(value, index, list) { + if (index == 0) { + shuffled[0] = value; + } else { + rand = Math.floor(Math.random() * (index + 1)); + shuffled[index] = shuffled[rand]; + shuffled[rand] = value; + } + }); + return shuffled; + }; + + // Sort the object's values by a criterion produced by an iterator. + _.sortBy = function(obj, iterator, context) { + return _.pluck(_.map(obj, function(value, index, list) { + return { + value : value, + criteria : iterator.call(context, value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }), 'value'); + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = function(obj, val) { + var result = {}; + var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; + each(obj, function(value, index) { + var key = iterator(value, index); + (result[key] || (result[key] = [])).push(value); + }); + return result; + }; + + // Use a comparator function to figure out at what index an object should + // be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iterator) { + iterator || (iterator = _.identity); + var low = 0, high = array.length; + while (low < high) { + var mid = (low + high) >> 1; + iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; + } + return low; + }; + + // Safely convert anything iterable into a real, live array. + _.toArray = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) return iterable.toArray(); + if (_.isArray(iterable)) return slice.call(iterable); + if (_.isArguments(iterable)) return slice.call(iterable); + return _.values(iterable); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + return _.toArray(obj).length; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head`. The **guard** check allows it to work + // with `_.map`. + _.first = _.head = function(array, n, guard) { + return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; + }; + + // Returns everything but the last entry of the array. Especcialy useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. The **guard** check allows it to work with + // `_.map`. + _.initial = function(array, n, guard) { + return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); + }; + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. The **guard** check allows it to work with `_.map`. + _.last = function(array, n, guard) { + if ((n != null) && !guard) { + return slice.call(array, Math.max(array.length - n, 0)); + } else { + return array[array.length - 1]; + } + }; + + // Returns everything but the first entry of the array. Aliased as `tail`. + // Especially useful on the arguments object. Passing an **index** will return + // the rest of the values in the array from that index onward. The **guard** + // check allows it to work with `_.map`. + _.rest = _.tail = function(array, index, guard) { + return slice.call(array, (index == null) || guard ? 1 : index); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, function(value){ return !!value; }); + }; + + // Return a completely flattened version of an array. + _.flatten = function(array, shallow) { + return _.reduce(array, function(memo, value) { + if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value)); + memo[memo.length] = value; + return memo; + }, []); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iterator) { + var initial = iterator ? _.map(array, iterator) : array; + var result = []; + _.reduce(initial, function(memo, el, i) { + if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) { + memo[memo.length] = el; + result[result.length] = array[i]; + } + return memo; + }, []); + return result; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(_.flatten(arguments, true)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. (Aliased as "intersect" for back-compat.) + _.intersection = _.intersect = function(array) { + var rest = slice.call(arguments, 1); + return _.filter(_.uniq(array), function(item) { + return _.every(rest, function(other) { + return _.indexOf(other, item) >= 0; + }); + }); + }; + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + _.difference = function(array) { + var rest = _.flatten(slice.call(arguments, 1)); + return _.filter(array, function(value){ return !_.include(rest, value); }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + var args = slice.call(arguments); + var length = _.max(_.pluck(args, 'length')); + var results = new Array(length); + for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); + return results; + }; + + // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), + // we need this function. Return the position of the first occurrence of an + // item in an array, or -1 if the item is not included in the array. + // Delegates to **ECMAScript 5**'s native `indexOf` if available. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = function(array, item, isSorted) { + if (array == null) return -1; + var i, l; + if (isSorted) { + i = _.sortedIndex(array, item); + return array[i] === item ? i : -1; + } + if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); + for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i; + return -1; + }; + + // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. + _.lastIndexOf = function(array, item) { + if (array == null) return -1; + if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); + var i = array.length; + while (i--) if (i in array && array[i] === item) return i; + return -1; + }; + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (arguments.length <= 1) { + stop = start || 0; + start = 0; + } + step = arguments[2] || 1; + + var len = Math.max(Math.ceil((stop - start) / step), 0); + var idx = 0; + var range = new Array(len); + + while(idx < len) { + range[idx++] = start; + start += step; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Reusable constructor function for prototype setting. + var ctor = function(){}; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Binding with arguments is also known as `curry`. + // Delegates to **ECMAScript 5**'s native `Function.bind` if available. + // We check for `func.bind` first, to fail fast when `func` is undefined. + _.bind = function bind(func, context) { + var bound, args; + if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError; + args = slice.call(arguments, 2); + return bound = function() { + if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); + ctor.prototype = func.prototype; + var self = new ctor; + var result = func.apply(self, args.concat(slice.call(arguments))); + if (Object(result) === result) return result; + return self; + }; + }; + + // Bind all of an object's methods to that object. Useful for ensuring that + // all callbacks defined on an object belong to it. + _.bindAll = function(obj) { + var funcs = slice.call(arguments, 1); + if (funcs.length == 0) funcs = _.functions(obj); + each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memo = {}; + hasher || (hasher = _.identity); + return function() { + var key = hasher.apply(this, arguments); + return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); + }; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ return func.apply(func, args); }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = function(func) { + return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); + }; + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. + _.throttle = function(func, wait) { + var context, args, timeout, throttling, more; + var whenDone = _.debounce(function(){ more = throttling = false; }, wait); + return function() { + context = this; args = arguments; + var later = function() { + timeout = null; + if (more) func.apply(context, args); + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + func.apply(context, args); + } + whenDone(); + throttling = true; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. + _.debounce = function(func, wait) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + func.apply(context, args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = function(func) { + var ran = false, memo; + return function() { + if (ran) return memo; + ran = true; + return memo = func.apply(this, arguments); + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return function() { + var args = [func].concat(slice.call(arguments, 0)); + return wrapper.apply(this, args); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var funcs = arguments; + return function() { + var args = arguments; + for (var i = funcs.length - 1; i >= 0; i--) { + args = [funcs[i].apply(this, args)]; + } + return args[0]; + }; + }; + + // Returns a function that will only be executed after being called N times. + _.after = function(times, func) { + if (times <= 0) return func(); + return function() { + if (--times < 1) { return func.apply(this, arguments); } + }; + }; + + // Object Functions + // ---------------- + + // Retrieve the names of an object's properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = nativeKeys || function(obj) { + if (obj !== Object(obj)) throw new TypeError('Invalid object'); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + return _.map(obj, _.identity); + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Fill in a given object with default properties. + _.defaults = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (obj[prop] == null) obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Internal recursive comparison function. + function eq(a, b, stack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. + if (a === b) return a !== 0 || 1 / a == 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a._chain) a = a._wrapped; + if (b._chain) b = b._wrapped; + // Invoke a custom `isEqual` method if one is provided. + if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b); + if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a); + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className != toString.call(b)) return false; + switch (className) { + // Strings, numbers, dates, and booleans are compared by value. + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return a == String(b); + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for + // other numeric values. + return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a == +b; + // RegExps are compared by their source patterns and flags. + case '[object RegExp]': + return a.source == b.source && + a.global == b.global && + a.multiline == b.multiline && + a.ignoreCase == b.ignoreCase; + } + if (typeof a != 'object' || typeof b != 'object') return false; + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + var length = stack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (stack[length] == a) return true; + } + // Add the first object to the stack of traversed objects. + stack.push(a); + var size = 0, result = true; + // Recursively compare objects and arrays. + if (className == '[object Array]') { + // Compare array lengths to determine if a deep comparison is necessary. + size = a.length; + result = size == b.length; + if (result) { + // Deep compare the contents, ignoring non-numeric properties. + while (size--) { + // Ensure commutative equality for sparse arrays. + if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break; + } + } + } else { + // Objects with different constructors are not equivalent. + if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false; + // Deep compare objects. + for (var key in a) { + if (_.has(a, key)) { + // Count the expected number of properties. + size++; + // Deep compare each member. + if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break; + } + } + // Ensure that both objects contain the same number of properties. + if (result) { + for (key in b) { + if (_.has(b, key) && !(size--)) break; + } + result = !size; + } + } + // Remove the first object from the stack of traversed objects. + stack.pop(); + return result; + } + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b, []); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; + for (var key in obj) if (_.has(obj, key)) return false; + return true; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType == 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) == '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + return obj === Object(obj); + }; + + // Is a given variable an arguments object? + _.isArguments = function(obj) { + return toString.call(obj) == '[object Arguments]'; + }; + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return !!(obj && _.has(obj, 'callee')); + }; + } + + // Is a given value a function? + _.isFunction = function(obj) { + return toString.call(obj) == '[object Function]'; + }; + + // Is a given value a string? + _.isString = function(obj) { + return toString.call(obj) == '[object String]'; + }; + + // Is a given value a number? + _.isNumber = function(obj) { + return toString.call(obj) == '[object Number]'; + }; + + // Is the given value `NaN`? + _.isNaN = function(obj) { + // `NaN` is the only value for which `===` is not reflexive. + return obj !== obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; + }; + + // Is a given value a date? + _.isDate = function(obj) { + return toString.call(obj) == '[object Date]'; + }; + + // Is the given value a regular expression? + _.isRegExp = function(obj) { + return toString.call(obj) == '[object RegExp]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Has own property? + _.has = function(obj, key) { + return hasOwnProperty.call(obj, key); + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iterators. + _.identity = function(value) { + return value; + }; + + // Run a function **n** times. + _.times = function (n, iterator, context) { + for (var i = 0; i < n; i++) iterator.call(context, i); + }; + + // Escape a string for HTML interpolation. + _.escape = function(string) { + return (''+string).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/'); + }; + + // Add your own custom functions to the Underscore object, ensuring that + // they're correctly added to the OOP wrapper as well. + _.mixin = function(obj) { + each(_.functions(obj), function(name){ + addToWrapper(name, _[name] = obj[name]); + }); + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = idCounter++; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /.^/; + + // Within an interpolation, evaluation, or escaping, remove HTML escaping + // that had been previously added. + var unescape = function(code) { + return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'"); + }; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(str, data) { + var c = _.templateSettings; + var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + + 'with(obj||{}){__p.push(\'' + + str.replace(/\\/g, '\\\\') + .replace(/'/g, "\\'") + .replace(c.escape || noMatch, function(match, code) { + return "',_.escape(" + unescape(code) + "),'"; + }) + .replace(c.interpolate || noMatch, function(match, code) { + return "'," + unescape(code) + ",'"; + }) + .replace(c.evaluate || noMatch, function(match, code) { + return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('"; + }) + .replace(/\r/g, '\\r') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + + "');}return __p.join('');"; + var func = new Function('obj', '_', tmpl); + if (data) return func(data, _); + return function(data) { + return func.call(this, data, _); + }; + }; + + // Add a "chain" function, which will delegate to the wrapper. + _.chain = function(obj) { + return _(obj).chain(); + }; + + // The OOP Wrapper + // --------------- + + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + var wrapper = function(obj) { this._wrapped = obj; }; + + // Expose `wrapper.prototype` as `_.prototype` + _.prototype = wrapper.prototype; + + // Helper function to continue chaining intermediate results. + var result = function(obj, chain) { + return chain ? _(obj).chain() : obj; + }; + + // A method to easily add functions to the OOP wrapper. + var addToWrapper = function(name, func) { + wrapper.prototype[name] = function() { + var args = slice.call(arguments); + unshift.call(args, this._wrapped); + return result(func.apply(_, args), this._chain); + }; + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + var wrapped = this._wrapped; + method.apply(wrapped, arguments); + var length = wrapped.length; + if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0]; + return result(wrapped, this._chain); + }; + }); + + // Add all accessor Array functions to the wrapper. + each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + return result(method.apply(this._wrapped, arguments), this._chain); + }; + }); + + // Start chaining a wrapped Underscore object. + wrapper.prototype.chain = function() { + this._chain = true; + return this; + }; + + // Extracts the result from a wrapped and chained object. + wrapper.prototype.value = function() { + return this._wrapped; + }; + +}).call(this); diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/package.json b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/package.json new file mode 100644 index 0000000..9e2b900 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/gex/package.json @@ -0,0 +1,22 @@ +{ + "name": "gex", + "description": "Glob expressions for JavaScript", + "keywords": ["glob","star","question","mark","expression","regular"], + "version": "0.0.1", + "homepage": "https://github.com/rjrodger/gex", + "author": "Richard Rodger (http://richardrodger.com/)", + "contributors": [ + "Richard Rodger (http://richardrodger.com/)" + ], + "dependencies": { + "underscore": ">=1.1.4" + }, + "main": "lib/gex", + "directories": { + "lib": "lib" + }, + "repository": { "type" : "git", "url" : "https://github.com/rjrodger/gex.git" }, + "engines": { + "node": "*" + } +} \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/LICENSE b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/NOTICE b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/NOTICE new file mode 100644 index 0000000..8e3d0af --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/NOTICE @@ -0,0 +1,5 @@ +Log Magic +Copyright (c) 2011, Paul Querna + +This product includes software developed by +Paul Querna (http://paul.querna.org). diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/README.md b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/README.md new file mode 100644 index 0000000..4ba36a2 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/README.md @@ -0,0 +1,44 @@ +Welcome to Log Magic. +==================== + +This project isn't usable yet. No promises. The Bellow is an idea. + +The goal is to have a fast and easy to use logging subsystem that can be dynamically +reconfigured to provide insight into production systems. + + +Getting Started +==================== + +If you had a file named like, "lib/foo/bar.js", at the top of it, you would put the following: + + var log = require('logmagic').local('mylib.foo.bar'); + +Then inside bar.js, you would just use the logger like any normal logger: + + log.info("Hello!") + log.error("Accepts format strings too ${SOME_VAR}", {SOME_VAR: "myvalue"}) + +In any other part of your application, you can reconfigure the logging subsystem at runtime, +making it easy to change log levels for specific modules dynamically. + + var logmagic = require('logmagic'); + logmagic.registerSink("mysink", function(level, message) { console.log(message); }); + + /* Send Info an higher in the root logger to stdout */ + logmagic.route("__root__", logmagic.INFO, "stdout") + + /* Reconfigure all children of mylib to log all debug messages to your custom sink */ + logmagic.route("mylib.*", logmagic.DEBUG, "mysink") + + +Builtin sinks include: + +* Standard Error + +Future features: +* Standard Out +* Facebook Scribe: https://github.com/facebook/scribe +* File +* Unix Socket +* Syslog diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/lib/graylog.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/lib/graylog.js new file mode 100644 index 0000000..54b1c4d --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/lib/graylog.js @@ -0,0 +1,103 @@ +/* + * Licensed to Paul Querna under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Paul Querna licenses this file to You 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. + */ + +var os = require('os'); + +var logobj = { + version: "1.0", + host: os.hostname(), + timestamp: null, + short_message: null, + full_message: null, + timestamp: null, + level: null, + facility: null, +}; + +var logcache = {}; + +function clone(obj) { + /* Shallow object clone */ + var target = {}; + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + target[i] = obj[i]; + } + } + return target; +} + +exports.logstr = function(module, level, message, obj) { + + if (level > 7) { + level = 7; + } + + var l = null; + + if (obj) { + /* begin fucking voodoo */ + + /** + * The 'easy' way to do this, is to create a new + * object every time: + * l = clone(logobj); + * + * But because of how node stores things in its slots, + * this is about 50% as fast as this hack using the keys + * of an object to store only one instance of it.... + * + * The observation we make is that most applications have a + * limited set of parameters that they pass into be logged, + * and the 'key' to this log object is almost always a static + * string. + */ + var keys = ""; + /* This is faster than Object.keys(obj).join(""); */ + for (var i in obj) { + keys += i; + } + + l = logcache[keys]; + if (!l) { + l = clone(logobj); + logcache[keys] = l; + } + + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + if (i == 'full_message') { + l['full_message'] = obj[i]; + } + else { + l["_" + i] = obj[i]; + } + } + } + } + else { + l = logobj; + } + + + l.facility = module; + l.timestamp = (new Date().getTime()) / 1000; + l.short_message = message; + l.level = level; + + return JSON.stringify(l); +} diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/lib/logmagic.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/lib/logmagic.js new file mode 100644 index 0000000..b369494 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/lib/logmagic.js @@ -0,0 +1,269 @@ +/* + * Licensed to Paul Querna under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Paul Querna licenses this file to You 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. + */ + +var graylog = require('./graylog'); + +function LoggerProxy(modulename) { + this.modulename = modulename; + this.loglevel = -1; +} + +/* Based on the Log levels available in Apache HTTP Server. */ +exports.EMERG = 0; /* system is unusable */ +exports.ALERT = 1; /* action must be taken immediately */ +exports.CRIT = 2; /* critical conditions */ +exports.ERR = 3; /* error conditions */ +exports.WARNING = 4; /* warning conditions */ +exports.NOTICE = 5; /* normal but significant condition */ +exports.INFO = 6; /* informational */ +exports.DEBUG = 7; /* debug-level messages */ +exports.TRACE1 = 8; /* trace-level 1 messages */ +exports.TRACE2 = 9; /* trace-level 2 messages */ +exports.TRACE3 = 10; /* trace-level 3 messages */ +exports.TRACE4 = 11; /* trace-level 4 messages */ +exports.TRACE5 = 12; /* trace-level 5 messages */ +exports.TRACE6 = 13; /* trace-level 6 messages */ +exports.TRACE7 = 14; /* trace-level 7 messages */ +exports.TRACE8 = 15; /* trace-level 8 messages */ + +var log_levels = ["EMERG", + "ALERT", + "CRIT", + "ERR", + "WARNING", + "NOTICE", + "INFO", + "DEBUG", + "TRACE1", + "TRACE2", + "TRACE3", + "TRACE4", + "TRACE5", + "TRACE6", + "TRACE7", + "TRACE8"]; + +var log_aliases = {"WARN": "WARNING", + "ERROR": "ERR", + "DBG": "DEBUG", + "MSG": "INFO", + "TRACE": "TRACE1"}; + +var known_sinks = {}; +var known_loggers = []; +var known_routes = []; +var rewriters = []; + +function applyRewrites(modulename, level, msg, extra) { + var i; + for (i = 0; i < rewriters.length; i++) { + extra = rewriters[i](modulename, level, msg, extra); + } + return extra; +} + +function buildLogMethod(modulename, level, callback) { + if (level >= exports.TRACE1) { + return function (msg, extra) { + if (!extra) { + extra = {}; + } + extra['full_message'] = new Error('Backtrace').stack; + extra = applyRewrites(modulename, level, msg, extra); + callback(modulename, level, msg, extra) + } + } + else { + return function (msg, extra) { + if (!extra) { + extra = {}; + } + extra = applyRewrites(modulename, level, msg, extra); + callback(modulename, level, msg, extra) + } + } +} + + +function applyFormatString(msg, extra) { + function replaceFunction(str, p1) { + if (extra.hasOwnProperty(p1)) { + return extra[p1]; + } + + return p1; + } + var regex = new RegExp(/\$\{(.*?)\}/g); + msg = msg.replace(regex, replaceFunction); + return msg; +} + +function buildFormattedLogMethod(modulename, level, callback) { + if (level >= exports.TRACE1) { + return function (msg, extra) { + if (!extra) { + extra = {}; + } + extra['full_message'] = new Error('Backtrace').stack; + extra = applyRewrites(modulename, level, msg, extra); + msg = applyFormatString(msg, extra); + callback(modulename, level, msg, extra) + } + } + else { + return function (msg, extra) { + if (!extra) { + extra = {}; + } + extra = applyRewrites(modulename, level, msg, extra); + msg = applyFormatString(msg, extra); + callback(modulename, level, msg, extra) + } + } +} + + +function nullLogger() { + /* Intentionally blank. */ +} + +function applyRoute(route, logger, modulename) { + logger.loglevel = route.loglevel; + for(var i=0; i= exports.EMERG && loglevel <= exports.TRACE8)) { + throw new Error("Invalid Log level: " + loglevel); + } + + /* TODO: Maybe it is okay to route before we have a sink loaded (?) */ + if (known_sinks[sinkname] === undefined) { + throw new Error("Invalid Sink: " + sinkname); + } + + known_routes.push({route: match, loglevel: loglevel, callback: known_sinks[sinkname]}); + + for(var i=0; i (http://paul.querna.org/)", + "main": "lib/logmagic.js", + "directories": { + "lib": "lib" + }, + "engines": { + "node": "*" + } +} \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/tests/bench.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/tests/bench.js new file mode 100644 index 0000000..f316f8f --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/tests/bench.js @@ -0,0 +1,13 @@ +var graylog = require('../lib/graylog'); +var ops = 100000; + +var start = (new Date().getTime()); +for (var i = 0; i < ops; i++) { + var str = graylog.logstr("testing.example.foo", 3, "hello world", {counter: i, account_id: 42, txnid: "fxxxxx"}); + var str = graylog.logstr("testing.example.bar", 9, "hello baksdfnsdf", {special: 'aaa', account_id: 42, txnid: "fxxxxx"}); +} +var end = (new Date().getTime()); + +var ms = (end - start); + +console.log(ops + " logstr operations in " + ms + "ms, " + (ops/ms) * 1000 + " (logstr/second)"); \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/tests/t.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/tests/t.js new file mode 100644 index 0000000..d539cdd --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/logmagic/tests/t.js @@ -0,0 +1,28 @@ +var logmagic = require('../lib/logmagic'); +var log = logmagic.local('mylib.foo.bar'); +//console.log(log); +log.info("Hello!"); +log.error("more stuff", {SOME_VAR: "myvalue"}); +log.errorf("more stuff: ${SOME_VAR}", {SOME_VAR: "myvalue"}); +log.trace("testing trace v0"); + +logmagic.route("__root__", logmagic.TRACE1, "console"); +logmagic.route("__root__", logmagic.TRACE1, "graylog2-stderr"); +log.trace("testing trace v1", {slug: 1}); + +log = logmagic.local('mylib.foo.cars'); +log.trace("hello world", {counter: 33, account_id: 42, txnid: "fxxxxx"}); +logmagic.addRewriter(function(modulename, level, msg, extra) { + if (extra.request) { + extra.accountId = extra.request.account.id; + extra.txnId = extra.request.txtId; + delete extra.request; + } + return extra; +}); + +log.trace("hello baksdfnsdf", {special: 'aaa', account_id: 42, txnid: "fxxxxx", full_message: "loooong message"}); + +log.dbg("hello xxxx", {request: {account: {id: 45}, txtId: "XXXXXXXXXXXXX"}}); + +//console.log(log); diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/.npmignore b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/.npmignore new file mode 100644 index 0000000..4fec19c --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/.npmignore @@ -0,0 +1 @@ +.lvimrc diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/README.md b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/README.md new file mode 100644 index 0000000..877eefb --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/README.md @@ -0,0 +1,82 @@ +Magic templates +=============== + +Templating framework for NodeJS inspired by Django templates. + +Note: This is a [strobe-templates](https://github.com/skid/strobe-templates) +fork with some additional features and bug fixes. + +For now, Strobe Templates have the following template tags: + + {% for x in y %}{% endfor %} + {% if x %}{% else if y %}{% else %}{% endif %} + {% extends template_name %} + {% include template_name %} + {% block block_name %} + +You can define your own template tags in the "tags.js" module. Template inheritance is done in the same way as Django, only in an asynchronous way. Strobe templates support caching of parsed templates. +One important difference from Django templates is that the render() method returns an array of strings. It's your job to call .join("") on the rendered output. + +Requirements +============ + +* node.js >= 0.1.95 (works with lesser versions if you remove the buffer.toString in the load method of the template prototype) + +Simple usage example +========================= + + var sys = require('sys') + , templates = require('template'); + + templates.setTemplatesDir('/path/to/templates/dir'); + templates.setDebug(false); + + var context = { foo: 1, bar: 2 }; + var template = new templates.Template('path/to/template.html'); + template.load( function( err, template ) { + if( err ) // load/parse errors (invalid filename, bad template syntax) + sys.puts( err ); + else + template.render( context, function( err, output ) { + if( err ) // render errors (invalid filename in context variables, bad context variables) + sys.puts( err ); + else + sys.puts( output.join("") ); + }); + }); + +Adding some default values to all context instances (Something like a context_processor in Django) + + var Context = require('template').Context; + // This will be available in all context insances + Context.addToDefault({ MEDIA_URL: "http://media.url/" }); + // Clear the defaults + Context.clearDefault(); + +Run a benchmark and a test output +================================= + + $ node tests/run.js + +Used Code +========= + +* Visionmedia's [ext](http://github.com/visionmedia/ext.js library) (extensions to Object and sprintf) + +Todos +===== + +* Add filters for variable tags + +License +======= + +(The MIT License) + +Copyright (c) 2010 Dusko Jordanovski + +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/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/context.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/context.js new file mode 100644 index 0000000..e8159b6 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/context.js @@ -0,0 +1,125 @@ +var util = require('util') + , isArray = Array.isArray + , DEFAULT_STACK = (global.SETTINGS && SETTINGS.CONTEXT_DEFAULT_STACK) || []; + +/** @class + * + * A Context contains all variables passed to the template + * by the view. You normally don't create contexts, but rather + * pass a simple hash (object) to the template's render method. + * The template then creates the context. + * + * We are not using simple hashes for this task + * because we need to push and pop additional contexts onto + * the original one. This is done by keeping the original hash + * in a stack on which we push/pop more context hashes. + * + * @param {Hash} original context + */ +function Context( hash ){ + (this.stack = [].concat(DEFAULT_STACK) ).push( hash ); + this.size = this.stack.length; +} + +/** + * Pushes a hash to the default context stack. + * Every context instance will the hashes pushed to the default. + * + * @param {Object} The hash to be pushed + */ +Context.addToDefault = function( hash ){ + if( typeof hash === 'object' ) + DEFAULT_STACK.push( hash ); +} + +/** + * Clears the default context stack + */ +Context.clearDefault = function(){ + DEFAULT_STACK = []; +} + +Context.prototype = { + /** + * Retrieves a variable from the context. If the value is not + * found in the topmost member of the stack it goes deeper. + * If not found, returns null. + * + * @param {String} name of the variable + * @returns {Mixed} the variable + */ + get: function( key ){ + var i = this.size + , stack = this.stack; + + if( key.indexOf(".") > -1 ) + return this.getPath( key ); + + while( i-- ) + if( key in stack[i] ) + return stack[i][key]; + + return null; + } + + /** + * Retrieves a variable path from the context. The path is + * dot-separated (variable.foo.bar). + * In this case the context looks for a key names 'variable'. + * After finding it, it looks for its 'foo' property and then + * for the 'bar' property of the found property. + * + * If the variable is not found in the context, returns null. + * If the variable is found, but does not have the property, + * returns undefined, like usual. + * + * @param {String} the variable path + * @returns {Mixed} whatever comes out + */ + , getPath: function( path ){ + path = isArray( path ) ? path : path.split("."); + var i = this.size + , key = path.shift() + , stack = this.stack; + while( i-- ) + if( key in stack[i] ) + return Object.getPath( stack[i][key], path ); + return null; + } + + /** + * Pushes a new context hash on the current context. + * + * @param {Hash} the new context + */ + , push: function( hash ){ + ++this.size; + this.stack.push( hash ); + } + + /** + * Pops the last added context hash from the stack + * + * @returns {Hash} what we just popped + */ + , pop: function( ){ + --this.size; + return this.stack.pop(); + } + + /** + * Returns a copy of the context at the moment. + * Use this when you need to save the current context + * and you expect it to change later. + * + * @returns {Object} the context copy + */ + , clone: function(){ + var c = new Context({}), i=0; + while( i < this.size ) + c.push( Object.merge( {}, this.stack[ i++ ] ) ); + return c; + } +} + +exports.Context = Context; diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/exceptions.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/exceptions.js new file mode 100644 index 0000000..fd40262 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/exceptions.js @@ -0,0 +1,20 @@ +/** + * Exception that's thrown when invalid markup is encoutered. + */ +exports.TSE = exports.TemplateSyntaxError = function( message ){ + this.name = "TemplateSyntaxError"; + this.message = message; + this.toString = function(){ return this.name + ": " + this.message; } +} +exports.TSE.prototype = new Error(); + +/** +* + * Exception that's thrown when other errors happen, like a missing file. + */ +exports.TE = exports.TemplateError = function( message ){ + this.name = "TemplateError"; + this.message = message; + this.toString = function(){ return this.name + ": " + this.message; } +} +exports.TE.prototype = new Error(); \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/extensions.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/extensions.js new file mode 100644 index 0000000..51ed8d1 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/extensions.js @@ -0,0 +1,113 @@ +/** + * The next code is only for the standalone version of the templates system. + * Dependencies: + * Object.merge() + * Object.getPath() + * String.prototype.fmt() which is a wrapper around sprintf() + * + * Since the Templates engine is pulled out of a larger framework, + * we conditionally define some dependencies if they're missing here. + * I know it's ugly, will fix it. + * + * Huge thanks to TJ Holowaychuk , + * this is mostly his code from the 'ext' nodejs module. + */ +if( typeof Object.merge !== 'function' || typeof Object.getPath !== 'function' || + typeof String.prototype.fmt !== 'function' ){ + + var extend = function(obj, props) { + Object.getOwnPropertyNames(props).forEach(function(prop){ + var descriptor = Object.getOwnPropertyDescriptor(props, prop); + descriptor.enumerable = false; + Object.defineProperty(obj, prop, descriptor); + }); + } + + if( typeof Object.merge !== 'function' ) + extend(Object, {merge:function (a, b) { + if (!b) + return a; + var keys = Object.keys(b); + for (var i = 0, len = keys.length; i < len; ++i) + a[keys[i]] = b[keys[i]]; + return a; + }}); + + if( typeof Object.getPath !== 'function' ) + extend(Object, {getPath:function( obj, path ){ + var p = Array.isArray(path) ? path : path.split("."); + for( var i=0, j=p.length; i http://www.tomaz.me", + "main": "./index", + "directories": { + "lib": "./lib" + }, + "engines": { + "node": ">= 0.1.95" + } +} diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/block.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/block.js new file mode 100644 index 0000000..5ddef09 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/block.js @@ -0,0 +1,24 @@ +var util = require('util') + , E = require('../exceptions'); + +exports.block = BLOCK; + +/** + * This is a block tag, like in Django + * {% block blockname %} + * ... html ... + * ... other tags ... + * ... more html ... + * {% endblock %} + * + */ +var validBlockParamRegex = /^\s*([a-zA-Z0-9\-_]+)\s*$/; +function BLOCK( params ){ + var match; + if( !( match = params.match( validBlockParamRegex ) ) ) + throw new E.TSE( "Invalid block name %s".fmt( params ) ); + + this.tagname = "block"; + this.name = match[1]; +} +BLOCK.expectsClosing = true; diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/extends.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/extends.js new file mode 100644 index 0000000..eeeb547 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/extends.js @@ -0,0 +1,53 @@ +var util = require('util') + , E = require('../exceptions') + , Template = require('../template').Template; + +exports['extends'] = EXTENDS; + +/** + * This is an extends tag, like in Django: + * {% extends "filename.html" %} + * + * It must ALWAYS be the first thing in the template. + * You can also extend dynamically defined templates: + * {% extends files.template %} - notice the lack of quotes + */ +var validExtendsParamRegex = /^\s*(["']?)([^.][a-zA-Z0-9\-_.\/]+)\1\s*$/; +function EXTENDS( params, parent, main ) { + var filepath; + if( !( filepath = params.match( validExtendsParamRegex ) ) ) + throw new E.TSE( "Invalid filename in extends tag: '%s'".fmt( params ) ); + + // This code is run before the token is pushed to the children + // array so we can safely check for preceding tokens like this + if( parent.children.length ) + throw new E.TSE("Extends tag is not at the beginning of template '%s'".fmt( parent.filepath )); + + // If template is blocking increase the blocked counter onthe main template + if( filepath[1] === "'" || filepath[1] === '"' ) { + this.template = new Template( filepath[2], main ); + this.template.load(); + } + // Filename is in a context var - parse template on render + else { + this.lazy = filepath[2]; + this.main = main; + } +} + +EXTENDS.renderFunction = function(context, callback, blocks ) { + if( this.lazy ) { + var filepath; + if( !( filepath = context.getPath( this.lazy ) ) ) + throw new E.TE( "Variable '%s' is not a valid filename".fmt( this.lazy ) ); + + new Template( filepath, this.main ).load(function( err, template ){ + if( err ) + callback( err, null ); + else + template.render( context, callback, blocks ); + }); + } + else + return [this.template.render( context, callback, blocks )]; +} diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/for.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/for.js new file mode 100644 index 0000000..16ce8cd --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/for.js @@ -0,0 +1,97 @@ +var E = require('../exceptions') + , getProto = Object.getPrototypeOf + , isArray = Array.isArray; + +exports['for'] = FOR; + +/** + * This is a for tag, like in Django: + * {% for val in vals %} ... {% endfor %} + */ +var validForParamRegex = /^(\w+) *(, *(\w+))? +in +(\w+([.]\w+)*)$/; +function FOR( params, parent ) { + var matches; + if( !( matches = params.match(validForParamRegex) ) ) + throw new E.TSE( "Invalid 'for' tag syntax: '%s'".fmt(params) ); + + this.var1 = matches[1], + this.var2 = matches[3], + this.lookup = matches[4]; + + if( !isNaN( +this.var1 ) || (this.var2 && !isNaN( +this.var2 )) || !isNaN( +this.lookup ) ) + throw new E.TSE( "Invalid variable names in '{% for %s %}'".fmt(params) ); + + this.tagname = "for"; +} + +/** + Add the following special variables to the forloop context: + + forloop.counter - current iteration of the loop (1 based) + forloop.counter0 - current iteration of the loop (0 based) + forloop.revcounter - number of iterations from the end of the loop (1 based) + forloop.revcounter0 - number of iterations from the end of the loop (0 based) + */ +function add_counter_vars(context, i, len) { + if (!context.hasOwnProperty('forloop')) { + throw new Error('Context does not have forloop property'); + } + + context.forloop.counter = (i + 1); + context.forloop.counter0 = i; + context.forloop.revcounter = (len - i); + context.forloop.revcounter0 = (len - i) - 1; +} + +FOR.renderFunction = function( context ){ + var iter, i, j=0, k, r + , ctx = { forloop:{} } + , output = [] + , var1 = this.var1 + , var2 = this.var2 + , lookup = this.lookup + , render = getProto(this).render; + + if( !( iter = context.getPath( lookup ) ) ) + return ""; // iterable not found; render nothing + + context.push( ctx ); + + if( isArray( iter ) ) { + for( i=0, j=iter.length; i=|<=|\!=|<|>| in ) ?(["']?.+?["']?))?$/; +function IF( params, parent ) { + var matches; + this.branches=[]; + + if( !( matches = params.match(validIfParamRegex) ) ) + throw new E.TSE( "Invalid 'if' tag syntax: '%s'".fmt(params) ); + + this.var1 = matches[1]; + this.var2 = matches[4]; + this.operator = matches[3] && matches[3].trim(); +} + +IF.compileFunction = function() { + var c + , i=0 + , curr=0 + , lastToken = false + , children = this.children + , branches = this.branches + , j = children.length; + + branches.push({ v1:this.var1, v2:this.var2, op:this.operator, start:0, end:j }); + for( ; i=" ? v1 >= v2 + : op === "!=" ? v1 !== v2 + : op === "<" ? v1 < v2 + : op === ">" ? v1 > v2 + // Execute 'in' operator (only option left) + : isArray(v2) || typeof v2 === 'string' ? v2.indexOf(v1) > -1 + : typeof v2 === 'object' ? v1 in v2 + : false; + + else if( v1 ) + found = true; + + if( found ) + break; + } + + if( !found ) + return []; + + return getProto(this).render.call(this, context, this.children.slice( branch.start, branch.end )); +} + +IF.expectsClosing = true; + +/* + * Return true if value is a string and contains quotes at the beginning and the end. + */ +function is_literal_string_value(value) { + if ((typeof(value) === 'string' && (value.length >= 3)) && + ((value[0] == '"' && value[value.length - 1] == '"') || (value[0] == '\'' && value[value.length - 1] == '\''))) { + return true; + } + + return false; +} + +/* + * Remove quotes from the beginning and end of a string. + */ +function strip_quotes_from_literal_string_value(value) { + return value.substring(1, value.length - 1); +} + +/** + * This is an else (with an optional if) tag. + */ +var removeIfRegex = /^if +/; +function ELSE( params, parent ){ + var matches, branches=[]; + + if( parent.tagname !== 'if' ) + throw new E.TSE( "'else' tag encountered outside an 'if' block" ); + + if( params === "" ) { + this.plain = true; // This is a plain else tag, not an 'else if' + this.var1 = true; + return; + } + + params = params.replace(removeIfRegex, ""); + if( !( matches = params.match(validIfParamRegex) ) ) + throw new E.TSE( "Invalid 'else if' tag syntax: '%s'".fmt(params) ); + + this.var1 = matches[1]; + this.var2 = matches[4]; + this.operator = matches[3] && matches[3].trim(); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/include.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/include.js new file mode 100644 index 0000000..e4beac1 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/include.js @@ -0,0 +1,61 @@ +var util = require('util') + , E = require('../exceptions') + , Template = require('../template').Template; + +exports.include = INCLUDE; + +/** + * Ninja string is a hack that alows us to change the + * contents of the string after we have pushed it into + * the rendering output. + */ +function ninjaString( value ){ this.value = value || []; } +ninjaString.prototype = { + toString: function(){ return this.value.join(""); } +}; + + +/** + * This is an include tag, like in Django: + * {% include "filename.html" %} + * + * The include does not render any blocks defined in it. + * + * You can also include dynamically defined templates: + * {% include files.template %} - notice the lack of quotes + */ +var validIncludeParamRegex = /^\s*(["']?)([^.][a-zA-Z0-9\-_.\/]+)\1\s*$/; +function INCLUDE( params, parent, main ) { + var filepath; + if( !( filepath = params.match( validIncludeParamRegex ) ) ) + throw new E.TSE( "Invalid filename in include tag: '%s'".fmt( params ) ); + + // If template is blocking it will bubble up to this token's parent. + if( filepath[1] === "'" || filepath[1] === '"' ) { + this.template = new Template( filepath[2], main ); + this.template.load(); + } + // Filename is in a context var - parse template on render + else { + this.lazy = filepath[2]; + this.main = main; + } +} + +INCLUDE.renderFunction = function( context ){ + var filepath; + if( this.lazy ) { + if( !( filepath = context.getPath( this.lazy ) ) ) + throw new E.TE( "Variable '%s' is not a valid filename".fmt( lazy ) ); + + var ns = new ninjaString(), frozen = context.clone(); + + new Template( filepath, this.main ).load( function( err, template ){ + if( template ) + ns.value = template.render( frozen ); + }); + return ns; + } + else + return this.template.render( context ); +} diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/index.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/index.js new file mode 100644 index 0000000..149a99a --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tags/index.js @@ -0,0 +1,6 @@ +exports['if'] = require('./if')['if']; +exports['else'] = require('./if')['else']; +exports['include'] = require('./include')['include']; +exports['block'] = require('./block')['block']; +exports['extends'] = require('./extends')['extends']; +exports['for'] = require('./for')['for']; diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/template.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/template.js new file mode 100644 index 0000000..8e1979f --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/template.js @@ -0,0 +1,43 @@ +// Template is separated form prototype to avoid circular imports + +/** @class + * + * A template always represents a physical file. + * You usually work with one (the first) instance of Template per + * request, and it is created by the controller. + * + * Templates are loaded (read from disk) and parsed asynchronously + * to obtain an array of 'children' which are the tempate tags and + * HTML strings (called tokens in common) in the template file. + * When the debug setting is set to false, these tokens are cached. + * + * While the template reads the file from the disk, it's 'blocked' property + * is set to a number greater than 0. It will not be rendered until its + * blocked counter reaches 0 again. The blocked counter decrements when + * the reading and parsing is finished. + * + * The main template (for example 'pages/home.html') is the one that is + * called by the controller. Some tags inside the template may reference + * other files, for example the {% extends "base.html" %} tag. This will + * create another instance of Template, load, parse and cache it. In + * case we don't have "base.html" cahced, the template will increase the + * blocked counter of *the main template* - in our case 'pages/home.html'. + * Again, nothing will render until the main template's blocked counter + * reaches zero again. + * + * On a warm cache, the reading and parsing almost never happens so the speed is + * considerably higher. + * + * @param {String} the filepath to the template file + * @param {Object} a refernce to the main template. If left out _this_ is used. + */ +exports.Template = function( filepath, main ){ + // Filepath relative to the templates directory + this.filepath = filepath; + // Contains the parsed tokens found in this template + this.children = []; + // Counts how many templates on which this one depends are still parsed + this.blocked = 0; + // A reference to the template that we initially called to render. + this.main = main || this; +} \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/templateproto.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/templateproto.js new file mode 100644 index 0000000..4d461a1 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/templateproto.js @@ -0,0 +1,239 @@ +var fs = require('fs') + , util = require('util') + , path = require('path') + , events = require('events') + , isArray = Array.isArray + + // Dependencies on template modules + , E = require('./exceptions') + , Context = require('./context').Context + , Template = require('./template').Template + , makeToken = require('./tokens').makeToken + + // These are also defined in tokens module + , STRING_TOKEN = 1 + , BLOCK_TOKEN = 2 + , BLOCK_TOKEN_END = 3 + , VAR_TOKEN = 4 + + // Some globals + , USE_CACHE = global.SETTINGS ? !SETTINGS.DEBUG : false + , TEMPLATES_DIR = global.SETTINGS ? SETTINGS.TEMPLATES_DIR : "" + + // Splits template by tags + , tagRegex = /(\{%.*?%\}|\{\{.*?\}\}|\{#.*?#\})/; + +Template.prototype = { + + /** + * Loads the template file and executes _callback_ when done. + * The callback is required and will be provided a reference + * to the template itself. A typical callback will render the + * template and finish the response. Example: + * + * {{{ + * template.load(function( template ){ + * template.render( context, function( result ){ + * response.write( result ); + * }); + * }); + * }}} + * + * _load_ will first look in the cache, and execute the callback + * If it doesn't find anything in the cache it will read and parse + * the file and then execute the callback. + * + * When a file needs to be read, the template sets up an eventEmitter + * that will fire when the template, and all it's subtemplates are ready. + * The function listening for events will fire the callback and unregister + * iteself so that it doesn't fire again. + * + * @param {Function} A callback to execute when loading is done. + */ + load: function( callback ) { + var filepath = this.filepath + , cb = typeof callback === "function"; + + // No errors could happen in here + if( filepath in Template.cache ) { + this.children = Template.cache[ filepath ]; + cb && callback( false, this ); + } + + else { // We need to perform blocking I/O + this.children = []; + var self = this; + + this.main.blocked++; + this.emitter = new events.EventEmitter(); + + fs.readFile( path.join( TEMPLATES_DIR, filepath ), function( err, buf ){ + if( err ) + self.main._err = new E.TE("'%s' with file '%s'. Missing a template?".fmt(err,filepath)); + + else try { + self.parse( buf.toString('utf8', 0, buf.length) ); // This may increase blocked counter + USE_CACHE && ( Template.cache[ filepath ] = self.children ); + } catch( e ) { self.main._err = e; } + + if( --self.main.blocked === 0 ) + self.main.emitter.emit( 'ready' ); + }); + + cb && self.main.emitter.addListener( 'ready', function() { + self.main.emitter.removeListener( 'ready', arguments.callee ); + callback( self.main._err, self ); + }); + } + } + + /** + * Parses the raw file data by splitting it into chunks. + * Each chunk is either a template tag string or a HTML string. + * The template tags are converted into tokens using _makeToken()_. + * The chunks are pushed into the _children_ array. When all is done + * we have the template ready to be rendered. The _children_ array is + * cached. + * + * @param {String} the template file (or string) + */ + , parse: function( data ){ + var tokens = data.trim().replace( /(^\n+)|(\n+$)/, "" ).split( tagRegex ) + , stack = [ this ] // a stack for nested block tags + , si = 0 // last element in the stack + , i, token; + + for( i=0; i five %} +{{four}} is bigger than {{five}} +{% else if five > 6 %} +{{five}} is bigger than 6? +{% else %} +The world is sane after all. +{% endif %} +{% for i in array %} +{% if i < 2 %} +{% include file %} +{% else %} +{% include "included.html" %} +{% if i == 3 %} +Nested If i == 3 +{% else %} +Nested Else +{% endif %} +{% endif %} +{% endfor %} +{% if "some string" == "some string" %} +some string == some string +{% endif %} +{% if greeting == "This text is a variable defined in the view." %} +greeting == This text is a variable defined in the view. +{% endif %} +{% if 'foo bar' != 'bar foo' %} +foo bar != bar foo +{% endif %} +{% endblock %} diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/run.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/run.js new file mode 100644 index 0000000..dab49ef --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/run.js @@ -0,0 +1,78 @@ +/** + * Call this script from the command line: + * $ node run.js + */ + +var T = require('../index') + , util = require('util') + , path = require('path'); + +T.setTemplatesDir( __dirname ); +T.setDebug( true ); + +util.puts( "\nRunning some benchmarks:" ); +util.puts( "*******************************************************" ); +var html =[ + "

This is the homepage

{{ greeting }}

", + "

", + "{% for i in l %}", + " {{i}}", + "{% if four > five %}", + "

{{four}} is bigger than {{five}}

", + "{% else if five > 6 %}", + "

{{five}} is bigger than 6

", + "{% else %}", + "

The world is sane after all.

", + "{% endif %}", + "{% endfor %}"].join("\n"); + +util.puts("\n", "Original html template: \n\n" + html, ""); +util.puts("Context: { greeting:'Hello World', four:4, five:5, l: [array with 100 elements] }", ""); + +util.puts( "*******************************************************" ); + +var l = []; +for( var i=0; i<100; i++ ) l.push("."); + +var d1 = new Date(); +var t2 = new T.Template(); +for( var i=0; i<10000; ++i ) + t2.parse(html); + +util.puts( "10K iterations on parsing the original string: " + (new Date() - d1) + " ms"); + +var d1 = new Date(); +var t2 = new T.Template(); +t2.parse(html); +for( var i=0; i<1000; ++i ) + t2.render({ greeting: "Hello World", four: 4, five: 5, l: l}); + +util.puts( "1000 iterations on rendering the parsed template: " + (new Date() - d1) + " ms"); + +util.puts( "\nParsing and loading from file:" ); +util.puts( "*******************************************************" ); +util.puts( "" ); + +var context = { + file: "included.html" + , extending: "base.html" + , four: 4 + , five: 5 + , array: [1,2,3,4] +}; + +// Add a default variable for all context instances +T.Context.addToDefault({ greeting: "This text is a variable defined in the view." }); + +var template = new T.Template( path.join( "page.html" ) ); +template.load( function( err, template ) { + if( err ) + util.puts( err ); + else + template.render( context, function( err, output ) { + if( err ) + util.puts( err ); + else + util.puts( output.join("").replace(/\n+/g,"\n") ); + }); +}); diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/run2.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/run2.js new file mode 100644 index 0000000..ecf227b --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/run2.js @@ -0,0 +1,54 @@ +/* + Test for http://github.com/skid/strobe-templates/issues#issue/1 + */ + +var util = require('util'); +var path = require('path'); +var assert = require('assert'); + +var T = require('../index') + +T.setTemplatesDir( __dirname ); + +var template = new T.Template(path.join('test.html')); + +function do_render() { + template.load(function (err, template) { + if (err) { + util.log(err); + return; + } + + template.render({}, function (err, rendered_template) { + if (err) { + util.log(err); + return; + } + + after_render(rendered_template); + return; + }) + }) +} + +var i = 0; +var rendered_template_length, new_length; +function after_render(rendered_template) { + if (i < 5) { + new_length = rendered_template.length; + + if (i == 0) { + rendered_template_length = new_length; + } + + assert.equal(new_length, rendered_template_length, + 'Rendered template length after call #' + i + + ' is not the same as the after the first call'); + + util.log(rendered_template); + do_render(); + i++; + } +} + +do_render(); diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/test.html b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/test.html new file mode 100644 index 0000000..ae1b136 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/test.html @@ -0,0 +1,2 @@ +One Two Three +End diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/test_forloop.html b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/test_forloop.html new file mode 100644 index 0000000..7d9d8bb --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tests/test_forloop.html @@ -0,0 +1,29 @@ +Array: +{% for item in array %} +item: {{ item }} + +counter: {{ forloop.counter }} +counter0: {{ forloop.counter0 }} +revcounter: {{ forloop.revcounter }} +revcounter0: {{ forloop.revcounter0 }} +{% endfor %} + +Object: +{% for property in obj %} +property: {{ property }} + +counter: {{ forloop.counter }} +counter0: {{ forloop.counter0 }} +revcounter: {{ forloop.revcounter }} +revcounter0: {{ forloop.revcounter0 }} +{% endfor %} + +String: +{% for c in str %} +char: {{ c }} + +counter: {{ forloop.counter }} +counter0: {{ forloop.counter0 }} +revcounter: {{ forloop.revcounter }} +revcounter0: {{ forloop.revcounter0 }} +{% endfor %} diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tokens.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tokens.js new file mode 100644 index 0000000..5c972c6 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/magic-templates/tokens.js @@ -0,0 +1,204 @@ +var util = require('util') + + // Template module dependencies + , E = require('./exceptions') + , tags = require('./tags') + + // Globals + , VAR_TOKEN_MISSING_WARNING = global.SETTINGS && SETTINGS.DEBUG ? "Missing variable '%s'" : "" + + , STRING_TOKEN = 1 + , BLOCK_TOKEN = 2 + , BLOCK_TOKEN_END = 3 + , VAR_TOKEN = 4 + + // Matches opening and closing tag delimiters + , blockTokenRegex = /^\{% *| *%\}$/g + , commentTokenRegex = /^\{# *| *#\}$/g + , varTokenRegex = /^\{\{ *| *\}\}$/g + + // A valid block-tag name + , validBlockNameRegex = /^\w+/ + + // A valid variable-tag name + , validVarNameRegex = /^[A-Za-z0-9_.]+/ + + // Shorthands + , isArray = Array.isArray; + +/** @class + * A Block Token (not to be confused with the 'block' tag) + * is a token defined by the {% and %} delimiters. + * Block tokens are template tags with a specific logic. + * The BlockToken class is responsible for deremining the tag type, + * overriding the default _render_ and _compile_ functions and + * calling the tag function on itself. + * The tag logic is defined in the ./tags module as a function, + * or can be defined by the user. + * Block tokens whose tag name begins with 'end' are considered + * closing tags. Example: {% if ... %} ... {% endif %}. This means + * that you can't make a tag with a name starting with 'end' + * + * @param {String} The tag name + * @param {String} Parameters passed to the tag + * @param {Object} A reference to the token/template that contains this token + * @param {Object} A reference to the main template + */ +var BlockToken = function( tagname, params, parent, main ){ + var tag; + // Closing tags begin with "end" like in {% for %}{% endfor %}. + if( tagname.indexOf("end") === 0 ) { + tagname = tagname.substr(3); + + if( !(tag = tags[ tagname ]) || !tag.expectsClosing ) + throw new E.TSE("Unknown closing tag '%s'".fmt( tagname )); + + if( parent.tagname !== tagname ) + throw new E.TSE( + "Unexpected closing tag 'end%s'; Expecting 'end%s'".fmt( tagname, parent.tagname )); + + this.type = BLOCK_TOKEN_END; + } + else { + // Check if tag exists + if( !( tag = tags[ tagname ] ) ) + throw new E.TSE( "Tag '%s' is not defined".fmt( tagname ) ); + + this.type = BLOCK_TOKEN; + this.tagname = tagname; + + // Copy some tag flags + tag.expectsClosing && ( this.children = [] ); + tag.renderFunction && ( this.render = tag.renderFunction ); + tag.compileFunction && ( this.compile = tag.compileFunction ); + + // Apply the tag function to this token + tag.call( this, params, parent, main ); + } +} + +BlockToken.prototype = { + /** + * This is the default block token render method + * It just loops through the token's children and appends + * whatever output their render method returns. + * Tags can everride this method for specific needs + * and can call this function by using: + * {{{ + * Object.getPrototypeOf(this).render.call(this,arguments) + * }}} + * + * If the children parameter is passed (it's supposed to be an + * array of tokens) it will be used instead of this token's children. + * + * @param {Object} the context to use when rendering + * @param {Array} children to render instead of this token's children + * @return {Array} the output. + */ + render: function( context, children ) { + var i, j, r, token + , output = [] + , tokens = children || this.children || []; + + for( i=0, j=tokens.length; iMissing variable '%s'" : ""; +} diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/README.md b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/README.md new file mode 100644 index 0000000..a553ac9 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/README.md @@ -0,0 +1,3 @@ +A `rm -rf` for node. + +Install with `npm install rimraf`, or just drop rimraf.js somewhere. diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/package.json b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/package.json new file mode 100644 index 0000000..293863f --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/package.json @@ -0,0 +1,8 @@ +{"name":"rimraf" +,"version":"1.0.1" +,"main":"rimraf.js" +,"description":"A deep deletion module for node (like `rm -rf`)" +,"author":"Isaac Z. Schlueter (http://blog.izs.me/)" +,"contributors":["Wayne Larsen (http://github.com/wvl)"] +,"repository":"git://github.com/isaacs/rimraf.git" +,"scripts":{"test":"cd test && bash run.sh"}} diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/rimraf.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/rimraf.js new file mode 100644 index 0000000..73aac2c --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/rimraf.js @@ -0,0 +1,81 @@ +module.exports = rimraf +rimraf.sync = rimrafSync + +var fs = require("fs") + , path = require("path") + +// for EBUSY handling +var waitBusy = {} + , maxBusyTries = 3 + +// for EMFILE handling +var resetTimer = null + , timeout = 0 + +function rimraf (p, cb_) { + rimraf_(p, function cb (er) { + if (er) { + if (er.message.match(/^EBUSY/)) { + // windows is annoying. + if (!waitBusy.hasOwnProperty(p)) waitBusy[p] = maxBusyTries + if (waitBusy[p]) { + waitBusy[p] -- + // give it 100ms more each time + var time = (maxBusyTries - waitBusy[p]) * 100 + return setTimeout(function () { rimraf_(p, cb) }, time) + } + } + if (er.message.match(/^EMFILE/)) { + setTimeout(function () { + rimraf_(p, cb) + }, timeout ++) + return + } + } + timout = 0 + cb_(er) + }) +} + +function asyncForEach (list, fn, cb) { + if (!list.length) cb() + var c = list.length + , errState = null + list.forEach(function (item, i, list) { + fn(item, function (er) { + if (errState) return + if (er) return cb(errState = er) + if (-- c === 0) return cb() + }) + }) +} + +function rimraf_ (p, cb) { + fs.lstat(p, function (er, s) { + if (er) return cb() + if (!s.isDirectory()) return fs.unlink(p, cb) + fs.readdir(p, function (er, files) { + if (er) return cb(er) + asyncForEach(files.map(function (f) { + return path.join(p, f) + }), rimraf, function (er) { + if (er) return cb(er) + fs.rmdir(p, cb) + }) + }) + }) +} + +// this looks simpler, but it will fail with big directory trees, +// or on slow stupid awful windows filesystems, +// and it's much slower, since the functional async version will +// actually delete up to 4 things at once, or whatever eio is +// configured to handle. +function rimrafSync (p) { + var s = fs.lstatSync(p) + if (!s.isDirectory()) return fs.unlinkSync(p) + fs.readdirSync(p).forEach(function (f) { + rimrafSync(path.join(p, f)) + }) + fs.rmdirSync(p) +} diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/run.sh b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/run.sh new file mode 100644 index 0000000..598f016 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/run.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -e +for i in test-*.js; do + echo -n $i ... + bash setup.sh + node $i + ! [ -d target ] + echo "pass" +done +rm -rf target diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/setup.sh b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/setup.sh new file mode 100644 index 0000000..2602e63 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/setup.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +set -e + +files=10 +folders=2 +depth=4 +target="$PWD/target" + +rm -rf target + +fill () { + local depth=$1 + local files=$2 + local folders=$3 + local target=$4 + + if ! [ -d $target ]; then + mkdir -p $target + fi + + local f + + f=$files + while [ $f -gt 0 ]; do + touch "$target/f-$depth-$f" + let f-- + done + + let depth-- + + if [ $depth -le 0 ]; then + return 0 + fi + + f=$folders + while [ $f -gt 0 ]; do + mkdir "$target/folder-$depth-$f" + fill $depth $files $folders "$target/d-$depth-$f" + let f-- + done +} + +fill $depth $files $folders $target + +# sanity assert +[ -d $target ] diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/test-async.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/test-async.js new file mode 100644 index 0000000..9c2e0b7 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/test-async.js @@ -0,0 +1,5 @@ +var rimraf = require("../rimraf") + , path = require("path") +rimraf(path.join(__dirname, "target"), function (er) { + if (er) throw er +}) diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/test-sync.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/test-sync.js new file mode 100644 index 0000000..eb71f10 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/rimraf/test/test-sync.js @@ -0,0 +1,3 @@ +var rimraf = require("../rimraf") + , path = require("path") +rimraf.sync(path.join(__dirname, "target")) diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/README.md b/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/README.md new file mode 100644 index 0000000..36a9ef5 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/README.md @@ -0,0 +1,104 @@ +Simple set datatype for JavaScript +========== + +This provides a set data type, with an API very close to that of [Python's sets module](http://docs.python.org/library/sets.html). + +Installation +---------- + +If you have the node package manager, this is easy: + + npm install simplesets + +You could also clone the git repository, and install it manually. + +Usage +---------- + +Here's an example of how you use it: + + var sets = require('simplesets'); + + var s1 = new sets.Set(['hello', 'world', 'how', 'are', 'you', 'today']); + var s2 = new sets.Set(['say', 'hello', 'to', 'the', 'world']); + + // Print out both of the sets, as arrays of their elements. + console.log('s1 =', s1.array()); + console.log('s2 =', s2.array()); + + // Do some set operations. + console.log('Intersection:', s1.intersection(s2).array()); + console.log('s1 - s2:', s1.difference(s2).array()); + console.log('s2 - s1:', s2.difference(s1).array()); + console.log('Union:', s1.union(s2).array()); + + // Make a set with numbers and strings. + var s3 = new sets.Set([1, 2, 3, 'a', 'b', 'c']); + console.log('Mixing data types:', s3.array()); + // Add in some more data types. + var my_dict = {foo: 42, bar: 'bazaar'}; + s3.add(my_dict); // This will add to the set... + s3.add(my_dict); // ...but now this will do nothing. + s3.remove(3); + s3.remove('c'); + console.log('New s3 =', s3.array()); + + // You can make shallow copies of sets. + var s4 = new sets.Set([1, 2, 3]); + var s5 = s4.copy(); + s4.add(42); + s5.remove(2); + console.log('s4 =', s4.array()); + console.log('s5 =', s5.array()); + +The set data type has the simplest, stupidest implementation possible: an unordered array. This is because of how JavaScript's data types work. If it were possible to compute a hash value from any data type, or get its memory address, then we could do something more elaborate. If `<` and `>` operations were defined for all data types, we could use some kind of balanced tree representation, or sorted arrays. If JavaScript objects supported arbitrary data types as indices, this would all be too easy. But none of those things is true, so we're stuck relying only on the `===` operation, and unsorted arrays. For small sets, this is not a problem. For larger sets, if performance of set operations turns out to be problematic, you may want to use a specialized set data type. For example, if your set members are all strings, you could represent sets as objects with set members as keys, and it would be fast. For this, use the `StringSet` class, described below. + +Set API +---------- + +The `Set` class has the following methods: + +* `new Set(items)`: Creates a new set. If an array `items` is given, its contents will be added to the set. + +* `has(x)`: Does this set contain an element `x`? Returns `true` or `false`. + +* `add(x)`: Add an element `x` to this set, and return this set. + +* `remove(x)`: Remove an element `x` from this set, if it is part of the set. If it is not part of the set, do nothing. Returns this set. + +* `union(other)`: Return a new set containing the items found in either this set, the other set, or both. + +* `intersection(other)`: Return a new set containing the items found in both this set and the other set. + +* `difference(other)`: Return a new set containing the items in this set that are not in the other set. + +* `symmetric_difference(other)`: Return a new set containing the items in either this set or the other set, but not both. + +* `issubset(other)`: Return `true` if every element of this set is in the other set. + +* `issuperset(other)`: Return `true` if every element of the other is in this set. + +* `equals(other)`: Return `true` if this set equals another set, i.e. if every element in each set is equal to an element in the other set. + +* `array()`: Return a copy of the items in the set, as an array. + +* `size()`: Return the size of the set. + +* `copy()`: Return a shallow copy of the set. + +* `pop()`: Remove and return a random element of the set, or null if the set is empty. + +* `pick()`: Return a random element of the set, or null if the set is empty. Unlike `pop`, does not remove the element from the set. + +* `each(callback)`: Call a callback function on each element of the set. If the set is changed by the callback, the results are undefined. The callback takes a single argument: the set element that it's being called on. + +The condition for determining whether two values are equal is the `===` operator. Therefore sets can support any mix of data types, as long as the data types can be compared for equality in some meaningful sense with `===`. + +Specialized sets +---------- + +If all of your set members have unique string representations, then you can create a set using object properties to keep track of the members. This takes advantage of the fast built-in object type in JavaScript, and is generally better than using general-purpose sets if there will not be collisions, e.g. a set containing both the number 42 and the string "42". + +The `StringSet` class behaves just like the `Set` class, but it uses this object-based encoding and requires that all set members have unique string representations. Instantiate it with `new StringSet(items)`, and the API is the same as described above. + +Note that `Set` will generally be faster and more memory-efficient than `StringSet` for sets with fewer than around 110 elements. `StringSet` is good for large sets, though. diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/examples/hello.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/examples/hello.js new file mode 100644 index 0000000..428ca33 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/examples/hello.js @@ -0,0 +1,35 @@ +// Some toy examples of how to use the Set class. + +var sets = require('simplesets'); + +var s1 = new sets.Set(['hello', 'world', 'how', 'are', 'you', 'today']); +var s2 = new sets.Set(['say', 'hello', 'to', 'the', 'world']); + +// Print out both of the sets, as arrays of their elements. +console.log('s1 =', s1.array()); +console.log('s2 =', s2.array()); + +// Do some set operations. +console.log('Intersection:', s1.intersection(s2).array()); +console.log('s1 - s2:', s1.difference(s2).array()); +console.log('s2 - s1:', s2.difference(s1).array()); +console.log('Union:', s1.union(s2).array()); + +// Make a set with numbers and strings. +var s3 = new sets.Set([1, 2, 3, 'a', 'b', 'c']); +console.log('Mixing data types:', s3.array()); +// Add in some more data types. +var my_dict = {foo: 42, bar: 'bazaar'}; +s3.add(my_dict); // This will add to the set... +s3.add(my_dict); // ...but now this will do nothing. +s3.remove(3); +s3.remove('c'); +console.log('New s3 =', s3.array()); + +// You can make shallow copies of sets. +var s4 = new sets.Set([1, 2, 3]); +var s5 = s4.copy(); +s4.add(42); +s5.remove(2); +console.log('s4 =', s4.array()); +console.log('s5 =', s5.array()); \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/lib/simplesets.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/lib/simplesets.js new file mode 100644 index 0000000..667b0ef --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/lib/simplesets.js @@ -0,0 +1,321 @@ +// Set code for Node.js, which stores objects in arrays. All sets are +// mutable, and set update operations happen destructively. However, +// operations like set intersection and difference create a new set. + +var SetPrototype = { + // Does this set contain an element x? Returns true or false. + has: function(x) { + return this._items.indexOf(x) >= 0; + }, + + // Add an element x to this set, and return this set. + add: function(x) { + if (!this.has(x)) this._items.push(x); + return this; + }, + + // Remove an element x from this set, if it is part of the set. If + // it is not part of the set, do nothing. Returns this set. + remove: function(x) { + var pos = this._items.indexOf(x); + if (pos >= 0) { + this._items.splice(pos, 1); + } + return this; + }, + + // Return a new set containing the items found in either this set, + // the other set, or both. + union: function(other) { + var result = new exports.Set(); + result._items = this._items.concat(); // Make a copy + for (var i = 0; i < other._items.length; i++) + result.add(other._items[i]); + return result; + }, + + // Return a new set containing the items found in both this set + // and the other set. + intersection: function(other) { + var result = new exports.Set(); + for (var i = 0; i < other._items.length; i++) + if (this.has(other._items[i])) + result._items.push(other._items[i]); + return result; + }, + + // Return a new set containing the items in this set that are not + // in the other set. + difference: function(other) { + var result = new exports.Set(); + for (var i = 0; i < this._items.length; i++) + if (!other.has(this._items[i])) + result._items.push(this._items[i]); + return result; + }, + + // Return a new set containing the items in either this set or the + // other set, but not both. + symmetric_difference: function(other) { + // Hideously inefficient -- but who uses this function, anyway? + return this.union(other).difference(this.intersection(other)); + }, + + // Return true if every element of this set is in the other set. + issubset: function(other) { + for (var i = 0; i < this._items.length; i++) + if (!other.has(this._items[i])) + return false; + return true; + }, + + // Return true if every element of the other is in this set. + issuperset: function(other) { + return other.issubset(this); + }, + + // Return a copy of the items in the set, as an array. + array: function() { + return this._items.concat(); + }, + + // Return the size of the set. + size: function() { + return this._items.length; + }, + + // Return a shallow copy of the set. + copy: function() { + var result = new exports.Set(); + result._items = this._items.concat(); + return result; + }, + + // Return a random element of the set, or null if the set is + // empty. Unlike pop, does not remove the element from the set. + pick: function() { + if (this._items.length === 0) return null; + + var i = Math.floor(Math.random() * this._items.length); + return this._items[i]; + }, + + // Remove and return a random element of the set, or null if the + // set is empty. + pop: function() { + if (this._items.length === 0) return null; + + var i = Math.floor(Math.random() * this._items.length); + return this._items.splice(i, 1)[0]; + }, + + // Return true if this set equals another set, i.e. if every + // element in each set is equal to an element in the other set. + equals: function(other) { + // Common case: sets are different size. + if (this.size() !== other.size()) return false; + + + // If sets are the same size, we can just check to see that + // every element in this set corresponds to an element in the + // other set. + for (var i = 0; i < this._items.length; i++) + if (!other.has(this._items[i])) + return false; + return true; + }, + + // Call a callback function on each element of the set. If the set + // is changed by the callback, the results are undefined. + each: function(callback) { + // If there's no callback, don't bother. + if (!callback) return; + + for (var i = 0; i < this._items.length; i++) + callback(this._items[i]); + } +}; + +exports.Set = function(items) { + // All items are stored in this list, in no particular order. + this._items = []; + + // If initial items were given, add them to the set. + if (typeof items !== "undefined") + for (var i = 0; i < items.length; i++) + this.add(items[i]); +}; + +exports.Set.prototype = SetPrototype; + + +var StringSetPrototype = { + // Does this set contain an element x? Returns true or false. + has: function(x) { + return this._items.hasOwnProperty(x); + }, + + // Add an element x to this set, and return this set. + add: function(x) { + if (!this.has(x)) { + this._items[x] = x; + this._size++; + } + return this; + }, + + // Remove an element x from this set, if it is part of the set. If + // it is not part of the set, do nothing. Returns this set. + remove: function(x) { + if (this.has(x)) { + delete this._items[x]; + this._size--; + } + return this; + }, + + // Return a new set containing the items found in either this set, + // the other set, or both. + union: function(other) { + var result = new exports.StringSet(); + for (var x in this._items) result.add(this._items[x]); + for (x in other._items) result.add(other._items[x]); + return result; + }, + + // Return a new set containing the items found in both this set + // and the other set. + intersection: function(other) { + var result = new exports.StringSet(); + for (var x in other._items) + if (this._items.hasOwnProperty(x)) + result.add(this._items[x]); + return result; + }, + + // Return a new set containing the items in this set that are not + // in the other set. + difference: function(other) { + var result = new exports.StringSet(); + for (var x in this._items) + if (!other._items.hasOwnProperty(x)) + result.add(this._items[x]); + return result; + }, + + // Return a new set containing the items in either this set or the + // other set, but not both. + symmetric_difference: function(other) { + // Hideously inefficient -- but who uses this function, anyway? + return this.union(other).difference(this.intersection(other)); + }, + + // Return true if every element of this set is in the other set. + issubset: function(other) { + for (var x in this._items) + if (!other._items.hasOwnProperty(x)) + return false; + return true; + }, + + // Return true if every element of the other is in this set. + issuperset: function(other) { + return other.issubset(this); + }, + + // Return a copy of the items in the set, as an array. + array: function() { + var arr = []; + for (var x in this._items) + arr.push(this._items[x]); + return arr; + }, + + // Return the size of the set. + size: function() { + return this._size; + }, + + // Return a shallow copy of the set. + copy: function() { + var result = new exports.StringSet(); + for (var x in this._items) result.add(this._items[x]); + return result; + }, + + // Return a random element of the set, or null if the set is + // empty. Unlike pop, does not remove the element from the set. + pick: function() { + if (this._size === 0) return null; + + var i = Math.floor(Math.random() * this._size); + for (var x in this._items) { + if (i === 0) return this._items[x]; + i--; + } + // This should never happen + return null; + }, + + // Remove and return a random element of the set, or null if the + // set is empty. + pop: function() { + if (this._size === 0) return null; + + var i = Math.floor(Math.random() * this._size); + for (var x in this._items) { + if (i === 0) { + var ret = this._items[x]; + this.remove(this._items[x]); + return ret; + } + i--; + } + // This should never happen + return null; + }, + + // Return true if this set equals another set, i.e. if every + // element in each set is equal to an element in the other set. + equals: function(other) { + // Common case: sets are different size. + if (this.size() !== other.size()) return false; + + // If sets are the same size, we can just check to see that + // every element in this set corresponds to an element in the + // other set. + for (var x in this._items) + if (!other.has(this._items[x])) + return false; + return true; + }, + + // Call a callback function on each element of the set. If the set + // is changed by the callback, the results are undefined. + each: function(callback) { + // If there's no callback, don't bother. + if (!callback) return; + + for (var x in this._items) + callback(this._items[x]); + } +} + +// A special type of set, where all keys have unique string +// representations. This works fine with a set containing only +// strings, or only numbers. However, if you want to have the number +// 42 and the string "42" in the same set, you should use the Set data +// type, not StringSet. +exports.StringSet = function(items) { + // All items are stored in an object. + this._items = {}; + // We maintain a size variable for the cardinality of the set. + this._size = 0; + + // If initial items were given, add them to the set. + if (typeof items !== "undefined") + for (var i = 0; i < items.length; i++) + this.add(items[i]); +}; + +exports.StringSet.prototype = StringSetPrototype; \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/package.json b/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/package.json new file mode 100644 index 0000000..3f2a35e --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/package.json @@ -0,0 +1,11 @@ +{ "name": "simplesets", + "version": "1.1.6", + "description": "Simple set data type, with API similar to Python's sets module.", + "author": "Peter Scott ", + "main": "./lib/simplesets.js", + "repository": {"type": "git", "url": "http://github.com/PeterScott/simplesets-nodejs.git"}, + "homepage": "http://github.com/PeterScott/simplesets-nodejs", + "scripts": { + "test": "node test/testsets.js" + } +} \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/test/testsets.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/test/testsets.js new file mode 100644 index 0000000..54a95ca --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/simplesets/test/testsets.js @@ -0,0 +1,180 @@ +var assert = require('assert'); +var sets = require('../lib/simplesets'); + +//////////////////// +// sets.Set tests +//////////////////// + +// Test basic set construction, add, remove, size, copy, equals, and has. +var s1 = new sets.Set([1, 2, 3]); +var s2 = new sets.Set(); +assert.equal(s1.size(), 3); +assert.equal(s2.size(), 0); +assert.equal(s1.has(2), true); +assert.equal(s1.has(4), false); +assert.equal(s2.has(1), false); +s1.remove(2); +s1.add(42); +s2.add(3); s2.add(4); +s2.remove(3); +assert.equal(s1.has(2), false); +assert.equal(s2.has(3), false); +assert.equal(s2.has(4), true); +assert.ok(s1.equals(new sets.Set([42, 1, 3]))); +assert.ok(s2.equals(s2)); +assert.ok(s1.equals(s1.copy())); +assert.ok(s1.copy() !== s1); +assert.ok(!s1.equals(s2)); +assert.ok(typeof s1.array() == typeof [1, 2, 3]); + +// Test two-set operations, using mixed number and string keys. +var s3 = new sets.Set([1, 2, 3, "1", "2", "3"]); +var s4 = new sets.Set([3, "1", "foo"]); +var nullset = new sets.Set(); +var s3sub = new sets.Set([1, "3", 2]); +assert.ok(s3.issuperset(s3sub)); +assert.ok(!s3sub.issuperset(s3)); +assert.ok(s3sub.issubset(s3)); +assert.ok(!s4.issubset(s3)); +assert.ok(s3.union(s4).equals(new sets.Set([1, 2, 3, "1", "2", "3", "foo"]))); +assert.ok(s3.intersection(s4).equals(new sets.Set(["1", 3]))); +assert.ok(s3.difference(s4).equals(new sets.Set([1, 2, "2", "3"]))); +assert.ok(s3.symmetric_difference(s4).equals(new sets.Set([1, 2, "2", "3", "foo"]))); +assert.ok(nullset.union(nullset.copy()).size() === 0); + +// Test the pop operation +var sa = new sets.Set([3, 1, 4, 1, 5, 9]); +var sb = new sets.Set(); + +for (var i = 0; i < 200; i++) { + var sa_copy = sa.copy(); + sb.add(sa_copy.pop()); + assert.ok(sa_copy.size() === sa.size() - 1); +} + +assert.ok(sb.issubset(sa)); + +// Test the pick operation, in much the same way. +var sa = new sets.Set([3, 1, 4, 1, 5, 9]); +var sb = new sets.Set(); + +for (var i = 0; i < 200; i++) { + var sa_old_size = sa.size(); + sb.add(sa.pick()); + assert.ok(sa.size() === sa_old_size); +} + +assert.ok(sb.issubset(sa)); +assert.ok(nullset.pick() === null); +assert.ok(nullset.pop() === null); +assert.ok(nullset.issubset(nullset)); + +// Make sure add and remove return the set, for chaining. +var s5 = new sets.Set(); +s5.add(3).add(4).remove(3); +assert.ok(s5.equals(new sets.Set([4]))); + +// Test each() function +function set_test_each(s) { + n = new sets.Set(); + s.each(function(x) { + assert.ok(!n.has(x)); + n.add(x); + }); + assert.ok(n.equals(s)); + assert.ok(s.equals(n)); +} +set_test_each(new sets.Set([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9])); +set_test_each(new sets.Set([1, 2, 3, "1", "2", "3", "foo"])); +set_test_each(new sets.Set()); +set_test_each(new sets.Set({foo: 42})); + +/////////////////////// +// sets.StringSet tests +/////////////////////// + +// Test basic set construction, add, remove, size, copy, equals, and has. +var s1 = new sets.StringSet([1, 2, 3]); +var s2 = new sets.StringSet(); +assert.equal(s1.size(), 3); +assert.equal(s2.size(), 0); +assert.equal(s1.has(2), true); +assert.equal(s1.has(4), false); +assert.equal(s2.has(1), false); +s1.remove(2); +s1.add(42); +s2.add(3); s2.add(4); +s2.remove(3); +assert.equal(s1.has(2), false); +assert.equal(s2.has(3), false); +assert.equal(s2.has(4), true); +assert.ok(s1.equals(new sets.StringSet([42, 1, 3]))); +assert.ok(s2.equals(s2)); +assert.ok(s1.equals(s1.copy())); +assert.ok(s1.copy() !== s1); +assert.ok(!s1.equals(s2)); +assert.ok(typeof s1.array() == typeof [1, 2, 3]); + +// Test two-set operations, using mixed number and string keys. +var s3 = new sets.StringSet([1, 2, 3, "11", "22", "33"]); +var s4 = new sets.StringSet([3, "11", "foo"]); +var nullset = new sets.StringSet(); +var s3sub = new sets.StringSet([1, "33", 2]); +assert.ok(s3.issuperset(s3sub)); +assert.ok(!s3sub.issuperset(s3)); +assert.ok(s3sub.issubset(s3)); +assert.ok(!s4.issubset(s3)); +assert.ok(s3.intersection(s4).equals(new sets.StringSet(["11", 3]))); +assert.ok(s3.difference(s4).equals(new sets.StringSet([1, 2, "22", "33"]))); +assert.ok(s3.symmetric_difference(s4).equals(new sets.StringSet([1, 2, "22", "33", "foo"]))); +assert.ok(nullset.union(nullset.copy()).size() === 0); + +// Test the pop operation +var sa = new sets.StringSet([3, 1, 4, 1, 5, 9]); +var sb = new sets.StringSet(); + +for (var i = 0; i < 200; i++) { + var sa_copy = sa.copy(); + sb.add(sa_copy.pop()); + assert.ok(sa_copy.size() === sa.size() - 1); +} + +assert.ok(sb.issubset(sa)); + +// Test the pick operation, in much the same way. +var sa = new sets.StringSet([3, 1, 4, 1, 5, 9]); +var sb = new sets.StringSet(); + +for (var i = 0; i < 200; i++) { + var sa_old_size = sa.size(); + sb.add(sa.pick()); + assert.ok(sa.size() === sa_old_size); +} + +assert.ok(sb.issubset(sa)); +assert.ok(nullset.pick() === null); +assert.ok(nullset.pop() === null); +assert.ok(nullset.issubset(nullset)); + +// Make sure add and remove return the set, for chaining. +var s5 = new sets.StringSet(); +s5.add(3).add(4).remove(3); +assert.ok(s5.equals(new sets.StringSet([4]))); + +// Test each() function +function stringset_test_each(s) { + n = new sets.StringSet(); + s.each(function(x) { + assert.ok(!n.has(x)); + n.add(x); + }); + assert.ok(n.equals(s)); + assert.ok(s.equals(n)); +} +set_test_each(new sets.StringSet([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9])); +set_test_each(new sets.StringSet([1, 2, 3, "11", "22", "33", "foo"])); +set_test_each(new sets.StringSet()); +set_test_each(new sets.StringSet({foo: 42})); + +// If we got to here, then... +console.log('All tests passed!'); \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/sprintf/README.md b/node_modules/cassandra-client/node_modules/whiskey/node_modules/sprintf/README.md new file mode 100644 index 0000000..00722ae --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/sprintf/README.md @@ -0,0 +1,14 @@ +# sprintf() for node + +## Install + + npm install sprintf + +## How to + +Works exactly like http://www.diveintojavascript.com/projects/javascript-sprintf, except that it exports those two functions: + + sprintf = requrie('sprintf').sprintf; + vsprintf = require('sprintf').vsprintf; + +Have fun! diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/sprintf/lib/sprintf.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/sprintf/lib/sprintf.js new file mode 100644 index 0000000..944701a --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/sprintf/lib/sprintf.js @@ -0,0 +1,189 @@ +/** +sprintf() for JavaScript 0.7-beta1 +http://www.diveintojavascript.com/projects/javascript-sprintf + +Copyright (c) Alexandru Marasteanu +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 sprintf() for JavaScript 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 Alexandru Marasteanu 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. + + +Changelog: +2010.11.07 - 0.7-beta1-node + - converted it to a node.js compatible module + +2010.09.06 - 0.7-beta1 + - features: vsprintf, support for named placeholders + - enhancements: format cache, reduced global namespace pollution + +2010.05.22 - 0.6: + - reverted to 0.4 and fixed the bug regarding the sign of the number 0 + Note: + Thanks to Raphael Pigulla (http://www.n3rd.org/) + who warned me about a bug in 0.5, I discovered that the last update was + a regress. I appologize for that. + +2010.05.09 - 0.5: + - bug fix: 0 is now preceeded with a + sign + - bug fix: the sign was not at the right position on padded results (Kamal Abdali) + - switched from GPL to BSD license + +2007.10.21 - 0.4: + - unit test and patch (David Baird) + +2007.09.17 - 0.3: + - bug fix: no longer throws exception on empty paramenters (Hans Pufal) + +2007.09.11 - 0.2: + - feature: added argument swapping + +2007.04.03 - 0.1: + - initial release +**/ + +var sprintf = (function() { + function get_type(variable) { + return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase(); + } + function str_repeat(input, multiplier) { + for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */} + return output.join(''); + } + + var str_format = function() { + if (!str_format.cache.hasOwnProperty(arguments[0])) { + str_format.cache[arguments[0]] = str_format.parse(arguments[0]); + } + return str_format.format.call(null, str_format.cache[arguments[0]], arguments); + }; + + str_format.format = function(parse_tree, argv) { + var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length; + for (i = 0; i < tree_length; i++) { + node_type = get_type(parse_tree[i]); + if (node_type === 'string') { + output.push(parse_tree[i]); + } + else if (node_type === 'array') { + match = parse_tree[i]; // convenience purposes only + if (match[2]) { // keyword argument + arg = argv[cursor]; + for (k = 0; k < match[2].length; k++) { + if (!arg.hasOwnProperty(match[2][k])) { + throw(sprintf('[sprintf] property "%s" does not exist', match[2][k])); + } + arg = arg[match[2][k]]; + } + } + else if (match[1]) { // positional argument (explicit) + arg = argv[match[1]]; + } + else { // positional argument (implicit) + arg = argv[cursor++]; + } + + if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) { + throw(sprintf('[sprintf] expecting number but found %s', get_type(arg))); + } + switch (match[8]) { + case 'b': arg = arg.toString(2); break; + case 'c': arg = String.fromCharCode(arg); break; + case 'd': arg = parseInt(arg, 10); break; + case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break; + case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break; + case 'o': arg = arg.toString(8); break; + case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break; + case 'u': arg = Math.abs(arg); break; + case 'x': arg = arg.toString(16); break; + case 'X': arg = arg.toString(16).toUpperCase(); break; + } + arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg); + pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' '; + pad_length = match[6] - String(arg).length; + pad = match[6] ? str_repeat(pad_character, pad_length) : ''; + output.push(match[5] ? arg + pad : pad + arg); + } + } + return output.join(''); + }; + + str_format.cache = {}; + + str_format.parse = function(fmt) { + var _fmt = fmt, match = [], parse_tree = [], arg_names = 0; + while (_fmt) { + if ((match = /^[^\x25]+/.exec(_fmt)) !== null) { + parse_tree.push(match[0]); + } + else if ((match = /^\x25{2}/.exec(_fmt)) !== null) { + parse_tree.push('%'); + } + else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) { + if (match[2]) { + arg_names |= 1; + var field_list = [], replacement_field = match[2], field_match = []; + if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { + field_list.push(field_match[1]); + while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') { + if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { + field_list.push(field_match[1]); + } + else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) { + field_list.push(field_match[1]); + } + else { + throw('[sprintf] huh?'); + } + } + } + else { + throw('[sprintf] huh?'); + } + match[2] = field_list; + } + else { + arg_names |= 2; + } + if (arg_names === 3) { + throw('[sprintf] mixing positional and named placeholders is not (yet) supported'); + } + parse_tree.push(match); + } + else { + throw('[sprintf] huh?'); + } + _fmt = _fmt.substring(match[0].length); + } + return parse_tree; + }; + + return str_format; +})(); + +var vsprintf = function(fmt, argv) { + argv.unshift(fmt); + return sprintf.apply(null, argv); +}; + +exports.sprintf = sprintf; +exports.vsprintf = vsprintf; \ No newline at end of file diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/sprintf/package.json b/node_modules/cassandra-client/node_modules/whiskey/node_modules/sprintf/package.json new file mode 100644 index 0000000..809ad35 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/sprintf/package.json @@ -0,0 +1,14 @@ +{ + "name": "sprintf", + "version": "0.1.1", + "engines": { + "node" : ">=0.2.4" + }, + "author": "Moritz Peters", + "directories": { + "lib": "./lib" + }, + "description": "Sprintf() for node.js", + "main": "./lib/sprintf" +} + diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/.lvimrc b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/.lvimrc new file mode 100644 index 0000000..4a67db4 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/.lvimrc @@ -0,0 +1,3 @@ +set tabstop=2 +set shiftwidth=2 +set expandtab diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/.npmignore b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/.npmignore new file mode 100644 index 0000000..c05f443 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/.npmignore @@ -0,0 +1,3 @@ +node_modules/ +.gitignore +.DS_Store diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/Makefile b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/Makefile new file mode 100644 index 0000000..3e78b33 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/Makefile @@ -0,0 +1,11 @@ +CWD=`pwd` + +FILES=`find tests -name test*.js -print0` + +test: + NODE_PATH=`pwd`/lib whiskey --tests "${CWD}/${FILES}" + +coverage: + NODE_PATH=`pwd`/lib whiskey --tests "${CWD}/${FILES}" --coverage --coverage-reporter html --coverage-dir coverage_html + +.PHONY: test coverage diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/index.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/index.js new file mode 100644 index 0000000..b9084ed --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/index.js @@ -0,0 +1,30 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +function exportVars(exportedVars) { + var varValue, varName; + + for (varName in exportedVars) { + if (exportedVars.hasOwnProperty(varName)) { + varValue = exportedVars[varName]; + exports = module.exports[varName] = varValue; + } + } +} + +exportVars(require('./lib/terminal')); +exportVars(require('./lib/spinner')); diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/lib/spinner.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/lib/spinner.js new file mode 100644 index 0000000..ae1ab72 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/lib/spinner.js @@ -0,0 +1,210 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var util = require('util'); +var tty = require('tty'); + +var sprintf = require('sprintf').sprintf; + +var dots = ['|', '/', '-', '\\']; + +/** + * Display a prompt followed by a little spinning character. Call tick + * repeatedly to update. + * @constructor + * @param {String} prompter The prompt string. + */ +function Spinner(prompter) { + this.ticks = 0; + this.promptstr = prompter; +} + +/** + * Start the spinner. + */ +Spinner.prototype.start = function() { + process.stdout.write('\n' + this.promptstr + ' '); + this.tick(); +}; + +/** + * Update the spinner with the given character, internal use only. + * + * @param {String} c The character to set. + */ +Spinner.prototype.update = function(c) { + process.stdout.write('\b' + c); +}; + +/** + * Call this repeatedly to spin the spinner. + */ +Spinner.prototype.tick = function() { + this.ticks++; + var c = dots[this.ticks % dots.length]; + this.update(c); +}; + +/** + * End the spinner. + */ +Spinner.prototype.end = function() { + process.stdout.write('\n'); +}; + +/** + * Show a prompt followed by an updating percentage value. + * @constructor + * @param {String} prompter The prompt string. + * @param {Number} max The value to use for 100%. + */ +function PercentSpinner(prompter, max) { + this.max = max; + this.current = 0; + this.promptstr = prompter; +} + +/** + * Start the spinner. + */ +PercentSpinner.prototype.start = function() { + process.stdout.write('\n' + this.promptstr + ' '); + this.tick(0); +}; + +/** + * Set the given percentage string, internal use only. + * + * @param {String} c The percentage string to set. + */ +PercentSpinner.prototype.update = function(c) { + process.stdout.write('\b\b\b\b\b' + c); +}; + +/** + * Update the spinner. Call this repeatedly with new values as they become + * available. + * + * @param {Number} value The current value to set the spinner to. + */ +PercentSpinner.prototype.tick = function(value) { + this.current = value; + var p = (this.current / this.max) * 100; + this.update(sprintf('%4d%%', p)); +}; + +/** + * End the spinner. + */ +PercentSpinner.prototype.end = function() { + process.stdout.write('\n'); +}; + +/** + * Show prompt, and on the next line an updating percentage value and bar. + * @constructor + * @param {String} prompter The prompt string. + * @param {Number} max The value to use for 100%. + */ +function PercentBarSpinner(prompter, max) { + this.current = 0; + this.max = max; + this.promptstr = prompter; +} + +/** + * Start the spinner. + */ +PercentBarSpinner.prototype.start = function() { + process.stdout.write(this.promptstr + '\n'); + this.tick(0); +}; + +/** + * Rewrite the current line, internal use only. + * + * @param {String} line The line to update to. + */ +PercentBarSpinner.prototype.update = function(line) { + process.stdout.write('\r' + line); +}; + +/** + * Update the spinner value. + * + * @param {Number} value The new value to use. + */ +PercentBarSpinner.prototype.tick = function(value) { + this.current = value; + var bar = this.barstr(); + var val = this.percent(); + this.update(sprintf(' %4d%%', val) + ' [' + this.barstr() + '] '); +}; + +/** + * End the spinner. + */ +PercentBarSpinner.prototype.end = function() { + process.stdout.write('\n'); +}; + +/** + * Get the width to use for the inside of the percentage bar. + * + * @return {Number} The width in columns. + */ +PercentBarSpinner.prototype.width = function() { + return tty.getWindowSize()[1] - 10; +}; + +/** + * Get the current percentage value. + * + * @return {Number} The percentage value. + */ +PercentBarSpinner.prototype.percent = function() { + return (this.current / this.max) * 100; +}; + +/** + * Get the string to use for the inside of the percentage bar. + * + * @return {String} The percentage bar string. + */ +PercentBarSpinner.prototype.barstr = function() { + var width = this.width(); + var p = Math.floor((this.current / this.max) * width); + if (p >= width) { + return new Array(width + 1).join('='); + } + else { + var offset = p === 0 ? -1 : 0; + return new Array(p).join('=') + '>' + new Array(width - p + offset + 1).join(' '); + } +}; + +exports.normalSpinner = function(prompter) { + return new Spinner(prompter); +}; + +exports.percentSpinner = function(prompter, max) { + return new PercentSpinner(prompter, max); +}; + +exports.percentBarSpinner = function(prompter, max) { + return new PercentBarSpinner(prompter, max); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/lib/terminal.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/lib/terminal.js new file mode 100644 index 0000000..80e22ea --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/lib/terminal.js @@ -0,0 +1,468 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var util = require('util'); + +var sprintf = require('sprintf').sprintf; + +/* If true, formatting will be applied to all the text passed to the puts function. */ + +var VERSION = '0.1.2'; + +var USE_ANSI_CODES = true; + +var PRINT_FUNC = util.print; +var PUTS_FUNC = util.puts; + +var RAINBOW_STYLES = [ + [31, 39], // red + [33, 39], // yelow + [32, 39], // green + [34, 39], // blue +]; + +/* Style table taken from the Node util module */ +var STYLES = { 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39], + 'rainbow': RAINBOW_STYLES +}; + +/* An array of terminal which support ANSI escape codes */ +var TERMINAL_SUPPORTS_ANSI_CODES = ['xterm', 'xterm-color', 'screen', 'vt100', 'vt100-color', + 'xterm-256color']; + +/* + * Return total length of all the style tags in the provided string. + * + * @param {Number} Length of all the style tags in the provided string. + */ +function getStylesLength(string) { + var i, styleNames, STYLESCount, style; + var STYLESLength = 0; + + + styleNames = Object.keys(STYLES); + STYLESCount = styleNames.length; + for (i = 0; i < STYLESCount; i++) { + style = styleNames[i]; + if (string.indexOf(sprintf('[%s]', style)) !== -1 && + string.indexOf(sprintf('[/%s]', style)) !== -1) { + STYLESLength += ((style.length * 2) + 5); + } + } + + return STYLESLength; +} + +/** + * Left pad the given string to the maximum width provided. + * + * @param {String} str Input string. + * @param {Number} width Desired length. + * @return {String} Left padded string. + */ +function lpad(str, width) { + var n, STYLESLength; + + str = String(str); + STYLESLength = getStylesLength(str); + n = (width + STYLESLength) - str.length; + + if (n < 1) { + return str; + } + + while (n--) { + str = ' ' + str; + } + + return str; +} + +/** + * Right Pad the given string to the maximum width provided. + * + * @param {String} str Input string. + * @param {Number} width Desired Lenght. + * @return {String} Right padded string. + */ +function rpad(str, width) { + var n, STYLESLength; + + str = String(str); + STYLESLength = getStylesLength(str); + n = (width + STYLESLength) - str.length; + + if (n < 1) { + return str; + } + + while (n--) { + str = str + ' '; + } + + return str; +} + +/** + * Print a formatted table to the standard output. + * + * @param {Array} columns Array of objects. Each object must contains the + * following properties (optional properties are marked with *): + * {String} title - column title + * {?String|?Array} valueProperty - name of the property in the rows object which + * holds the value for this column. + * If formatFunction is defined this value can + * also be an array which will be passed to this + * function. + * {?Number} paddingLeft - left pad the string to the width provided + * {?Number} paddingRight - right pad the string to the width provided + * {Function} formatFunction* - a function which is applied for each value + * of this column. + * + * @param {Array} rows Array of objects which hold the values for each column. + * @param {String} noDataText The text which is printed to standard output if + * the rows array is empty. + */ +function printTable(columns, rows, noDataText) { + var i, valuePropertyLen, valueProperyItem; + var string, columnTitle, valueProperty, value, paddingLeft, paddingRight; + var _noDataText = noDataText || 'No data available'; + + if (rows.length === 0) { + PRINT_FUNC(_noDataText); + } else { + columns.forEach(function(column) { + columnTitle = column.title; + + if (column.hasOwnProperty('paddingLeft')) { + paddingLeft = column.paddingLeft; + } else { + paddingLeft = 0; + column.paddingLeft = 0; + } + + if (column.hasOwnProperty('paddingRight')) { + paddingRight = column.paddingRight; + } else { + paddingRight = 0; + column.paddingRight = 0; + } + + string = lpad(columnTitle, paddingLeft); + string = rpad(string, column.paddingRight); + + PRINT_FUNC(string); + }); + + PRINT_FUNC('\n'); + + rows.forEach(function(row) { + columns.forEach(function(column) { + columnTitle = column.title; + valueProperty = column.valueProperty || columnTitle.toLowerCase(); + value = row[valueProperty]; + + if (column.hasOwnProperty('formatFunction')) { + if (!(valueProperty instanceof Array)) { + value = [ value ]; + } + else { + value = []; + valuePropertyLen = valueProperty.length; + for (i = 0; i < valuePropertyLen; i++) { + valueProperyItem = valueProperty[i]; + value.push(row[valueProperyItem]); + } + } + + value = column.formatFunction.apply(null, value); + } + + string = lpad(value, column.paddingLeft); + string = rpad(string, column.paddingRight); + + PRINT_FUNC(string); + }); + + PRINT_FUNC('\n'); + }); + } + + PRINT_FUNC('\n'); +} + +/** + * Print the provided text to stdout preceeded by the specified number of + * spaces and wrapped, at spaces, to a maximum of the specified width. + * + * @param {String} text The text to print. + * @param {Number} width The maximum line length, defaults to 80. + * @param {Number} indent How many spaces to use as indent, defaults to 2. + * @param {Function} outputFunction Output function (defaults to PUTS_FUNC). + */ +function printWrapped(text, width, indent, outputFunction) { + var chunk, STYLESLength, splitIndex, remaining, indentstr; + width = width || 80; + indent = indent || 2; + outputFunction = outputFunction || PUTS_FUNC; + STYLESLength = getStylesLength(text); + + indentstr = new Array(indent + 1).join(' '); + width = width + STYLESLength; + remaining = text; + + while (remaining.length > (width - indent)) { + chunk = remaining.slice(0, (width - indent)); + splitIndex = chunk.lastIndexOf(' '); + chunk = chunk.slice(0, splitIndex); + remaining = remaining.substr(splitIndex + 1); + outputFunction(indentstr + chunk); + } + + outputFunction(indentstr + remaining); +} + +/* + * Ask user a question and return the input. + * + * @param {String} question Question which is sent to standard output + * @param {Array} validOptions Array of valid options (e.g. ['yes', 'no']) + * @param {String} defaultOption Option which is used as a default if empty line is received + * @param {Function} outputFunction Output function (defaults to PRINT_FUNC). + * @param {Function} callback Callback which is called with user input + */ +function prompt(question, validOptions, defaultOption, outputFunction, callback) { + outputFunction = outputFunction || PRINT_FUNC; + var stdin = process.openStdin(); + stdin.resume(); + var options, option, questionMark, dataString; + + if (validOptions) { + if (defaultOption && validOptions.indexOf(defaultOption) === -1) { + throw new Error(sprintf('Invalid default option: %s', defaultOption)); + } + + option = (defaultOption) ? sprintf(' [%s]', defaultOption) : ''; + options = sprintf(' (%s)%s', validOptions.join('/'), option); + } + else { + options = ''; + } + + if (question[question.length - 1] === '?') { + question = question.substr(0, (question.length - 1)); + questionMark = '?'; + } + else { + questionMark = ''; + } + + outputFunction(sprintf('%s%s%s ', question, options, questionMark)); + + function handleData(data) { + dataString = data.toString().trim(); + + if (!dataString && (validOptions && defaultOption)) { + dataString = defaultOption; + } + + if (dataString) { + if (validOptions && validOptions.indexOf(dataString) === -1) { + outputFunction(sprintf('Invalid option "%s", valid options are: %s', dataString, + validOptions.join(', '))); + return; + } + + // Pause is necessary to get Node to exit without manual intervention + stdin.pause(); + stdin.removeListener('data', handleData); + callback(dataString); + } + } + + stdin.on('data', handleData); +} + +/* + * Replaces style tags with string provided by the replaceFunction. + * + * @param {String} string String with the formatting tags (tags can also be nested). For example: + * [italic]italic text[/italic] [bold][red]bold red text[/red][/bold] + * @param {Function} replaceFunction Function which is called with matched style tags and the + * text in-between. The function needs to return a string which + * replaces the provided text. + * + * @return {String} String which has been iterated over and passed to the replaceFunction. +*/ +function formatTags(string, replaceFunction) { + var stylized = string; + var styleRegex = Object.keys(STYLES).join('|'); + var key, regex; + + if (!string) { + return ''; + } + + if (typeof string !== 'string') { + return string; + } + + for (key in STYLES) { + if (STYLES.hasOwnProperty(key)) { + if (stylized.indexOf(sprintf('[%s]', key)) === -1) { + continue; + } + + regex = new RegExp(sprintf('(\\[(%s)\\])(.*?)(\\[/(%s)\\])', key, key), 'gi'); + stylized = stylized.replace(regex, replaceFunction); + } + } + + return stylized; +} + +/* + * Apply formatting to the input string (replaces formatting tag with the corresponding ANSI escape codes). + * + * @param {String} string String with the formatting tags (tags can also be nested). For example: + * [italic]italic text[/italic] [bold][red]bold red text[/red][/bold] + * + * @return {String} String with formatting applied. + */ +function stylize(string) { + function replaceFunction(str, p1, p2, p3) { + var i, leni = RAINBOW_STYLES.length - 1, j = 0, lenj = p3.length, + newStr = ''; + + if (p2 === 'rainbow') { + for (j = 0; j < lenj; j++) { + i = (j % leni); + newStr += sprintf('\033[%sm%s\033[%sm', RAINBOW_STYLES[i][0], p3[j], + RAINBOW_STYLES[i][1]); + } + + return newStr; + } + + return sprintf('\033[%sm%s\033[%sm', STYLES[p2][0], p3, STYLES[p2][1]); + } + + return formatTags(string, replaceFunction); +} + +/* + * Remove style tags from the input string. + * + * @param {String} string String with the formatting tags (tags can also be nested). For example: + * [italic]italic text[/italic] [bold][red]bold red text[/red][/bold] + * + * @return {String} String without the style tags. +*/ +function stripStyles(string) { + function replaceFunction(str, p1, p2, p3) { + return sprintf('%s', p3); + } + + return formatTags(string, replaceFunction); +} + +function output(styles) { + var term = process.env.TERM; + var useStyles = styles; + + if (useStyles === undefined || useStyles === null) { + if (!USE_ANSI_CODES || !term || TERMINAL_SUPPORTS_ANSI_CODES.indexOf(term.toLowerCase()) === -1) { + useStyles = false; + } + else { + useStyles = true; + } + } + + for (var i = 1; i < arguments.length; i++) { + if (useStyles) { + PUTS_FUNC(stylize(arguments[i])); + } + else { + PUTS_FUNC(stripStyles(arguments[i])); + } + } +} + +/* + * Automatically detect based on the TERM value if the styles should be used and + * call puts function for each of the input arguments. + */ +function puts() { + var args = [ null ].concat(Array.prototype.slice.call(arguments)); + output.apply(null, args); +} + +/* + * Apply formatting and call puts function for each of the input arguments. + */ +function putsStyle() { + var args = [ true ].concat(Array.prototype.slice.call(arguments)); + output.apply(null, args); +} + +/* + * Strip style tags from the input and call puts function for each of the input + * arguments. + */ +function putsNoStyle() { + var args = [ false ].concat(Array.prototype.slice.call(arguments)); + output.apply(null, args); +} + +function disableStyles() { + USE_ANSI_CODES = false; +} + +function enableStyles() { + USE_ANSI_CODES = true; +} + +exports.VERSION = VERSION; + +exports.getStylesLength = getStylesLength; +exports.lpad = lpad; +exports.rpad = rpad; +exports.printTable = printTable; +exports.printWrapped = printWrapped; +exports.prompt = prompt; +exports.formatTags = formatTags; +exports.stylize = stylize; +exports.stripStyles = stripStyles; +exports.puts = puts; +exports.putsStyle = putsStyle; +exports.putsNoStyle = putsNoStyle; + +exports.disableStyles = disableStyles; +exports.enableStyles = enableStyles; diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/package.json b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/package.json new file mode 100644 index 0000000..b48f19c --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/package.json @@ -0,0 +1,34 @@ +{ + "name": "terminal", + "description": "A collection of different terminal utility functions.", + "version": "0.1.3", + "author": "Cloudkick, Inc. http://www.cloudkick.com", + "keywords": [ "terminal", "term", "colors", "style" ], + "homepage": "https://github.com/cloudkick/node-terminal", + "license": "Apache 2.0", + "repository": { + "type": "git", + "url": "git://github.com/cloudkick/node-terminal.git" + }, + "modules": { + "terminal": "./lib/terminal", + "spinner": "./lib/spinner" + }, + "directories": { + "lib": "./lib", + "example": "./example" + }, + "scripts": { + "test": "make test" + }, + "dependencies": { + "sprintf": ">= 0.1.1" + }, + "devDependencies": { + "whiskey": "= 0.3.2" + }, + "engines": { + "node": ">= 0.4.0" + }, + "main": "./index" +} diff --git a/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/tests/test-terminal.js b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/tests/test-terminal.js new file mode 100644 index 0000000..4ee31dc --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/node_modules/terminal/tests/test-terminal.js @@ -0,0 +1,215 @@ +/* + * Licensed to Cloudkick, Inc ('Cloudkick') under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Cloudkick licenses this file to You 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. + */ + +var util = require('util'); +var events = require('events'); + +var terminal = require('terminal'); + +exports['test_getStylesLength'] = function(test, assert) { + var i, string, styleLength; + var strings = [ + 'foobar', + '[blue]foo[/blue]', + '[bold][blue]foobar[/blue] moo[/bold]' + ]; + var styleLengths = [ + 0, + 13, + 26 + ]; + + for (i = 0; i < strings.length; i++) { + string = strings[i]; + styleLength = styleLengths[i]; + + assert.equal(terminal.getStylesLength(string), styleLength); + } + + test.finish(); +}; + +exports['test_lpad_and_rpad'] = function(test, assert) { + var i, string, padWidth; + var strings = [ + 'foo', + 'foobar', + 'bar x', + ]; + var padWidths = [ + 20, + 10, + 20, + 30 + ]; + + for (i = 0; i < strings.length; i++) { + string = strings[i]; + padWidth = padWidths[i]; + + assert.equal(terminal.lpad(string, padWidth).length, padWidth); + assert.ok(terminal.lpad(string, padWidth).indexOf(string) === padWidth - string.length); + assert.equal(terminal.rpad(string, padWidth).length, padWidth); + assert.ok(terminal.rpad(string, padWidth).indexOf(string) === 0); + } + + test.finish(); +}; + +exports['test_printWrapped'] = function(test, assert) { + test.finish(); +}; + +exports['test_prompt'] = function(test, assert) { + var buffer = ''; + var gotResult = false; + var exceptionCount = 0; + var oldPutsFunc = terminal.PUTS_FUNC; + var oldOpenStdin = process.openStdin; + + function MockStdin() { + } + + util.inherits(MockStdin, events.EventEmitter); + + MockStdin.prototype.pause = function() {}; + MockStdin.prototype.resume = function() {}; + MockStdin.prototype._emitData = function(data) { + this.emit(data); + }; + + // @TODO: Mock process.stdin and verify the whole flow + + function bufferFunc(data) { + buffer += data; + } + + function handleResult(input) { + gotResult = true; + } + + // Test invalid default option + try { + terminal.prompt('test question?', ['y', 'n'], 'u', bufferFunc, handleResult); + } + catch (err) { + exceptionCount++; + assert.match(err.message, /invalid default option/i); + } + + // Test normal flow + var mockStdinInstance = new MockStdin(); + process.openStdin = function() { + return mockStdinInstance; + }; + + // Invalid option + terminal.prompt('yes?', ['y', 'n'], 'n', bufferFunc, handleResult); + mockStdinInstance.emit('data', 'x'); + + // Valid result, callback should be called + mockStdinInstance.emit('data', 'y'); + + process.openStdin = oldOpenStdin; + assert.equal(exceptionCount, 1); + assert.ok(gotResult); + assert.ok(buffer.indexOf('Invalid option "x"') !== -1); + assert.ok(buffer.indexOf('Invalid option "x"') !== -1); + test.finish(); +}; + +exports['test_formatTags'] = function(test, assert) { + var i, string, expectedString; + var strings = [ + 'foo', + '[inextsitent]test[/inextsitent]', + '[blue]test[/blue]', + '[blue]test[/red]' + ]; + + var expectedStrings = [ + 'foo', + '[inextsitent]test[/inextsitent]', + 'test', + '[blue]test[/red]' + ]; + + function replaceFunction(str, p1, p2, p3) { + return p3; + } + + for (i = 0; i < strings.length; i++) { + string = strings[i]; + expectedString = expectedStrings[i]; + + assert.equal(terminal.formatTags(string, replaceFunction), expectedString); + } + + test.finish(); +}; + +exports['test_stylize'] = function(test, assert) { + var i, string, expectedString; + var strings = [ + '', + 'foo', + '[inextsitent]test[/inextsitent]', + '[blue]test[/blue]', + '[blue]test[/red]' + ]; + + var expectedStrings = [ + '', + 'foo', + '[inextsitent]test[/inextsitent]', + '\u001b[34mtest\u001b[39m', + '[blue]test[/red]' + ]; + + for (i = 0; i < strings.length; i++) { + string = strings[i]; + expectedString = expectedStrings[i]; + + assert.equal(terminal.stylize(string), expectedString); + } + + test.finish(); +}; + + +exports['test_stripStyles'] = function(test, assert) { + var i, string, expectedString; + var strings = [ + 'foobar', + '[blue]foo[/blue]', + '[bold][blue]foobar[/blue] moo[/bold]' + ]; + var expectedStrings = [ + 'foobar', + 'foo', + 'foobar moo' + ]; + + for (i = 0; i < strings.length; i++) { + string = strings[i]; + expectedString = expectedStrings[i]; + + assert.equal(terminal.stripStyles(string), expectedString); + } + + test.finish(); +}; diff --git a/node_modules/cassandra-client/node_modules/whiskey/package.json b/node_modules/cassandra-client/node_modules/whiskey/package.json new file mode 100644 index 0000000..414ec45 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/package.json @@ -0,0 +1,41 @@ +{ + "name": "whiskey", + "description": "A simple test runner for NodeJS applications.", + "version": "0.6.7", + "author": "Cloudkick, Inc. http://www.cloudkick.com", + "keywords": [ "whiskey", "tests", "test runner", "testing", "tdd", "coverage", "test coverage"], + "homepage": "https://github.com/cloudkick/whiskey", + "repository": { + "type": "git", + "url": "git://github.com/cloudkick/whiskey.git" + }, + "directories": { + "lib": "./lib", + "example": "./example", + "bin": "./bin" + }, + "scripts": { + "test": "make test" + }, + "dependencies": { + "sprintf": ">= 0.1.1", + "async": ">= 0.1.9", + "magic-templates": "= 0.1.1", + "rimraf": "= 1.0.1", + "terminal": "= 0.1.3", + "gex": "= 0.0.1", + "simplesets": "= 1.1.6", + "logmagic": "= 0.1.4" + }, + "engines": { + "node": ">= 0.4.0" + }, + "main": "./index", + "bin": "./bin/whiskey", + "licenses" : [ + { + "type" : "Apache", + "url" : "http://www.apache.org/licenses/LICENSE-2.0.html" + } + ] +} diff --git a/node_modules/cassandra-client/node_modules/whiskey/test/run.sh b/node_modules/cassandra-client/node_modules/whiskey/test/run.sh new file mode 100755 index 0000000..3fddc54 --- /dev/null +++ b/node_modules/cassandra-client/node_modules/whiskey/test/run.sh @@ -0,0 +1,265 @@ +#!/usr/bin/env bash +CWD=`pwd` + +"${CWD}/bin/whiskey" --tests "${CWD}/example/test-success.js" + +if [ $? -ne 0 ]; then + echo "tests should pass" + exit 1 +fi + +"${CWD}/bin/whiskey" --tests "${CWD}/example/test-failure.js" + +if [ $? -ne 2 ]; then + echo "2 tests should fail" + exit 1 +fi + +"${CWD}/bin/whiskey" --failfast --timeout 500 \ + --tests --concurrency 100 "${CWD}/example/test-failure.js ${CWD}/example/test-timeout.js" + +if [ $? -ne 1 ]; then + echo "1 test should fail" + exit 1 +fi + +"${CWD}/bin/whiskey" --failfast --timeout 500 \ + --tests "${CWD}/example/test-timeout.js ${CWD}/example/test-failure.js ${CWD}/example/test-timeout.js" + +if [ $? -ne 1 ]; then + echo "1 test should fail" + exit 1 +fi + +"${CWD}/bin/whiskey" --timeout 1000 --tests "${CWD}/example/test-timeout.js" + +if [ ! $? -eq 1 ]; then + echo "test should time out" + exit 1 +fi + +"${CWD}/bin/whiskey" --timeout 1000 --tests "${CWD}/example/test-timeout-blocking.js" + +if [ ! $? -eq 1 ]; then + echo "test should time out" + exit 1 +fi + +"${CWD}/bin/whiskey" --tests "${CWD}/example/test-setup-and-teardown.js" + +if [ $? -ne 0 ]; then + echo "test should pass" + exit 1 +fi + +# Test file does not exist +"${CWD}/bin/whiskey" --tests "${CWD}/example/test-inexistent.js" + +if [ $? -ne 1 ]; then + echo "1 test should fail" + exit 1 +fi + +"${CWD}/bin/whiskey" --tests "${CWD}/example/test-setup-fail.js" + +if [ $? -ne 3 ]; then + echo "3 tests should fail" + exit 1 +fi + +# Test relative path +"${CWD}/bin/whiskey" --tests "example/test-success.js" + +if [ $? -ne 0 ]; then + echo "tests should pass." + exit 1 +fi + +# Test multiple files +"${CWD}/bin/whiskey" --tests "${CWD}/example/test-success.js ${CWD}/example/test-failure.js" + +if [ ! $? -gt 0 ]; then + echo "2 tests should fail" + exit 1 +fi + +# Test test init file +FOLDER_EXISTS=0 +rm -rf ${CWD}/example/test-123456 + +"${CWD}/bin/whiskey" --test-init-file "${CWD}/example/init.js" --tests "${CWD}/example/test-success.js" + +if [ -d ${CWD}/example/test-123456 ]; then + FOLDER_EXISTS=1 +fi + +rm -rf ${CWD}/example/test-123456 + +if [ $? -ne 0 ] || [ ${FOLDER_EXISTS} -ne 1 ]; then + echo ${FOLDER_EXISTS} + echo "test should pass m" + exit 1 +fi + +# test uncaught exceptions +"${CWD}/bin/whiskey" --tests "${CWD}/example/test-uncaught.js" + +if [ $? -ne 5 ]; then + echo "5 tests should fail" + exit 1 +fi + +# Test chdir +"${CWD}/bin/whiskey" --tests "${CWD}/example/test-chdir.js" + +if [ $? -ne 1 ]; then + echo "1 test should fail" + exit 1 +fi + +"${CWD}/bin/whiskey" --tests "${CWD}/example/test-chdir.js" --chdir "${CWD}/example/" + +if [ $? -ne 0 ]; then + echo "tests should pass y" + exit 1 +fi + +# Test per test init function +"${CWD}/bin/whiskey" --test-init-file "${CWD}/example/init-test.js" --tests "${CWD}/example/test-init-function.js" + +if [ $? -ne 0 ]; then + echo "tests should pass x" + exit 1 +fi + +# Test init function timeout (callback in init function is not called) +"${CWD}/bin/whiskey" --timeout 2000 --test-init-file "${CWD}/example/init-timeout.js" --tests "${CWD}/example/test-failure.js" + +if [ $? -ne 1 ]; then + echo "1 test should fail (callback in init function is not called)" + exit 1 +fi + +# Test setUp function timeout (setUp function .finish() is not called) +"${CWD}/bin/whiskey" --timeout 1000 --tests "${CWD}/example/test-setup-timeout.js" --chdir "${CWD}/example/" + +if [ $? -ne 1 ]; then + echo "1 test should fail (setUp timeout)" + exit 1 +fi + +# Test tearDown function timeout (tearDown function .finish() is not called) +"${CWD}/bin/whiskey" --timeout 2000 --tests "${CWD}/example/test-teardown-timeout.js" --chdir "${CWD}/example/" + +if [ $? -ne 2 ]; then + echo "1 test should fail (tearDown timeout)" + exit 1 +fi + +"${CWD}/bin/whiskey" --timeout 2000 --tests "${CWD}/example/test-custom-assert-functions.js" + +if [ $? -ne 2 ]; then + echo "2 tests should fail" + exit 1 +fi + +"${CWD}/bin/whiskey" --timeout 2000 \ + --tests "${CWD}/example/test-custom-assert-functions.js" \ + --custom-assert-module "${CWD}/example/custom-assert-functions.js" + +if [ $? -ne 1 ]; then + echo "1 test should fail" + exit 1 +fi + +"${CWD}/example/test-stdout-and-stderr-is-captured-on-timeout.js" + +if [ $? -ne 0 ]; then + echo "test file stdout and stderr was not properly captured during test timeout" + exit 1 +fi + +# Verify that when a test file timeout the tests which haven't time out are +# reported properly +"${CWD}/example/test-succeeded-tests-are-reported-on-timeout.js" + +if [ $? -ne 0 ]; then + echo "succeeded tests were not reported properly upon a test file timeout" + exit 1 +fi + +# Verify that coverage works properly +if [ "$(which jscoverage)" ]; then + "${CWD}/example/test-jscoverage.js" + + if [ $? -ne 0 ]; then + echo "coverage does not work properly" + exit 1 + fi +else + echo 'jscoverage not installed, skipping coverage tests' +fi + +# Make sure that the child which blocks after call .finish() is killed and +# timeout properly reported +"${CWD}/bin/whiskey" --timeout 1000 \ + --tests "${CWD}/example/test-timeout-after-finish.js" + +if [ $? -ne 1 ]; then + echo "1 test should timeout" + exit 1 +fi + +# Scope leaks test (sequential and parallel mode) +"${CWD}/example/test-leaks.js" + +if [ $? -ne 0 ]; then + echo "scope leaks were not reported properly" + exit 1 +fi + +# No test function is exported, it should quit immediately +"${CWD}/bin/whiskey" --timeout 1000 \ + --tests "${CWD}/example/test-no-test-functions.js" + +if [ $? -ne 0 ]; then + echo "test didn't exit with zero exit code" + exit 1 +fi + +"${CWD}/bin/whiskey" --timeout 1000 \ + --tests "${CWD}/example/test-skipped.js" + +if [ $? -ne 0 ]; then + echo "test didn't exit with zero exit code" + exit 1 +fi + +"${CWD}/bin/whiskey" --timeout 1000 \ + --tests "${CWD}/example/test-custom-assert-methods.js" + +if [ $? -ne 0 ]; then + echo "test didn't exit with zero exit code" + exit 1 +fi + +# Test pattern name matching +"${CWD}/bin/whiskey" --timeout 1000 \ + --tests "example.test-failure.test_one_is_not*" + +if [ $? -ne 1 ]; then + echo "test didn't exit with 1 exit code" + exit 1 +fi + +"${CWD}/bin/whiskey" --timeout 1000 \ + --tests "${CWD}/example/test-getFilePathAndPattern.js" + +if [ $? -ne 0 ]; then + echo "test didn't exit with zero exit code" + exit 1 +fi + +echo "" +echo "* * * Whiskey test suite PASSED. * * *" +exit 0 diff --git a/node_modules/cassandra-client/package.json b/node_modules/cassandra-client/package.json new file mode 100644 index 0000000..1f84e75 --- /dev/null +++ b/node_modules/cassandra-client/package.json @@ -0,0 +1,39 @@ +{ + "author": "Gary Dusbabek ", + "contributors": [ + "Eric Evans ", + "Gary Dusbabek ", + "Tomaž Muraus ", + "Patrick Negri ", + "Christoph Tavan " + ], + "name": "cassandra-client", + "description": "Node.js CQL driver for Apache Cassandra", + "version": "0.8.2", + "homepage": "http://code.google.com/a/apache-extras.org/p/cassandra-node/", + "repository": { + "type": "git", + "url": "https://code.google.com/a/apache-extras.org/p/cassandra-node/" + }, + "main": "node-cassandra-client", + "directories": { + "lib": "lib" + }, + "scripts": { + "test": "whiskey --tests \"test/test_driver.js test/test_decoder.js test/test_uuid.js\" --dependencies test/dependencies.json --scope-leaks --timeout 30000" + }, + "engines": { + "node": ">= 0.6.7" + }, + "dependencies": { + "async": ">= 0.1.12", + "thrift": ">= 0.6.0-1", + "whiskey": ">= 0.6.1", + "node-uuid": ">= 1.3.3" + }, + "devDependencies": {}, + "licenses" : [{ + "type": "Apache", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }] +} diff --git a/node_modules/cassandra-client/test/cass.sh b/node_modules/cassandra-client/test/cass.sh new file mode 100755 index 0000000..ac42f90 --- /dev/null +++ b/node_modules/cassandra-client/test/cass.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +basedir=`dirname $0` + +export CASSANDRA_CONF=$basedir/conf/ + +if [ ! $CASS_HOME ]; then + CASS_HOME="/opt/cassandra" +fi + + +rm -rf /tmp/cass/* +exec $CASS_HOME/bin/cassandra -f diff --git a/node_modules/cassandra-client/test/cass2.sh b/node_modules/cassandra-client/test/cass2.sh new file mode 100755 index 0000000..a70fc90 --- /dev/null +++ b/node_modules/cassandra-client/test/cass2.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +basedir=`dirname $0` + +export CASSANDRA_CONF=$basedir/conf2/ + +if [ ! $CASS_HOME ]; then + CASS_HOME="/opt/cassandra" +fi + + +rm -rf /tmp/cass/* +exec $CASS_HOME/bin/cassandra -f diff --git a/node_modules/cassandra-client/test/cass3.sh b/node_modules/cassandra-client/test/cass3.sh new file mode 100755 index 0000000..210e456 --- /dev/null +++ b/node_modules/cassandra-client/test/cass3.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +basedir=`dirname $0` + +export CASSANDRA_CONF=$basedir/conf3/ + +if [ ! $CASS_HOME ]; then + CASS_HOME="/opt/cassandra" +fi + + +rm -rf /tmp/cass/* +exec $CASS_HOME/bin/cassandra -f diff --git a/node_modules/cassandra-client/test/conf/cassandra-env.sh b/node_modules/cassandra-client/test/conf/cassandra-env.sh new file mode 100644 index 0000000..5e595c2 --- /dev/null +++ b/node_modules/cassandra-client/test/conf/cassandra-env.sh @@ -0,0 +1,194 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +calculate_heap_sizes() +{ + case "`uname`" in + Linux) + system_memory_in_mb=`free -m | awk '/Mem:/ {print $2}'` + system_cpu_cores=`egrep -c 'processor([[:space:]]+):.*' /proc/cpuinfo` + break + ;; + FreeBSD) + system_memory_in_bytes=`sysctl hw.physmem | awk '{print $2}'` + system_memory_in_mb=`expr $system_memory_in_bytes / 1024 / 1024` + system_cpu_cores=`sysctl hw.ncpu | awk '{print $2}'` + break + ;; + SunOS) + system_memory_in_mb=`prtconf | awk '/Memory size:/ {print $3}'` + system_cpu_cores=`psrinfo | wc -l` + break + ;; + *) + # assume reasonable defaults for e.g. a modern desktop or + # cheap server + system_memory_in_mb="2048" + system_cpu_cores="2" + ;; + esac + + # set max heap size based on the following + # max(min(1/2 ram, 1024MB), min(1/4 ram, 8GB)) + # calculate 1/2 ram and cap to 1024MB + # calculate 1/4 ram and cap to 8192MB + # pick the max + half_system_memory_in_mb=`expr $system_memory_in_mb / 2` + quarter_system_memory_in_mb=`expr $half_system_memory_in_mb / 2` + if [ "$half_system_memory_in_mb" -gt "1024" ] + then + half_system_memory_in_mb="1024" + fi + if [ "$quarter_system_memory_in_mb" -gt "8192" ] + then + quarter_system_memory_in_mb="8192" + fi + if [ "$half_system_memory_in_mb" -gt "$quarter_system_memory_in_mb" ] + then + max_heap_size_in_mb="$half_system_memory_in_mb" + else + max_heap_size_in_mb="$quarter_system_memory_in_mb" + fi + MAX_HEAP_SIZE="${max_heap_size_in_mb}M" + + # Young gen: min(max_sensible_per_modern_cpu_core * num_cores, 1/4 * heap size) + max_sensible_yg_per_core_in_mb="100" + max_sensible_yg_in_mb=`expr $max_sensible_yg_per_core_in_mb "*" $system_cpu_cores` + + desired_yg_in_mb=`expr $max_heap_size_in_mb / 4` + + if [ "$desired_yg_in_mb" -gt "$max_sensible_yg_in_mb" ] + then + HEAP_NEWSIZE="${max_sensible_yg_in_mb}M" + else + HEAP_NEWSIZE="${desired_yg_in_mb}M" + fi +} + +# Override these to set the amount of memory to allocate to the JVM at +# start-up. For production use you almost certainly want to adjust +# this for your environment. MAX_HEAP_SIZE is the total amount of +# memory dedicated to the Java heap; HEAP_NEWSIZE refers to the size +# of the young generation. Both MAX_HEAP_SIZE and HEAP_NEWSIZE should +# be either set or not (if you set one, set the other). +# +# The main trade-off for the young generation is that the larger it +# is, the longer GC pause times will be. The shorter it is, the more +# expensive GC will be (usually). +# +# The example HEAP_NEWSIZE assumes a modern 8-core+ machine for decent pause +# times. If in doubt, and if you do not particularly want to tweak, go with +# 100 MB per physical CPU core. + +#MAX_HEAP_SIZE="4G" +#HEAP_NEWSIZE="800M" + +if [ "x$MAX_HEAP_SIZE" = "x" ] && [ "x$HEAP_NEWSIZE" = "x" ]; then + calculate_heap_sizes +else + if [ "x$MAX_HEAP_SIZE" = "x" ] || [ "x$HEAP_NEWSIZE" = "x" ]; then + echo "please set or unset MAX_HEAP_SIZE and HEAP_NEWSIZE in pairs (see cassandra-env.sh)" + exit 1 + fi +fi + +# Specifies the default port over which Cassandra will be available for +# JMX connections. +JMX_PORT="7199" + + +# Here we create the arguments that will get passed to the jvm when +# starting cassandra. + +# enable assertions. disabling this in production will give a modest +# performance benefit (around 5%). +JVM_OPTS="$JVM_OPTS -ea" + +# add the jamm javaagent +check_openjdk=`"${JAVA:-java}" -version 2>&1 | awk '{if (NR == 2) {print $1}}'` +if [ "$check_openjdk" != "OpenJDK" ] +then + JVM_OPTS="$JVM_OPTS -javaagent:$CASSANDRA_HOME/lib/jamm-0.2.5.jar" +fi + +# enable thread priorities, primarily so we can give periodic tasks +# a lower priority to avoid interfering with client workload +JVM_OPTS="$JVM_OPTS -XX:+UseThreadPriorities" +# allows lowering thread priority without being root. see +# http://tech.stolsvik.com/2010/01/linux-java-thread-priorities-workaround.html +JVM_OPTS="$JVM_OPTS -XX:ThreadPriorityPolicy=42" + +# min and max heap sizes should be set to the same value to avoid +# stop-the-world GC pauses during resize, and so that we can lock the +# heap in memory on startup to prevent any of it from being swapped +# out. +JVM_OPTS="$JVM_OPTS -Xms${MAX_HEAP_SIZE}" +JVM_OPTS="$JVM_OPTS -Xmx${MAX_HEAP_SIZE}" +JVM_OPTS="$JVM_OPTS -Xmn${HEAP_NEWSIZE}" +JVM_OPTS="$JVM_OPTS -XX:+HeapDumpOnOutOfMemoryError" + +# set jvm HeapDumpPath with CASSANDRA_HEAPDUMP_DIR +if [ "x$CASSANDRA_HEAPDUMP_DIR" != "x" ]; then + JVM_OPTS="$JVM_OPTS -XX:HeapDumpPath=$CASSANDRA_HEAPDUMP_DIR/cassandra-`date +%s`-pid$$.hprof" +fi + +if [ "`uname`" = "Linux" ] ; then + # reduce the per-thread stack size to minimize the impact of Thrift + # thread-per-client. (Best practice is for client connections to + # be pooled anyway.) Only do so on Linux where it is known to be + # supported. + JVM_OPTS="$JVM_OPTS -Xss128k" +fi + +# GC tuning options +JVM_OPTS="$JVM_OPTS -XX:+UseParNewGC" +JVM_OPTS="$JVM_OPTS -XX:+UseConcMarkSweepGC" +JVM_OPTS="$JVM_OPTS -XX:+CMSParallelRemarkEnabled" +JVM_OPTS="$JVM_OPTS -XX:SurvivorRatio=8" +JVM_OPTS="$JVM_OPTS -XX:MaxTenuringThreshold=1" +JVM_OPTS="$JVM_OPTS -XX:CMSInitiatingOccupancyFraction=75" +JVM_OPTS="$JVM_OPTS -XX:+UseCMSInitiatingOccupancyOnly" + +# GC logging options -- uncomment to enable +# JVM_OPTS="$JVM_OPTS -XX:+PrintGCDetails" +# JVM_OPTS="$JVM_OPTS -XX:+PrintGCDateStamps" +# JVM_OPTS="$JVM_OPTS -XX:+PrintHeapAtGC" +# JVM_OPTS="$JVM_OPTS -XX:+PrintTenuringDistribution" +# JVM_OPTS="$JVM_OPTS -XX:+PrintGCApplicationStoppedTime" +# JVM_OPTS="$JVM_OPTS -XX:+PrintPromotionFailure" +# JVM_OPTS="$JVM_OPTS -XX:PrintFLSStatistics=1" +# JVM_OPTS="$JVM_OPTS -Xloggc:/var/log/cassandra/gc-`date +%s`.log" + +# uncomment to have Cassandra JVM listen for remote debuggers/profilers on port 1414 +# JVM_OPTS="$JVM_OPTS -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1414" + +# Prefer binding to IPv4 network intefaces (when net.ipv6.bindv6only=1). See +# http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6342561 (short version: +# comment out this entry to enable IPv6 support). +JVM_OPTS="$JVM_OPTS -Djava.net.preferIPv4Stack=true" + +# jmx: metrics and administration interface +# +# add this if you're having trouble connecting: +# JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=" +# +# see +# http://blogs.sun.com/jmxetc/entry/troubleshooting_connection_problems_in_jconsole +# for more on configuring JMX through firewalls, etc. (Short version: +# get it working with no firewall first.) +JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT" +JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.ssl=false" +JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=false" diff --git a/node_modules/cassandra-client/test/conf/cassandra.yaml b/node_modules/cassandra-client/test/conf/cassandra.yaml new file mode 100644 index 0000000..7316d35 --- /dev/null +++ b/node_modules/cassandra-client/test/conf/cassandra.yaml @@ -0,0 +1,47 @@ +authenticator: org.apache.cassandra.auth.AllowAllAuthenticator +authority: org.apache.cassandra.auth.AllowAllAuthority +auto_bootstrap: true +cluster_name: Test Cluster +column_index_size_in_kb: 64 +commitlog_directory: [/tmp/cass/commitlog] +commitlog_sync: periodic +commitlog_sync_period_in_ms: 10000 +compaction_preheat_key_cache: true +concurrent_reads: 4 +concurrent_writes: 4 +data_file_directories: [/tmp/cass/data] +dynamic_snitch: true +dynamic_snitch_badness_threshold: 0.0 +dynamic_snitch_reset_interval_in_ms: 600000 +dynamic_snitch_update_interval_in_ms: 100 +encryption_options: {internode_encryption: none, keystore: conf/.keystore, keystore_password: cassandra, + truststore: conf/.truststore, truststore_password: cassandra} +endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch +flush_largest_memtables_at: 0.75 +hinted_handoff_enabled: false +hinted_handoff_throttle_delay_in_ms: 50 +in_memory_compaction_limit_in_mb: 64 +incremental_backups: false +index_interval: 128 +initial_token: 0 +listen_address: 127.0.0.1 +max_hint_window_in_ms: 3600000 +memtable_flush_queue_size: 4 +partitioner: org.apache.cassandra.dht.ByteOrderedPartitioner +reduce_cache_capacity_to: 0.59999999999999998 +reduce_cache_sizes_at: 0.84999999999999998 +request_scheduler: org.apache.cassandra.scheduler.NoScheduler +rpc_address: 127.0.0.1 +rpc_keepalive: true +rpc_port: 19170 +rpc_timeout_in_ms: 10000 +saved_caches_directory: [/tmp/cass/savedcaches] +seed_provider: +- class_name: org.apache.cassandra.locator.SimpleSeedProvider + parameters: + - {seeds: 127.0.0.1} +sliced_buffer_size_in_kb: 64 +snapshot_before_compaction: false +storage_port: 17001 +thrift_framed_transport_size_in_mb: 15 +thrift_max_message_length_in_mb: 16 diff --git a/node_modules/cassandra-client/test/conf/log4j-server.properties b/node_modules/cassandra-client/test/conf/log4j-server.properties new file mode 100644 index 0000000..8750e5b --- /dev/null +++ b/node_modules/cassandra-client/test/conf/log4j-server.properties @@ -0,0 +1,31 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# for production, you should probably set pattern to %c instead of %l. +# (%l is slower.) + +# output messages into a rolling log file as well as stdout +log4j.rootLogger=DEBUG,stdout + +# stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p %d{HH:mm:ss,SSS} %m%n + +# Application logging options +#log4j.logger.org.apache.cassandra=DEBUG +#log4j.logger.org.apache.cassandra.db=DEBUG +#log4j.logger.org.apache.cassandra.service.StorageProxy=DEBUG diff --git a/node_modules/cassandra-client/test/conf2/cassandra-env.sh b/node_modules/cassandra-client/test/conf2/cassandra-env.sh new file mode 100644 index 0000000..c37c941 --- /dev/null +++ b/node_modules/cassandra-client/test/conf2/cassandra-env.sh @@ -0,0 +1,194 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +calculate_heap_sizes() +{ + case "`uname`" in + Linux) + system_memory_in_mb=`free -m | awk '/Mem:/ {print $2}'` + system_cpu_cores=`egrep -c 'processor([[:space:]]+):.*' /proc/cpuinfo` + break + ;; + FreeBSD) + system_memory_in_bytes=`sysctl hw.physmem | awk '{print $2}'` + system_memory_in_mb=`expr $system_memory_in_bytes / 1024 / 1024` + system_cpu_cores=`sysctl hw.ncpu | awk '{print $2}'` + break + ;; + SunOS) + system_memory_in_mb=`prtconf | awk '/Memory size:/ {print $3}'` + system_cpu_cores=`psrinfo | wc -l` + break + ;; + *) + # assume reasonable defaults for e.g. a modern desktop or + # cheap server + system_memory_in_mb="2048" + system_cpu_cores="2" + ;; + esac + + # set max heap size based on the following + # max(min(1/2 ram, 1024MB), min(1/4 ram, 8GB)) + # calculate 1/2 ram and cap to 1024MB + # calculate 1/4 ram and cap to 8192MB + # pick the max + half_system_memory_in_mb=`expr $system_memory_in_mb / 2` + quarter_system_memory_in_mb=`expr $half_system_memory_in_mb / 2` + if [ "$half_system_memory_in_mb" -gt "1024" ] + then + half_system_memory_in_mb="1024" + fi + if [ "$quarter_system_memory_in_mb" -gt "8192" ] + then + quarter_system_memory_in_mb="8192" + fi + if [ "$half_system_memory_in_mb" -gt "$quarter_system_memory_in_mb" ] + then + max_heap_size_in_mb="$half_system_memory_in_mb" + else + max_heap_size_in_mb="$quarter_system_memory_in_mb" + fi + MAX_HEAP_SIZE="${max_heap_size_in_mb}M" + + # Young gen: min(max_sensible_per_modern_cpu_core * num_cores, 1/4 * heap size) + max_sensible_yg_per_core_in_mb="100" + max_sensible_yg_in_mb=`expr $max_sensible_yg_per_core_in_mb "*" $system_cpu_cores` + + desired_yg_in_mb=`expr $max_heap_size_in_mb / 4` + + if [ "$desired_yg_in_mb" -gt "$max_sensible_yg_in_mb" ] + then + HEAP_NEWSIZE="${max_sensible_yg_in_mb}M" + else + HEAP_NEWSIZE="${desired_yg_in_mb}M" + fi +} + +# Override these to set the amount of memory to allocate to the JVM at +# start-up. For production use you almost certainly want to adjust +# this for your environment. MAX_HEAP_SIZE is the total amount of +# memory dedicated to the Java heap; HEAP_NEWSIZE refers to the size +# of the young generation. Both MAX_HEAP_SIZE and HEAP_NEWSIZE should +# be either set or not (if you set one, set the other). +# +# The main trade-off for the young generation is that the larger it +# is, the longer GC pause times will be. The shorter it is, the more +# expensive GC will be (usually). +# +# The example HEAP_NEWSIZE assumes a modern 8-core+ machine for decent pause +# times. If in doubt, and if you do not particularly want to tweak, go with +# 100 MB per physical CPU core. + +MAX_HEAP_SIZE="512M" +HEAP_NEWSIZE="32M" + +if [ "x$MAX_HEAP_SIZE" = "x" ] && [ "x$HEAP_NEWSIZE" = "x" ]; then + calculate_heap_sizes +else + if [ "x$MAX_HEAP_SIZE" = "x" ] || [ "x$HEAP_NEWSIZE" = "x" ]; then + echo "please set or unset MAX_HEAP_SIZE and HEAP_NEWSIZE in pairs (see cassandra-env.sh)" + exit 1 + fi +fi + +# Specifies the default port over which Cassandra will be available for +# JMX connections. +JMX_PORT="8201" + + +# Here we create the arguments that will get passed to the jvm when +# starting cassandra. + +# enable assertions. disabling this in production will give a modest +# performance benefit (around 5%). +JVM_OPTS="$JVM_OPTS -ea" + +# add the jamm javaagent +check_openjdk=`"${JAVA:-java}" -version 2>&1 | awk '{if (NR == 2) {print $1}}'` +if [ "$check_openjdk" != "OpenJDK" ] +then + JVM_OPTS="$JVM_OPTS -javaagent:$CASSANDRA_HOME/lib/jamm-0.2.5.jar" +fi + +# enable thread priorities, primarily so we can give periodic tasks +# a lower priority to avoid interfering with client workload +JVM_OPTS="$JVM_OPTS -XX:+UseThreadPriorities" +# allows lowering thread priority without being root. see +# http://tech.stolsvik.com/2010/01/linux-java-thread-priorities-workaround.html +JVM_OPTS="$JVM_OPTS -XX:ThreadPriorityPolicy=42" + +# min and max heap sizes should be set to the same value to avoid +# stop-the-world GC pauses during resize, and so that we can lock the +# heap in memory on startup to prevent any of it from being swapped +# out. +JVM_OPTS="$JVM_OPTS -Xms${MAX_HEAP_SIZE}" +JVM_OPTS="$JVM_OPTS -Xmx${MAX_HEAP_SIZE}" +JVM_OPTS="$JVM_OPTS -Xmn${HEAP_NEWSIZE}" +JVM_OPTS="$JVM_OPTS -XX:+HeapDumpOnOutOfMemoryError" + +# set jvm HeapDumpPath with CASSANDRA_HEAPDUMP_DIR +if [ "x$CASSANDRA_HEAPDUMP_DIR" != "x" ]; then + JVM_OPTS="$JVM_OPTS -XX:HeapDumpPath=$CASSANDRA_HEAPDUMP_DIR/cassandra-`date +%s`-pid$$.hprof" +fi + +if [ "`uname`" = "Linux" ] ; then + # reduce the per-thread stack size to minimize the impact of Thrift + # thread-per-client. (Best practice is for client connections to + # be pooled anyway.) Only do so on Linux where it is known to be + # supported. + JVM_OPTS="$JVM_OPTS -Xss128k" +fi + +# GC tuning options +JVM_OPTS="$JVM_OPTS -XX:+UseParNewGC" +JVM_OPTS="$JVM_OPTS -XX:+UseConcMarkSweepGC" +JVM_OPTS="$JVM_OPTS -XX:+CMSParallelRemarkEnabled" +JVM_OPTS="$JVM_OPTS -XX:SurvivorRatio=8" +JVM_OPTS="$JVM_OPTS -XX:MaxTenuringThreshold=1" +JVM_OPTS="$JVM_OPTS -XX:CMSInitiatingOccupancyFraction=75" +JVM_OPTS="$JVM_OPTS -XX:+UseCMSInitiatingOccupancyOnly" + +# GC logging options -- uncomment to enable +# JVM_OPTS="$JVM_OPTS -XX:+PrintGCDetails" +# JVM_OPTS="$JVM_OPTS -XX:+PrintGCDateStamps" +# JVM_OPTS="$JVM_OPTS -XX:+PrintHeapAtGC" +# JVM_OPTS="$JVM_OPTS -XX:+PrintTenuringDistribution" +# JVM_OPTS="$JVM_OPTS -XX:+PrintGCApplicationStoppedTime" +# JVM_OPTS="$JVM_OPTS -XX:+PrintPromotionFailure" +# JVM_OPTS="$JVM_OPTS -XX:PrintFLSStatistics=1" +# JVM_OPTS="$JVM_OPTS -Xloggc:/var/log/cassandra/gc-`date +%s`.log" + +# uncomment to have Cassandra JVM listen for remote debuggers/profilers on port 1414 +# JVM_OPTS="$JVM_OPTS -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1414" + +# Prefer binding to IPv4 network intefaces (when net.ipv6.bindv6only=1). See +# http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6342561 (short version: +# comment out this entry to enable IPv6 support). +JVM_OPTS="$JVM_OPTS -Djava.net.preferIPv4Stack=true" + +# jmx: metrics and administration interface +# +# add this if you're having trouble connecting: +# JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=" +# +# see +# http://blogs.sun.com/jmxetc/entry/troubleshooting_connection_problems_in_jconsole +# for more on configuring JMX through firewalls, etc. (Short version: +# get it working with no firewall first.) +JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT" +JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.ssl=false" +JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=false" diff --git a/node_modules/cassandra-client/test/conf2/cassandra.yaml b/node_modules/cassandra-client/test/conf2/cassandra.yaml new file mode 100644 index 0000000..38cfa02 --- /dev/null +++ b/node_modules/cassandra-client/test/conf2/cassandra.yaml @@ -0,0 +1,47 @@ +authenticator: org.apache.cassandra.auth.AllowAllAuthenticator +authority: org.apache.cassandra.auth.AllowAllAuthority +auto_bootstrap: false +cluster_name: Test Cluster +column_index_size_in_kb: 64 +commitlog_directory: [/tmp/cass2/commitlog] +commitlog_sync: periodic +commitlog_sync_period_in_ms: 10000 +compaction_preheat_key_cache: true +concurrent_reads: 4 +concurrent_writes: 4 +data_file_directories: [/tmp/cass2/data] +dynamic_snitch: true +dynamic_snitch_badness_threshold: 0.0 +dynamic_snitch_reset_interval_in_ms: 600000 +dynamic_snitch_update_interval_in_ms: 100 +encryption_options: {internode_encryption: none, keystore: conf/.keystore, keystore_password: cassandra, + truststore: conf/.truststore, truststore_password: cassandra} +endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch +flush_largest_memtables_at: 0.75 +hinted_handoff_enabled: false +hinted_handoff_throttle_delay_in_ms: 50 +in_memory_compaction_limit_in_mb: 64 +incremental_backups: false +index_interval: 128 +initial_token: 56713727820156410577229101238628035242 +listen_address: 127.0.0.2 +max_hint_window_in_ms: 3600000 +memtable_flush_queue_size: 4 +partitioner: org.apache.cassandra.dht.ByteOrderedPartitioner +reduce_cache_capacity_to: 0.59999999999999998 +reduce_cache_sizes_at: 0.84999999999999998 +request_scheduler: org.apache.cassandra.scheduler.NoScheduler +rpc_address: 127.0.0.2 +rpc_keepalive: true +rpc_port: 19170 +rpc_timeout_in_ms: 10000 +saved_caches_directory: [/tmp/cass2/savedcaches] +seed_provider: +- class_name: org.apache.cassandra.locator.SimpleSeedProvider + parameters: + - {seeds: 127.0.0.1} +sliced_buffer_size_in_kb: 64 +snapshot_before_compaction: false +storage_port: 17001 +thrift_framed_transport_size_in_mb: 15 +thrift_max_message_length_in_mb: 16 diff --git a/node_modules/cassandra-client/test/conf2/log4j-server.properties b/node_modules/cassandra-client/test/conf2/log4j-server.properties new file mode 100644 index 0000000..8750e5b --- /dev/null +++ b/node_modules/cassandra-client/test/conf2/log4j-server.properties @@ -0,0 +1,31 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# for production, you should probably set pattern to %c instead of %l. +# (%l is slower.) + +# output messages into a rolling log file as well as stdout +log4j.rootLogger=DEBUG,stdout + +# stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p %d{HH:mm:ss,SSS} %m%n + +# Application logging options +#log4j.logger.org.apache.cassandra=DEBUG +#log4j.logger.org.apache.cassandra.db=DEBUG +#log4j.logger.org.apache.cassandra.service.StorageProxy=DEBUG diff --git a/node_modules/cassandra-client/test/conf3/cassandra-env.sh b/node_modules/cassandra-client/test/conf3/cassandra-env.sh new file mode 100644 index 0000000..1840592 --- /dev/null +++ b/node_modules/cassandra-client/test/conf3/cassandra-env.sh @@ -0,0 +1,194 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +calculate_heap_sizes() +{ + case "`uname`" in + Linux) + system_memory_in_mb=`free -m | awk '/Mem:/ {print $2}'` + system_cpu_cores=`egrep -c 'processor([[:space:]]+):.*' /proc/cpuinfo` + break + ;; + FreeBSD) + system_memory_in_bytes=`sysctl hw.physmem | awk '{print $2}'` + system_memory_in_mb=`expr $system_memory_in_bytes / 1024 / 1024` + system_cpu_cores=`sysctl hw.ncpu | awk '{print $2}'` + break + ;; + SunOS) + system_memory_in_mb=`prtconf | awk '/Memory size:/ {print $3}'` + system_cpu_cores=`psrinfo | wc -l` + break + ;; + *) + # assume reasonable defaults for e.g. a modern desktop or + # cheap server + system_memory_in_mb="2048" + system_cpu_cores="2" + ;; + esac + + # set max heap size based on the following + # max(min(1/2 ram, 1024MB), min(1/4 ram, 8GB)) + # calculate 1/2 ram and cap to 1024MB + # calculate 1/4 ram and cap to 8192MB + # pick the max + half_system_memory_in_mb=`expr $system_memory_in_mb / 2` + quarter_system_memory_in_mb=`expr $half_system_memory_in_mb / 2` + if [ "$half_system_memory_in_mb" -gt "1024" ] + then + half_system_memory_in_mb="1024" + fi + if [ "$quarter_system_memory_in_mb" -gt "8192" ] + then + quarter_system_memory_in_mb="8192" + fi + if [ "$half_system_memory_in_mb" -gt "$quarter_system_memory_in_mb" ] + then + max_heap_size_in_mb="$half_system_memory_in_mb" + else + max_heap_size_in_mb="$quarter_system_memory_in_mb" + fi + MAX_HEAP_SIZE="${max_heap_size_in_mb}M" + + # Young gen: min(max_sensible_per_modern_cpu_core * num_cores, 1/4 * heap size) + max_sensible_yg_per_core_in_mb="100" + max_sensible_yg_in_mb=`expr $max_sensible_yg_per_core_in_mb "*" $system_cpu_cores` + + desired_yg_in_mb=`expr $max_heap_size_in_mb / 4` + + if [ "$desired_yg_in_mb" -gt "$max_sensible_yg_in_mb" ] + then + HEAP_NEWSIZE="${max_sensible_yg_in_mb}M" + else + HEAP_NEWSIZE="${desired_yg_in_mb}M" + fi +} + +# Override these to set the amount of memory to allocate to the JVM at +# start-up. For production use you almost certainly want to adjust +# this for your environment. MAX_HEAP_SIZE is the total amount of +# memory dedicated to the Java heap; HEAP_NEWSIZE refers to the size +# of the young generation. Both MAX_HEAP_SIZE and HEAP_NEWSIZE should +# be either set or not (if you set one, set the other). +# +# The main trade-off for the young generation is that the larger it +# is, the longer GC pause times will be. The shorter it is, the more +# expensive GC will be (usually). +# +# The example HEAP_NEWSIZE assumes a modern 8-core+ machine for decent pause +# times. If in doubt, and if you do not particularly want to tweak, go with +# 100 MB per physical CPU core. + +MAX_HEAP_SIZE="512M" +HEAP_NEWSIZE="32M" + +if [ "x$MAX_HEAP_SIZE" = "x" ] && [ "x$HEAP_NEWSIZE" = "x" ]; then + calculate_heap_sizes +else + if [ "x$MAX_HEAP_SIZE" = "x" ] || [ "x$HEAP_NEWSIZE" = "x" ]; then + echo "please set or unset MAX_HEAP_SIZE and HEAP_NEWSIZE in pairs (see cassandra-env.sh)" + exit 1 + fi +fi + +# Specifies the default port over which Cassandra will be available for +# JMX connections. +JMX_PORT="8203" + + +# Here we create the arguments that will get passed to the jvm when +# starting cassandra. + +# enable assertions. disabling this in production will give a modest +# performance benefit (around 5%). +JVM_OPTS="$JVM_OPTS -ea" + +# add the jamm javaagent +check_openjdk=`"${JAVA:-java}" -version 2>&1 | awk '{if (NR == 2) {print $1}}'` +if [ "$check_openjdk" != "OpenJDK" ] +then + JVM_OPTS="$JVM_OPTS -javaagent:$CASSANDRA_HOME/lib/jamm-0.2.5.jar" +fi + +# enable thread priorities, primarily so we can give periodic tasks +# a lower priority to avoid interfering with client workload +JVM_OPTS="$JVM_OPTS -XX:+UseThreadPriorities" +# allows lowering thread priority without being root. see +# http://tech.stolsvik.com/2010/01/linux-java-thread-priorities-workaround.html +JVM_OPTS="$JVM_OPTS -XX:ThreadPriorityPolicy=42" + +# min and max heap sizes should be set to the same value to avoid +# stop-the-world GC pauses during resize, and so that we can lock the +# heap in memory on startup to prevent any of it from being swapped +# out. +JVM_OPTS="$JVM_OPTS -Xms${MAX_HEAP_SIZE}" +JVM_OPTS="$JVM_OPTS -Xmx${MAX_HEAP_SIZE}" +JVM_OPTS="$JVM_OPTS -Xmn${HEAP_NEWSIZE}" +JVM_OPTS="$JVM_OPTS -XX:+HeapDumpOnOutOfMemoryError" + +# set jvm HeapDumpPath with CASSANDRA_HEAPDUMP_DIR +if [ "x$CASSANDRA_HEAPDUMP_DIR" != "x" ]; then + JVM_OPTS="$JVM_OPTS -XX:HeapDumpPath=$CASSANDRA_HEAPDUMP_DIR/cassandra-`date +%s`-pid$$.hprof" +fi + +if [ "`uname`" = "Linux" ] ; then + # reduce the per-thread stack size to minimize the impact of Thrift + # thread-per-client. (Best practice is for client connections to + # be pooled anyway.) Only do so on Linux where it is known to be + # supported. + JVM_OPTS="$JVM_OPTS -Xss128k" +fi + +# GC tuning options +JVM_OPTS="$JVM_OPTS -XX:+UseParNewGC" +JVM_OPTS="$JVM_OPTS -XX:+UseConcMarkSweepGC" +JVM_OPTS="$JVM_OPTS -XX:+CMSParallelRemarkEnabled" +JVM_OPTS="$JVM_OPTS -XX:SurvivorRatio=8" +JVM_OPTS="$JVM_OPTS -XX:MaxTenuringThreshold=1" +JVM_OPTS="$JVM_OPTS -XX:CMSInitiatingOccupancyFraction=75" +JVM_OPTS="$JVM_OPTS -XX:+UseCMSInitiatingOccupancyOnly" + +# GC logging options -- uncomment to enable +# JVM_OPTS="$JVM_OPTS -XX:+PrintGCDetails" +# JVM_OPTS="$JVM_OPTS -XX:+PrintGCDateStamps" +# JVM_OPTS="$JVM_OPTS -XX:+PrintHeapAtGC" +# JVM_OPTS="$JVM_OPTS -XX:+PrintTenuringDistribution" +# JVM_OPTS="$JVM_OPTS -XX:+PrintGCApplicationStoppedTime" +# JVM_OPTS="$JVM_OPTS -XX:+PrintPromotionFailure" +# JVM_OPTS="$JVM_OPTS -XX:PrintFLSStatistics=1" +# JVM_OPTS="$JVM_OPTS -Xloggc:/var/log/cassandra/gc-`date +%s`.log" + +# uncomment to have Cassandra JVM listen for remote debuggers/profilers on port 1414 +# JVM_OPTS="$JVM_OPTS -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1414" + +# Prefer binding to IPv4 network intefaces (when net.ipv6.bindv6only=1). See +# http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6342561 (short version: +# comment out this entry to enable IPv6 support). +JVM_OPTS="$JVM_OPTS -Djava.net.preferIPv4Stack=true" + +# jmx: metrics and administration interface +# +# add this if you're having trouble connecting: +# JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=" +# +# see +# http://blogs.sun.com/jmxetc/entry/troubleshooting_connection_problems_in_jconsole +# for more on configuring JMX through firewalls, etc. (Short version: +# get it working with no firewall first.) +JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT" +JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.ssl=false" +JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=false" diff --git a/node_modules/cassandra-client/test/conf3/cassandra.yaml b/node_modules/cassandra-client/test/conf3/cassandra.yaml new file mode 100644 index 0000000..aba887a --- /dev/null +++ b/node_modules/cassandra-client/test/conf3/cassandra.yaml @@ -0,0 +1,47 @@ +authenticator: org.apache.cassandra.auth.AllowAllAuthenticator +authority: org.apache.cassandra.auth.AllowAllAuthority +auto_bootstrap: false +cluster_name: Test Cluster +column_index_size_in_kb: 64 +commitlog_directory: [/tmp/cass3/commitlog] +commitlog_sync: periodic +commitlog_sync_period_in_ms: 10000 +compaction_preheat_key_cache: true +concurrent_reads: 4 +concurrent_writes: 4 +data_file_directories: [/tmp/cass3/data] +dynamic_snitch: true +dynamic_snitch_badness_threshold: 0.0 +dynamic_snitch_reset_interval_in_ms: 600000 +dynamic_snitch_update_interval_in_ms: 100 +encryption_options: {internode_encryption: none, keystore: conf/.keystore, keystore_password: cassandra, + truststore: conf/.truststore, truststore_password: cassandra} +endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch +flush_largest_memtables_at: 0.75 +hinted_handoff_enabled: false +hinted_handoff_throttle_delay_in_ms: 50 +in_memory_compaction_limit_in_mb: 64 +incremental_backups: false +index_interval: 128 +initial_token: 113427455640312821154458202477256070485 +listen_address: 127.0.0.3 +max_hint_window_in_ms: 3600000 +memtable_flush_queue_size: 4 +partitioner: org.apache.cassandra.dht.ByteOrderedPartitioner +reduce_cache_capacity_to: 0.59999999999999998 +reduce_cache_sizes_at: 0.84999999999999998 +request_scheduler: org.apache.cassandra.scheduler.NoScheduler +rpc_address: 127.0.0.3 +rpc_keepalive: true +rpc_port: 19170 +rpc_timeout_in_ms: 10000 +saved_caches_directory: [/tmp/cass3/savedcaches] +seed_provider: +- class_name: org.apache.cassandra.locator.SimpleSeedProvider + parameters: + - {seeds: 127.0.0.1} +sliced_buffer_size_in_kb: 64 +snapshot_before_compaction: false +storage_port: 17001 +thrift_framed_transport_size_in_mb: 15 +thrift_max_message_length_in_mb: 16 diff --git a/node_modules/cassandra-client/test/conf3/log4j-server.properties b/node_modules/cassandra-client/test/conf3/log4j-server.properties new file mode 100644 index 0000000..8750e5b --- /dev/null +++ b/node_modules/cassandra-client/test/conf3/log4j-server.properties @@ -0,0 +1,31 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# for production, you should probably set pattern to %c instead of %l. +# (%l is slower.) + +# output messages into a rolling log file as well as stdout +log4j.rootLogger=DEBUG,stdout + +# stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p %d{HH:mm:ss,SSS} %m%n + +# Application logging options +#log4j.logger.org.apache.cassandra=DEBUG +#log4j.logger.org.apache.cassandra.db=DEBUG +#log4j.logger.org.apache.cassandra.service.StorageProxy=DEBUG diff --git a/node_modules/cassandra-client/test/dependencies.json b/node_modules/cassandra-client/test/dependencies.json new file mode 100644 index 0000000..7865124 --- /dev/null +++ b/node_modules/cassandra-client/test/dependencies.json @@ -0,0 +1,13 @@ +{ + "cassandra": { + "cmd": ["test/cass.sh"], + "cwd": ["__dirname", ".."], + "log_file": "test-cassandra.log", + "wait_for": "socket", + "wait_for_options": { + "host": "127.0.0.1", + "port": 19170 + }, + "timeout": 10000 + } +} diff --git a/node_modules/cassandra-client/test/test_decoder.js b/node_modules/cassandra-client/test/test_decoder.js new file mode 100644 index 0000000..c7f97d9 --- /dev/null +++ b/node_modules/cassandra-client/test/test_decoder.js @@ -0,0 +1,257 @@ +/* + * Copyright 2011 Rackspace + * + * 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. + * + */ + + +var BigInteger = require('../lib/bigint').BigInteger; +var bytesToBigLong = require('../lib/decoder').bytesToBigLong; +var bytesToNum = require('../lib/decoder').bytesToNum; +var bufferToString = require('../lib/decoder').bufferToString; +var UUID = require('../lib/uuid'); + +function makeBuffer(string) { + return new Buffer(string, 'binary'); +} + +// friggen big integer library is broken. +exports.testBigIntegerBrokenness = function(test, assert) { + // the the v8 lib behaved like the java BigInteger, this test would pass. + + // this is how the zeroes we read out of the database get constructed. + var zero1 = new BigInteger([0]); + assert.ok(zero1); + + // this is how zeroes will be constructed by programmers. + var zero2 = new BigInteger('0'); + assert.ok(zero2); + + // notice: they are not equal, but if the v8 lib _really_ behaved like java.math.BigInteger (which it claims to emulate) + // equality should be achived. + assert.ok(!zero1.equals(zero2)); + + // instead, we need to rely on bytesToBigLong to return the right thing. + assert.ok(zero2.equals(bytesToBigLong(makeBuffer('\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000')))); + + test.finish(); +}; + +exports.testNumConversion = function(test, assert) { + assert.strictEqual('0', bytesToNum(makeBuffer('\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000')).toString()); // 1 + assert.strictEqual('1', bytesToNum(makeBuffer('\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001')).toString()); // 1 + assert.strictEqual('2', bytesToNum(makeBuffer('\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0002')).toString()); // 2 + assert.strictEqual('255' ,bytesToNum(makeBuffer('\u0000\u0000\u0000\u0000\u0000\u0000\u0000ÿ')).toString()); // 255 + assert.strictEqual('2550' ,bytesToNum(makeBuffer('\u0000\u0000\u0000\u0000\u0000\u0000\tö')).toString()); // 2550 + assert.strictEqual('8025521', bytesToNum(makeBuffer('\u0000\u0000\u0000\u0000\u0000zu±')).toString()); // 8025521 + assert.strictEqual('218025521', bytesToNum(makeBuffer('\u0000\u0000\u0000\u0000\fþÎ1')).toString()); // 218025521 + + // these values ensure that none 8 byte sequences work as well. + assert.strictEqual(2147483647, bytesToNum(makeBuffer('\u007f\u00ff\u00ff\u00ff'))); // [127,-1,-1,-1] + assert.strictEqual(-2147483648, bytesToNum(makeBuffer('\u0080\u0000\u0000\u0000'))); // [-128,0,0,0] + assert.strictEqual(-1, bytesToNum(makeBuffer('\u00ff'))); // [-1] + assert.strictEqual(1, bytesToNum(makeBuffer('\u0001'))); // [1] + + assert.strictEqual('-1', bytesToNum(makeBuffer('ÿÿÿÿÿÿÿÿ')).toString()); + test.finish(); +}; + +exports.testLongConversion = function(test, assert) { + assert.ok(bytesToBigLong); + // we have to compare against strings. + assert.ok(new BigInteger('0').equals(bytesToBigLong(makeBuffer('\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000')))); + assert.strictEqual('0', bytesToBigLong(makeBuffer('\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000')).toString()); // 1 + assert.strictEqual('1', bytesToBigLong(makeBuffer('\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001')).toString()); // 1 + assert.strictEqual('2', bytesToBigLong(makeBuffer('\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0002')).toString()); // 2 + assert.strictEqual('255' ,bytesToBigLong(makeBuffer('\u0000\u0000\u0000\u0000\u0000\u0000\u0000ÿ')).toString()); // 255 + assert.strictEqual('2550' ,bytesToBigLong(makeBuffer('\u0000\u0000\u0000\u0000\u0000\u0000\tö')).toString()); // 2550 + assert.strictEqual('8025521', bytesToBigLong(makeBuffer('\u0000\u0000\u0000\u0000\u0000zu±')).toString()); // 8025521 + assert.strictEqual('218025521', bytesToBigLong(makeBuffer('\u0000\u0000\u0000\u0000\fþÎ1')).toString()); // 218025521 + assert.strictEqual('6544218025521', bytesToBigLong(makeBuffer('\u0000\u0000\u0005ó±Ên1')).toString()); // 6544218025521 + assert.strictEqual('8776496549718025521', bytesToBigLong(makeBuffer('yÌa\u001c²be1')).toString()); // 8776496549718025521 + assert.strictEqual('-1', bytesToBigLong(makeBuffer('ÿÿÿÿÿÿÿÿ')).toString()); // -1 + + test.finish(); +}; + +/** make sure sign extension and unsigned/signed conversions don't bite us. */ +exports.testBigIntEdges = function(test, assert) { + + assert.ok(new BigInteger([255]).equals(new BigInteger([-1]))); + assert.ok(new BigInteger([245]).equals(new BigInteger([-11]))); + assert.deepEqual(new BigInteger([255]).toByteArray(), new BigInteger([-1]).toByteArray()); + assert.deepEqual(new BigInteger([245]).toByteArray(), new BigInteger([-11]).toByteArray()); + assert.deepEqual(new BigInteger([255]), new BigInteger([-1])); + assert.deepEqual(new BigInteger([245]), new BigInteger([-11])); + + test.finish(); +}; + +/** verify byte array fidelity with java.math.BigInteger */ +exports.testBigInt = function(test, assert) { + // these arrays were generated using java program below. + var expectedArrays = [ + [ 23 ], + [ 0, -127 ], + [ 1, 3 ], + [ 4, 5 ], + [ 32, 0, 0, 0, 0 ], + [ 64, 0, 0, 0, 0 ], + [ 0, -128, 0, 0, 0, 0 ], + [ 76, 75, 89, -94, 112, -83, 123, -128 ], + [ 32, 23, -123, 66, -123, 31, -109, -128 ], + [ 122, -80, -3, 114, -84, 96, 0 ], + [ 8, 0, 0, 0, 0, 0, 0, 0, 0 ], + [ 12, 53, 8, 15, -119, 11, -105, 14, -72, 55, -128 ], + [ 16, 0, 0, 0, 0, 0, 0, 0, 0 ], + [ 0, -14, -67, -117, 113, -67, 39, -92, 104, -1, -84, 60 ], + [ -23 ], + [ -1, 127 ], + [ -2, -3 ], + [ -5, -5 ], + [ -32, 0, 0, 0, 0 ], + [ -64, 0, 0, 0, 0 ], + [ -128, 0, 0, 0, 0 ], + [ -77, -76, -90, 93, -113, 82, -124, -128 ], + [ -33, -24, 122, -67, 122, -32, 108, -128 ], + [ -123, 79, 2, -115, 83, -96, 0 ], + [ -8, 0, 0, 0, 0, 0, 0, 0, 0 ], + [ -13, -54, -9, -16, 118, -12, 104, -15, 71, -56, -128 ], + [ -16, 0, 0, 0, 0, 0, 0, 0, 0 ], + [ -1, 13, 66, 116, -114, 66, -40, 91, -105, 0, 83, -60 ] + ]; + var nums = [ + '23', + '129', + '259', + '1029', + '137438953472', + '274877906944', + '549755813888', + '5497586324345813888', + '2312463454425813888', + '34534549755813888', + '147573952589676412928', + '14757543952358956762412928', + '295147905179352825856', + '293455147905179352825834556', + + '-23', + '-129', + '-259', + '-1029', + '-137438953472', + '-274877906944', + '-549755813888', + '-5497586324345813888', + '-2312463454425813888', + '-34534549755813888', + '-147573952589676412928', + '-14757543952358956762412928', + '-295147905179352825856', + '-293455147905179352825834556' + ]; + assert.equal(expectedArrays.length, nums.length); + for (var i = 0; i < nums.length; i++) { + assert.deepEqual(new BigInteger(nums[i]).toByteArray(), expectedArrays[i]); + assert.deepEqual(new BigInteger(nums[i]).toByteArray(), new BigInteger(expectedArrays[i]).toByteArray()); + } + + test.finish(); +/** +The expected values were all generated from this program: + +import java.math.BigInteger; + +public class TestBigInt { + private static final String[] ints = { + "23", + "129", + "259", + "1029", + "137438953472", + "274877906944", + "549755813888", + "5497586324345813888", + "2312463454425813888", + "34534549755813888", + "147573952589676412928", + "14757543952358956762412928", + "295147905179352825856", + "293455147905179352825834556", + + "-23", + "-129", + "-259", + "-1029", + "-137438953472", + "-274877906944", + "-549755813888", + "-5497586324345813888", + "-2312463454425813888", + "-34534549755813888", + "-147573952589676412928", + "-14757543952358956762412928", + "-295147905179352825856", + "-293455147905179352825834556" + }; + + public static void main(String args[]) { + for (String s : ints) + System.out.println(toString(new BigInteger(s).toByteArray())); + } + + private static String toString(byte[] arr) { + StringBuilder sb = new StringBuilder("[ "); + for (byte b : arr) { + sb.append((int)b).append(", "); + } + return sb.toString().substring(0, sb.length()-2) + " ]"; + } +} + */ +}; + +exports.testUUID = function(test, assert) { + + /* from java: + ddf09190-6612-11e0-0000-fe8ebeead9f8->[221,240,145,144,102,18,17,224,0,0,254,142,190,234,217,248,] + ddf0b8a0-6612-11e0-0000-1e4e5d5425fc->[221,240,184,160,102,18,17,224,0,0,30,78,93,84,37,252,] + ddf0b8a1-6612-11e0-0000-90f061abd1ff->[221,240,184,161,102,18,17,224,0,0,144,240,97,171,209,255,] + */ + var strings = ['ddf09190-6612-11e0-0000-fe8ebeead9f8', + 'ddf0b8a0-6612-11e0-0000-1e4e5d5425fc', + 'ddf0b8a1-6612-11e0-0000-90f061abd1ff']; + var arrays = [[221,240,145,144,102,18,17,224,0,0,254,142,190,234,217,248], + [221,240,184,160,102,18,17,224,0,0,30,78,93,84,37,252], + [221,240,184,161,102,18,17,224,0,0,144,240,97,171,209,255]]; + + assert.strictEqual(strings.length, arrays.length); + for (var i = 0; i < strings.length; i++) { + assert.deepEqual( UUID.fromString(strings[i]), UUID.fromBytes(arrays[i]) ); + } + test.finish(); +}; + +exports.testHexing = function(test, assert) { + var buf = new Buffer(6); + buf[0] = 0x00; + buf[1] = 0x33; + buf[2] = 0x66; + buf[3] = 0x99; + buf[4] = 0xcc; + buf[5] = 0xff; + assert.strictEqual('00336699ccff', buf.toString('hex')); + test.finish(); +}; diff --git a/node_modules/cassandra-client/test/test_driver.js b/node_modules/cassandra-client/test/test_driver.js new file mode 100644 index 0000000..f639787 --- /dev/null +++ b/node_modules/cassandra-client/test/test_driver.js @@ -0,0 +1,1119 @@ +/* + * Copyright 2011 Rackspace + * + * 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. + * + */ + + +var assert = require('assert'); +var console = require('console'); +var EventEmitter = require('events').EventEmitter; +var http = require('http'); + +var async = require('async'); + +var BigInteger = require('../lib/bigint').BigInteger; + +var Connection = require('../lib/driver').Connection; +var PooledConnection = require('../lib/driver').PooledConnection; +var ConnectionInPool = require('../lib/driver').ConnectionInPool; +var ttypes = require('../lib/gen-nodejs/cassandra_types'); +var Keyspace = require('../node-cassandra-client').Keyspace; +var System = require('../lib/system').System; +var KsDef = require('../lib/system').KsDef; +var CfDef = require('../lib/system').CfDef; +var UUID = require('../lib/driver').UUID; +var util = require('./util'); +var decoder = require('../lib/decoder'); + +var CASSANDRA_PORT = 19170; + +function merge(a, b) { + var c = {}, attrname; + + for (attrname in a) { + if (a.hasOwnProperty(attrname)) { + c[attrname] = a[attrname]; + } + } + for (attrname in b) { + if (b.hasOwnProperty(attrname)) { + c[attrname] = b[attrname]; + } + } + return c; +}; + +function stringToHex(s) { + var buf = ''; + for (var i = 0; i < s.length; i++) { + buf += s.charCodeAt(i).toString(16); + } + return buf; +} + + +function connect(options, callback) { + if (typeof options === 'function') { + callback = options; + options = {}; + } + + var defaultOptions = { + host: '127.0.0.1', + port: CASSANDRA_PORT, + keyspace: 'Keyspace1', + use_bigints: true + }; + var connOptions = merge(defaultOptions, options); + var handler = new EventEmitter(); + handler.on('error', function(err) { + callback(err, null); + }); + handler.on('ready', function(con) { + callback(null, con); + }); + var con = new Connection(connOptions); + con.on('log', function(level, message) { + if (['cql'].indexOf(level) !== -1) { + return; + } + console.log('log event: %s -- %j', level, message); + }); + con.connect(function(err) { + if (err) { + callback(err, null); + } else { + callback(null, con); + } + }); +} + +exports.setUp = function(test, assert) { + var sys = new System('127.0.0.1:'+CASSANDRA_PORT); + var ksName = 'Keyspace1'; + var close = function() { + sys.close(function() { + sys.close(); + console.log('System keyspace closed'); + }); + }; + sys.describeKeyspace(ksName, function(descErr, ksDef) { + if (descErr) { + console.log('adding test keyspace'); + var standard1 = new CfDef({keyspace: ksName, name: 'Standard1', column_type: 'Standard', comparator_type: 'UTF8Type', default_validation_class: 'UTF8Type'}); + var cfLong = new CfDef({keyspace: ksName, name: 'CfLong', column_type: 'Standard', comparator_type: 'LongType', default_validation_class: 'LongType', key_validation_class: 'LongType'}); + var cfInt = new CfDef({keyspace: ksName, name: 'CfInt', column_type: 'Standard', comparator_type: 'IntegerType', default_validation_class: 'IntegerType', key_validation_class: 'IntegerType'}); + var cfUtf8 = new CfDef({keyspace: ksName, name: 'CfUtf8', column_type: 'Standard', comparator_type: 'UTF8Type', default_validation_class: 'UTF8Type', key_validation_class: 'UTF8Type'}); + var cfBytes = new CfDef({keyspace: ksName, name: 'CfBytes', column_type: 'Standard', comparator_type: 'BytesType', default_validation_class: 'BytesType', key_validation_class: 'BytesType'}); + var cfUuid = new CfDef({keyspace: ksName, name: 'CfUuid', column_type: 'Standard', comparator_type: 'TimeUUIDType', default_validation_class: 'TimeUUIDType', key_validation_class: 'TimeUUIDType'}); + var cfUgly = new CfDef({keyspace: ksName, name: 'CfUgly', column_type: 'Standard', comparator_type: 'UTF8Type', + default_validation_class: 'LongType', key_validation_class: 'IntegerType', + column_metadata: [ + new ttypes.ColumnDef({name: 'int_col', validation_class: 'IntegerType'}), + new ttypes.ColumnDef({name: 'string_col', validation_class: 'UTF8Type'}), + new ttypes.ColumnDef({name: 'uuid_col', validation_class: 'TimeUUIDType'}) + ]}); + var cfCounter = new CfDef({keyspace: ksName, name: 'CfCounter', column_type: 'Standard', comparator_type: 'AsciiType', default_validation_class: 'CounterColumnType', key_validation_class: 'AsciiType'}); + var super1 = new CfDef({keyspace: ksName, name: 'Super1', column_type: 'Super', comparator_type: 'UTF8Type', subcomparator_type: 'UTF8Type'}); + var keyspace1 = new KsDef({name: ksName, strategy_class: 'org.apache.cassandra.locator.SimpleStrategy', strategy_options: {'replication_factor': '1'}, cf_defs: [standard1, super1, cfInt, cfUtf8, cfLong, cfBytes, cfUuid, cfUgly, cfCounter]}); + sys.addKeyspace(keyspace1, function(addErr) { + console.log(addErr); + close(); + if (addErr) { + assert.ifError(addErr); + } else { + console.log('keyspace created'); + test.finish(); + } + }); + } else { + close(); + console.log(ksDef.name + ' keyspace already exists'); + test.finish(); + } + }); +}; + +exports.tearDown = function(test, assert) { + connect(function(err, con) { + if (err) { + assert.ifError(err); + con.close(); + test.finish(); + return; + } + + con.execute('DROP KEYSPACE ?', ['Keyspace1'], function(dropErr, res) { + assert.ifError(dropErr); + con.close(); + test.finish(); + }); + }); +}; + +exports.testWhiskyIsWorking = function(test, assert) { + assert.throws(function() { + assert.ok(false); + }, require('assert').AssertionError); + test.finish(); +}; + +exports.testNoResults = function(test, assert) { + connect(function(err, con) { + if (err) { + con.close(); + assert.ifError(err); + test.finish(); + } else { + con.execute('select * from CfLong where key=999999999', [], function(err, rows) { + con.close(); + assert.ok(rows); + // NOTE: There is a bug in some newer minor cassandra versions so this + // check is temporary commented out + // https://issues.apache.org/jira/browse/CASSANDRA-3424 + //assert.strictEqual(rows.rowCount(), 0); + assert.strictEqual(err, null); + test.finish(); + }); + } + }); +}; + +exports.testSelectCount = function(test, assert) { + var con = null; + + async.waterfall([ + connect, + + function executeCountQuery(_con, callback) { + con = _con; + con.execute('SELECT COUNT(*) FROM CfLong', [], function(err, rows) { + assert.ifError(err); + assert.equal(rows[0].cols[0].value, 0); + callback(); + }); + }, + + function insertFiveRows(callback) { + async.forEach([1, 2, 3, 4, 5], function(i, callback) { + con.execute('UPDATE CfLong SET 1=1 WHERE key=?', [i], callback); + }, callback); + }, + + function executeCountQuery(callback) { + con.execute('SELECT COUNT(*) FROM CfLong', [], function(err, rows) { + assert.ifError(err); + assert.strictEqual(rows[0].cols[0].value, 5); + callback(); + }); + }, + ], + + function(err) { + if (con) { + con.close(); + } + + assert.ifError(err); + test.finish(); + }); +}; + +exports.testSimpleUpdate = function(test, assert) { + connect(function(err, con) { + if (err) { + assert.ifError(err); + test.finish(); + } else { + var key = stringToHex('key0'); + con.execute('update Standard1 set ?=?, ?=? where key=?', ['cola', 'valuea', 'colb', 'valueb', key], function(updateErr) { + if (updateErr) { + con.close(); + assert.ifError(updateErr); + test.finish(); + } else { + con.execute('select ?, ? from Standard1 where key=?', ['cola', 'colb', key], function(selectErr, rows) { + con.close(); + assert.ifError(selectErr); + assert.strictEqual(rows.rowCount(), 1); + var row = rows[0]; + assert.strictEqual('cola', row.cols[0].name.toString()); + assert.strictEqual('valuea', row.cols[0].value.toString()); + test.finish(); + }); + } + }); + } + }); +}; + +exports.testConnectToBadUrl = function(test, assert) { + connect({port:19171}, function(err, con) { + assert.ok(err); + assert.strictEqual(err.code, 'ECONNREFUSED'); + test.finish(); + }); +}; + +exports.testConnectionKeyspaceDoesNotExistConnect = function(test, assert) { + connect({keyspace: 'doesnotexist.'}, function(err, conn) { + assert.ok(err); + assert.equal(err.name, 'NotFoundException') + assert.equal(err.message, 'ColumnFamily or Keyspace does not exist'); + assert.ok(!conn); + test.finish(); + }); +}; + +exports.testPooledConnectionKeyspaceDoesNotExistConnect = function(test, assert) { + var con = new PooledConnection({hosts: ['127.0.0.1:19170'], + keyspace: 'doesNotExist.', + use_bigints: false}); + con.execute('SELECT * FROM foo', [], function(err) { + assert.ok(err); + assert.equal(err.message, 'ColumnFamily or Keyspace does not exist'); + assert.equal(err.name, 'NotFoundException') + test.finish(); + }); +}; + +exports.testCounterUpdate = function(test, assert) { + connect(function(err0, con) { + assert.ifError(err0); + con.execute('UPDATE CfCounter SET ? = ? + 3 WHERE KEY = ?', + ['a', 'a', 'test'], + function(err1, res0) { + if (err1) { + con.close(); + assert.ifError(err1); + test.finish(); + } else { + con.execute('SELECT ? FROM CfCounter WHERE KEY = ?', + ['a', 'test'], + function(err2, res1) { + if (err2) { + con.close(); + assert.ifError(err2); + test.finish(); + } else { + con.close(); + assert.strictEqual(res1[0].colHash['a'].toString(), '3'); + test.finish(); + } + }); + } + }); + }); +}; + +exports.testUpdateWithNull = function(test, assert) { + connect(function(err, con) { + if (err) { + assert.ifError(err); + test.finish(); + } else { + var key = stringToHex('key0'); + con.execute('update Standard1 set ?=?, ?=? where key=?', ['cola', null, 'colb', 'valueb', key], function(updateErr) { + con.close(); + assert.ok(updateErr); + test.finish(); + }); + } + }); +}; + +exports.testSimpleDelete = function(test, assert) { + connect(function(err, con) { + if (err) { + assert.ok(false); + test.finish(); + } else { + var key = stringToHex('key2'); + con.execute('update Standard1 set ?=?, ?=? where key=?', ['colx', 'xxx', 'colz', 'bbb', key], function(updateErr) { + if (updateErr) { + con.close(); + + } else { + con.execute('delete ?,? from Standard1 where key in (?)', ['colx', 'colz', key], function(delErr) { + if (delErr) { + con.close(); + assert.ok(false); + test.finish(); + } else { + con.execute('select ?,? from Standard1 where key=?', ['colx', 'colz', key], function(selErr, rows) { + con.close(); + if (selErr) { + assert.ok(false); + } else { + assert.strictEqual(rows.rowCount(), 1); + var row = rows[0]; + assert.strictEqual(0, row.colCount()); + } + test.finish(); + }); + } + }); + } + }); + } + }); +}; + +exports.testLongNoBigint = function(test, assert) { + connect(function(err, con) { + if (err) { + assert.ok(false); + test.finish(); + } else { + assert.ok(true); + assert.strictEqual(con.connectionInfo.use_bigints, true); + con.connectionInfo.use_bigints = false; + assert.strictEqual(con.connectionInfo.use_bigints, false); + + var updParms = [1,2,99]; + con.execute('update CfLong set ?=? where key=?', updParms, function(updErr) { + if (updErr) { + con.close(); + assert.ok(false); + test.finish(); + } else { + con.execute('select ? from CfLong where key=?', [1, 99], function(selErr, rows) { + con.close(); + assert.strictEqual(rows.rowCount(), 1); + var row = rows[0]; + assert.strictEqual(1, row.colCount()); + assert.strictEqual(1, row.cols[0].name); + assert.strictEqual(2, row.cols[0].value); + test.finish(); + }); + } + }); + } + }); +}; + +exports.testIntNoBigint = function(test, assert) { + connect(function(err, con) { + if (err) { + assert.ok(false); + test.finish(); + } else { + assert.ok(true); + assert.strictEqual(con.connectionInfo.use_bigints, true); + con.connectionInfo.use_bigints = false; + assert.strictEqual(con.connectionInfo.use_bigints, false); + + var updParms = [1,2,99]; + con.execute('update CfInt set ?=? where key=?', updParms, function(updErr) { + if (updErr) { + con.close(); + assert.ok(false); + test.finish(); + } else { + con.execute('select ? from CfInt where key=?', [1, 99], function(selErr, rows) { + con.close(); + assert.strictEqual(rows.rowCount(), 1); + var row = rows[0]; + assert.strictEqual(1, row.colCount()); + assert.strictEqual(1, row.cols[0].name); + assert.strictEqual(2, row.cols[0].value); + test.finish(); + }); + } + }); + } + }); +}; + +exports.testBinary = function(test, assert) { + connect(function(err, con) { + assert.ifError(err); + var key = 'binarytest'; + var binaryParams = [util.randomBuffer(), util.randomBuffer(), util.randomBuffer()]; + con.execute('update CfBytes set ?=? where key=?', binaryParams, function(updErr) { + if (updErr) { + con.close(); + assert.ok(false); + test.finish(); + } else { + con.execute('select ? from CfBytes where key=?', [binaryParams[0], binaryParams[2]], function(selErr, rows) { + con.close(); + assert.strictEqual(rows.rowCount(), 1); + var row = rows[0]; + assert.strictEqual(row.key.toString('base64'), binaryParams[2].toString('base64')); + assert.strictEqual(row.cols[0].name.toString('base64'), binaryParams[0].toString('base64')); + assert.strictEqual(row.cols[0].value.toString('base64'), binaryParams[1].toString('base64')); + test.finish(); + }); + } + }); + }); +}; + +exports.testLong = function(test, assert) { + connect(function(err, con) { + if (err) { + assert.ok(false); + test.finish(); + } else { + // the third pair is ±2^62, which overflows the 53 bits in the fp mantissa js uses for numbers (should lose precision + // coming back), but still fits nicely in an 8-byte long (it should work). + // notice how updParams will take either a string or BigInteger + var key = 123456; + var updParms = [1, 2, 3, 4, '4611686018427387904', new BigInteger('-4611686018427387904'), key]; + var selParms = [1, 3, new BigInteger('4611686018427387904'), key]; + con.execute('update CfLong set ?=?,?=?,?=? where key=?', updParms, function(updErr) { + if (updErr) { + con.close(); + assert.ok(false); + test.finish(); + } else { + con.execute('select ?,?,? from CfLong where key=?', selParms, function(selErr, rows) { + con.close(); + if (selErr) { + assert.ok(false); + } else { + assert.strictEqual(rows.rowCount(), 1); + var row = rows[0]; + assert.strictEqual(3, row.colCount()); + + assert.ok(new BigInteger('1').equals(row.cols[0].name)); + assert.ok(new BigInteger('2').equals(row.cols[0].value)); + assert.ok(new BigInteger('3').equals(row.cols[1].name)); + assert.ok(new BigInteger('4').equals(row.cols[1].value)); + assert.ok(new BigInteger('4611686018427387904').equals(row.cols[2].name)); + assert.ok(new BigInteger('-4611686018427387904').equals(row.cols[2].value)); + + assert.ok(new BigInteger('2').equals(row.colHash['1'])); + assert.ok(new BigInteger('4').equals(row.colHash['3'])); + assert.ok(new BigInteger('-4611686018427387904').equals(row.colHash['4611686018427387904'])); + } + test.finish(); + }); + } + }); + } + }); +}; + +exports.testSlice = function(test, assert) { + connect(function(err, con) { + if (err) { + assert.ok(false); + test.finish(); + } else { + con.execute('update CfLong set -5=-55, -4=-44, -3=-33, -2=-22, -1=-11, 0=0, 1=11, 2=22, 3=33, 4=44, 5=55 where key=12345', [], function(updErr) { + if (updErr) { + con.close(); + assert.ok(false); + test.finish(); + } else { + con.execute('select ?..? from CfLong where key=12345', [-2, 2], function(selErr, rows) { + con.close(); + if (selErr) { + assert.ok(false); + } else { + assert.strictEqual(rows.rowCount(), 1); + var row = rows[0]; + assert.strictEqual(5, row.colCount()); + assert.ok(row.cols[1].name.equals(new BigInteger('-1'))); + assert.ok(row.cols[1].value.equals(new BigInteger('-11'))); + assert.ok(row.cols[3].name.equals(new BigInteger('1'))); + assert.ok(row.cols[3].value.equals(new BigInteger('11'))); + } + test.finish(); + }); + } + }); + } + }); +}; + +exports.testReverseSlice = function(test, assert) { + connect(function(err, con) { + if (err) { + assert.ok(false); + test.finish(); + } else { + con.execute('update CfLong set -5=-55, -4=-44, -3=-33, -2=-22, -1=-11, 0=0, 1=11, 2=22, 3=33, 4=44, 5=55 where key=12345', [], function(updErr) { + if (updErr) { + con.close(); + assert.ok(false); + test.finish(); + } else { + con.execute('select REVERSED ?..? from CfLong where key=12345', [2, -2], function(selErr, rows) { + con.close(); + if (selErr) { + assert.ok(false); + } else { + assert.strictEqual(rows.rowCount(), 1); + var row = rows[0]; + assert.strictEqual(5, row.colCount()); + assert.ok(row.cols[3].name.equals(new BigInteger('-1'))); + assert.ok(row.cols[3].value.equals(new BigInteger('-11'))); + assert.ok(row.cols[1].name.equals(new BigInteger('1'))); + assert.ok(row.cols[1].value.equals(new BigInteger('11'))); + } + test.finish(); + }); + } + }); + } + }); +}; + +exports.testReversedSliceLimit = function(test, assert) { + connect(function(err, con) { + if (err) { + assert.ok(false); + test.finish(); + } else { + con.execute('update CfLong set -5=-55, -4=-44, -3=-33, -2=-22, -1=-11, 0=0, 1=11, 2=22, 3=33, 4=44, 5=55 where key=12345', [], function(updErr) { + if (updErr) { + con.close(); + assert.ok(false); + test.finish(); + } else { + con.execute('select first 3 REVERSED ?..? from CfLong where key=12345', [2, -2], function(selErr, rows) { + con.close(); + if (selErr) { + assert.ok(false); + } else { + assert.strictEqual(rows.rowCount(), 1); + var row = rows[0]; + assert.strictEqual(3, row.colCount()); + assert.ok(row.cols[1].name.equals(new BigInteger('1'))); + assert.ok(row.cols[1].value.equals(new BigInteger('11'))); + assert.ok(row.cols[2].name.equals(new BigInteger('0'))); + assert.ok(row.cols[2].value.equals(new BigInteger('0'))); + assert.equal(row.cols[2].name, 0); + assert.equal(row.cols[2].value, 0); + } + test.finish(); + }); + } + }); + } + }); +}; + +exports.testReversedSlice = function(test, assert) { + connect(function(err, con) { + if (err) { + assert.ok(false); + test.finish(); + } else { + con.execute('update CfLong set -5=-55, -4=-44, -3=-33, -2=-22, -1=-11, 0=0, 1=11, 2=22, 3=33, 4=44, 5=55 where key=12345', [], function(updErr) { + if (updErr) { + con.close(); + assert.ok(false); + test.finish(); + } else { + con.execute('select REVERSED ?..? from CfLong where key=12345', [2, -2], function(selErr, rows) { + con.close(); + if (selErr) { + assert.ok(false); + } else { + assert.strictEqual(rows.rowCount(), 1); + var row = rows[0]; + assert.strictEqual(5, row.colCount()); + assert.ok(row.cols[3].name.equals(new BigInteger('-1'))); + assert.ok(row.cols[3].value.equals(new BigInteger('-11'))); + assert.ok(row.cols[1].name.equals(new BigInteger('1'))); + assert.ok(row.cols[1].value.equals(new BigInteger('11'))); + } + test.finish(); + }); + } + }); + } + }); +}; + +exports.testInt = function(test, assert) { + connect(function(err, con) { + if (err) { + assert.ok(false); + test.finish(); + } else { + // make sure to use some numbers that will overflow a 64 bit signed value. + var updParms = [1, 11, -1, -11, '8776496549718567867543025521', '-8776496549718567867543025521', '3456543434345654345332453455633']; + var selParms = [-1, 1, '8776496549718567867543025521', '3456543434345654345332453455633']; + con.execute('update CfInt set ?=?, ?=?, ?=? where key=?', updParms, function(updErr) { + if (updErr) { + con.close(); + assert.ok(false); + test.finish(); + } else { + con.execute('select ?, ?, ? from CfInt where key=?', selParms, function(selErr, rows) { + con.close(); + if (selErr) { + assert.ok(false); + } else { + var row = rows[0]; + assert.strictEqual(rows.rowCount(), 1); + assert.strictEqual(3, row.colCount()); + + assert.ok(new BigInteger('-1').equals(row.cols[0].name)); + assert.ok(new BigInteger('-11').equals(row.cols[0].value)); + assert.ok(new BigInteger('1').equals(row.cols[1].name)); + assert.ok(new BigInteger('11').equals(row.cols[1].value)); + assert.ok(new BigInteger('8776496549718567867543025521').equals(row.cols[2].name)); + assert.ok(new BigInteger('-8776496549718567867543025521').equals(row.cols[2].value)); + + assert.ok(new BigInteger('11').equals(row.colHash['1'])); + assert.ok(new BigInteger('-11').equals(row.colHash['-1'])); + assert.ok(new BigInteger('-8776496549718567867543025521').equals(row.colHash['8776496549718567867543025521'])); + } + test.finish(); + }); + } + }); + } + }); +}; + +exports.testUUID = function(test, assert) { + // make sure we're not comparing the same things. + assert.ok(!UUID.fromString('6f8483b0-65e0-11e0-0000-fe8ebeead9fe').equals(UUID.fromString('6fd589e0-65e0-11e0-0000-7fd66bb03aff'))); + assert.ok(!UUID.fromString('6fd589e0-65e0-11e0-0000-7fd66bb03aff').equals(UUID.fromString('fa6a8870-65fa-11e0-0000-fe8ebeead9fd'))); + connect(function(err, con) { + if (err) { + assert.ok(false); + test.finish(); + } else { + // again, demonstrate that we can use strings or objectifications. + var updParms = ['6f8483b0-65e0-11e0-0000-fe8ebeead9fe', '6fd45160-65e0-11e0-0000-fe8ebeead9fe', '6fd589e0-65e0-11e0-0000-7fd66bb03aff', '6fd6e970-65e0-11e0-0000-fe8ebeead9fe', 'fa6a8870-65fa-11e0-0000-fe8ebeead9fd']; + var selParms = ['6f8483b0-65e0-11e0-0000-fe8ebeead9fe', '6fd589e0-65e0-11e0-0000-7fd66bb03aff', 'fa6a8870-65fa-11e0-0000-fe8ebeead9fd']; + con.execute('update CfUuid set ?=?, ?=? where key=?', updParms, function(updErr) { + if (updErr) { + con.close(); + assert.ok(false); + test.finish(); + } else { + con.execute('select ?, ? from CfUuid where key=?', selParms, function(selErr, rows) { + con.close(); + if (selErr) { + assert.ok(false); + } else { + assert.strictEqual(rows.rowCount(), 1); + var row = rows[0]; + assert.strictEqual(2, row.colCount()); + + assert.ok(UUID.fromString('6f8483b0-65e0-11e0-0000-fe8ebeead9fe').equals(row.cols[0].name)); + assert.ok(UUID.fromString('6fd45160-65e0-11e0-0000-fe8ebeead9fe').equals(row.cols[0].value)); + assert.ok(UUID.fromString('6fd589e0-65e0-11e0-0000-7fd66bb03aff').equals(row.cols[1].name)); + assert.ok(UUID.fromString('6fd6e970-65e0-11e0-0000-fe8ebeead9fe').equals(row.cols[1].value)); + + assert.ok(row.colHash[(UUID.fromString('6fd589e0-65e0-11e0-0000-7fd66bb03aff'))].equals(row.cols[1].value)); + assert.ok(row.colHash[(row.cols[0].name)].equals(row.cols[0].value)); + assert.ok(row.colHash[(UUID.fromString('6f8483b0-65e0-11e0-0000-fe8ebeead9fe'))].equals(row.cols[0].value)); + assert.ok(row.colHash[(row.cols[1].name)].equals(row.cols[1].value)); + } + test.finish(); + }); + } + }); + } + }); +}; + +exports.testCustomValidators = function(test, assert) { + connect(function(err, con) { + if (err) { + assert.ok(false); + test.finish(); + } else { + var updParms = ['normal', 25, 'int_col', 21, 'string_col', 'test_string_value', 'uuid_col', '6f8483b0-65e0-11e0-0000-fe8ebeead9fe', 211]; + var selParms = ['normal', 'int_col', 'string_col', 'uuid_col', 211]; + con.execute('update CfUgly set ?=?, ?=?, ?=?, ?=? where key=?', updParms, function(updErr) { + if (updErr) { + con.close(); + assert.ok(false); + test.finish(); + } else { + con.execute('select ?, ?, ?, ? from CfUgly where key=?', selParms, function(selErr, rows) { + con.close(); + if (selErr) { + assert.ok(false); + } else { + assert.strictEqual(rows.rowCount(), 1); + var row = rows[0]; + assert.strictEqual(4, row.colCount()); + + assert.ok(row.colHash.normal.equals(new BigInteger('25'))); + assert.ok(row.colHash.int_col.equals(new BigInteger('21'))); + assert.ok(row.colHash.string_col.toString() === 'test_string_value'); + assert.ok(row.colHash.uuid_col.toString() == '6f8483b0-65e0-11e0-0000-fe8ebeead9fe'); + } + test.finish(); + }); + } + }); + } + }); +}; + +// this test only works an order-preserving partitioner. +// it also uses an event-based approach to doing things. +//exports.ZDISABLED_testMultipleRows = function(test, assert) { +// // go through the motions of creating a new keyspace every time. we do this to ensure only the things in there are +// // what I expect. +// +// var sys = new Connection('127.0.0.1', CASSANDRA_PORT, 'system', null, null, {use_bigints: true}); +// sys.connect(function(err) { +// if (err) { +// assert.ok(false) +// test.finish(); +// } else { +// var ev = new EventEmitter(); +// // attempt to drop the keyspace on error. +// ev.on('syserr', function() { +// console.log('syserr'); +// sys.execute('drop keyspace ints', function(err) {}); +// sys.close(); +// assert.ok(false); +// test.finish(); +// }); +// +// // keyspace is there for sure. don't know about the cf. +// ev.on('ksready', function() { +// console.log('keyspace created'); +// sys.close(); +// var con = new Connection('127.0.0.1', CASSANDRA_PORT, 'ints', null, null, {use_bigints: true}); +// con.execute('create columnfamily cfints (key int primary key) with comparator=int and default_validation=int', null, function(err) { +// con.close(); +// if (err) { +// ev.emit('syserr'); +// } else { +// ev.emit('cfready'); +// } +// }); +// con.close(); +// }); +// +// // column family is ready, do the test. +// ev.on('cfready', function() { +// +// // insert 100 rows. +// var con = new Connection('127.0.0.1', 19170, 'ints', null, null, {use_bigints: true}); +// var count = 100; +// var num = 0; +// for (var i = 0; i < count; i++) { +// con.execute('update cfints set ?=? where key=?', [1, i, i], function(err) { +// if (err) { +// con.close(); +// ev.emit('syserr'); +// } else { +// num += 1; +// +// // after all the rows are in, do a query. +// if (num >= count) { +// con.execute('select ? from cfints where key > ? and key < ?', [1, 10, 20], function(serr, rows) { +// con.close(); +// assert.strictEqual(rows.rowCount(), 11); +// }); +// } +// } +// }); +// } +// }); +// +// // start everything off. +// sys.execute('drop keyspace ints', null, function(dropErr) { +// if (!dropErr) { +// console.log('keyspace dropped'); +// } +// sys.execute('create keyspace ints with strategy_class=SimpleStrategy and strategy_options:replication_factor=1', null, function(createKsErr) { +// if (createKsErr) { +// ev.emit('syserr'); +// } else { +// ev.emit('ksready'); +// } +// }); +// }); +// } +// }); +//}; + + +exports.testPooledConnectionFailover = function(test, assert) { + var hosts = ['google.com:8000', '127.0.0.1:6567', '127.0.0.1:19170', '127.0.0.2']; + var conn = new PooledConnection({'hosts': hosts, 'keyspace': 'Keyspace1', use_bigints: true, 'timeout': 5000}); + + async.series([ + function executeQueries(callback) { + conn.execute('UPDATE CfUgly SET A=1 WHERE KEY=1', [], function(err) { + assert.ifError(err); + callback(); + }); + } + ], + + function(err) { + conn.shutdown(); + test.finish(); + }); +}; + +exports.testLearnStepTimeout = function(test, assert) { + var server = null; + var hosts = ['127.0.0.1:8688', '127.0.0.1:19170']; + var conn = new PooledConnection({'hosts': hosts, 'keyspace': 'Keyspace1', use_bigints: true, 'timeout': 5000}); + + async.series([ + function startHttpServer(callback) { + server = http.createServer(function (req, res) { + res.end('test\n'); + }); + server.listen(8688, '127.0.0.1', callback); + }, + + function executeQueryPooledConnection(callback) { + conn.execute('UPDATE CfUgly SET A=1 WHERE KEY=1', [], function(err) { + assert.ifError(err); + callback(); + }); + } + ], + + function(err) { + if (server) { + server.close(); + } + + conn.shutdown(); + test.finish(); + }); +}; + +exports.testPooledConnection = function(test, assert) { + function bail(conn, err) { + conn.shutdown(); + assert.ifError(err); + test.finish(); + } + + //var hosts = ["127.0.0.2:9170", "127.0.0.1:9170"]; + var hosts = ["127.0.0.1:19170"]; + var conn = new PooledConnection({'hosts': hosts, 'keyspace': 'Keyspace1', use_bigints: true}); + + var range = new Array(100).join(' ').split(' '); + + // Hammer time... + conn.execute('UPDATE CfUgly SET A=1 WHERE KEY=1', [], function(err) { + if (err) { bail(conn, err); } + + async.forEach(range, function (_, callback) { + conn.execute('SELECT A FROM CfUgly WHERE KEY=1', [], function(err, rows) { + if (err) { bail(conn, err); } + assert.strictEqual(rows.rowCount(), 1); + var row = rows[0]; + assert.strictEqual(row.cols[0].name.toString(), 'A'); + callback(); + }); + }, + + function(err) { + conn.shutdown(); + test.finish(); + }); + }); +}; + +exports.testTimeLogging = function(test, assert) { + var hosts = ["127.0.0.1:19170"]; + var baseOptions = {'hosts': hosts, 'keyspace': 'Keyspace1', use_bigints: true}; + var options1 = merge(baseOptions, {}); + var options2 = merge(baseOptions, {'log_time': true}); + var conn1 = new PooledConnection(options1); + var conn2 = new PooledConnection(options2); + + var logObjsCql = []; + var logObjsTime = []; + + var appendLog = function(level, message) { + if (level === 'cql') { + logObjsCql.push(message); + } + if (level === 'timing') { + logObjsTime.push(message); + } + }; + conn1.on('log', appendLog); + conn2.on('log', appendLog); + + conn1.execute('UPDATE CfUgly SET A=1 WHERE KEY=1', [], function(err) { + var logObj; + assert.ifError(err); + + // Timing log is disabled, logObjs should be empty. + assert.equal(logObjsCql.length, 1); + assert.equal(logObjsTime.length, 0); + + logObj = logObjsCql[0]; + assert.ok(logObj.hasOwnProperty('query')); + assert.ok(logObj.hasOwnProperty('parameterized_query')); + assert.ok(logObj.hasOwnProperty('args')); + assert.ok(!logObj.hasOwnProperty('time')); + + conn2.execute('SELECT A FROM CfUgly WHERE KEY=1', [], function(err, rows) { + var logObj; + assert.ifError(err); + assert.strictEqual(rows.rowCount(), 1); + + // Timing log is enabled, logObjs should have 1 item + assert.equal(logObjsCql.length, 2); + assert.equal(logObjsTime.length, 1); + logObj = logObjsTime[0]; + + assert.ok(logObj.hasOwnProperty('query')); + assert.ok(logObj.hasOwnProperty('parameterized_query')); + assert.ok(logObj.hasOwnProperty('args')); + assert.ok(logObj.hasOwnProperty('time')); + + conn1.shutdown(conn2.shutdown(test.finish)); + }); + }); +}; + + +exports.testConnectionInPool = function(test, assert) { + var con = new ConnectionInPool({ + host: '127.0.0.1', + port: 19170, + keyspace: 'Keyspace1', + use_bigints: true + }); + con.connect(function(err) { + if (err) { + assert.ifError(err); + } else { + con.close(); + test.finish(); + } + }); +}; + + +exports.testPooledConnectionLoad = function(test, assert) { + var hosts = ['127.0.0.1:19170']; + var conn = new PooledConnection({'hosts': hosts, 'keyspace': 'Keyspace1', 'timeout': 10000}); + + var count = 3000; + + async.waterfall([ + // establish connections prior to executing statements. + //conn.connect.bind(conn), + function(cb) { + conn.execute('TRUNCATE CfUtf8', [], cb); + }, + function(res, cb) { + var executes = []; + for (var i = 0; i < count; i++) { + (function(index) { + executes.push(function(parallelCb) { + conn.execute('UPDATE CfUtf8 SET ? = ? WHERE KEY = ?', [ + 'testCol', + 'testVal', + 'testKey'+index + ], parallelCb); + }); + })(i); + } + async.parallel(executes, function(err) { + assert.ifError(err); + cb(); + }); + }, + function(cb) { + conn.execute('SELECT COUNT(*) FROM CfUtf8', [], cb); + }, + function(res, cb) { + assert.equal(res[0].colHash.count, count); + cb(); + }, + function(cb) { + conn.execute('TRUNCATE CfUtf8', [], cb); + }, + function(res, cb) { + conn.shutdown(cb); + } + ], + function(err) { + assert.ifError(err); + test.finish(); + }); +}; + + +// We want to test if all executes of a pooled connection are finished before +// the shutdown callback is called. +exports.testPooledConnectionShutdown = function(test, assert) { + var hosts = ['127.0.0.1:19170']; + var conn = new PooledConnection({'hosts': hosts, 'keyspace': 'Keyspace1'}); + + var expected = 100; + var cbcount = 0; + var spy = function(err, res) { + assert.ifError(err); + cbcount++; + }; + + for (var i = 0; i < expected; i++) { + (function(index) { + conn.execute('UPDATE CfUtf8 SET ? = ? WHERE KEY = ?', ['col', 'val', 'key'+index], spy); + })(i); + } + conn.shutdown(function(err) { + assert.ifError(err); + assert.equal(cbcount, expected); + test.finish(); + }); +}; + +exports.testPooledConnectionShutdownTwice = function(test, assert) { + var hosts = ['127.0.0.1:19170']; + var conn = new PooledConnection({'hosts': hosts, 'keyspace': 'Keyspace1'}); + + var expected = 100; + var cbcount = 0; + var spy = function(err, res) { + assert.ifError(err); + cbcount++; + }; + + for (var i = 0; i < expected; i++) { + (function(index) { + conn.execute('UPDATE CfUtf8 SET ? = ? WHERE KEY = ?', ['col', 'val', 'key'+index], spy); + })(i); + } + + assert.ok(!conn.shuttingDown); + conn.shutdown(function(err) { + assert.ifError(err); + assert.equal(cbcount, expected); + assert.ok(secondCbCalledImmediatelyWithError); + test.finish(); + }); + + // Make sure second callback gets called immediately with an error + var secondCbCalledImmediatelyWithError = false; + assert.ok(conn.shuttingDown); + conn.shutdown(function(err) { + assert.ok(err); + secondCbCalledImmediatelyWithError = true; + }); +}; diff --git a/node_modules/cassandra-client/test/test_uuid.js b/node_modules/cassandra-client/test/test_uuid.js new file mode 100644 index 0000000..5f8f414 --- /dev/null +++ b/node_modules/cassandra-client/test/test_uuid.js @@ -0,0 +1,105 @@ +// some tests for the uuid-js module. + +var UUID = require('../lib/uuid'); + +var UUID_FORMAT = { + v1: /[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i, + v4: /[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i +}; + +exports['test_uuid_random_v4'] = function(test, assert) { + var uuid = new UUID(); + assert.ok(uuid.toString().match(UUID_FORMAT.v4)); + test.finish(); +}; +exports['test_uuid_from_time_v1'] = function(test, assert) { + var ts = 1314735336312; + var uuid = UUID.fromTime(ts); + assert.ok(uuid.toString().match(UUID_FORMAT.v1)); + ts += 1; + uuid = UUID.minUUID(ts); + assert.ok(uuid.toString().match(UUID_FORMAT.v1)); + uuid = UUID.maxUUID(ts); + assert.ok(uuid.toString().match(UUID_FORMAT.v1)); + test.finish(); +}; + +exports['test_uuid_from_buffer'] = function(test, assert) { + var buf = new Buffer('\u00ee\u00a1\u006c\u00c0\u00cf\u00bd\u0011\u00e0\u0017' + + '\u000a\u00dd\u0026\u0075\u0027\u009e\u0008', 'binary'); + var uuid = UUID.fromBytes(buf); + assert.strictEqual(uuid.toString(), 'eea16cc0-cfbd-11e0-170a-dd2675279e08'); + test.finish(); +}; + +// As per RFC 4122 regressions in time should result in the clockseq being +// incremented to ensure uniqueness of v1 UUIDs +exports['test_uuid_backwards_in_time'] = function(test, assert) { + var ts = 1314735336316; + var ns = 0; + var uuidTs = UUID.fromTime(ts).toString(); + // This is like setting the system-time to a future value: + var uuidFuture = UUID.fromTime(ts + 5000).toString(); + // Now this is like setting the system-clock back in time which must result + // in the clock_seq field of the UUID being incremented to avoid collisions. + var uuidTsSame = UUID.fromTime(ts).toString(); + + // UUIDs generated from same TS after going back in time must differ + // since clockseq must have been updated + assert.ok(uuidTs !== uuidTsSame); + assert.ok(uuidTs !== uuidFuture); // duh + assert.strictEqual(uuidTs.split('-')[0], uuidTsSame.split('-')[0]); + assert.strictEqual(uuidTs.split('-')[1], uuidTsSame.split('-')[1]); + assert.strictEqual(uuidTs.split('-')[2], uuidTsSame.split('-')[2]); + test.finish(); +}; + +// Generating multiple successive UUIDs for the same millisecond should be +// supported by the uuid library for highly concurrent applications. Note that +// v1 UUIDs are based on 100ns intervals while javascript only offers +// millisecond resolution times, so the UUID lib should have an internal +// "100nanosecond-counter" to allow generating 10k v1 UUIDs/millisecond. +exports['test_uuid_same_ms'] = function(test, assert) { + var ts = 1314735336316; + var uuidTs = UUID.fromTime(ts).toString(); + var uuidTsSame = UUID.fromTime(ts).toString(); + // UUIDs generated for the same millisecond must differ + assert.ok(uuidTs !== uuidTsSame); + // time low should differ by a 100ns tick. + assert.strictEqual(parseInt(uuidTsSame.split('-')[0], 16) - parseInt(uuidTs.split('-')[0], 16), 1); + // but time mid and hi should definitely be the same. + assert.strictEqual(uuidTs.split('-')[1], uuidTsSame.split('-')[1]); + assert.strictEqual(uuidTs.split('-')[2], uuidTsSame.split('-')[2]); + test.finish(); +}; + +// v1 time-UUIDs are generated with 100ns resolution and cassandra compares all +// 60 time bits when comparing time-UUIDs. So for range-queries we always need +// UUIDs that have the 100ns count set to 0 for the beginning of a range +// and set to 9999 for the end of a range to miss no values. +exports['test_uuid_same_ms_min_max'] = function(test, assert) { + var ts = 1314735336320; + var uuidTs = UUID.minUUID(ts).toString(); + var uuidTsSame = UUID.maxUUID(ts).toString(); + // UUIDs generated for the same millisecond must differ + assert.ok(uuidTs !== uuidTsSame); + // time low should differ by the full range of 9999 100ns tick. + assert.strictEqual(parseInt(uuidTsSame.split('-')[0], 16) - parseInt(uuidTs.split('-')[0], 16), 9999); + // but time mid and hi should definitely be the same. + assert.strictEqual(uuidTs.split('-')[1], uuidTsSame.split('-')[1]); + assert.strictEqual(uuidTs.split('-')[2], uuidTsSame.split('-')[2]); + test.finish(); +}; +exports['test_uuid_same_ms_min_nextmin'] = function(test, assert) { + var ts = 1314735336320; + var uuidTs = UUID.minUUID(ts).toString(); + var uuidTsNext = UUID.minUUID(ts+1).toString(); + // UUIDs generated for the same millisecond must differ + assert.ok(uuidTs !== uuidTsNext); + // time low should differ by the full range of 9999 100ns tick. + assert.strictEqual(parseInt(uuidTsNext.split('-')[0], 16) - parseInt(uuidTs.split('-')[0], 16), 10000); + // but time mid and hi should definitely be the same. + assert.strictEqual(uuidTs.split('-')[1], uuidTsNext.split('-')[1]); + assert.strictEqual(uuidTs.split('-')[2], uuidTsNext.split('-')[2]); + test.finish(); +}; diff --git a/node_modules/cassandra-client/test/util.js b/node_modules/cassandra-client/test/util.js new file mode 100644 index 0000000..9b5daf9 --- /dev/null +++ b/node_modules/cassandra-client/test/util.js @@ -0,0 +1,23 @@ + +// min is inclusive, max is exclusive. +function randomInt(min, max) { + if (min === undefined) { + min = -2147483648; + } + if (max === undefined) { + max = 2147483647 + } + return Math.round(Math.random() * (max - min) + min); +} + +function randomBuffer(sz) { + sz = sz || randomInt(10, 100); + var buf = new Buffer(sz); + for (var i = 0; i < sz; i++) { + buf[i] = randomInt(0, 255); + } + return buf; +} + +exports.randomInt = randomInt; +exports.randomBuffer = randomBuffer; \ No newline at end of file diff --git a/node_modules/nodeunit/.npmignore b/node_modules/nodeunit/.npmignore new file mode 100644 index 0000000..1a82501 --- /dev/null +++ b/node_modules/nodeunit/.npmignore @@ -0,0 +1,3 @@ +dist +stamp-build +test/fixtures/dir2 diff --git a/node_modules/nodeunit/CONTRIBUTORS.md b/node_modules/nodeunit/CONTRIBUTORS.md new file mode 100644 index 0000000..fba3609 --- /dev/null +++ b/node_modules/nodeunit/CONTRIBUTORS.md @@ -0,0 +1,68 @@ +Nodeunit contributors (sorted alphabeticaly) +============================================ + +* **[Alex Gorbatchev](https://github.com/alexgorbatchev)** + + * Deeper default object inspection + * Timeout to ensure flushing of console output (default reporter) + +* **[Alex Wolfe](https://github.com/alexkwolfe)** + + * HTML test reporter + +* **[Caolan McMahon](https://github.com/caolan)** + + * Author and maintainer + * Most features develpopment + +* **[Carl Fürstenberg](https://github.com/azatoth)** + + * Debian-friendly Makefile, supports both 'node' and 'nodejs' executables + * Sandbox utility + * Minimal test reporter + +* **[Gerad Suyderhoud](https://github.com/gerad)** + + * First comand-line tool + +* **[Kadir Pekel](https://github.com/kadirpekel)** + + * Improvements to default test reporter + * HTTP test utility + +* **[Λlisue](https://github.com/lambdalisue)** + + * Add machineout reporter + +* **[Matthias Lübken](https://github.com/luebken)** + + * Utility functions for tracking incomplete tests on exit + +* **[Oleg Efimov](https://github.com/Sannis)** + + * Adding 'make lint' and fixing nodelint errors + * Option parsing, --help text and config file support + * Reporters option for command-line tool + +* **[Orlando Vazquez](https://github.com/orlandov)** + + * Added jUnit XML reporter + +* **[Ryan Dahl](https://github.com/ry)** + + * Add package.json + +* **[Sam Stephenson](https://github.com/sstephenson)** + + * Coffee-script support + +* **[Thomas Mayfield](https://github.com/thegreatape)** + + * Async setUp and tearDown support for testCase + +* **[Maciej Małecki](https://github.com/mmalecki)** + + * Removal of `testCase` + +**[Full contributors list](https://github.com/caolan/nodeunit/contributors).** + diff --git a/node_modules/nodeunit/LICENSE b/node_modules/nodeunit/LICENSE new file mode 100644 index 0000000..b7f9d50 --- /dev/null +++ b/node_modules/nodeunit/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010 Caolan McMahon + +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/node_modules/nodeunit/Makefile b/node_modules/nodeunit/Makefile new file mode 100644 index 0000000..8f8d8cb --- /dev/null +++ b/node_modules/nodeunit/Makefile @@ -0,0 +1,177 @@ +PACKAGE = nodeunit +NODEJS = $(if $(shell test -f /usr/bin/nodejs && echo "true"),nodejs,node) + +PREFIX ?= /usr/local +BINDIR ?= $(PREFIX)/bin +DATADIR ?= $(PREFIX)/share +MANDIR ?= $(PREFIX)/share/man +LIBDIR ?= $(PREFIX)/lib +NODEJSLIBDIR ?= $(LIBDIR)/$(NODEJS) + +BUILDDIR = dist + +DOCS = $(shell find doc -name '*.md' \ + |sed 's|.md|.1|g' \ + |sed 's|doc/|man1/|g' \ + ) + + +$(shell if [ ! -d $(BUILDDIR) ]; then mkdir $(BUILDDIR); fi) + +all: build doc + +browser: + # super hacky build script for browser version! + mkdir -p $(BUILDDIR)/browser + rm -rf $(BUILDDIR)/browser/* + # build browser version of nodeunit.js + cat share/license.js >> $(BUILDDIR)/browser/nodeunit.js + echo "nodeunit = (function(){" >> $(BUILDDIR)/browser/nodeunit.js + cat deps/json2.js >> $(BUILDDIR)/browser/nodeunit.js + # make assert global + echo "var assert = this.assert = {};" >> $(BUILDDIR)/browser/nodeunit.js + echo "var types = {};" >> $(BUILDDIR)/browser/nodeunit.js + echo "var core = {};" >> $(BUILDDIR)/browser/nodeunit.js + echo "var nodeunit = {};" >> $(BUILDDIR)/browser/nodeunit.js + echo "var reporter = {};" >> $(BUILDDIR)/browser/nodeunit.js + cat deps/async.js >> $(BUILDDIR)/browser/nodeunit.js + echo "(function(exports){" >> $(BUILDDIR)/browser/nodeunit.js + cat lib/assert.js >> $(BUILDDIR)/browser/nodeunit.js + echo "})(assert);" >> $(BUILDDIR)/browser/nodeunit.js + echo "(function(exports){" >> $(BUILDDIR)/browser/nodeunit.js + cat lib/types.js >> $(BUILDDIR)/browser/nodeunit.js + echo "})(types);" >> $(BUILDDIR)/browser/nodeunit.js + echo "(function(exports){" >> $(BUILDDIR)/browser/nodeunit.js + cat lib/core.js >> $(BUILDDIR)/browser/nodeunit.js + echo "})(core);" >> $(BUILDDIR)/browser/nodeunit.js + echo "(function(exports){" >> $(BUILDDIR)/browser/nodeunit.js + cat lib/reporters/browser.js >> $(BUILDDIR)/browser/nodeunit.js + echo "})(reporter);" >> $(BUILDDIR)/browser/nodeunit.js + echo "nodeunit = core;" >> $(BUILDDIR)/browser/nodeunit.js + echo "nodeunit.assert = assert;" >> $(BUILDDIR)/browser/nodeunit.js + echo "nodeunit.reporter = reporter;" >> $(BUILDDIR)/browser/nodeunit.js + echo "nodeunit.run = reporter.run;" >> $(BUILDDIR)/browser/nodeunit.js + echo "return nodeunit; })();" >> $(BUILDDIR)/browser/nodeunit.js + cp $(BUILDDIR)/browser/nodeunit.js $(BUILDDIR)/browser/.nodeunit.js + sed "/\@REMOVE_LINE_FOR_BROWSER/d" <$(BUILDDIR)/browser/.nodeunit.js > $(BUILDDIR)/browser/nodeunit.js + rm $(BUILDDIR)/browser/.nodeunit.js + # copy nodeunit.css + cp share/nodeunit.css $(BUILDDIR)/browser/nodeunit.css + # create nodeunit.min.js + node_modules/uglify-js/bin/uglifyjs $(BUILDDIR)/browser/nodeunit.js > $(BUILDDIR)/browser/nodeunit.min.js + # create test scripts + mkdir -p $(BUILDDIR)/browser/test + cp test/test.html $(BUILDDIR)/browser/test/test.html + # test-base.js + echo "(function (exports) {" > $(BUILDDIR)/browser/test/test-base.js + cat test/test-base.js >> $(BUILDDIR)/browser/test/test-base.js + echo "})(this.test_base = {});" >> $(BUILDDIR)/browser/test/test-base.js + cp $(BUILDDIR)/browser/test/test-base.js $(BUILDDIR)/browser/.test-base.js + sed "/\@REMOVE_LINE_FOR_BROWSER/d" <$(BUILDDIR)/browser/.test-base.js > $(BUILDDIR)/browser/test/test-base.js + rm $(BUILDDIR)/browser/.test-base.js + # test-runmodule.js + echo "(function (exports) {" > $(BUILDDIR)/browser/test/test-runmodule.js + cat test/test-runmodule.js >> $(BUILDDIR)/browser/test/test-runmodule.js + echo "})(this.test_runmodule = {});" >> $(BUILDDIR)/browser/test/test-runmodule.js + cp $(BUILDDIR)/browser/test/test-runmodule.js $(BUILDDIR)/browser/.test-runmodule.js + sed "/\@REMOVE_LINE_FOR_BROWSER/d" <$(BUILDDIR)/browser/.test-runmodule.js > $(BUILDDIR)/browser/test/test-runmodule.js + rm $(BUILDDIR)/browser/.test-runmodule.js + # test-runtest.js + echo "(function (exports) {" > $(BUILDDIR)/browser/test/test-runtest.js + cat test/test-runtest.js >> $(BUILDDIR)/browser/test/test-runtest.js + echo "})(this.test_runtest = {});" >> $(BUILDDIR)/browser/test/test-runtest.js + cp $(BUILDDIR)/browser/test/test-runtest.js $(BUILDDIR)/browser/.test-runtest.js + sed "/\@REMOVE_LINE_FOR_BROWSER/d" <$(BUILDDIR)/browser/.test-runtest.js > $(BUILDDIR)/browser/test/test-runtest.js + rm $(BUILDDIR)/browser/.test-runtest.js + # test-testcase.js + echo "(function (exports) {" > $(BUILDDIR)/browser/test/test-testcase.js + cat test/test-testcase.js >> $(BUILDDIR)/browser/test/test-testcase.js + echo "})(this.test_testcase = {});" >> $(BUILDDIR)/browser/test/test-testcase.js + cp $(BUILDDIR)/browser/test/test-testcase.js $(BUILDDIR)/browser/.test-testcase.js + sed "/\@REMOVE_LINE_FOR_BROWSER/d" <$(BUILDDIR)/browser/.test-testcase.js > $(BUILDDIR)/browser/test/test-testcase.js + rm $(BUILDDIR)/browser/.test-testcase.js + # test-testcase-legacy.js + echo "(function (exports) {" > $(BUILDDIR)/browser/test/test-testcase-legacy.js + cat test/test-testcase-legacy.js >> $(BUILDDIR)/browser/test/test-testcase-legacy.js + echo "})(this.test_testcase_legacy = {});" >> $(BUILDDIR)/browser/test/test-testcase-legacy.js + cp $(BUILDDIR)/browser/test/test-testcase-legacy.js $(BUILDDIR)/browser/.test-testcase-legacy.js + sed "/\@REMOVE_LINE_FOR_BROWSER/d" <$(BUILDDIR)/browser/.test-testcase-legacy.js > $(BUILDDIR)/browser/test/test-testcase-legacy.js + rm $(BUILDDIR)/browser/.test-testcase-legacy.js + # copy nodeunit.js to dist/browser/test to make it easier for me to host and + # run on windows VMs with IE + cp $(BUILDDIR)/browser/nodeunit.js $(BUILDDIR)/browser/test/nodeunit.js + cp $(BUILDDIR)/browser/nodeunit.css $(BUILDDIR)/browser/test/nodeunit.css + +commonjs: + # super hacky build script for browser commonjs version! + ##### make commonjs browser module ###### + mkdir -p $(BUILDDIR)/commonjs + rm -rf $(BUILDDIR)/commonjs/* + mkdir -p $(BUILDDIR)/commonjs/deps + cp deps/json2.js $(BUILDDIR)/commonjs/deps + cp deps/async.js $(BUILDDIR)/commonjs/deps + echo "var async = require('async');" >> $(BUILDDIR)/commonjs/nodeunit.js + echo "var assert = {};" >> $(BUILDDIR)/commonjs/nodeunit.js + echo "var types = {};" >> $(BUILDDIR)/commonjs/nodeunit.js + echo "var core = {};" >> $(BUILDDIR)/commonjs/nodeunit.js + echo "var nodeunit = {};" >> $(BUILDDIR)/commonjs/nodeunit.js + echo "var reporter = {};" >> $(BUILDDIR)/commonjs/nodeunit.js + echo "(function(exports){" >> $(BUILDDIR)/commonjs/nodeunit.js + cat lib/assert.js >> $(BUILDDIR)/commonjs/nodeunit.js + echo "})(assert);" >> $(BUILDDIR)/commonjs/nodeunit.js + echo "(function(exports){" >> $(BUILDDIR)/commonjs/nodeunit.js + cat lib/types.js >> $(BUILDDIR)/commonjs/nodeunit.js + echo "})(types);" >> $(BUILDDIR)/commonjs/nodeunit.js + echo "(function(exports){" >> $(BUILDDIR)/commonjs/nodeunit.js + cat lib/core.js >> $(BUILDDIR)/commonjs/nodeunit.js + echo "})(core);" >> $(BUILDDIR)/commonjs/nodeunit.js + echo "module.exports = core;" >> $(BUILDDIR)/commonjs/nodeunit.js + echo "(function(exports, nodeunit){" >> $(BUILDDIR)/commonjs/nodeunit.js + cat lib/reporters/browser.js >> $(BUILDDIR)/commonjs/nodeunit.js + echo "})(reporter, module.exports);" >> $(BUILDDIR)/commonjs/nodeunit.js + echo "module.exports.assert = assert;" >> $(BUILDDIR)/commonjs/nodeunit.js + echo "module.exports.reporter = reporter;" >> $(BUILDDIR)/commonjs/nodeunit.js + echo "module.exports.run = reporter.run;" >> $(BUILDDIR)/commonjs/nodeunit.js + sed -i "/\@REMOVE_LINE_FOR_BROWSER/d" $(BUILDDIR)/commonjs/nodeunit.js + sed -i "/\@REMOVE_LINE_FOR_COMMONJS/d" $(BUILDDIR)/commonjs/nodeunit.js + ##### end of commonjs browser module ##### + +build: stamp-build + +stamp-build: $(wildcard deps/* lib/*.js) + touch $@; + mkdir -p $(BUILDDIR)/nodeunit + cp -R bin node_modules deps index.js lib package.json share $(BUILDDIR)/nodeunit + printf '#!/bin/sh\n$(NODEJS) $(NODEJSLIBDIR)/$(PACKAGE)/bin/nodeunit $$@' > $(BUILDDIR)/nodeunit.sh + +test: + $(NODEJS) ./bin/nodeunit test + +install: build + install -d $(NODEJSLIBDIR) + cp -a $(BUILDDIR)/nodeunit $(NODEJSLIBDIR) + install -m 0755 $(BUILDDIR)/nodeunit.sh $(BINDIR)/nodeunit + install -d $(MANDIR)/man1/ + cp -a man1/nodeunit.1 $(MANDIR)/man1/ + +uninstall: + rm -rf $(NODEJSLIBDIR)/nodeunit $(NODEJSLIBDIR)/nodeunit.js $(BINDIR)/nodeunit + rm -rf $(MANDIR)/man1/nodeunit.1 + +clean: + rm -rf $(BUILDDIR) stamp-build + +lint: + nodelint --config nodelint.cfg ./index.js ./bin/nodeunit ./bin/nodeunit.json ./lib/*.js ./lib/reporters/*.js ./test/*.js + +doc: man1 $(DOCS) + @true + +man1: + @if ! test -d man1 ; then mkdir -p man1 ; fi + +# use `npm install ronn` for this to work. +man1/%.1: doc/%.md + ronn --roff $< > $@ + +.PHONY: browser test install uninstall build all diff --git a/node_modules/nodeunit/README.md b/node_modules/nodeunit/README.md new file mode 100644 index 0000000..359a9c7 --- /dev/null +++ b/node_modules/nodeunit/README.md @@ -0,0 +1,443 @@ +Nodeunit +======== + +Simple syntax, powerful tools. Nodeunit provides easy async unit testing for +node.js and the browser. + +* Simple to use +* Just export the tests from a module +* Works with node.js and in the browser. +* Helps you avoid common pitfalls when testing asynchronous code +* Easy to add test cases with setUp and tearDown functions if you wish +* Flexible reporters for custom output, built-in support for HTML and jUnit XML +* Allows the use of mocks and stubs + +__Contributors__ + +* [alexgorbatchev](https://github.com/alexgorbatchev) +* [alexkwolfe](https://github.com/alexkwolfe) +* [azatoth](https://github.com/azatoth) +* [kadirpekel](https://github.com/kadirpekel) +* [lambdalisue](https://github.com/lambdalisue) +* [luebken](https://github.com/luebken) +* [orlandov](https://github.com/orlandov) +* [Sannis](https://github.com/Sannis) +* [sstephenson](https://github.com/sstephenson) +* [thegreatape](https://github.com/thegreatape) +* [mmalecki](https://github.com/mmalecki) +* and thanks to [cjohansen](https://github.com/cjohansen) for input and advice + on implementing setUp and tearDown functions. See + [cjohansen's fork](https://github.com/cjohansen/nodeunit). + +Also, check out gerad's [nodeunit-dsl](https://github.com/gerad/nodeunit-dsl) +project, which implements a 'pretty dsl on top of nodeunit'. + +More contributor information can be found in the +[CONTRIBUTORS.md](https://github.com/caolan/nodeunit/blob/master/CONTRIBUTORS.md) +file. + +Usage +----- + +Here is an example unit test module: + + exports.testSomething = function(test){ + test.expect(1); + test.ok(true, "this assertion should pass"); + test.done(); + }; + + exports.testSomethingElse = function(test){ + test.ok(false, "this assertion should fail"); + test.done(); + }; + +When run using the included test runner, this will output the following: + + + +Installation +------------ + +There are two options for installing nodeunit: + +1. Clone / download nodeunit from [github](https://github.com/caolan/nodeunit), + then: + + make && sudo make install + +2. Install via npm: + + npm install nodeunit + +API Documentation +----------------- + +Nodeunit uses the functions available in the node.js +[assert module](http://nodejs.org/docs/v0.4.2/api/assert.html): + +* __ok(value, [message])__ - Tests if value is a true value. +* __equal(actual, expected, [message])__ - Tests shallow, coercive equality + with the equal comparison operator ( == ). +* __notEqual(actual, expected, [message])__ - Tests shallow, coercive + non-equality with the not equal comparison operator ( != ). +* __deepEqual(actual, expected, [message])__ - Tests for deep equality. +* __notDeepEqual(actual, expected, [message])__ - Tests for any deep + inequality. +* __strictEqual(actual, expected, [message])__ - Tests strict equality, as + determined by the strict equality operator ( === ) +* __notStrictEqual(actual, expected, [message])__ - Tests strict non-equality, + as determined by the strict not equal operator ( !== ) +* __throws(block, [error], [message])__ - Expects block to throw an error. +* __doesNotThrow(block, [error], [message])__ - Expects block not to throw an + error. +* __ifError(value)__ - Tests if value is not a false value, throws if it is a + true value. Useful when testing the first argument, error in callbacks. + +Nodeunit also provides the following functions within tests: + +* __expect(amount)__ - Specify how many assertions are expected to run within a + test. Very useful for ensuring that all your callbacks and assertions are + run. +* __done()__ - Finish the current test function, and move on to the next. ALL + tests should call this! + +Nodeunit aims to be simple and easy to learn. This is achieved through using +existing structures (such as node.js modules) to maximum effect, and reducing +the API where possible, to make it easier to digest. + +Tests are simply exported from a module, but they are still run in the order +they are defined. + +__Note:__ Users of old nodeunit versions may remember using ok, equals and same +in the style of qunit, instead of the assert functions above. These functions +still exist for backwards compatibility, and are simply aliases to their assert +module counterparts. + + +Asynchronous Testing +-------------------- + +When testing asynchronous code, there are a number of sharp edges to watch out +for. Thankfully, nodeunit is designed to help you avoid as many of these +pitfalls as possible. For the most part, testing asynchronous code in nodeunit +_just works_. + + +### Tests run in series + +While running tests in parallel seems like a good idea for speeding up your +test suite, in practice I've found it means writing much more complicated +tests. Because of node's module cache, running tests in parallel means mocking +and stubbing is pretty much impossible. One of the nicest things about testing +in javascript is the ease of doing stubs: + + var _readFile = fs.readFile; + fs.readFile = function(path, callback){ + // its a stub! + }; + // test function that uses fs.readFile + + // we're done + fs.readFile = _readFile; + +You cannot do this when running tests in parallel. In order to keep testing as +simple as possible, nodeunit avoids it. Thankfully, most unit-test suites run +fast anyway. + + +### Explicit ending of tests + +When testing async code its important that tests end at the correct point, not +just after a given number of assertions. Otherwise your tests can run short, +ending before all assertions have completed. Its important to detect too +many assertions as well as too few. Combining explicit ending of tests with +an expected number of assertions helps to avoid false test passes, so be sure +to use the test.expect() method at the start of your test functions, and +test.done() when finished. + + +Groups, setUp and tearDown +-------------------------- + +Nodeunit allows the nesting of test functions: + + exports.test1 = function (test) { + ... + } + + exports.group = { + test2: function (test) { + ... + }, + test3: function (test) { + ... + } + } + +This would be run as: + + test1 + group - test2 + group - test3 + +Using these groups, Nodeunit allows you to define a `setUp` function, which is +run before each test, and a `tearDown` function, which is run after each test +calls `test.done()`: + + module.exports = { + setUp: function (callback) { + this.foo = 'bar'; + callback(); + }, + tearDown: function (callback) { + // clean up + callback(); + }, + test1: function (test) { + test.equals(this.foo, 'bar'); + test.done(); + } + }; + +In this way, its possible to have multiple groups of tests in a module, each +group with its own setUp and tearDown functions. + + +Running Tests +------------- + +Nodeunit comes with a basic command-line test runner, which can be installed +using 'sudo make install'. Example usage: + + nodeunit testmodule1.js testfolder [...] + +The default test reporter uses color output, because I think that's more fun :) I +intend to add a no-color option in future. To give you a feeling of the fun you'll +be having writing tests, lets fix the example at the start of the README: + + + +Ahhh, Doesn't that feel better? + +When using the included test runner, it will exit using the failed number of +assertions as the exit code. Exiting with 0 when all tests pass. + + +### Command-line Options + +* __--reporter FILE__ - you can set the test reporter to a custom module or +on of the modules in nodeunit/lib/reporters, when omitted, the default test runner +is used. +* __--list-reporters__ - list available build-in reporters. +* __--config FILE__ - load config options from a JSON file, allows +the customisation of color schemes for the default test reporter etc. See +bin/nodeunit.json for current available options. +* __--version__ or __-v__ - report nodeunit version +* __--help__ - show nodeunit help + + +Running tests in the browser +---------------------------- + +Nodeunit tests can also be run inside the browser. For example usage, see +the examples/browser folder. The basic syntax is as follows: + +__test.html__ + + + + Example Test Suite + + + + + + +

+ + +nodeunit with vim +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +There is [nodeunit.vim](https://github.com/lambdalisue/nodeunit.vim) so you can use nodeunit with VIM. +That compiler use __machineout__ reporter and it is useful to use with [vim-makegreen](https://github.com/reinh/vim-makegreen) + + + +Contributing +------------ + +Contributions to the project are most welcome, so feel free to fork and improve. +When submitting a pull request, please run 'make lint' first to ensure +we're following a consistent coding style. diff --git a/node_modules/nodeunit/bin/nodeunit b/node_modules/nodeunit/bin/nodeunit new file mode 100755 index 0000000..4b3f4d5 --- /dev/null +++ b/node_modules/nodeunit/bin/nodeunit @@ -0,0 +1,133 @@ +#!/usr/bin/env node + +var + fs = require('fs'), + path = require('path'); + +// TODO: remove this when https://github.com/joyent/node/pull/1312 +// lands in core. +// +// Until then, use console.log from npm (https://gist.github.com/1077544) +require('../deps/console.log'); + +//require.paths.push(process.cwd()); +var args = (process.ARGV || process.argv).slice(2); + +var files = []; + +var testrunner, + config_file, + config_param_found = false, + output_param_found = false, + reporter_file = 'default', + reporter_param_found = false, + testspec_param_found = false; + testFullSpec_param_found = false; + +var usage = "Usage: nodeunit [options] testmodule1.js testfolder [...] \n" + + "Options:\n\n" + + " --config FILE the path to a JSON file with options\n" + + " --reporter FILE optional path to a reporter file to customize the output\n" + + " --list-reporters list available build-in reporters\n" + + " -t name, specify a test to run\n" + + " -f fullname, specify a specific test to run. fullname is built so: \"outerGroup - .. - innerGroup - testName\"\n" + + " -h, --help display this help and exit\n" + + " -v, --version output version information and exit"; + + + +// load default options +var content = fs.readFileSync(__dirname + '/nodeunit.json', 'utf8'); +var options = JSON.parse(content); + +// a very basic pseudo --options parser +args.forEach(function (arg) { + if (arg.slice(0, 9) === "--config=") { + config_file = arg.slice(9); + } else if (arg === '--config') { + config_param_found = true; + } else if (config_param_found) { + config_file = arg; + config_param_found = false; + } else if (arg.slice(0, 9) === "--output=") { + options.output = arg.slice(9); + } else if (arg === '--output') { + output_param_found = true; + } else if (output_param_found) { + options.output = arg; + output_param_found = false; + } else if (arg.slice(0, 11) === "--reporter=") { + reporter_file = arg.slice(11); + } else if (arg === '--reporter') { + reporter_param_found = true; + } else if (reporter_param_found) { + reporter_file = arg; + reporter_param_found = false; + } else if (arg === '-t') { + testspec_param_found = true; + } else if (testspec_param_found) { + options.testspec = arg; + testspec_param_found = false; + } else if (arg === '-f') { + testFullSpec_param_found = true; + } else if (testFullSpec_param_found) { + options.testFullSpec= arg; + testFullSpec_param_found = false; + } else if (arg === '--list-reporters') { + var reporters = fs.readdirSync(__dirname + '/../lib/reporters'); + reporters = reporters.filter(function (reporter_file) { + return (/\.js$/).test(reporter_file); + }).map(function (reporter_file) { + return reporter_file.replace(/\.js$/, ''); + }).filter(function (reporter_file) { + return reporter_file !== 'index'; + }); + console.log('Build-in reporters: '); + reporters.forEach(function (reporter_file) { + var reporter = require('../lib/reporters/' + reporter_file); + console.log(' * ' + reporter_file + (reporter.info ? ': ' + reporter.info : '')); + }); + process.exit(0); + } else if ((arg === '-v') || (arg === '--version')) { + var content = fs.readFileSync(__dirname + '/../package.json', 'utf8'); + var pkg = JSON.parse(content); + console.log(pkg.version); + process.exit(0); + } else if ((arg === '-h') || (arg === '--help')) { + console.log(usage); + process.exit(0); + } else { + files.push(arg); + } +}); + +if (files.length === 0) { + console.log('Files required.'); + console.log(usage); + process.exit(1); +} + +if (config_file) { + content = fs.readFileSync(config_file, 'utf8'); + var custom_options = JSON.parse(content); + + for (var option in custom_options) { + if (typeof option === 'string') { + options[option] = custom_options[option]; + } + } +} + +var builtin_reporters = require(__dirname + '/../lib/reporters'); +if (reporter_file in builtin_reporters) { + testrunner = builtin_reporters[reporter_file]; +} +else { + testrunner = require(reporter_file); +} + +testrunner.run(files, options, function(err) { + if (err) { + process.exit(1); + } +}); diff --git a/node_modules/nodeunit/bin/nodeunit.json b/node_modules/nodeunit/bin/nodeunit.json new file mode 100644 index 0000000..5c7778f --- /dev/null +++ b/node_modules/nodeunit/bin/nodeunit.json @@ -0,0 +1,10 @@ +{ + "error_prefix": "\u001B[31m", + "error_suffix": "\u001B[39m", + "ok_prefix": "\u001B[32m", + "ok_suffix": "\u001B[39m", + "bold_prefix": "\u001B[1m", + "bold_suffix": "\u001B[22m", + "assertion_prefix": "\u001B[35m", + "assertion_suffix": "\u001B[39m" +} diff --git a/node_modules/nodeunit/browser b/node_modules/nodeunit/browser new file mode 120000 index 0000000..df69758 --- /dev/null +++ b/node_modules/nodeunit/browser @@ -0,0 +1 @@ +dist/browser \ No newline at end of file diff --git a/node_modules/nodeunit/deps/async.js b/node_modules/nodeunit/deps/async.js new file mode 100644 index 0000000..d81255f --- /dev/null +++ b/node_modules/nodeunit/deps/async.js @@ -0,0 +1,623 @@ +/*global setTimeout: false, console: false */ +(function () { + + var async = {}; + + // global on the server, window in the browser + var root = this, + previous_async = root.async; + + if (typeof module !== 'undefined' && module.exports) { + module.exports = async; + } + else { + root.async = async; + } + + async.noConflict = function () { + root.async = previous_async; + return async; + }; + + //// cross-browser compatiblity functions //// + + var _forEach = function (arr, iterator) { + if (arr.forEach) { + return arr.forEach(iterator); + } + for (var i = 0; i < arr.length; i += 1) { + iterator(arr[i], i, arr); + } + }; + + var _map = function (arr, iterator) { + if (arr.map) { + return arr.map(iterator); + } + var results = []; + _forEach(arr, function (x, i, a) { + results.push(iterator(x, i, a)); + }); + return results; + }; + + var _reduce = function (arr, iterator, memo) { + if (arr.reduce) { + return arr.reduce(iterator, memo); + } + _forEach(arr, function (x, i, a) { + memo = iterator(memo, x, i, a); + }); + return memo; + }; + + var _keys = function (obj) { + if (Object.keys) { + return Object.keys(obj); + } + var keys = []; + for (var k in obj) { + if (obj.hasOwnProperty(k)) { + keys.push(k); + } + } + return keys; + }; + + var _indexOf = function (arr, item) { + if (arr.indexOf) { + return arr.indexOf(item); + } + for (var i = 0; i < arr.length; i += 1) { + if (arr[i] === item) { + return i; + } + } + return -1; + }; + + //// exported async module functions //// + + //// nextTick implementation with browser-compatible fallback //// + if (typeof process === 'undefined' || !(process.nextTick)) { + async.nextTick = function (fn) { + setTimeout(fn, 0); + }; + } + else { + async.nextTick = process.nextTick; + } + + async.forEach = function (arr, iterator, callback) { + if (!arr.length) { + return callback(); + } + var completed = 0; + _forEach(arr, function (x) { + iterator(x, function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + if (completed === arr.length) { + callback(); + } + } + }); + }); + }; + + async.forEachSeries = function (arr, iterator, callback) { + if (!arr.length) { + return callback(); + } + var completed = 0; + var iterate = function () { + iterator(arr[completed], function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + if (completed === arr.length) { + callback(); + } + else { + iterate(); + } + } + }); + }; + iterate(); + }; + + + var doParallel = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.forEach].concat(args)); + }; + }; + var doSeries = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.forEachSeries].concat(args)); + }; + }; + + + var _asyncMap = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (err, v) { + results[x.index] = v; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + }; + async.map = doParallel(_asyncMap); + async.mapSeries = doSeries(_asyncMap); + + + // reduce only has a series version, as doing reduce in parallel won't + // work in many situations. + async.reduce = function (arr, memo, iterator, callback) { + async.forEachSeries(arr, function (x, callback) { + iterator(memo, x, function (err, v) { + memo = v; + callback(err); + }); + }, function (err) { + callback(err, memo); + }); + }; + // inject alias + async.inject = async.reduce; + // foldl alias + async.foldl = async.reduce; + + async.reduceRight = function (arr, memo, iterator, callback) { + var reversed = _map(arr, function (x) { + return x; + }).reverse(); + async.reduce(reversed, memo, iterator, callback); + }; + // foldr alias + async.foldr = async.reduceRight; + + var _filter = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.filter = doParallel(_filter); + async.filterSeries = doSeries(_filter); + // select alias + async.select = async.filter; + async.selectSeries = async.filterSeries; + + var _reject = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (!v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.reject = doParallel(_reject); + async.rejectSeries = doSeries(_reject); + + var _detect = function (eachfn, arr, iterator, main_callback) { + eachfn(arr, function (x, callback) { + iterator(x, function (result) { + if (result) { + main_callback(x); + } + else { + callback(); + } + }); + }, function (err) { + main_callback(); + }); + }; + async.detect = doParallel(_detect); + async.detectSeries = doSeries(_detect); + + async.some = function (arr, iterator, main_callback) { + async.forEach(arr, function (x, callback) { + iterator(x, function (v) { + if (v) { + main_callback(true); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(false); + }); + }; + // any alias + async.any = async.some; + + async.every = function (arr, iterator, main_callback) { + async.forEach(arr, function (x, callback) { + iterator(x, function (v) { + if (!v) { + main_callback(false); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(true); + }); + }; + // all alias + async.all = async.every; + + async.sortBy = function (arr, iterator, callback) { + async.map(arr, function (x, callback) { + iterator(x, function (err, criteria) { + if (err) { + callback(err); + } + else { + callback(null, {value: x, criteria: criteria}); + } + }); + }, function (err, results) { + if (err) { + return callback(err); + } + else { + var fn = function (left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }; + callback(null, _map(results.sort(fn), function (x) { + return x.value; + })); + } + }); + }; + + async.auto = function (tasks, callback) { + callback = callback || function () {}; + var keys = _keys(tasks); + if (!keys.length) { + return callback(null); + } + + var completed = []; + + var listeners = []; + var addListener = function (fn) { + listeners.unshift(fn); + }; + var removeListener = function (fn) { + for (var i = 0; i < listeners.length; i += 1) { + if (listeners[i] === fn) { + listeners.splice(i, 1); + return; + } + } + }; + var taskComplete = function () { + _forEach(listeners, function (fn) { + fn(); + }); + }; + + addListener(function () { + if (completed.length === keys.length) { + callback(null); + } + }); + + _forEach(keys, function (k) { + var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k]; + var taskCallback = function (err) { + if (err) { + callback(err); + // stop subsequent errors hitting callback multiple times + callback = function () {}; + } + else { + completed.push(k); + taskComplete(); + } + }; + var requires = task.slice(0, Math.abs(task.length - 1)) || []; + var ready = function () { + return _reduce(requires, function (a, x) { + return (a && _indexOf(completed, x) !== -1); + }, true); + }; + if (ready()) { + task[task.length - 1](taskCallback); + } + else { + var listener = function () { + if (ready()) { + removeListener(listener); + task[task.length - 1](taskCallback); + } + }; + addListener(listener); + } + }); + }; + + async.waterfall = function (tasks, callback) { + if (!tasks.length) { + return callback(); + } + callback = callback || function () {}; + var wrapIterator = function (iterator) { + return function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + var args = Array.prototype.slice.call(arguments, 1); + var next = iterator.next(); + if (next) { + args.push(wrapIterator(next)); + } + else { + args.push(callback); + } + async.nextTick(function () { + iterator.apply(null, args); + }); + } + }; + }; + wrapIterator(async.iterator(tasks))(); + }; + + async.parallel = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + async.map(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args || null); + }); + } + }, callback); + } + else { + var results = {}; + async.forEach(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.series = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + async.mapSeries(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args || null); + }); + } + }, callback); + } + else { + var results = {}; + async.forEachSeries(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.iterator = function (tasks) { + var makeCallback = function (index) { + var fn = function () { + if (tasks.length) { + tasks[index].apply(null, arguments); + } + return fn.next(); + }; + fn.next = function () { + return (index < tasks.length - 1) ? makeCallback(index + 1): null; + }; + return fn; + }; + return makeCallback(0); + }; + + async.apply = function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + return function () { + return fn.apply( + null, args.concat(Array.prototype.slice.call(arguments)) + ); + }; + }; + + var _concat = function (eachfn, arr, fn, callback) { + var r = []; + eachfn(arr, function (x, cb) { + fn(x, function (err, y) { + r = r.concat(y || []); + cb(err); + }); + }, function (err) { + callback(err, r); + }); + }; + async.concat = doParallel(_concat); + async.concatSeries = doSeries(_concat); + + async.whilst = function (test, iterator, callback) { + if (test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.whilst(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.until = function (test, iterator, callback) { + if (!test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.until(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.queue = function (worker, concurrency) { + var workers = 0; + var tasks = []; + var q = { + concurrency: concurrency, + push: function (data, callback) { + tasks.push({data: data, callback: callback}); + async.nextTick(q.process); + }, + process: function () { + if (workers < q.concurrency && tasks.length) { + var task = tasks.splice(0, 1)[0]; + workers += 1; + worker(task.data, function () { + workers -= 1; + if (task.callback) { + task.callback.apply(task, arguments); + } + q.process(); + }); + } + }, + length: function () { + return tasks.length; + } + }; + return q; + }; + + var _console_fn = function (name) { + return function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + fn.apply(null, args.concat([function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (typeof console !== 'undefined') { + if (err) { + if (console.error) { + console.error(err); + } + } + else if (console[name]) { + _forEach(args, function (x) { + console[name](x); + }); + } + } + }])); + }; + }; + async.log = _console_fn('log'); + async.dir = _console_fn('dir'); + /*async.info = _console_fn('info'); + async.warn = _console_fn('warn'); + async.error = _console_fn('error');*/ + + async.memoize = function (fn, hasher) { + var memo = {}; + hasher = hasher || function (x) { + return x; + }; + return function () { + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + var key = hasher.apply(null, args); + if (key in memo) { + callback.apply(null, memo[key]); + } + else { + fn.apply(null, args.concat([function () { + memo[key] = arguments; + callback.apply(null, arguments); + }])); + } + }; + }; + +}()); diff --git a/node_modules/nodeunit/deps/console.log.js b/node_modules/nodeunit/deps/console.log.js new file mode 100644 index 0000000..fe146c1 --- /dev/null +++ b/node_modules/nodeunit/deps/console.log.js @@ -0,0 +1,55 @@ +/* + A console.log that won't leave you hanging when node exits + 90% of this file was ripped from node.js + + License: see: https://github.com/joyent/node/blob/master/lib/console.js + */ + + // console object +var formatRegExp = /%[sdj]/g; +function format(f) { + var util = require('util'); + + if (typeof f !== 'string') { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(util.inspect(arguments[i])); + } + return objects.join(' '); + } + + + var i = 1; + var args = arguments; + var str = String(f).replace(formatRegExp, function(x) { + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': return JSON.stringify(args[i++]); + default: + return x; + } + }); + for (var len = args.length, x = args[i]; i < len; x = args[++i]) { + if (x === null || typeof x !== 'object') { + str += ' ' + x; + } else { + str += ' ' + util.inspect(x); + } + } + return str; +} + +console.log = function() { + var res = process.stdout.write(format.apply(this, arguments) + '\n'); + + // this is the first time stdout got backed up + if (!res && !process.stdout.pendingWrite) { + process.stdout.pendingWrite = true; + + // magic sauce: keep node alive until stdout has flushed + process.stdout.once('drain', function () { + process.stdout.draining = false; + }); + } +}; diff --git a/node_modules/nodeunit/deps/ejs/History.md b/node_modules/nodeunit/deps/ejs/History.md new file mode 100644 index 0000000..00d2b5b --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/History.md @@ -0,0 +1,70 @@ + +0.4.3 / 2011-06-20 +================== + + * Fixed stacktraces line number when used multiline js expressions [Octave] + +0.4.2 / 2011-05-11 +================== + + * Added client side support + +0.4.1 / 2011-04-21 +================== + + * Fixed error context + +0.4.0 / 2011-04-21 +================== + + * Added; ported jade's error reporting to ejs. [slaskis] + +0.3.1 / 2011-02-23 +================== + + * Fixed optional `compile()` options + +0.3.0 / 2011-02-14 +================== + + * Added 'json' filter [Yuriy Bogdanov] + * Use exported version of parse function to allow monkey-patching [Anatoliy Chakkaev] + +0.2.1 / 2010-10-07 +================== + + * Added filter support + * Fixed _cache_ option. ~4x performance increase + +0.2.0 / 2010-08-05 +================== + + * Added support for global tag config + * Added custom tag support. Closes #5 + * Fixed whitespace bug. Closes #4 + +0.1.0 / 2010-08-04 +================== + + * Faster implementation [ashleydev] + +0.0.4 / 2010-08-02 +================== + + * Fixed single quotes for content outside of template tags. [aniero] + * Changed; `exports.compile()` now expects only "locals" + +0.0.3 / 2010-07-15 +================== + + * Fixed single quotes + +0.0.2 / 2010-07-09 +================== + + * Fixed newline preservation + +0.0.1 / 2010-07-09 +================== + + * Initial release diff --git a/node_modules/nodeunit/deps/ejs/Makefile b/node_modules/nodeunit/deps/ejs/Makefile new file mode 100644 index 0000000..a8b00d9 --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/Makefile @@ -0,0 +1,20 @@ + +SRC = $(shell find lib -name "*.js" -type f) +UGLIFY_FLAGS = --no-mangle + +test: + @./node_modules/.bin/expresso test/*.test.js + +ejs.js: $(SRC) + @node support/compile.js $^ + +ejs.min.js: ejs.js + @uglifyjs $(UGLIFY_FLAGS) $< > $@ \ + && du ejs.min.js \ + && du ejs.js + +clean: + rm -f ejs.js + rm -f ejs.min.js + +.PHONY: test \ No newline at end of file diff --git a/node_modules/nodeunit/deps/ejs/Readme.md b/node_modules/nodeunit/deps/ejs/Readme.md new file mode 100644 index 0000000..58cb10a --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/Readme.md @@ -0,0 +1,152 @@ + +# EJS + +Embedded JavaScript templates. + +## Installation + + $ npm install ejs + +## Features + + * Complies with the [Express](http://expressjs.com) view system + * Static caching of intermediate JavaScript + * Unbuffered code for conditionals etc `<% code %>` + * Escapes html by default with `<%= code %>` + * Unescaped buffering with `<%- code %>` + * Supports tag customization + * Filter support for designer-friendly templates + * Client-side support + +## Example + + <% if (user) { %> +

<%= user.name %>

+ <% } %> + +## Usage + + ejs.compile(str, options); + // => Function + + ejs.render(str, options); + // => str + +## Options + + - `locals` Local variables object + - `cache` Compiled functions are cached, requires `filename` + - `filename` Used by `cache` to key caches + - `scope` Function execution context + - `debug` Output generated function body + - `open` Open tag, defaulting to "<%" + - `close` Closing tag, defaulting to "%>" + +## Custom tags + +Custom tags can also be applied globally: + + var ejs = require('ejs'); + ejs.open = '{{'; + ejs.close = '}}'; + +Which would make the following a valid template: + +

{{= title }}

+ +## Filters + +EJS conditionally supports the concept of "filters". A "filter chain" +is a designer friendly api for manipulating data, without writing JavaScript. + +Filters can be applied by supplying the _:_ modifier, so for example if we wish to take the array `[{ name: 'tj' }, { name: 'mape' }, { name: 'guillermo' }]` and output a list of names we can do this simply with filters: + +Template: + +

<%=: users | map:'name' | join %>

+ +Output: + +

Tj, Mape, Guillermo

+ +Render call: + + ejs.render(str, { + locals: { + users: [ + { name: 'tj' }, + { name: 'mape' }, + { name: 'guillermo' } + ] + } + }); + +Or perhaps capitalize the first user's name for display: + +

<%=: users | first | capitalize %>

+ +## Filter list + +Currently these filters are available: + + - first + - last + - capitalize + - downcase + - upcase + - sort + - sort_by:'prop' + - size + - length + - plus:n + - minus:n + - times:n + - divided_by:n + - join:'val' + - truncate:n + - truncate_words:n + - replace:pattern,substitution + - prepend:val + - append:val + - map:'prop' + - reverse + - get:'prop' + +## Adding filters + + To add a filter simply add a method to the `.filters` object: + +```js +ejs.filters.last = function(obj) { + return obj[obj.length - 1]; +}; +``` + +## client-side support + + include `./ejs.js` or `./ejs.min.js` and `require("ejs").compile(str)`. + +## License + +(The MIT License) + +Copyright (c) 2009-2010 TJ Holowaychuk <tj@vision-media.ca> + +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/node_modules/nodeunit/deps/ejs/benchmark.js b/node_modules/nodeunit/deps/ejs/benchmark.js new file mode 100644 index 0000000..7b267e1 --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/benchmark.js @@ -0,0 +1,14 @@ + + +var ejs = require('./lib/ejs'), + str = '<% if (foo) { %>

<%= foo %>

<% } %>', + times = 50000; + +console.log('rendering ' + times + ' times'); + +var start = new Date; +while (times--) { + ejs.render(str, { cache: true, filename: 'test', locals: { foo: 'bar' }}); +} + +console.log('took ' + (new Date - start) + 'ms'); \ No newline at end of file diff --git a/node_modules/nodeunit/deps/ejs/ejs.js b/node_modules/nodeunit/deps/ejs/ejs.js new file mode 100644 index 0000000..b8c6aa1 --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/ejs.js @@ -0,0 +1,531 @@ + +// CommonJS require() + +function require(p){ + var path = require.resolve(p) + , mod = require.modules[path]; + if (!mod) throw new Error('failed to require "' + p + '"'); + if (!mod.exports) { + mod.exports = {}; + mod.call(mod.exports, mod, mod.exports, require.relative(path)); + } + return mod.exports; + } + +require.modules = {}; + +require.resolve = function (path){ + var orig = path + , reg = path + '.js' + , index = path + '/index.js'; + return require.modules[reg] && reg + || require.modules[index] && index + || orig; + }; + +require.register = function (path, fn){ + require.modules[path] = fn; + }; + +require.relative = function (parent) { + return function(p){ + if ('.' != p[0]) return require(p); + + var path = parent.split('/') + , segs = p.split('/'); + path.pop(); + + for (var i = 0; i < segs.length; i++) { + var seg = segs[i]; + if ('..' == seg) path.pop(); + else if ('.' != seg) path.push(seg); + } + + return require(path.join('/')); + }; + }; + + +require.register("ejs.js", function(module, exports, require){ + +/*! + * EJS + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('./utils'); + +/** + * Library version. + */ + +exports.version = '0.4.2'; + +/** + * Filters. + * + * @type Object + */ + +var filters = exports.filters = require('./filters'); + +/** + * Intermediate js cache. + * + * @type Object + */ + +var cache = {}; + +/** + * Clear intermediate js cache. + * + * @api public + */ + +exports.clearCache = function(){ + cache = {}; +}; + +/** + * Translate filtered code into function calls. + * + * @param {String} js + * @return {String} + * @api private + */ + +function filtered(js) { + return js.substr(1).split('|').reduce(function(js, filter){ + var parts = filter.split(':') + , name = parts.shift() + , args = parts.shift() || ''; + if (args) args = ', ' + args; + return 'filters.' + name + '(' + js + args + ')'; + }); +}; + +/** + * Re-throw the given `err` in context to the + * `str` of ejs, `filename`, and `lineno`. + * + * @param {Error} err + * @param {String} str + * @param {String} filename + * @param {String} lineno + * @api private + */ + +function rethrow(err, str, filename, lineno){ + var lines = str.split('\n') + , start = Math.max(lineno - 3, 0) + , end = Math.min(lines.length, lineno + 3); + + // Error context + var context = lines.slice(start, end).map(function(line, i){ + var curr = i + start + 1; + return (curr == lineno ? ' >> ' : ' ') + + curr + + '| ' + + line; + }).join('\n'); + + // Alter exception message + err.path = filename; + err.message = (filename || 'ejs') + ':' + + lineno + '\n' + + context + '\n\n' + + err.message; + + throw err; +} + +/** + * Parse the given `str` of ejs, returning the function body. + * + * @param {String} str + * @return {String} + * @api public + */ + +var parse = exports.parse = function(str, options){ + var options = options || {} + , open = options.open || exports.open || '<%' + , close = options.close || exports.close || '%>'; + + var buf = [ + "var buf = [];" + , "\nwith (locals) {" + , "\n buf.push('" + ]; + + var lineno = 1; + + for (var i = 0, len = str.length; i < len; ++i) { + if (str.slice(i, open.length + i) == open) { + i += open.length + + var prefix, postfix, line = '__stack.lineno=' + lineno; + switch (str[i]) { + case '=': + prefix = "', escape((" + line + ', '; + postfix = ")), '"; + ++i; + break; + case '-': + prefix = "', (" + line + ', '; + postfix = "), '"; + ++i; + break; + default: + prefix = "');" + line + ';'; + postfix = "; buf.push('"; + } + + var start = i; + var end = str.indexOf(close, i); + var js = str.substring(i, end); + var n = 0; + while ((n = js.indexOf("\n", n)) > -1) { + n++; + lineno++; + } + if (js[0] == ':') js = filtered(js); + buf.push(prefix, js, postfix); + i += end - start + close.length - 1; + + } else if (str[i] == "\\") { + buf.push("\\\\"); + } else if (str[i] == "'") { + buf.push("\\'"); + } else if (str[i] == "\r") { + buf.push(" "); + } else if (str[i] == "\n") { + buf.push("\\n"); + lineno++; + } else { + buf.push(str[i]); + } + } + + buf.push("');\n}\nreturn buf.join('');"); + return buf.join(''); +}; + +/** + * Compile the given `str` of ejs into a `Function`. + * + * @param {String} str + * @param {Object} options + * @return {Function} + * @api public + */ + +var compile = exports.compile = function(str, options){ + options = options || {}; + + var input = JSON.stringify(str) + , filename = options.filename + ? JSON.stringify(options.filename) + : 'undefined'; + + // Adds the fancy stack trace meta info + str = [ + 'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };', + rethrow.toString(), + 'try {', + exports.parse(str, options), + '} catch (err) {', + ' rethrow(err, __stack.input, __stack.filename, __stack.lineno);', + '}' + ].join("\n"); + + if (options.debug) console.log(str); + var fn = new Function('locals, filters, escape', str); + return function(locals){ + return fn.call(this, locals, filters, utils.escape); + } +}; + +/** + * Render the given `str` of ejs. + * + * Options: + * + * - `locals` Local variables object + * - `cache` Compiled functions are cached, requires `filename` + * - `filename` Used by `cache` to key caches + * - `scope` Function execution context + * - `debug` Output generated function body + * - `open` Open tag, defaulting to "<%" + * - `close` Closing tag, defaulting to "%>" + * + * @param {String} str + * @param {Object} options + * @return {String} + * @api public + */ + +exports.render = function(str, options){ + var fn + , options = options || {}; + if (options.cache) { + if (options.filename) { + fn = cache[options.filename] || (cache[options.filename] = compile(str, options)); + } else { + throw new Error('"cache" option requires "filename".'); + } + } else { + fn = compile(str, options); + } + return fn.call(options.scope, options.locals || {}); +}; + +/** + * Expose to require(). + */ + +if (require.extensions) { + require.extensions['.ejs'] = function(module, filename) { + source = require('fs').readFileSync(filename, 'utf-8'); + module._compile(compile(source, {}), filename); + }; +} else if (require.registerExtension) { + require.registerExtension('.ejs', function(src) { + return compile(src, {}); + }); +} + +}); // module: ejs.js + +require.register("filters.js", function(module, exports, require){ + +/*! + * EJS - Filters + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * First element of the target `obj`. + */ + +exports.first = function(obj) { + return obj[0]; +}; + +/** + * Last element of the target `obj`. + */ + +exports.last = function(obj) { + return obj[obj.length - 1]; +}; + +/** + * Capitalize the first letter of the target `str`. + */ + +exports.capitalize = function(str){ + str = String(str); + return str[0].toUpperCase() + str.substr(1, str.length); +}; + +/** + * Downcase the target `str`. + */ + +exports.downcase = function(str){ + return String(str).toLowerCase(); +}; + +/** + * Uppercase the target `str`. + */ + +exports.upcase = function(str){ + return String(str).toUpperCase(); +}; + +/** + * Sort the target `obj`. + */ + +exports.sort = function(obj){ + return Object.create(obj).sort(); +}; + +/** + * Sort the target `obj` by the given `prop` ascending. + */ + +exports.sort_by = function(obj, prop){ + return Object.create(obj).sort(function(a, b){ + a = a[prop], b = b[prop]; + if (a > b) return 1; + if (a < b) return -1; + return 0; + }); +}; + +/** + * Size or length of the target `obj`. + */ + +exports.size = exports.length = function(obj) { + return obj.length; +}; + +/** + * Add `a` and `b`. + */ + +exports.plus = function(a, b){ + return Number(a) + Number(b); +}; + +/** + * Subtract `b` from `a`. + */ + +exports.minus = function(a, b){ + return Number(a) - Number(b); +}; + +/** + * Multiply `a` by `b`. + */ + +exports.times = function(a, b){ + return Number(a) * Number(b); +}; + +/** + * Divide `a` by `b`. + */ + +exports.divided_by = function(a, b){ + return Number(a) / Number(b); +}; + +/** + * Join `obj` with the given `str`. + */ + +exports.join = function(obj, str){ + return obj.join(str || ', '); +}; + +/** + * Truncate `str` to `len`. + */ + +exports.truncate = function(str, len){ + str = String(str); + return str.substr(0, len); +}; + +/** + * Truncate `str` to `n` words. + */ + +exports.truncate_words = function(str, n){ + var str = String(str) + , words = str.split(/ +/); + return words.slice(0, n).join(' '); +}; + +/** + * Replace `pattern` with `substitution` in `str`. + */ + +exports.replace = function(str, pattern, substitution){ + return String(str).replace(pattern, substitution || ''); +}; + +/** + * Prepend `val` to `obj`. + */ + +exports.prepend = function(obj, val){ + return Array.isArray(obj) + ? [val].concat(obj) + : val + obj; +}; + +/** + * Append `val` to `obj`. + */ + +exports.append = function(obj, val){ + return Array.isArray(obj) + ? obj.concat(val) + : obj + val; +}; + +/** + * Map the given `prop`. + */ + +exports.map = function(arr, prop){ + return arr.map(function(obj){ + return obj[prop]; + }); +}; + +/** + * Reverse the given `obj`. + */ + +exports.reverse = function(obj){ + return Array.isArray(obj) + ? obj.reverse() + : String(obj).split('').reverse().join(''); +}; + +/** + * Get `prop` of the given `obj`. + */ + +exports.get = function(obj, prop){ + return obj[prop]; +}; + +/** + * Packs the given `obj` into json string + */ +exports.json = function(obj){ + return JSON.stringify(obj); +}; +}); // module: filters.js + +require.register("utils.js", function(module, exports, require){ + +/*! + * EJS + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Escape the given string of `html`. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function(html){ + return String(html) + .replace(/&(?!\w+;)/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +}; + +}); // module: utils.js diff --git a/node_modules/nodeunit/deps/ejs/ejs.min.js b/node_modules/nodeunit/deps/ejs/ejs.min.js new file mode 100644 index 0000000..6b72d94 --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/ejs.min.js @@ -0,0 +1,2 @@ +// CommonJS require() +function require(p){var path=require.resolve(p),mod=require.modules[path];if(!mod)throw new Error('failed to require "'+p+'"');mod.exports||(mod.exports={},mod.call(mod.exports,mod,mod.exports,require.relative(path)));return mod.exports}require.modules={},require.resolve=function(path){var orig=path,reg=path+".js",index=path+"/index.js";return require.modules[reg]&®||require.modules[index]&&index||orig},require.register=function(path,fn){require.modules[path]=fn},require.relative=function(parent){return function(p){if("."!=p[0])return require(p);var path=parent.split("/"),segs=p.split("/");path.pop();for(var i=0;i> ":" ")+curr+"| "+line}).join("\n");err.path=filename,err.message=(filename||"ejs")+":"+lineno+"\n"+context+"\n\n"+err.message;throw err}var parse=exports.parse=function(str,options){var options=options||{},open=options.open||exports.open||"<%",close=options.close||exports.close||"%>",buf=["var buf = [];","\nwith (locals) {","\n buf.push('"],lineno=1;for(var i=0,len=str.length;ib)return 1;if(a/g,">").replace(/"/g,""")}}) \ No newline at end of file diff --git a/node_modules/nodeunit/deps/ejs/examples/client.html b/node_modules/nodeunit/deps/ejs/examples/client.html new file mode 100644 index 0000000..7081a04 --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/examples/client.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/node_modules/nodeunit/deps/ejs/examples/list.ejs b/node_modules/nodeunit/deps/ejs/examples/list.ejs new file mode 100644 index 0000000..d571330 --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/examples/list.ejs @@ -0,0 +1,7 @@ +<% if (names.length) { %> +
    + <% names.forEach(function(name){ %> +
  • <%= name %>
  • + <% }) %> +
+<% } %> \ No newline at end of file diff --git a/node_modules/nodeunit/deps/ejs/examples/list.js b/node_modules/nodeunit/deps/ejs/examples/list.js new file mode 100644 index 0000000..9cd7168 --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/examples/list.js @@ -0,0 +1,16 @@ + +/** + * Module dependencies. + */ + +var ejs = require('../') + , fs = require('fs') + , str = fs.readFileSync(__dirname + '/list.ejs', 'utf8'); + +var ret = ejs.render(str, { + locals: { + names: ['foo', 'bar', 'baz'] + } +}); + +console.log(ret); \ No newline at end of file diff --git a/node_modules/nodeunit/deps/ejs/index.js b/node_modules/nodeunit/deps/ejs/index.js new file mode 100644 index 0000000..20bf71a --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/index.js @@ -0,0 +1,2 @@ + +module.exports = require('./lib/ejs'); \ No newline at end of file diff --git a/node_modules/nodeunit/deps/ejs/lib/ejs.js b/node_modules/nodeunit/deps/ejs/lib/ejs.js new file mode 100644 index 0000000..46afa74 --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/lib/ejs.js @@ -0,0 +1,251 @@ + +/*! + * EJS + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('./utils'); + +/** + * Library version. + */ + +exports.version = '0.4.3'; + +/** + * Filters. + * + * @type Object + */ + +var filters = exports.filters = require('./filters'); + +/** + * Intermediate js cache. + * + * @type Object + */ + +var cache = {}; + +/** + * Clear intermediate js cache. + * + * @api public + */ + +exports.clearCache = function(){ + cache = {}; +}; + +/** + * Translate filtered code into function calls. + * + * @param {String} js + * @return {String} + * @api private + */ + +function filtered(js) { + return js.substr(1).split('|').reduce(function(js, filter){ + var parts = filter.split(':') + , name = parts.shift() + , args = parts.shift() || ''; + if (args) args = ', ' + args; + return 'filters.' + name + '(' + js + args + ')'; + }); +}; + +/** + * Re-throw the given `err` in context to the + * `str` of ejs, `filename`, and `lineno`. + * + * @param {Error} err + * @param {String} str + * @param {String} filename + * @param {String} lineno + * @api private + */ + +function rethrow(err, str, filename, lineno){ + var lines = str.split('\n') + , start = Math.max(lineno - 3, 0) + , end = Math.min(lines.length, lineno + 3); + + // Error context + var context = lines.slice(start, end).map(function(line, i){ + var curr = i + start + 1; + return (curr == lineno ? ' >> ' : ' ') + + curr + + '| ' + + line; + }).join('\n'); + + // Alter exception message + err.path = filename; + err.message = (filename || 'ejs') + ':' + + lineno + '\n' + + context + '\n\n' + + err.message; + + throw err; +} + +/** + * Parse the given `str` of ejs, returning the function body. + * + * @param {String} str + * @return {String} + * @api public + */ + +var parse = exports.parse = function(str, options){ + var options = options || {} + , open = options.open || exports.open || '<%' + , close = options.close || exports.close || '%>'; + + var buf = [ + "var buf = [];" + , "\nwith (locals) {" + , "\n buf.push('" + ]; + + var lineno = 1; + + for (var i = 0, len = str.length; i < len; ++i) { + if (str.slice(i, open.length + i) == open) { + i += open.length + + var prefix, postfix, line = '__stack.lineno=' + lineno; + switch (str.substr(i, 1)) { + case '=': + prefix = "', escape((" + line + ', '; + postfix = ")), '"; + ++i; + break; + case '-': + prefix = "', (" + line + ', '; + postfix = "), '"; + ++i; + break; + default: + prefix = "');" + line + ';'; + postfix = "; buf.push('"; + } + + var end = str.indexOf(close, i) + , js = str.substring(i, end) + , start = i + , n = 0; + + while (~(n = js.indexOf("\n", n))) n++, lineno++; + if (js.substr(0, 1) == ':') js = filtered(js); + buf.push(prefix, js, postfix); + i += end - start + close.length - 1; + + } else if (str.substr(i, 1) == "\\") { + buf.push("\\\\"); + } else if (str.substr(i, 1) == "'") { + buf.push("\\'"); + } else if (str.substr(i, 1) == "\r") { + buf.push(" "); + } else if (str.substr(i, 1) == "\n") { + buf.push("\\n"); + lineno++; + } else { + buf.push(str.substr(i, 1)); + } + } + + buf.push("');\n}\nreturn buf.join('');"); + return buf.join(''); +}; + +/** + * Compile the given `str` of ejs into a `Function`. + * + * @param {String} str + * @param {Object} options + * @return {Function} + * @api public + */ + +var compile = exports.compile = function(str, options){ + options = options || {}; + + var input = JSON.stringify(str) + , filename = options.filename + ? JSON.stringify(options.filename) + : 'undefined'; + + // Adds the fancy stack trace meta info + str = [ + 'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };', + rethrow.toString(), + 'try {', + exports.parse(str, options), + '} catch (err) {', + ' rethrow(err, __stack.input, __stack.filename, __stack.lineno);', + '}' + ].join("\n"); + + if (options.debug) console.log(str); + var fn = new Function('locals, filters, escape', str); + return function(locals){ + return fn.call(this, locals, filters, utils.escape); + } +}; + +/** + * Render the given `str` of ejs. + * + * Options: + * + * - `locals` Local variables object + * - `cache` Compiled functions are cached, requires `filename` + * - `filename` Used by `cache` to key caches + * - `scope` Function execution context + * - `debug` Output generated function body + * - `open` Open tag, defaulting to "<%" + * - `close` Closing tag, defaulting to "%>" + * + * @param {String} str + * @param {Object} options + * @return {String} + * @api public + */ + +exports.render = function(str, options){ + var fn + , options = options || {}; + if (options.cache) { + if (options.filename) { + fn = cache[options.filename] || (cache[options.filename] = compile(str, options)); + } else { + throw new Error('"cache" option requires "filename".'); + } + } else { + fn = compile(str, options); + } + return fn.call(options.scope, options.locals || {}); +}; + +/** + * Expose to require(). + */ + +if (require.extensions) { + require.extensions['.ejs'] = function(module, filename) { + source = require('fs').readFileSync(filename, 'utf-8'); + module._compile(compile(source, {}), filename); + }; +} else if (require.registerExtension) { + require.registerExtension('.ejs', function(src) { + return compile(src, {}); + }); +} diff --git a/node_modules/nodeunit/deps/ejs/lib/filters.js b/node_modules/nodeunit/deps/ejs/lib/filters.js new file mode 100644 index 0000000..d425c8d --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/lib/filters.js @@ -0,0 +1,198 @@ + +/*! + * EJS - Filters + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * First element of the target `obj`. + */ + +exports.first = function(obj) { + return obj[0]; +}; + +/** + * Last element of the target `obj`. + */ + +exports.last = function(obj) { + return obj[obj.length - 1]; +}; + +/** + * Capitalize the first letter of the target `str`. + */ + +exports.capitalize = function(str){ + str = String(str); + return str[0].toUpperCase() + str.substr(1, str.length); +}; + +/** + * Downcase the target `str`. + */ + +exports.downcase = function(str){ + return String(str).toLowerCase(); +}; + +/** + * Uppercase the target `str`. + */ + +exports.upcase = function(str){ + return String(str).toUpperCase(); +}; + +/** + * Sort the target `obj`. + */ + +exports.sort = function(obj){ + return Object.create(obj).sort(); +}; + +/** + * Sort the target `obj` by the given `prop` ascending. + */ + +exports.sort_by = function(obj, prop){ + return Object.create(obj).sort(function(a, b){ + a = a[prop], b = b[prop]; + if (a > b) return 1; + if (a < b) return -1; + return 0; + }); +}; + +/** + * Size or length of the target `obj`. + */ + +exports.size = exports.length = function(obj) { + return obj.length; +}; + +/** + * Add `a` and `b`. + */ + +exports.plus = function(a, b){ + return Number(a) + Number(b); +}; + +/** + * Subtract `b` from `a`. + */ + +exports.minus = function(a, b){ + return Number(a) - Number(b); +}; + +/** + * Multiply `a` by `b`. + */ + +exports.times = function(a, b){ + return Number(a) * Number(b); +}; + +/** + * Divide `a` by `b`. + */ + +exports.divided_by = function(a, b){ + return Number(a) / Number(b); +}; + +/** + * Join `obj` with the given `str`. + */ + +exports.join = function(obj, str){ + return obj.join(str || ', '); +}; + +/** + * Truncate `str` to `len`. + */ + +exports.truncate = function(str, len){ + str = String(str); + return str.substr(0, len); +}; + +/** + * Truncate `str` to `n` words. + */ + +exports.truncate_words = function(str, n){ + var str = String(str) + , words = str.split(/ +/); + return words.slice(0, n).join(' '); +}; + +/** + * Replace `pattern` with `substitution` in `str`. + */ + +exports.replace = function(str, pattern, substitution){ + return String(str).replace(pattern, substitution || ''); +}; + +/** + * Prepend `val` to `obj`. + */ + +exports.prepend = function(obj, val){ + return Array.isArray(obj) + ? [val].concat(obj) + : val + obj; +}; + +/** + * Append `val` to `obj`. + */ + +exports.append = function(obj, val){ + return Array.isArray(obj) + ? obj.concat(val) + : obj + val; +}; + +/** + * Map the given `prop`. + */ + +exports.map = function(arr, prop){ + return arr.map(function(obj){ + return obj[prop]; + }); +}; + +/** + * Reverse the given `obj`. + */ + +exports.reverse = function(obj){ + return Array.isArray(obj) + ? obj.reverse() + : String(obj).split('').reverse().join(''); +}; + +/** + * Get `prop` of the given `obj`. + */ + +exports.get = function(obj, prop){ + return obj[prop]; +}; + +/** + * Packs the given `obj` into json string + */ +exports.json = function(obj){ + return JSON.stringify(obj); +}; \ No newline at end of file diff --git a/node_modules/nodeunit/deps/ejs/lib/utils.js b/node_modules/nodeunit/deps/ejs/lib/utils.js new file mode 100644 index 0000000..8d569d6 --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/lib/utils.js @@ -0,0 +1,23 @@ + +/*! + * EJS + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Escape the given string of `html`. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function(html){ + return String(html) + .replace(/&(?!\w+;)/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +}; + \ No newline at end of file diff --git a/node_modules/nodeunit/deps/ejs/package.json b/node_modules/nodeunit/deps/ejs/package.json new file mode 100644 index 0000000..224b4ff --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/package.json @@ -0,0 +1,11 @@ +{ + "name": "ejs", + "description": "Embedded JavaScript templates", + "version": "0.4.3", + "author": "TJ Holowaychuk ", + "keywords": ["template", "engine", "ejs"], + "devDependencies": { + "expresso": "0.9.2" + }, + "main": "./lib/ejs.js" +} \ No newline at end of file diff --git a/node_modules/nodeunit/deps/ejs/support/compile.js b/node_modules/nodeunit/deps/ejs/support/compile.js new file mode 100644 index 0000000..edd3815 --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/support/compile.js @@ -0,0 +1,173 @@ + +/** + * Module dependencies. + */ + +var fs = require('fs'); + +/** + * Arguments. + */ + +var args = process.argv.slice(2) + , pending = args.length + , files = {}; + +console.log(''); + +// parse arguments + +args.forEach(function(file){ + var mod = file.replace('lib/', ''); + fs.readFile(file, 'utf8', function(err, js){ + if (err) throw err; + console.log(' \033[90mcompile : \033[0m\033[36m%s\033[0m', file); + files[file] = parse(js); + --pending || compile(); + }); +}); + +/** + * Parse the given `js`. + */ + +function parse(js) { + return parseInheritance(parseConditionals(js)); +} + +/** + * Parse __proto__. + */ + +function parseInheritance(js) { + return js + .replace(/^ *(\w+)\.prototype\.__proto__ * = *(\w+)\.prototype *;?/gm, function(_, child, parent){ + return child + '.prototype = new ' + parent + ';\n' + + child + '.prototype.constructor = '+ child + ';\n'; + }); +} + +/** + * Parse the given `js`, currently supporting: + * + * 'if' ['node' | 'browser'] + * 'end' + * + */ + +function parseConditionals(js) { + var lines = js.split('\n') + , len = lines.length + , buffer = true + , browser = false + , buf = [] + , line + , cond; + + for (var i = 0; i < len; ++i) { + line = lines[i]; + if (/^ *\/\/ *if *(node|browser)/gm.exec(line)) { + cond = RegExp.$1; + buffer = browser = 'browser' == cond; + } else if (/^ *\/\/ *end/.test(line)) { + buffer = true; + browser = false; + } else if (browser) { + buf.push(line.replace(/^( *)\/\//, '$1')); + } else if (buffer) { + buf.push(line); + } + } + + return buf.join('\n'); +} + +/** + * Compile the files. + */ + +function compile() { + var buf = ''; + buf += '\n// CommonJS require()\n\n'; + buf += browser.require + '\n\n'; + buf += 'require.modules = {};\n\n'; + buf += 'require.resolve = ' + browser.resolve + ';\n\n'; + buf += 'require.register = ' + browser.register + ';\n\n'; + buf += 'require.relative = ' + browser.relative + ';\n\n'; + args.forEach(function(file){ + var js = files[file]; + file = file.replace('lib/', ''); + buf += '\nrequire.register("' + file + '", function(module, exports, require){\n'; + buf += js; + buf += '\n}); // module: ' + file + '\n'; + }); + fs.writeFile('ejs.js', buf, function(err){ + if (err) throw err; + console.log(' \033[90m create : \033[0m\033[36m%s\033[0m', 'ejs.js'); + console.log(); + }); +} + +// refactored version of weepy's +// https://github.com/weepy/brequire/blob/master/browser/brequire.js + +var browser = { + + /** + * Require a module. + */ + + require: function require(p){ + var path = require.resolve(p) + , mod = require.modules[path]; + if (!mod) throw new Error('failed to require "' + p + '"'); + if (!mod.exports) { + mod.exports = {}; + mod.call(mod.exports, mod, mod.exports, require.relative(path)); + } + return mod.exports; + }, + + /** + * Resolve module path. + */ + + resolve: function(path){ + var orig = path + , reg = path + '.js' + , index = path + '/index.js'; + return require.modules[reg] && reg + || require.modules[index] && index + || orig; + }, + + /** + * Return relative require(). + */ + + relative: function(parent) { + return function(p){ + if ('.' != p.substr(0, 1)) return require(p); + + var path = parent.split('/') + , segs = p.split('/'); + path.pop(); + + for (var i = 0; i < segs.length; i++) { + var seg = segs[i]; + if ('..' == seg) path.pop(); + else if ('.' != seg) path.push(seg); + } + + return require(path.join('/')); + }; + }, + + /** + * Register a module. + */ + + register: function(path, fn){ + require.modules[path] = fn; + } +}; \ No newline at end of file diff --git a/node_modules/nodeunit/deps/ejs/test/ejs.test.js b/node_modules/nodeunit/deps/ejs/test/ejs.test.js new file mode 100644 index 0000000..624157d --- /dev/null +++ b/node_modules/nodeunit/deps/ejs/test/ejs.test.js @@ -0,0 +1,269 @@ + +/** + * Module dependencies. + */ + +var ejs = require('../') + , assert = require('assert'); + +module.exports = { + 'test .version': function(){ + assert.ok(/^\d+\.\d+\.\d+$/.test(ejs.version), 'Test .version format'); + }, + + 'test html': function(){ + assert.equal('

yay

', ejs.render('

yay

')); + }, + + 'test buffered code': function(){ + var html = '

tj

', + str = '

<%= name %>

', + locals = { name: 'tj' }; + assert.equal(html, ejs.render(str, { locals: locals })); + }, + + 'test unbuffered code': function(){ + var html = '

tj

', + str = '<% if (name) { %>

<%= name %>

<% } %>', + locals = { name: 'tj' }; + assert.equal(html, ejs.render(str, { locals: locals })); + }, + + 'test `scope` option': function(){ + var html = '

tj

', + str = '

<%= this %>

'; + assert.equal(html, ejs.render(str, { scope: 'tj' })); + }, + + 'test escaping': function(){ + assert.equal('<script>', ejs.render('<%= " + + + + + + + + diff --git a/node_modules/nodeunit/examples/nested/nested_reporter_test.unit.js b/node_modules/nodeunit/examples/nested/nested_reporter_test.unit.js new file mode 100644 index 0000000..612adcd --- /dev/null +++ b/node_modules/nodeunit/examples/nested/nested_reporter_test.unit.js @@ -0,0 +1,94 @@ +var testCase = require('nodeunit').testCase; +/* + This is an example test suite to demonstrate the nested test reporter. + Run with --reporter nested, e.g., + nodeunit --reporter nested nested_reporter_test.unit.js + + The test output should be something like: + + nested_reporter_test.unit.js + Test 0.1 (pass) + TC 1 + TC 1.1 + Test 1.1.1 (pass) + TC 2 + TC 2.1 + TC 2.1.1 + Test 2.1.1.1 (pass) + Test 2.1.1.2 (pass) + TC 2.2.1 + Test 2.2.1.1 (pass) + TC 2.2.1.1 + Test 2.2.1.1.1 (pass) + Test 2.2.1.2 (pass) + TC 3 + TC 3.1 + TC 3.1.1 + Test 3.1.1.1 (should fail) (fail) ✖ + AssertionError: false == true + // stack trace here. + + FAILURES: 1/8 assertions failed (6ms) +*/ + +module.exports = testCase({ + "Test 0.1": function(test) { + test.ok(true); + test.done(); + }, + + "TC 1": testCase({ + "TC 1.1": testCase({ + "Test 1.1.1": function(test) { + test.ok(true); + test.done(); + } + }) + }), + + "TC 2": testCase({ + "TC 2.1": testCase({ + "TC 2.1.1": testCase({ + "Test 2.1.1.1": function(test) { + test.ok(true); + test.done(); + }, + + "Test 2.1.1.2": function(test) { + test.ok(true); + test.done(); + } + }), + + "TC 2.2.1": testCase({ + "Test 2.2.1.1": function(test) { + test.ok(true); + test.done(); + }, + + "TC 2.2.1.1": testCase({ + "Test 2.2.1.1.1": function(test) { + test.ok(true); + test.done(); + }, + }), + + "Test 2.2.1.2": function(test) { + test.ok(true); + test.done(); + } + }) + }) + }), + + "TC 3": testCase({ + "TC 3.1": testCase({ + "TC 3.1.1": testCase({ + "Test 3.1.1.1 (should fail)": function(test) { + test.ok(false); + test.done(); + } + }) + }) + }) +}); diff --git a/node_modules/nodeunit/img/example_fail.png b/node_modules/nodeunit/img/example_fail.png new file mode 100644 index 0000000000000000000000000000000000000000..78ff4258cd574420da27fcf38b4711d02db58a92 GIT binary patch literal 38642 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 literal 0 HcmV?d00001 diff --git a/node_modules/nodeunit/img/example_machineout.png b/node_modules/nodeunit/img/example_machineout.png new file mode 100644 index 0000000000000000000000000000000000000000..c6bfa27b56900e91282095c43b34b4e67854a0cd GIT binary patch literal 422136 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 z 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
KTihal9Ajl|fXZjNHfLk6}?0P-qs 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%0AFUWX!S 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 +// +// 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 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. + + +var pSlice = Array.prototype.slice; + +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = exports; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({message: message, actual: actual, expected: expected}) + +assert.AssertionError = function AssertionError (options) { + this.name = "AssertionError"; + this.message = options.message; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + var stackStartFunction = options.stackStartFunction || fail; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } +}; +// code from util.inherits in node +assert.AssertionError.super_ = Error; + + +// EDITED FOR BROWSER COMPATIBILITY: replaced Object.create call +// TODO: test what effect this may have +var ctor = function () { this.constructor = assert.AssertionError; }; +ctor.prototype = Error.prototype; +assert.AssertionError.prototype = new ctor(); + + +assert.AssertionError.prototype.toString = function() { + if (this.message) { + return [this.name+":", this.message].join(' '); + } else { + return [ this.name+":" + , JSON.stringify(this.expected ) + , this.operator + , JSON.stringify(this.actual) + ].join(" "); + } +}; + +// assert.AssertionError instanceof Error + +assert.AssertionError.__proto__ = Error.prototype; + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +assert.ok = function ok(value, message) { + if (!!!value) fail(value, true, message, "==", assert.ok); +}; + +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, "==", assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, "!=", assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected)) { + fail(actual, expected, message, "deepEqual", assert.deepEqual); + } +}; + +var Buffer = null; +if (typeof require !== 'undefined' && typeof process !== 'undefined') { + try { + Buffer = require('buffer').Buffer; + } + catch (e) { + // May be a CommonJS environment other than Node.js + Buffer = null; + } +} + +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (actual instanceof Date && expected instanceof Date) { + return actual.getTime() === expected.getTime(); + + // 7.2.1 If the expcted value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object that refers to the same source and options + } else if (actual instanceof RegExp && expected instanceof RegExp) { + return actual.source === expected.source && + actual.global === expected.global && + actual.ignoreCase === expected.ignoreCase && + actual.multiline === expected.multiline; + + } else if (Buffer && actual instanceof Buffer && expected instanceof Buffer) { + return (function() { + var i, len; + + for (i = 0, len = expected.length; i < len; i++) { + if (actual[i] !== expected[i]) { + return false; + } + } + return actual.length === expected.length; + })(); + // 7.3. Other pairs that do not both pass typeof value == "object", + // equivalence is determined by ==. + } else if (typeof actual != 'object' && typeof expected != 'object') { + return actual == expected; + + // 7.4. For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical "prototype" property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } +} + +function isUndefinedOrNull (value) { + return value === null || value === undefined; +} + +function isArguments (object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv (a, b) { + if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) + return false; + // an identical "prototype" property. + if (a.prototype !== b.prototype) return false; + //~~~I've managed to break Object.keys through screwy arguments passing. + // Converting to array solves the problem. + if (isArguments(a)) { + if (!isArguments(b)) { + return false; + } + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b); + } + try{ + var ka = _keys(a), + kb = _keys(b), + key, i; + } catch (e) {//happens when one is a string literal and the other isn't + return false; + } + // having the same number of owned properties (keys incorporates hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key] )) + return false; + } + return true; +} + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected)) { + fail(actual, expected, message, "notDeepEqual", assert.notDeepEqual); + } +}; + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, "===", assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as determined by !==. +// assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, "!==", assert.notStrictEqual); + } +}; + +function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } + + if (expected instanceof RegExp) { + return expected.test(actual.message || actual); + } else if (actual instanceof expected) { + return true; + } else if (expected.call({}, actual) === true) { + return true; + } + + return false; +} + +function _throws(shouldThrow, block, expected, message) { + var actual; + + if (typeof expected === 'string') { + message = expected; + expected = null; + } + + try { + block(); + } catch (e) { + actual = e; + } + + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + + (message ? ' ' + message : '.'); + + if (shouldThrow && !actual) { + fail('Missing expected exception' + message); + } + + if (!shouldThrow && expectedException(actual, expected)) { + fail('Got unwanted exception' + message); + } + + if ((shouldThrow && actual && expected && + !expectedException(actual, expected)) || (!shouldThrow && actual)) { + throw actual; + } +} + +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [true].concat(pSlice.call(arguments))); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [false].concat(pSlice.call(arguments))); +}; + +assert.ifError = function (err) { if (err) {throw err;}}; diff --git a/node_modules/nodeunit/lib/core.js b/node_modules/nodeunit/lib/core.js new file mode 100644 index 0000000..5281bc7 --- /dev/null +++ b/node_modules/nodeunit/lib/core.js @@ -0,0 +1,318 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + * + * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. + * Only code on that line will be removed, it's mostly to avoid requiring code + * that is node specific + */ + +/** + * Module dependencies + */ + +var async = require('../deps/async'), //@REMOVE_LINE_FOR_BROWSER + nodeunit = require('./nodeunit'), //@REMOVE_LINE_FOR_BROWSER + types = require('./types'); //@REMOVE_LINE_FOR_BROWSER + + +/** + * Added for browser compatibility + */ + +var _keys = function (obj) { + if (Object.keys) { + return Object.keys(obj); + } + var keys = []; + for (var k in obj) { + if (obj.hasOwnProperty(k)) { + keys.push(k); + } + } + return keys; +}; + + +var _copy = function (obj) { + var nobj = {}; + var keys = _keys(obj); + for (var i = 0; i < keys.length; i += 1) { + nobj[keys[i]] = obj[keys[i]]; + } + return nobj; +}; + + +/** + * Runs a test function (fn) from a loaded module. After the test function + * calls test.done(), the callback is executed with an assertionList as its + * second argument. + * + * @param {String} name + * @param {Function} fn + * @param {Object} opt + * @param {Function} callback + * @api public + */ + +exports.runTest = function (name, fn, opt, callback) { + var options = types.options(opt); + + options.testStart(name); + var start = new Date().getTime(); + var test = types.test(name, start, options, callback); + + try { + fn(test); + } + catch (e) { + test.done(e); + } +}; + +/** + * Takes an object containing test functions or other test suites as properties + * and runs each in series. After all tests have completed, the callback is + * called with a list of all assertions as the second argument. + * + * If a name is passed to this function it is prepended to all test and suite + * names that run within it. + * + * @param {String} name + * @param {Object} suite + * @param {Object} opt + * @param {Function} callback + * @api public + */ + +exports.runSuite = function (name, suite, opt, callback) { + suite = wrapGroup(suite); + var keys = _keys(suite); + + async.concatSeries(keys, function (k, cb) { + var prop = suite[k], _name; + + _name = name ? [].concat(name, k) : [k]; + _name.toString = function () { + // fallback for old one + return this.join(' - '); + }; + + if (typeof prop === 'function') { + var in_name = false, + in_specific_test = (_name.toString() === opt.testFullSpec) ? true : false; + for (var i = 0; i < _name.length; i += 1) { + if (_name[i] === opt.testspec) { + in_name = true; + } + } + + if ((!opt.testFullSpec || in_specific_test) && (!opt.testspec || in_name)) { + if (opt.moduleStart) { + opt.moduleStart(); + } + exports.runTest(_name, suite[k], opt, cb); + } + else { + return cb(); + } + } + else { + exports.runSuite(_name, suite[k], opt, cb); + } + }, callback); +}; + +/** + * Run each exported test function or test suite from a loaded module. + * + * @param {String} name + * @param {Object} mod + * @param {Object} opt + * @param {Function} callback + * @api public + */ + +exports.runModule = function (name, mod, opt, callback) { + var options = _copy(types.options(opt)); + + var _run = false; + var _moduleStart = options.moduleStart; + + mod = wrapGroup(mod); + + function run_once() { + if (!_run) { + _run = true; + _moduleStart(name); + } + } + options.moduleStart = run_once; + + var start = new Date().getTime(); + + exports.runSuite(null, mod, options, function (err, a_list) { + var end = new Date().getTime(); + var assertion_list = types.assertionList(a_list, end - start); + options.moduleDone(name, assertion_list); + if (nodeunit.complete) { + nodeunit.complete(name, assertion_list); + } + callback(null, a_list); + }); +}; + +/** + * Treats an object literal as a list of modules keyed by name. Runs each + * module and finished with calling 'done'. You can think of this as a browser + * safe alternative to runFiles in the nodeunit module. + * + * @param {Object} modules + * @param {Object} opt + * @api public + */ + +// TODO: add proper unit tests for this function +exports.runModules = function (modules, opt) { + var all_assertions = []; + var options = types.options(opt); + var start = new Date().getTime(); + + async.concatSeries(_keys(modules), function (k, cb) { + exports.runModule(k, modules[k], options, cb); + }, + function (err, all_assertions) { + var end = new Date().getTime(); + options.done(types.assertionList(all_assertions, end - start)); + }); +}; + + +/** + * Wraps a test function with setUp and tearDown functions. + * Used by testCase. + * + * @param {Function} setUp + * @param {Function} tearDown + * @param {Function} fn + * @api private + */ + +var wrapTest = function (setUp, tearDown, fn) { + return function (test) { + var context = {}; + if (tearDown) { + var done = test.done; + test.done = function (err) { + try { + tearDown.call(context, function (err2) { + if (err && err2) { + test._assertion_list.push( + types.assertion({error: err}) + ); + return done(err2); + } + done(err || err2); + }); + } + catch (e) { + done(e); + } + }; + } + if (setUp) { + setUp.call(context, function (err) { + if (err) { + return test.done(err); + } + fn.call(context, test); + }); + } + else { + fn.call(context, test); + } + }; +}; + + +/** + * Returns a serial callback from two functions. + * + * @param {Function} funcFirst + * @param {Function} funcSecond + * @api private + */ + +var getSerialCallback = function (fns) { + if (!fns.length) { + return null; + } + return function (callback) { + var that = this; + var bound_fns = []; + for (var i = 0, len = fns.length; i < len; i++) { + (function (j) { + bound_fns.push(function () { + return fns[j].apply(that, arguments); + }); + })(i); + } + return async.series(bound_fns, callback); + }; +}; + + +/** + * Wraps a group of tests with setUp and tearDown functions. + * Used by testCase. + * + * @param {Object} group + * @param {Array} setUps - parent setUp functions + * @param {Array} tearDowns - parent tearDown functions + * @api private + */ + +var wrapGroup = function (group, setUps, tearDowns) { + var tests = {}; + + var setUps = setUps ? setUps.slice(): []; + var tearDowns = tearDowns ? tearDowns.slice(): []; + + if (group.setUp) { + setUps.push(group.setUp); + delete group.setUp; + } + if (group.tearDown) { + tearDowns.unshift(group.tearDown); + delete group.tearDown; + } + + var keys = _keys(group); + + for (var i = 0; i < keys.length; i += 1) { + var k = keys[i]; + if (typeof group[k] === 'function') { + tests[k] = wrapTest( + getSerialCallback(setUps), + getSerialCallback(tearDowns), + group[k] + ); + } + else if (typeof group[k] === 'object') { + tests[k] = wrapGroup(group[k], setUps, tearDowns); + } + } + return tests; +}; + + +/** + * Backwards compatibility for test suites using old testCase API + */ + +exports.testCase = function (suite) { + return suite; +}; diff --git a/node_modules/nodeunit/lib/nodeunit.js b/node_modules/nodeunit/lib/nodeunit.js new file mode 100644 index 0000000..e20e974 --- /dev/null +++ b/node_modules/nodeunit/lib/nodeunit.js @@ -0,0 +1,104 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + */ + +/** + * Module dependencies + */ + +var async = require('../deps/async'), + types = require('./types'), + utils = require('./utils'), + core = require('./core'), + reporters = require('./reporters'), + assert = require('./assert'), + path = require('path') + events = require('events'); + + +/** + * Export sub-modules. + */ + +exports.types = types; +exports.utils = utils; +exports.reporters = reporters; +exports.assert = assert; + +// backwards compatibility +exports.testrunner = { + run: function () { + console.log( + 'WARNING: nodeunit.testrunner is going to be deprecated, please ' + + 'use nodeunit.reporters.default instead!' + ); + return reporters['default'].run.apply(this, arguments); + } +}; + + +/** + * Export all core functions + */ + +for (var k in core) { + exports[k] = core[k]; +}; + + +/** + * Load modules from paths array and run all exported tests in series. If a path + * is a directory, load all supported file types inside it as modules. This only + * reads 1 level deep in the directory and does not recurse through + * sub-directories. + * + * @param {Array} paths + * @param {Object} opt + * @api public + */ + +exports.runFiles = function (paths, opt) { + var all_assertions = []; + var options = types.options(opt); + var start = new Date().getTime(); + + if (!paths.length) { + return options.done(types.assertionList(all_assertions)); + } + + utils.modulePaths(paths, function (err, files) { + if (err) throw err; + async.concatSeries(files, function (file, cb) { + var name = path.basename(file); + exports.runModule(name, require(file), options, cb); + }, + function (err, all_assertions) { + var end = new Date().getTime(); + exports.done() + options.done(types.assertionList(all_assertions, end - start)); + }); + }); + +}; + +/* Export all prototypes from events.EventEmitter */ +var label; +for (label in events.EventEmitter.prototype) { + exports[label] = events.EventEmitter.prototype[label]; +} + +/* Emit event 'complete' on completion of a test suite. */ +exports.complete = function(name, assertions) +{ + exports.emit('complete', name, assertions); +}; + +/* Emit event 'complete' on completion of all tests. */ +exports.done = function() +{ + exports.emit('done'); +}; + +module.exports = exports; diff --git a/node_modules/nodeunit/lib/reporters/browser.js b/node_modules/nodeunit/lib/reporters/browser.js new file mode 100644 index 0000000..9836c90 --- /dev/null +++ b/node_modules/nodeunit/lib/reporters/browser.js @@ -0,0 +1,121 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + * + * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. + * Only code on that line will be removed, its mostly to avoid requiring code + * that is node specific + */ + + +/** + * NOTE: this test runner is not listed in index.js because it cannot be + * used with the command-line tool, only inside the browser. + */ + + +/** + * Reporter info string + */ + +exports.info = "Browser-based test reporter"; + + +/** + * Run all tests within each module, reporting the results + * + * @param {Array} files + * @api public + */ + +exports.run = function (modules, options) { + var start = new Date().getTime(), div; + options = options || {}; + div = options.div || document.body; + + function setText(el, txt) { + if ('innerText' in el) { + el.innerText = txt; + } + else if ('textContent' in el){ + el.textContent = txt; + } + } + + function getOrCreate(tag, id) { + var el = document.getElementById(id); + if (!el) { + el = document.createElement(tag); + el.id = id; + div.appendChild(el); + } + return el; + }; + + var header = getOrCreate('h1', 'nodeunit-header'); + var banner = getOrCreate('h2', 'nodeunit-banner'); + var userAgent = getOrCreate('h2', 'nodeunit-userAgent'); + var tests = getOrCreate('ol', 'nodeunit-tests'); + var result = getOrCreate('p', 'nodeunit-testresult'); + + setText(userAgent, navigator.userAgent); + + nodeunit.runModules(modules, { + moduleStart: function (name) { + /*var mheading = document.createElement('h2'); + mheading.innerText = name; + results.appendChild(mheading); + module = document.createElement('ol'); + results.appendChild(module);*/ + }, + testDone: function (name, assertions) { + var test = document.createElement('li'); + var strong = document.createElement('strong'); + strong.innerHTML = name + ' (' + + '' + assertions.failures() + ', ' + + '' + assertions.passes() + ', ' + + assertions.length + + ')'; + test.className = assertions.failures() ? 'fail': 'pass'; + test.appendChild(strong); + + var aList = document.createElement('ol'); + aList.style.display = 'none'; + test.onclick = function () { + var d = aList.style.display; + aList.style.display = (d == 'none') ? 'block': 'none'; + }; + for (var i=0; i' + (a.error.stack || a.error) + ''; + li.className = 'fail'; + } + else { + li.innerHTML = a.message || a.method || 'no message'; + li.className = 'pass'; + } + aList.appendChild(li); + } + test.appendChild(aList); + tests.appendChild(test); + }, + done: function (assertions) { + var end = new Date().getTime(); + var duration = end - start; + + var failures = assertions.failures(); + banner.className = failures ? 'fail': 'pass'; + + result.innerHTML = 'Tests completed in ' + duration + + ' milliseconds.
' + + assertions.passes() + ' assertions of ' + + '' + assertions.length + ' passed, ' + + assertions.failures() + ' failed.'; + } + }); +}; diff --git a/node_modules/nodeunit/lib/reporters/default.js b/node_modules/nodeunit/lib/reporters/default.js new file mode 100644 index 0000000..9b4c66a --- /dev/null +++ b/node_modules/nodeunit/lib/reporters/default.js @@ -0,0 +1,131 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + */ + +/** + * Module dependencies + */ + +var nodeunit = require('../nodeunit'), + utils = require('../utils'), + fs = require('fs'), + track = require('../track'), + path = require('path'), + AssertionError = require('../assert').AssertionError; + +/** + * Reporter info string + */ + +exports.info = "Default tests reporter"; + + +/** + * Run all tests within each module, reporting the results to the command-line. + * + * @param {Array} files + * @api public + */ + +exports.run = function (files, options, callback) { + + if (!options) { + // load default options + var content = fs.readFileSync( + __dirname + '/../../bin/nodeunit.json', 'utf8' + ); + options = JSON.parse(content); + } + + var error = function (str) { + return options.error_prefix + str + options.error_suffix; + }; + var ok = function (str) { + return options.ok_prefix + str + options.ok_suffix; + }; + var bold = function (str) { + return options.bold_prefix + str + options.bold_suffix; + }; + var assertion_message = function (str) { + return options.assertion_prefix + str + options.assertion_suffix; + }; + + var start = new Date().getTime(); + var tracker = track.createTracker(function (tracker) { + if (tracker.unfinished()) { + console.log(''); + console.log(error(bold( + 'FAILURES: Undone tests (or their setups/teardowns): ' + ))); + var names = tracker.names(); + for (var i = 0; i < names.length; i += 1) { + console.log('- ' + names[i]); + } + console.log(''); + console.log('To fix this, make sure all tests call test.done()'); + process.reallyExit(tracker.unfinished()); + } + }); + + var opts = { + testspec: options.testspec, + testFullSpec: options.testFullSpec, + moduleStart: function (name) { + console.log('\n' + bold(name)); + }, + testDone: function (name, assertions) { + tracker.remove(name); + + if (!assertions.failures()) { + console.log('✔ ' + name); + } + else { + console.log(error('✖ ' + name) + '\n'); + assertions.forEach(function (a) { + if (a.failed()) { + a = utils.betterErrors(a); + if (a.error instanceof AssertionError && a.message) { + console.log( + 'Assertion Message: ' + + assertion_message(a.message) + ); + } + console.log(a.error.stack + '\n'); + } + }); + } + }, + done: function (assertions, end) { + var end = end || new Date().getTime(); + var duration = end - start; + if (assertions.failures()) { + console.log( + '\n' + bold(error('FAILURES: ')) + assertions.failures() + + '/' + assertions.length + ' assertions failed (' + + assertions.duration + 'ms)' + ); + } + else { + console.log( + '\n' + bold(ok('OK: ')) + assertions.length + + ' assertions (' + assertions.duration + 'ms)' + ); + } + + if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined); + }, + testStart: function(name) { + tracker.put(name); + } + }; + if (files && files.length) { + var paths = files.map(function (p) { + return path.join(process.cwd(), p); + }); + nodeunit.runFiles(paths, opts); + } else { + nodeunit.runModules(files,opts); + } +}; diff --git a/node_modules/nodeunit/lib/reporters/eclipse.js b/node_modules/nodeunit/lib/reporters/eclipse.js new file mode 100644 index 0000000..6775ff1 --- /dev/null +++ b/node_modules/nodeunit/lib/reporters/eclipse.js @@ -0,0 +1,104 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + */ + +/** + * Module dependencies + */ + +var nodeunit = require('../nodeunit'), + utils = require('../utils'), + fs = require('fs'), + track = require('../track'), + path = require('path'), + AssertionError = require('../assert').AssertionError; + +/** + * Reporter info string + */ + +exports.info = "Reporter for eclipse plugin"; + + +/** + * Run all tests within each module, reporting the results to the command-line. + * + * @param {Array} files + * @api public + */ + +exports.run = function (files, options, callback) { + + var start = new Date().getTime(); + var paths = files.map(function (p) { + if (p.indexOf('/') === 0) { + return p; + } + return path.join(process.cwd(), p); + }); + var tracker = track.createTracker(function (tracker) { + if (tracker.unfinished()) { + console.log(''); + console.log('FAILURES: Undone tests (or their setups/teardowns): '); + var names = tracker.names(); + for (var i = 0; i < names.length; i += 1) { + console.log('- ' + names[i]); + } + console.log(''); + console.log('To fix this, make sure all tests call test.done()'); + process.reallyExit(tracker.unfinished()); + } + }); + + nodeunit.runFiles(paths, { + testspec: undefined, + moduleStart: function (name) { + console.log('\n' + name); + }, + testDone: function (name, assertions) { + tracker.remove(name); + + if (!assertions.failures()) { + console.log('✔ ' + name); + } + else { + console.log('✖ ' + name + '\n'); + assertions.forEach(function (a) { + if (a.failed()) { + a = utils.betterErrors(a); + if (a.error instanceof AssertionError && a.message) { + console.log( + 'Assertion Message: ' + a.message + ); + } + console.log(a.error.stack + '\n'); + } + }); + } + }, + done: function (assertions, end) { + var end = end || new Date().getTime(); + var duration = end - start; + if (assertions.failures()) { + console.log( + '\n' + 'FAILURES: ' + assertions.failures() + + '/' + assertions.length + ' assertions failed (' + + assertions.duration + 'ms)' + ); + } + else { + console.log( + '\n' + 'OK: ' + assertions.length + + ' assertions (' + assertions.duration + 'ms)' + ); + } + + if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined); + }, + testStart: function (name) { + tracker.put(name); + } + }); +}; diff --git a/node_modules/nodeunit/lib/reporters/html.js b/node_modules/nodeunit/lib/reporters/html.js new file mode 100644 index 0000000..80866b6 --- /dev/null +++ b/node_modules/nodeunit/lib/reporters/html.js @@ -0,0 +1,110 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + */ + +/** + * Module dependencies + */ + +var nodeunit = require('../nodeunit'), + utils = require('../utils'), + fs = require('fs'), + path = require('path'), + AssertionError = require('assert').AssertionError; + +/** + * Reporter info string + */ + +exports.info = "Report tests result as HTML"; + +/** + * Run all tests within each module, reporting the results to the command-line. + * + * @param {Array} files + * @api public + */ + +exports.run = function (files, options, callback) { + + var start = new Date().getTime(); + var paths = files.map(function (p) { + return path.join(process.cwd(), p); + }); + + console.log(''); + console.log(''); + console.log(''); + console.log(''); + console.log(''); + console.log(''); + nodeunit.runFiles(paths, { + testspec: options.testspec, + testFullSpec: options.testFullSpec, + moduleStart: function (name) { + console.log('

' + name + '

'); + console.log('
    '); + }, + testDone: function (name, assertions) { + if (!assertions.failures()) { + console.log('
  1. ' + name + '
  2. '); + } + else { + console.log('
  3. ' + name); + assertions.forEach(function (a) { + if (a.failed()) { + a = utils.betterErrors(a); + if (a.error instanceof AssertionError && a.message) { + console.log('
    ' + + 'Assertion Message: ' + a.message + + '
    '); + } + console.log('
    ');
    +                        console.log(a.error.stack);
    +                        console.log('
    '); + } + }); + console.log('
  4. '); + } + }, + moduleDone: function () { + console.log('
'); + }, + done: function (assertions) { + var end = new Date().getTime(); + var duration = end - start; + if (assertions.failures()) { + console.log( + '

FAILURES: ' + assertions.failures() + + '/' + assertions.length + ' assertions failed (' + + assertions.duration + 'ms)

' + ); + } + else { + console.log( + '

OK: ' + assertions.length + + ' assertions (' + assertions.duration + 'ms)

' + ); + } + console.log(''); + console.log(''); + + if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined); + } + }); +}; diff --git a/node_modules/nodeunit/lib/reporters/index.js b/node_modules/nodeunit/lib/reporters/index.js new file mode 100644 index 0000000..b3989c0 --- /dev/null +++ b/node_modules/nodeunit/lib/reporters/index.js @@ -0,0 +1,14 @@ +module.exports = { + 'junit': require('./junit'), + 'default': require('./default'), + 'skip_passed': require('./skip_passed'), + 'minimal': require('./minimal'), + 'html': require('./html'), + 'eclipse': require('./eclipse'), + 'machineout': require('./machineout'), + 'tap': require('./tap'), + 'nested': require('./nested'), + 'verbose' : require('./verbose') + // browser test reporter is not listed because it cannot be used + // with the command line tool, only inside a browser. +}; diff --git a/node_modules/nodeunit/lib/reporters/junit.js b/node_modules/nodeunit/lib/reporters/junit.js new file mode 100644 index 0000000..d9a1d02 --- /dev/null +++ b/node_modules/nodeunit/lib/reporters/junit.js @@ -0,0 +1,180 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + */ + +/** + * Module dependencies + */ + +var nodeunit = require('../nodeunit'), + utils = require('../utils'), + fs = require('fs'), + path = require('path'), + async = require('../../deps/async'), + AssertionError = require('assert').AssertionError, + child_process = require('child_process'), + ejs = require('../../deps/ejs'); + + +/** + * Reporter info string + */ + +exports.info = "jUnit XML test reports"; + + +/** + * Ensures a directory exists using mkdir -p. + * + * @param {String} path + * @param {Function} callback + * @api private + */ + +var ensureDir = function (path, callback) { + var mkdir = child_process.spawn('mkdir', ['-p', path]); + mkdir.on('error', function (err) { + callback(err); + callback = function(){}; + }); + mkdir.on('exit', function (code) { + if (code === 0) callback(); + else callback(new Error('mkdir exited with code: ' + code)); + }); +}; + + +/** + * Returns absolute version of a path. Relative paths are interpreted + * relative to process.cwd() or the cwd parameter. Paths that are already + * absolute are returned unaltered. + * + * @param {String} p + * @param {String} cwd + * @return {String} + * @api public + */ + +var abspath = function (p, /*optional*/cwd) { + if (p[0] === '/') return p; + cwd = cwd || process.cwd(); + return path.normalize(path.join(cwd, p)); +}; + + +/** + * Run all tests within each module, reporting the results to the command-line, + * then writes out junit-compatible xml documents. + * + * @param {Array} files + * @api public + */ + +exports.run = function (files, opts, callback) { + if (!opts.output) { + console.error( + 'Error: No output directory defined.\n' + + '\tEither add an "output" property to your nodeunit.json config ' + + 'file, or\n\tuse the --output command line option.' + ); + return; + } + opts.output = abspath(opts.output); + var error = function (str) { + return opts.error_prefix + str + opts.error_suffix; + }; + var ok = function (str) { + return opts.ok_prefix + str + opts.ok_suffix; + }; + var bold = function (str) { + return opts.bold_prefix + str + opts.bold_suffix; + }; + + var start = new Date().getTime(); + var paths = files.map(function (p) { + return path.join(process.cwd(), p); + }); + + var modules = {} + var curModule; + + nodeunit.runFiles(paths, { + testspec: opts.testspec, + testFullSpec: opts.testFullSpec, + moduleStart: function (name) { + curModule = { + errorCount: 0, + failureCount: 0, + tests: 0, + testcases: [], + name: name + }; + modules[name] = curModule; + }, + testDone: function (name, assertions) { + var testcase = {name: name}; + for (var i=0; i name_slice(['TC1', 'TC1.1', 'mytest'], 1); + * "TC1,TC1.1" + */ + var name_slice = function (name_arr, end_index) { + return name_arr.slice(0, end_index + 1).join(","); + }; + + var indent = (function () { + var txt = ''; + var i; + for (i = 0; i < spaces_per_indent; i++) { + txt += ' '; + } + return txt; + }()); + + // Indent once for each indent_level + var add_indent = function (txt, indent_level) { + var k; + for (k = 0; k < indent_level; k++) { + txt += indent; + } + return txt; + }; + + // If it's not the last element of the name_arr, it's a testCase. + var is_testCase = function (name_arr, index) { + return index === name_arr.length - 1 ? false : true; + }; + + var testCase_line = function (txt) { + return txt + "\n"; + }; + + /** + * Prints (console.log) the nested test status line(s). + * + * @param {Array} name_arr - Array of name elements. + * @param {String} status - either 'pass' or 'fail'. + * @example + * > print_status(['TC1', 'TC1.1', 'mytest'], 'pass'); + * TC1 + * TC1.1 + * mytest (pass) + */ + var print_status = function (name_arr, status) { + var txt = ''; + var _name_slice, part, i; + for (i = 0; i < name_arr.length; i++) { + _name_slice = name_slice(name_arr, i); + part = name_arr[i]; + if (!tracker.already_printed[_name_slice]) { + txt = add_indent(txt, i); + if (is_testCase(name_arr, i)) { + txt += testCase_line(part); + } else { + txt += status_text(part, status); + } + tracker.already_printed[_name_slice] = true; + } + } + console.log(txt); + }; + + nodeunit.runFiles(paths, { + testspec: options.testspec, + testFullSpec: options.testFullSpec, + moduleStart: function (name) { + console.log('\n' + bold(name)); + }, + testDone: function (name, assertions) { + tracker.remove(name); + + if (!assertions.failures()) { + print_status(name, 'pass'); + } else { + print_status(name, 'fail'); + assertions.forEach(function (a) { + if (a.failed()) { + a = utils.betterErrors(a); + if (a.error instanceof AssertionError && a.message) { + console.log( + 'Assertion Message: ' + + assertion_message(a.message) + ); + } + console.log(a.error.stack + '\n'); + } + }); + } + }, + done: function (assertions, end) { + end = end || new Date().getTime(); + var duration = end - start; + if (assertions.failures()) { + console.log( + '\n' + bold(error('FAILURES: ')) + assertions.failures() + + '/' + assertions.length + ' assertions failed (' + + assertions.duration + 'ms)' + ); + } else { + console.log( + '\n' + bold(ok('OK: ')) + assertions.length + + ' assertions (' + assertions.duration + 'ms)' + ); + } + }, + testStart: function (name) { + tracker.put(name); + } + }); +}; diff --git a/node_modules/nodeunit/lib/reporters/skip_passed.js b/node_modules/nodeunit/lib/reporters/skip_passed.js new file mode 100644 index 0000000..299a99a --- /dev/null +++ b/node_modules/nodeunit/lib/reporters/skip_passed.js @@ -0,0 +1,108 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + */ + +/** + * Module dependencies + */ + +var nodeunit = require('../nodeunit'), + utils = require('../utils'), + fs = require('fs'), + path = require('path'), + AssertionError = require('assert').AssertionError; + +/** + * Reporter info string + */ + +exports.info = "Skip passed tests output"; + +/** + * Run all tests within each module, reporting the results to the command-line. + * + * @param {Array} files + * @api public + */ + +exports.run = function (files, options, callback) { + + if (!options) { + // load default options + var content = fs.readFileSync( + __dirname + '/../../bin/nodeunit.json', 'utf8' + ); + options = JSON.parse(content); + } + + var error = function (str) { + return options.error_prefix + str + options.error_suffix; + }; + var ok = function (str) { + return options.ok_prefix + str + options.ok_suffix; + }; + var bold = function (str) { + return options.bold_prefix + str + options.bold_suffix; + }; + var assertion_message = function (str) { + return options.assertion_prefix + str + options.assertion_suffix; + }; + + var start = new Date().getTime(); + var paths = files.map(function (p) { + return path.join(process.cwd(), p); + }); + + nodeunit.runFiles(paths, { + testspec: options.testspec, + testFullSpec: options.testFullSpec, + moduleStart: function (name) { + console.log('\n' + bold(name)); + }, + testDone: function (name, assertions) { + if (assertions.failures()) { + console.log(error('✖ ' + name) + '\n'); + assertions.forEach(function (a) { + if (a.failed()) { + a = utils.betterErrors(a); + if (a.error instanceof AssertionError && a.message) { + console.log( + 'Assertion Message: ' + assertion_message(a.message) + ); + } + console.log(a.error.stack + '\n'); + } + }); + } + }, + moduleDone: function (name, assertions) { + if (!assertions.failures()) { + console.log('✔ all tests passed'); + } + else { + console.log(error('✖ some tests failed')); + } + }, + done: function (assertions) { + var end = new Date().getTime(); + var duration = end - start; + if (assertions.failures()) { + console.log( + '\n' + bold(error('FAILURES: ')) + assertions.failures() + + '/' + assertions.length + ' assertions failed (' + + assertions.duration + 'ms)' + ); + } + else { + console.log( + '\n' + bold(ok('OK: ')) + assertions.length + + ' assertions (' + assertions.duration + 'ms)' + ); + } + + if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined); + } + }); +}; diff --git a/node_modules/nodeunit/lib/reporters/tap.js b/node_modules/nodeunit/lib/reporters/tap.js new file mode 100644 index 0000000..b057460 --- /dev/null +++ b/node_modules/nodeunit/lib/reporters/tap.js @@ -0,0 +1,65 @@ +/** + * Module dependencies + */ + +var nodeunit = require('../nodeunit'), + path = require('path'), + assert = require('tap-assert'), + TapProducer = require('tap-producer'); + +/** + * Reporter info string + */ + +exports.info = "TAP output"; + +/** + * Run all tests within each module, reporting the results to the command-line. + * + * @param {Array} files + * @api public + */ + +exports.run = function (files, options) { + + if (!options) { + // load default options + var content = fs.readFileSync( + __dirname + '/../../bin/nodeunit.json', 'utf8' + ); + options = JSON.parse(content); + } + + var paths = files.map(function (p) { + return path.join(process.cwd(), p); + }); + var output = new TapProducer(); + output.pipe(process.stdout); + + nodeunit.runFiles(paths, { + testStart: function (name) { + output.write(name.toString()); + }, + testDone: function (name, assertions) { + assertions.forEach(function (e) { + var extra = {}; + if (e.error) { + extra.error = { + name: e.error.name, + message: e.error.message, + stack: e.error.stack.split(/\n/).filter(function (line) { + // exclude line of "types.js" + return ! RegExp(/types.js:83:39/).test(line); + }).join('\n') + }; + extra.wanted = e.error.expected; + extra.found = e.error.actual; + } + output.write(assert(e.passed(), e.message, extra)); + }); + }, + done: function (assertions) { + output.end(); + } + }); +}; diff --git a/node_modules/nodeunit/lib/reporters/verbose.js b/node_modules/nodeunit/lib/reporters/verbose.js new file mode 100644 index 0000000..228271b --- /dev/null +++ b/node_modules/nodeunit/lib/reporters/verbose.js @@ -0,0 +1,123 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + */ + +/** + * Module dependencies + */ + +var nodeunit = require('../nodeunit'), + utils = require('../utils'), + fs = require('fs'), + track = require('../track'), + path = require('path'); + AssertionError = require('../assert').AssertionError; + +/** + * Reporter info string + */ + +exports.info = "Verbose tests reporter" + + +/** + * Run all tests within each module, reporting the results to the command-line. + * + * @param {Array} files + * @api public + */ + +exports.run = function (files, options) { + + if (!options) { + // load default options + var content = fs.readFileSync( + __dirname + '/../../bin/nodeunit.json', 'utf8' + ); + options = JSON.parse(content); + } + + var error = function (str) { + return options.error_prefix + str + options.error_suffix; + }; + var ok = function (str) { + return options.ok_prefix + str + options.ok_suffix; + }; + var bold = function (str) { + return options.bold_prefix + str + options.bold_suffix; + }; + var assertion_message = function (str) { + return options.assertion_prefix + str + options.assertion_suffix; + }; + + var start = new Date().getTime(); + var paths = files.map(function (p) { + return path.join(process.cwd(), p); + }); + var tracker = track.createTracker(function (tracker) { + if (tracker.unfinished()) { + console.log(''); + console.log(error(bold( + 'FAILURES: Undone tests (or their setups/teardowns): ' + ))); + var names = tracker.names(); + for (var i = 0; i < names.length; i += 1) { + console.log('- ' + names[i]); + } + console.log(''); + console.log('To fix this, make sure all tests call test.done()'); + process.reallyExit(tracker.unfinished()); + } + }); + + nodeunit.runFiles(paths, { + testspec: options.testspec, + testFullSpec: options.testFullSpec, + moduleStart: function (name) { + console.log('\n' + bold(name)); + }, + testDone: function (name, assertions) { + tracker.remove(name); + + if (!assertions.failures()) { + console.log('✔ ' + name); + } + else { + console.log(error('✖ ' + name)); + } + // verbose so print everything + assertions.forEach(function (a) { + if (a.failed()) { + console.log(error(' ✖ ' + a.message)); + a = utils.betterErrors(a); + console.log(' ' + a.error.stack); + } + else { + console.log(' ✔ ' + a.message); + } + }); + }, + done: function (assertions, end) { + var end = end || new Date().getTime(); + var duration = end - start; + if (assertions.failures()) { + console.log( + '\n' + bold(error('FAILURES: ')) + assertions.failures() + + '/' + assertions.length + ' assertions failed (' + + assertions.duration + 'ms)' + ); + } + else { + console.log( + '\n' + bold(ok('OK: ')) + assertions.length + + ' assertions (' + assertions.duration + 'ms)' + ); + } + }, + testStart: function(name) { + tracker.put(name); + } + }); +}; diff --git a/node_modules/nodeunit/lib/track.js b/node_modules/nodeunit/lib/track.js new file mode 100644 index 0000000..5af98ad --- /dev/null +++ b/node_modules/nodeunit/lib/track.js @@ -0,0 +1,48 @@ +/*! + * Simple util module to track tests. Adds a process.exit hook to print + * the undone tests. + */ + + +exports.createTracker = function (on_exit) { + var names = {}; + var tracker = { + names: function () { + var arr = []; + for (var k in names) { + if (names.hasOwnProperty(k)) { + arr.push(k); + } + } + return arr; + }, + unfinished: function () { + return tracker.names().length; + }, + put: function (testname) { + names[testname] = testname; + }, + remove: function (testname) { + delete names[testname]; + } + }; + + process.on('exit', function() { + on_exit = on_exit || exports.default_on_exit; + on_exit(tracker); + }); + + return tracker; +}; + +exports.default_on_exit = function (tracker) { + if (tracker.unfinished()) { + console.log(''); + console.log('Undone tests (or their setups/teardowns): '); + var names = tracker.names(); + for (var i = 0; i < names.length; i += 1) { + console.log(names[i]); + } + process.reallyExit(tracker.unfinished()); + } +}; diff --git a/node_modules/nodeunit/lib/types.js b/node_modules/nodeunit/lib/types.js new file mode 100644 index 0000000..2cdd1ef --- /dev/null +++ b/node_modules/nodeunit/lib/types.js @@ -0,0 +1,189 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + * + * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. + * Only code on that line will be removed, it's mostly to avoid requiring code + * that is node specific + */ + +/** + * Module dependencies + */ + +var assert = require('./assert'), //@REMOVE_LINE_FOR_BROWSER + async = require('../deps/async'); //@REMOVE_LINE_FOR_BROWSER + + +/** + * Creates assertion objects representing the result of an assert call. + * Accepts an object or AssertionError as its argument. + * + * @param {object} obj + * @api public + */ + +exports.assertion = function (obj) { + return { + method: obj.method || '', + message: obj.message || (obj.error && obj.error.message) || '', + error: obj.error, + passed: function () { + return !this.error; + }, + failed: function () { + return Boolean(this.error); + } + }; +}; + +/** + * Creates an assertion list object representing a group of assertions. + * Accepts an array of assertion objects. + * + * @param {Array} arr + * @param {Number} duration + * @api public + */ + +exports.assertionList = function (arr, duration) { + var that = arr || []; + that.failures = function () { + var failures = 0; + for (var i = 0; i < this.length; i += 1) { + if (this[i].failed()) { + failures += 1; + } + } + return failures; + }; + that.passes = function () { + return that.length - that.failures(); + }; + that.duration = duration || 0; + return that; +}; + +/** + * Create a wrapper function for assert module methods. Executes a callback + * after it's complete with an assertion object representing the result. + * + * @param {Function} callback + * @api private + */ + +var assertWrapper = function (callback) { + return function (new_method, assert_method, arity) { + return function () { + var message = arguments[arity - 1]; + var a = exports.assertion({method: new_method, message: message}); + try { + assert[assert_method].apply(null, arguments); + } + catch (e) { + a.error = e; + } + callback(a); + }; + }; +}; + +/** + * Creates the 'test' object that gets passed to every test function. + * Accepts the name of the test function as its first argument, followed by + * the start time in ms, the options object and a callback function. + * + * @param {String} name + * @param {Number} start + * @param {Object} options + * @param {Function} callback + * @api public + */ + +exports.test = function (name, start, options, callback) { + var expecting; + var a_list = []; + + var wrapAssert = assertWrapper(function (a) { + a_list.push(a); + if (options.log) { + async.nextTick(function () { + options.log(a); + }); + } + }); + + var test = { + done: function (err) { + if (expecting !== undefined && expecting !== a_list.length) { + var e = new Error( + 'Expected ' + expecting + ' assertions, ' + + a_list.length + ' ran' + ); + var a1 = exports.assertion({method: 'expect', error: e}); + a_list.push(a1); + if (options.log) { + async.nextTick(function () { + options.log(a1); + }); + } + } + if (err) { + var a2 = exports.assertion({error: err}); + a_list.push(a2); + if (options.log) { + async.nextTick(function () { + options.log(a2); + }); + } + } + var end = new Date().getTime(); + async.nextTick(function () { + var assertion_list = exports.assertionList(a_list, end - start); + options.testDone(name, assertion_list); + callback(null, a_list); + }); + }, + ok: wrapAssert('ok', 'ok', 2), + same: wrapAssert('same', 'deepEqual', 3), + equals: wrapAssert('equals', 'equal', 3), + expect: function (num) { + expecting = num; + }, + _assertion_list: a_list + }; + // add all functions from the assert module + for (var k in assert) { + if (assert.hasOwnProperty(k)) { + test[k] = wrapAssert(k, k, assert[k].length); + } + } + return test; +}; + +/** + * Ensures an options object has all callbacks, adding empty callback functions + * if any are missing. + * + * @param {Object} opt + * @return {Object} + * @api public + */ + +exports.options = function (opt) { + var optionalCallback = function (name) { + opt[name] = opt[name] || function () {}; + }; + + optionalCallback('moduleStart'); + optionalCallback('moduleDone'); + optionalCallback('testStart'); + optionalCallback('testDone'); + //optionalCallback('log'); + + // 'done' callback is not optional. + + return opt; +}; diff --git a/node_modules/nodeunit/lib/utils.js b/node_modules/nodeunit/lib/utils.js new file mode 100644 index 0000000..5efd26c --- /dev/null +++ b/node_modules/nodeunit/lib/utils.js @@ -0,0 +1,203 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + */ + +/** + * Module dependencies + */ + +var async = require('../deps/async'), + fs = require('fs'), + util = require('util'), + Script = process.binding('evals').Script || process.binding('evals').NodeScript, + http = require('http'); + + +/** + * Detect if coffee-script is available and search for .coffee as an + * extension in modulePaths if it is. + */ + +var extensionPattern; +try { + require('coffee-script'); + extensionPattern = /\.(?:js|coffee)$/; +} +catch (e) { + extensionPattern = /\.js$/; +} + + +/** + * Finds all modules at each path in an array, If a path is a directory, it + * returns all supported file types inside it. This only reads 1 level deep in + * the directory and does not recurse through sub-directories. + * + * The extension (.js, .coffee etc) is stripped from the filenames so they can + * simply be require()'ed. + * + * @param {Array} paths + * @param {Function} callback + * @api public + */ + +exports.modulePaths = function (paths, callback) { + async.concat(paths, function (p, cb) { + fs.stat(p, function (err, stats) { + if (err) { + return cb(err); + } + if (stats.isFile()) { + return cb(null, [p]); + } + if (stats.isDirectory()) { + fs.readdir(p, function (err, files) { + if (err) { + return cb(err); + } + + // filter out any filenames with unsupported extensions + var modules = files.filter(function (filename) { + return extensionPattern.exec(filename); + }); + + // remove extension from module name and prepend the + // directory path + var fullpaths = modules.map(function (filename) { + var mod_name = filename.replace(extensionPattern, ''); + return [p, mod_name].join('/'); + }); + + // sort filenames here, because Array.map changes order + fullpaths.sort(); + + cb(null, fullpaths); + }); + } + }); + }, callback); +}; + +/** + * Evaluates JavaScript files in a sandbox, returning the context. The first + * argument can either be a single filename or an array of filenames. If + * multiple filenames are given their contents are concatenated before + * evalution. The second argument is an optional context to use for the sandbox. + * + * @param files + * @param {Object} sandbox + * @return {Object} + * @api public + */ + +exports.sandbox = function (files, /*optional*/sandbox) { + var source, script, result; + if (!(files instanceof Array)) { + files = [files]; + } + source = files.map(function (file) { + return fs.readFileSync(file, 'utf8'); + }).join(''); + + if (!sandbox) { + sandbox = {}; + } + script = new Script(source); + result = script.runInNewContext(sandbox); + return sandbox; +}; + +/** + * Provides a http request, response testing environment. + * + * Example: + * + * var httputil = require('nodeunit').utils.httputil + * exports.testSomething = function(test) { + * httputil(function (req, resp) { + * resp.writeHead(200, {}); + * resp.end('test data'); + * }, + * function(server, client) { + * client.fetch('GET', '/', {}, function(resp) { + * test.equal('test data', resp.body); + * server.close(); + * test.done(); + * }) + * }); + * }; + * + * @param {Function} cgi + * @param {Function} envReady + * @api public + */ +exports.httputil = function (cgi, envReady) { + var hostname = process.env.HOSTNAME || 'localhost'; + var port = process.env.PORT || 3000; + + var server = http.createServer(cgi); + server.listen(port, hostname); + + var client = http.createClient(port, hostname); + client.fetch = function (method, path, headers, respReady) { + var request = this.request(method, path, headers); + request.end(); + request.on('response', function (response) { + response.setEncoding('utf8'); + response.on('data', function (chunk) { + if (response.body) { + response.body += chunk; + } else { + response.body = chunk; + } + }); + response.on('end', function () { + if (response.headers['content-type'] === 'application/json') { + response.bodyAsObject = JSON.parse(response.body); + } + respReady(response); + }); + }); + }; + + process.nextTick(function () { + if (envReady && typeof envReady === 'function') { + envReady(server, client); + } + }); +}; + + +/** + * Improves formatting of AssertionError messages to make deepEqual etc more + * readable. + * + * @param {Object} assertion + * @return {Object} + * @api public + */ + +exports.betterErrors = function (assertion) { + if (!assertion.error) return assertion; + + var e = assertion.error; + if (e.actual && e.expected) { + var actual = util.inspect(e.actual, false, 10).replace(/\n$/, ''); + var expected = util.inspect(e.expected, false, 10).replace(/\n$/, ''); + var multiline = ( + actual.indexOf('\n') !== -1 || + expected.indexOf('\n') !== -1 + ); + var spacing = (multiline ? '\n' : ' '); + e._message = e.message; + e.stack = ( + e.name + ':' + spacing + + actual + spacing + e.operator + spacing + + expected + '\n' + + e.stack.split('\n').slice(1).join('\n') + ); + } + return assertion; +}; diff --git a/node_modules/nodeunit/man1/nodeunit.1 b/node_modules/nodeunit/man1/nodeunit.1 new file mode 100644 index 0000000..450772d --- /dev/null +++ b/node_modules/nodeunit/man1/nodeunit.1 @@ -0,0 +1,95 @@ +.\" Generated with Ronnjs/v0.1 +.\" http://github.com/kapouer/ronnjs/ +. +.TH "NODEUNIT" "1" "October 2010" "" "" +. +.SH "NAME" +\fBnodeunit\fR \-\- simple node\.js unit testing tool +. +.SH "SYNOPSIS" +. +.nf +nodeunit [options] [ \.\.\.] +. +.fi +. +.SH "DESCRIPTION" +Nodeunit is a simple unit testing tool based on the node\.js assert module\. +. +.IP "\(bu" 4 +Simple to use +. +.IP "\(bu" 4 +Just export the tests from a module +. +.IP "\(bu" 4 +Helps you avoid common pitfalls when testing asynchronous code +. +.IP "\(bu" 4 +Easy to add test cases with setUp and tearDown functions if you wish +. +.IP "\(bu" 4 +Allows the use of mocks and stubs +. +.IP "" 0 +. +.SH "OPTIONS" + \fB\-\-config FILE\fR: +. +.br + Load config options from a JSON file, allows the customisation + of color schemes for the default test reporter etc\. + See bin/nodeunit\.json for current available options\. +. +.P + \fB\-\-reporter FILE\fR: +. +.br + You can set the test reporter to a custom module or on of the modules + in nodeunit/lib/reporters, when omitted, the default test runner is used\. +. +.P + \fB\-\-list\-reporters\fR: +. +.br + List available build\-in reporters\. +. +.P + \fB\-h\fR, \fB\-\-help\fR: +. +.br + Display the help and exit\. +. +.P + \fB\-v\fR, \fB\-\-version\fR: +. +.br + Output version information and exit\. +. +.P + \fB\fR: + You can run nodeunit on specific files or on all \fI*\.js\fR files inside +. +.br + a directory\. +. +.SH "AUTHORS" +Written by Caolan McMahon and other nodeunit contributors\. +. +.br +Contributors list: \fIhttp://github\.com/caolan/nodeunit/contributors\fR\|\. +. +.SH "REPORTING BUGS" +Report nodeunit bugs to \fIhttp://github\.com/caolan/nodeunit/issues\fR\|\. +. +.SH "COPYRIGHT" +Copyright © 2010 Caolan McMahon\. +. +.br +Nodeunit has been released under the MIT license: +. +.br +\fIhttp://github\.com/caolan/nodeunit/raw/master/LICENSE\fR\|\. +. +.SH "SEE ALSO" +node(1) diff --git a/node_modules/nodeunit/node_modules/tap-assert/AUTHORS b/node_modules/nodeunit/node_modules/tap-assert/AUTHORS new file mode 100644 index 0000000..96726f8 --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-assert/AUTHORS @@ -0,0 +1,2 @@ +Isaac Z. Schlueter (http://blog.izs.me) +baudehlo diff --git a/node_modules/nodeunit/node_modules/tap-assert/LICENSE b/node_modules/nodeunit/node_modules/tap-assert/LICENSE new file mode 100644 index 0000000..05a4010 --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-assert/LICENSE @@ -0,0 +1,23 @@ +Copyright 2009, 2010, 2011 Isaac Z. Schlueter. +All rights reserved. + +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/node_modules/nodeunit/node_modules/tap-assert/README.md b/node_modules/nodeunit/node_modules/tap-assert/README.md new file mode 100644 index 0000000..6792aa6 --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-assert/README.md @@ -0,0 +1,3 @@ +An assert module for node-tap. + +More coming. diff --git a/node_modules/nodeunit/node_modules/tap-assert/assert.js b/node_modules/nodeunit/node_modules/tap-assert/assert.js new file mode 100644 index 0000000..8d3bba0 --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-assert/assert.js @@ -0,0 +1,396 @@ +// an assert module that returns tappable data for each assertion. + +module.exports = assert + +var syns = {} + , id = 1 + +function assert (ok, message, extra) { + if (extra && extra.skip) return assert.skip(message, extra) + + //console.error("assert %j", [ok, message, extra]) + //if (extra && extra.skip) return assert.skip(message, extra) + //console.error("assert", [ok, message, extra]) + ok = !!ok + var res = { id : id ++, ok: ok } + + var caller = getCaller(extra && extra.error) + if (extra && extra.error) { + res.type = extra.error.name + res.message = extra.error.message + res.code = extra.error.code + || extra.error.type + res.errno = extra.error.errno + delete extra.error + } + if (caller.file) { + res.file = caller.file + res.line = +caller.line + res.column = +caller.column + } + res.stack = caller.stack + + res.name = message || "(unnamed assert)" + + if (extra) Object.keys(extra).forEach(function (k) { + if (!res.hasOwnProperty(k)) res[k] = extra[k] + }) + + // strings and objects are hard to diff by eye + if (!ok && + res.hasOwnProperty("found") && + res.hasOwnProperty("wanted") && + res.found !== res.wanted) { + if (typeof res.wanted !== typeof res.found || + typeof res.wanted === "object" && (!res.found || !res.wanted)) { + res.type = { found: typeof found + , wanted: typeof wanted } + } else if (typeof res.wanted === "string") { + res.diff = diffString(res.found, res.wanted) + } else if (typeof res.wanted === "object") { + res.diff = diffObject(res.found, res.wanted) + } + } + + //console.error("assert return", res) + + return res +} +assert.ok = assert +syns.ok = [ "true", "assert" ] + + +function notOk (ok, message, extra) { + return assert(!ok, message, extra) +} +assert.notOk = notOk +syns.notOk = [ "false", "notok" ] + +function error (er, message, extra) { + if (!er) { + // just like notOk(er) + return assert(!er, message, extra) + } + message = message || er.message + extra = extra || {} + extra.error = er + return assert.fail(message, extra) +} +assert.error = error +syns.error = [ "ifError", "ifErr", "iferror" ] + + +function pass (message, extra) { + return assert(true, message, extra) +} +assert.pass = pass + +function fail (message, extra) { + //console.error("assert.fail", [message, extra]) + //if (extra && extra.skip) return assert.skip(message, extra) + return assert(false, message, extra) +} +assert.fail = fail + +function skip (message, extra) { + //console.error("assert.skip", message, extra) + if (!extra) extra = {} + return { id: id ++, skip: true, name: message || "" } +} +assert.skip = skip + +function throws (fn, wanted, message, extra) { + if (typeof wanted === "string") { + extra = message + message = wanted + wanted = null + } + + if (extra && extra.skip) return assert.skip(message, extra) + + var found = null + try { + fn() + } catch (e) { + found = { name: e.name, message: e.message } + } + + extra = extra || {} + + extra.found = found + if (wanted) { + wanted = { name: wanted.name, message: wanted.message } + extra.wanted = wanted + } + + if (!message) { + message = "Expected to throw" + if (wanted) message += ": "+wanted.name + " " + wanted.message + } + + return (wanted) ? assert.similar(found, wanted, message, extra) + : assert.ok(found, message, extra) +} +assert.throws = throws + + +function doesNotThrow (fn, message, extra) { + if (extra && extra.skip) return assert.skip(message, extra) + var found = null + try { + fn() + } catch (e) { + found = {name: e.name, message: e.message} + } + message = message || "Should not throw" + + return assert.equal(found, null, message, extra) +} +assert.doesNotThrow = doesNotThrow + + +function equal (a, b, message, extra) { + if (extra && extra.skip) return assert.skip(message, extra) + extra = extra || {} + message = message || "should be equal" + extra.found = a + extra.wanted = b + return assert(a === b, message, extra) +} +assert.equal = equal +syns.equal = ["equals" + ,"isEqual" + ,"is" + ,"strictEqual" + ,"strictEquals"] + + +function equivalent (a, b, message, extra) { + if (extra && extra.skip) return assert.skip(message, extra) + var extra = extra || {} + message = message || "should be equivalent" + extra.found = a + extra.wanted = b + return assert(stringify(a) === stringify(b), message, extra) +} +assert.equivalent = equivalent +syns.equivalent = ["isEquivalent" + ,"looseEqual" + ,"looseEquals" + ,"isDeeply" + ,"same" + ,"deepEqual" + ,"deepEquals"] + + +function inequal (a, b, message, extra) { + if (extra && extra.skip) return assert.skip(message, extra) + extra = extra || {} + message = message || "should not be equal" + extra.found = a + extra.doNotWant = b + return assert(a !== b, message, extra) +} +assert.inequal = inequal +syns.inequal = ["notEqual" + ,"notEquals" + ,"isNotEqual" + ,"isNot" + ,"not" + ,"doesNotEqual" + ,"isInequal"] + + +function inequivalent (a, b, message, extra) { + if (extra && extra.skip) return assert.skip(message, extra) + extra = extra || {} + message = message || "should not be equivalent" + extra.found = a + extra.doNotWant = b + return assert(stringify(a) !== stringify(b), message, extra) +} +assert.inequivalent = inequivalent +syns.inequivalent = ["notEquivalent" + ,"notDeepEqual" + ,"notDeeply" + ,"isNotDeepEqual" + ,"isNotDeeply" + ,"isNotEquivalent" + ,"isInequivalent"] + +function similar (a, b, message, extra) { + if (extra && extra.skip) return assert.skip(message, extra) + // test that a has all the fields in b + message = message || "should be similar" + return equivalent(selectFields(a, b), b, message, extra) +} +assert.similar = similar +syns.similar = ["isSimilar" + ,"has" + ,"hasFields" + ,"like" + ,"isLike"] + +function dissimilar (a, b, message, extra) { + if (extra && extra.skip) return assert.skip(message, extra) + // test that a has all the fields in b + message = message || "should be dissimilar" + return inequivalent(selectFields(a, b), b, message, extra) +} +assert.dissimilar = dissimilar +syns.dissimilar = ["unsimilar" + ,"notSimilar" + ,"unlike" + ,"isUnlike" + ,"notLike" + ,"isNotLike" + ,"doesNotHave" + ,"isNotSimilar" + ,"isDissimilar"] + +function type (thing, t, message, extra) { + if (extra && extra.skip) return assert.skip(message, extra) + var name = t + if (typeof name === "function") name = name.name || "(anonymous ctor)" + //console.error("name=%s", name) + message = message || "type is "+name + var type = typeof thing + //console.error("type=%s", type) + if (!thing && type === "object") type = "null" + if (type === "object" && t !== "object") { + if (typeof t === "function") { + //console.error("it is a function!") + extra = extra || {} + extra.found = Object.getPrototypeOf(thing).constructor.name + extra.wanted = name + //console.error(thing instanceof t, name) + return assert.ok(thing instanceof t, message, extra) + } + + //console.error("check prototype chain") + // check against classnames or objects in prototype chain, as well. + // type(new Error("asdf"), "Error") + // type(Object.create(foo), foo) + var p = thing + while (p = Object.getPrototypeOf(p)) { + if (p === t || p.constructor && p.constructor.name === t) { + type = name + break + } + } + } + //console.error(type, name, type === name) + return assert.equal(type, name, message, extra) +} +assert.type = type +syns.type = ["isa"] + +// synonyms are helpful. +Object.keys(syns).forEach(function (c) { + syns[c].forEach(function (s) { + Object.defineProperty(assert, s, { value: assert[c], enumerable: false }) + }) +}) + +// helpers below + +function selectFields (a, b) { + // get the values in A of the fields in B + var ret = Array.isArray(b) ? [] : {} + Object.keys(b).forEach(function (k) { + if (!a.hasOwnProperty(k)) return + var v = b[k] + , av = a[k] + if (v && av && typeof v === "object" && typeof av === "object") { + ret[k] = selectFields(av, v) + } else ret[k] = av + }) + return ret +} + +function stringify (a) { + return JSON.stringify(a, (function () { + var seen = [] + , keys = [] + return function (key, val) { + var s = seen.indexOf(val) + if (s !== -1) { + return "[Circular: "+keys[s]+"]" + } + if (val && typeof val === "object" || typeof val === "function") { + seen.push(val) + keys.push(val["!"] || val.name || key || "") + if (typeof val === "function") { + return val.toString().split(/\n/)[0] + } + var proto = Object.getPrototypeOf(val) + } + return val + }})()) +} + +function diffString (f, w) { + if (w === f) return null + var p = 0 + , l = w.length + while (p < l && w.charAt(p) === f.charAt(p)) p ++ + w = stringify(w).substr(1).replace(/"$/, "") + f = stringify(f).substr(1).replace(/"$/, "") + return diff(f, w, p) +} + +function diffObject (f, w) { + var f = stringify(f) + , w = stringify(w) + , l = w.length + if (f === w) return null + var p = 0 + while (p < l && f.charAt(p) === w.charAt(p)) p ++ + return diff(f, w, p) +} + +function diff (f, w, p) { + if (w === f) return null + var i = p || 0 // it's going to be at least p. JSON can only be bigger. + , l = w.length + while (i < l && w.charAt(i) === f.charAt(i)) i ++ + var pos = Math.max(0, i - 20) + w = w.substr(pos, 40) + f = f.substr(pos, 40) + var pointer = i - pos + return "FOUND: "+f+"\n" + + "WANTED: "+w+"\n" + + (new Array(pointer + 9).join(" ")) + + "^ (at position = "+p+")" +} + +function getCaller (er) { + // get the first file/line that isn't this file. + if (!er) er = new Error + var stack = er.stack || "" + stack = stack.split(/\n/) + for (var i = 1, l = stack.length; i < l; i ++) { + var s = stack[i].match(/\(([^):]+):([0-9]+):([0-9]+)\)$/) + if (!s) continue + var file = s[1] + , line = +s[2] + , col = +s[3] + if (file.indexOf(__dirname) === 0) continue + if (file.match(/tap-test\/test.js$/)) continue + else break + } + var res = {} + if (file && file !== __filename && !file.match(/tap-test\/test.js$/)) { + res.file = file + res.line = line + res.column = col + } + + res.stack = stack.slice(1).map(function (s) { + return s.replace(/^\s*at\s*/, "") + }) + + return res +} + + diff --git a/node_modules/nodeunit/node_modules/tap-assert/package.json b/node_modules/nodeunit/node_modules/tap-assert/package.json new file mode 100644 index 0000000..bfc2c5c --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-assert/package.json @@ -0,0 +1,29 @@ +{ + "name": "tap-assert", + "version": "0.0.10", + "description": "An assertion module that returns TAP result objects", + "main": "./assert.js", + "author": "Isaac Z. Schlueter (http://blog.izs.me/)", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/tap-assert.git" + }, + "keywords": [ + "assert", + "test", + "tap" + ], + "license": { + "type": "MIT", + "url": "https://github.com/isaacs/tap-assert/raw/master/LICENSE" + }, + "contributors": [ + "Isaac Z. Schlueter (http://blog.izs.me)", + "baudehlo " + ], + "dependencies": {}, + "devDependencies": {}, + "engines": { + "node": "*" + } +} diff --git a/node_modules/nodeunit/node_modules/tap-producer/README.md b/node_modules/nodeunit/node_modules/tap-producer/README.md new file mode 100644 index 0000000..bd96254 --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-producer/README.md @@ -0,0 +1,4 @@ +Sometimes, you need to produce some TAPs. + +Not like when you go to the store, and check to see if the melons are +ripe. That's tapping on produce. This is different. diff --git a/node_modules/nodeunit/node_modules/tap-producer/node_modules/inherits/README.md b/node_modules/nodeunit/node_modules/tap-producer/node_modules/inherits/README.md new file mode 100644 index 0000000..b2beaed --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-producer/node_modules/inherits/README.md @@ -0,0 +1,51 @@ +A dead simple way to do inheritance in JS. + + var inherits = require("inherits") + + function Animal () { + this.alive = true + } + Animal.prototype.say = function (what) { + console.log(what) + } + + inherits(Dog, Animal) + function Dog () { + Dog.super.apply(this) + } + Dog.prototype.sniff = function () { + this.say("sniff sniff") + } + Dog.prototype.bark = function () { + this.say("woof woof") + } + + inherits(Chihuahua, Dog) + function Chihuahua () { + Chihuahua.super.apply(this) + } + Chihuahua.prototype.bark = function () { + this.say("yip yip") + } + + // also works + function Cat () { + Cat.super.apply(this) + } + Cat.prototype.hiss = function () { + this.say("CHSKKSS!!") + } + inherits(Cat, Animal, { + meow: function () { this.say("miao miao") } + }) + Cat.prototype.purr = function () { + this.say("purr purr") + } + + + var c = new Chihuahua + assert(c instanceof Chihuahua) + assert(c instanceof Dog) + assert(c instanceof Animal) + +The actual function is laughably small. 10-lines small. diff --git a/node_modules/nodeunit/node_modules/tap-producer/node_modules/inherits/inherits.js b/node_modules/nodeunit/node_modules/tap-producer/node_modules/inherits/inherits.js new file mode 100644 index 0000000..061b396 --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-producer/node_modules/inherits/inherits.js @@ -0,0 +1,29 @@ +module.exports = inherits + +function inherits (c, p, proto) { + proto = proto || {} + var e = {} + ;[c.prototype, proto].forEach(function (s) { + Object.getOwnPropertyNames(s).forEach(function (k) { + e[k] = Object.getOwnPropertyDescriptor(s, k) + }) + }) + c.prototype = Object.create(p.prototype, e) + c.super = p +} + +//function Child () { +// Child.super.call(this) +// console.error([this +// ,this.constructor +// ,this.constructor === Child +// ,this.constructor.super === Parent +// ,Object.getPrototypeOf(this) === Child.prototype +// ,Object.getPrototypeOf(Object.getPrototypeOf(this)) +// === Parent.prototype +// ,this instanceof Child +// ,this instanceof Parent]) +//} +//function Parent () {} +//inherits(Child, Parent) +//new Child diff --git a/node_modules/nodeunit/node_modules/tap-producer/node_modules/inherits/package.json b/node_modules/nodeunit/node_modules/tap-producer/node_modules/inherits/package.json new file mode 100644 index 0000000..5beb005 --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-producer/node_modules/inherits/package.json @@ -0,0 +1,7 @@ +{ "name" : "inherits" +, "description": "A tiny simple way to do classic inheritance in js" +, "version" : "1.0.0" +, "keywords" : ["inheritance", "class", "klass", "oop", "object-oriented"] +, "main" : "./inherits.js" +, "repository" : "https://github.com/isaacs/inherits" +, "author" : "Isaac Z. Schlueter (http://blog.izs.me/)" } diff --git a/node_modules/nodeunit/node_modules/tap-producer/node_modules/tap-results/README.md b/node_modules/nodeunit/node_modules/tap-producer/node_modules/tap-results/README.md new file mode 100644 index 0000000..6a00fc9 --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-producer/node_modules/tap-results/README.md @@ -0,0 +1,2 @@ +This is a module for keeping track of tap result objects, counting them +up, etc. diff --git a/node_modules/nodeunit/node_modules/tap-producer/node_modules/tap-results/package.json b/node_modules/nodeunit/node_modules/tap-producer/node_modules/tap-results/package.json new file mode 100644 index 0000000..1882b77 --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-producer/node_modules/tap-results/package.json @@ -0,0 +1,11 @@ +{ + "name": "tap-results", + "version": "0.0.2", + "description": "A util for keeping track of tap result objects", + "main": "./results.js", + "author": "Isaac Z. Schlueter (http://blog.izs.me/)", + "repository": "https://github.com/isaacs/tap-results", + "dependencies": { + "inherits": "~1.0.0" + } +} diff --git a/node_modules/nodeunit/node_modules/tap-producer/node_modules/tap-results/results.js b/node_modules/nodeunit/node_modules/tap-producer/node_modules/tap-results/results.js new file mode 100644 index 0000000..46ef2e5 --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-producer/node_modules/tap-results/results.js @@ -0,0 +1,68 @@ +// A class for counting up results in a test harness. + +module.exports = Results + +var inherits = require("inherits") + , EventEmitter = require("events").EventEmitter + +inherits(Results, EventEmitter) + +function Results (r) { + //console.error("result constructor", r) + this.ok = true + this.addSet(r) +} + +Results.prototype.addSet = function (r) { + //console.error("add set of results", r) + r = r || {ok: true} + ; [ "todo" + , "todoPass" + , "todoFail" + , "skip" + , "skipPass" + , "skipFail" + , "pass" + , "passTotal" + , "fail" + , "failTotal" + , "tests" + , "testsTotal" ].forEach(function (k) { + this[k] = (this[k] || 0) + (r[k] || 0) + //console.error([k, this[k]]) + }, this) + + this.ok = this.ok && r.ok && true + this.bailedOut = this.bailedOut || r.bailedOut || false + this.list = (this.list || []).concat(r.list || []) + this.emit("set", this.list) + //console.error("after addSet", this) +} + +Results.prototype.add = function (r, addToList) { + //console.error("add result", r) + var pf = r.ok ? "pass" : "fail" + , PF = r.ok ? "Pass" : "Fail" + + this.testsTotal ++ + this[pf + "Total"] ++ + + if (r.skip) { + this["skip" + PF] ++ + this.skip ++ + } else if (r.todo) { + this["todo" + PF] ++ + this.todo ++ + } else { + this.tests ++ + this[pf] ++ + } + + if (r.bailout || typeof r.bailout === "string") this.bailedOut = true + this.ok = !!(this.ok && r.ok) + + if (addToList === false) return + this.list = this.list || [] + this.list.push(r) + this.emit("result", r) +} diff --git a/node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/LICENSE b/node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/LICENSE new file mode 100644 index 0000000..187e8db --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011 Isaac Z. Schlueter + +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/node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/README.md b/node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/README.md new file mode 100644 index 0000000..954d063 --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/README.md @@ -0,0 +1,20 @@ +This is a thingie to parse the "yamlish" format used to serialize +objects in the TAP format. + +It's like yaml, but just a tiny little bit smaller. + +Usage: + + var yamlish = require("yamlish") + // returns a string like: + /* + some: + object: + - full + - of + pretty: things + */ + yamlish.encode({some:{object:["full", "of"]}, pretty:"things"}) + + // returns the object + yamlish.decode(someYamlishString) diff --git a/node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/package.json b/node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/package.json new file mode 100644 index 0000000..22b58dd --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/package.json @@ -0,0 +1,9 @@ +{ "name" : "yamlish" +, "description" : "Parser/encoder for the yamlish format" +, "repository":"https://github.com/isaacs/yamlish" +, "version" : "0.0.4" +, "main" : "yamlish.js" +, "keywords" : [ "yaml", "yamlish", "test", "anything", "protocol", "tap"] +, "license" : { "type" : "MIT" + , "url" : "http://github.com/isaacs/yamlish/raw/master/LICENSE" } +, "author" : "Isaac Z. Schlueter (http://blog.izs.me/)" } diff --git a/node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/yamlish.js b/node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/yamlish.js new file mode 100644 index 0000000..ea35431 --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-producer/node_modules/yamlish/yamlish.js @@ -0,0 +1,260 @@ +exports.encode = encode +exports.decode = decode + +var seen = [] +function encode (obj, indent) { + var deep = arguments[2] + if (!indent) indent = " " + + if (obj instanceof String || + Object.prototype.toString.call(obj) === "[object String]") { + obj = obj.toString() + } + + if (obj instanceof Number || + Object.prototype.toString.call(obj) === "[object Number]") { + obj = obj.valueOf() + } + + // take out the easy ones. + switch (typeof obj) { + case "string": + obj = obj.trim() + if (obj.indexOf("\n") !== -1) { + return "|\n" + indent + obj.split(/\r?\n/).join("\n"+indent) + } else { + return JSON.stringify(obj) + } + + case "number": + return obj.toString(10) + + case "function": + return encode(obj.toString(), indent, true) + + case "boolean": + return obj.toString() + + case "undefined": + // fallthrough + case "object": + // at this point we know it types as an object + if (!obj) return "~" + + if (obj instanceof Date || + Object.prototype.toString.call(obj) === "[object Date]") { + return JSON.stringify("[Date " + obj.toISOString() + "]") + } + + if (obj instanceof RegExp || + Object.prototype.toString.call(obj) === "[object RegExp]") { + return JSON.stringify(obj.toString()) + } + + if (obj instanceof Boolean || + Object.prototype.toString.call(obj) === "[object Boolean]") { + return obj.toString() + } + + if (seen.indexOf(obj) !== -1) { + return "[Circular]" + } + seen.push(obj) + + if (typeof Buffer === "function" && + typeof Buffer.isBuffer === "function" && + Buffer.isBuffer(obj)) return obj.inspect() + + if (obj instanceof Error) { + var o = { name: obj.name + , message: obj.message + , type: obj.type } + + if (obj.code) o.code = obj.code + if (obj.errno) o.errno = obj.errno + if (obj.type) o.type = obj.type + obj = o + } + + var out = "" + + if (Array.isArray(obj)) { + var out = "\n" + indent + "- " +obj.map(function (item) { + return encode(item, indent + " ", true) + }).join("\n"+indent + "- ") + break + } + + // an actual object + var keys = Object.keys(obj) + , niceKeys = keys.map(function (k) { + return (k.match(/^[a-zA-Z0-9_]+$/) ? k : JSON.stringify(k)) + ": " + }) + //console.error(keys, niceKeys, obj) + var maxLength = Math.max.apply(Math, niceKeys.map(function (k) { + return k.length + }).concat(0)) + //console.error(niceKeys, maxLength) + + var spaces = new Array(maxLength + 1).join(" ") + + if (!deep) indent += " " + out = "\n" + indent + keys.map(function (k, i) { + var niceKey = niceKeys[i] + return niceKey + spaces.substr(niceKey.length) + + encode(obj[k], indent + " ", true) + }).join("\n" + indent) + break + + default: return "" + } + if (!deep) seen.length = 0 + return out +} + +function decode (str) { + var v = str.trim() + , d + , dateRe = /^\[Date ([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}(?::[0-9]{2})?(?:\.[0-9]{3})?(?:[A-Z]+)?)\]$/ + + if (v === "~") return null + + try { + var jp = JSON.parse(str) + } catch (e) { + var jp = "" + } + + if (jp && + typeof jp === "string" && + (d = jp.match(dateRe)) && + (d = Date.parse(d[1]))) { + return new Date(d) + } + + if (typeof jp === "boolean") return jp + if (v && !isNaN(v)) return parseInt(v, 10) + + // something interesting. + var lines = str.split(/\r?\n/) + // check if it's some kind of string or something. + // if the first line is > or | then it's a wrapping indented string. + // if the first line is blank, and there are many lines, + // then it's an array or object. + // otherwise, it's just "" + var first = lines.shift().trim() + if (lines.length) lines = undent(lines) + switch (first) { + case "|": + return lines.join("\n") + case ">": + return lines.join("\n").split(/\n{2,}/).map(function (l) { + return l.split(/\n/).join(" ") + }).join("\n") + default: + if (!lines.length) return first + // array or object. + // the first line will be either "- value" or "key: value" + return lines[0].charAt(0) === "-" ? decodeArr(lines) : decodeObj(lines) + } +} + +function decodeArr (lines) { + var out = [] + , key = 0 + , val = [] + for (var i = 0, l = lines.length; i < l; i ++) { + // if it starts with a -, then it's a new thing + var line = lines[i] + if (line.charAt(0) === "-") { + if (val.length) { + out[key ++] = decode(val.join("\n")) + val.length = 0 + } + val.push(line.substr(1).trim()) + } else if (line.charAt(0) === " ") { + val.push(line) + } else return [] + } + if (val.length) { + out[key ++] = decode(val.join("\n")) + } + return out +} + +function decodeObj (lines) { + var out = {} + , val = [] + , key = null + + for (var i = 0, l = lines.length; i < l; i ++) { + var line = lines[i] + if (line.charAt(0) === " ") { + val.push(line) + continue + } + // some key:val + if (val.length) { + out[key] = decode(val.join("\n")) + val.length = 0 + } + // parse out the quoted key + var first + if (line.charAt(0) === "\"") { + for (var ii = 1, ll = line.length, esc = false; ii < ll; ii ++) { + var c = line.charAt(ii) + if (c === "\\") { + esc = !esc + } else if (c === "\"" && !esc) { + break + } + } + key = JSON.parse(line.substr(0, ii + 1)) + line = line.substr(ii + 1) + first = line.substr(line.indexOf(":") + 1).trim() + } else { + var kv = line.split(":") + key = kv.shift() + first = kv.join(":").trim() + } + // now we've set a key, and "first" has the first line of the value. + val.push(first.trim()) + } + if (val.length) out[key] = decode(val.join("\n")) + return out +} + +function undent (lines) { + var i = lines[0].match(/^\s*/)[0].length + return lines.map(function (line) { + return line.substr(i) + }) +} + + +// XXX Turn this into proper tests. +if (require.main === module) { +var obj = [{"bigstring":new Error().stack} + ,{ar:[{list:"of"},{some:"objects"}]} + ,{date:new Date()} + ,{"super huge string":new Error().stack} + ] + +Date.prototype.toJSON = function (k, val) { + console.error(k, val, this) + return this.toISOString() + " (it's a date)" +} + +var enc = encode(obj) + , dec = decode(enc) + , encDec = encode(dec) + +console.error(JSON.stringify({ obj : obj + , enc : enc.split(/\n/) + , dec : dec }, null, 2), encDec === enc) + +var num = 100 + , encNum = encode(num) + , decEncNum = decode(encNum) +console.error([num, encNum, decEncNum]) +} diff --git a/node_modules/nodeunit/node_modules/tap-producer/package.json b/node_modules/nodeunit/node_modules/tap-producer/package.json new file mode 100644 index 0000000..6e6238f --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-producer/package.json @@ -0,0 +1,12 @@ +{ "name" : "tap-producer" +, "version" : "0.0.1" +, "description" : "A module for producing TAP output" +, "main" : "./tap-producer.js" +, "author" : "Isaac Z. Schlueter (http://blog.izs.me/)" +, "repository" : "https://github.com/isaacs/tap-producer" +, "dependencies" : + { "inherits" : "*" + , "tap-results" : "0.x" + , "yamlish" : "*" + } +} diff --git a/node_modules/nodeunit/node_modules/tap-producer/tap-producer.js b/node_modules/nodeunit/node_modules/tap-producer/tap-producer.js new file mode 100644 index 0000000..6aaa8c1 --- /dev/null +++ b/node_modules/nodeunit/node_modules/tap-producer/tap-producer.js @@ -0,0 +1,113 @@ +module.exports = TapProducer + +var Results = require("tap-results") + , inherits = require("inherits") + , yamlish = require("yamlish") + +TapProducer.encode = function (result, diag) { + var tp = new TapProducer(diag) + , out = "" + tp.on("data", function (c) { out += c }) + if (Array.isArray(result)) { + result.forEach(tp.write, tp) + } else tp.write(result) + tp.end() + return out +} + +inherits(TapProducer, require("stream").Stream) +function TapProducer (diag) { + TapProducer.super.call(this) + this.diag = diag + this.count = 0 + this.readable = this.writable = true + this.results = new Results +} + +TapProducer.prototype.trailer = true + +TapProducer.prototype.write = function (res) { + // console.error("TapProducer.write", res) + if (typeof res === "function") throw new Error("wtf?") + if (!this.writable) this.emit("error", new Error("not writable")) + + var diag = res.diag + if (diag === undefined) diag = this.diag + + this.emit("data", encodeResult(res, this.count + 1, diag)) + + if (typeof res === "string") return true + + this.results.add(res, false) + this.count ++ +} + +TapProducer.prototype.end = function (res) { + if (res) this.write(res) + this.emit("data", "\n1.."+this.results.testsTotal+"\n") + if (this.trailer && typeof this.trailer !== "string") { + // summary trailer. + var trailer = "tests "+this.results.testsTotal + "\n" + if (this.results.pass) { + trailer += "pass " + this.results.pass + "\n" + } + if (this.results.fail) { + trailer += "fail " + this.results.fail + "\n" + } + if (this.results.skip) { + trailer += "skip "+this.results.skip + "\n" + } + if (this.results.todo) { + trailer += "todo "+this.results.todo + "\n" + } + if (this.results.bailedOut) { + trailer += "bailed out" + "\n" + } + + if (this.results.testsTotal === this.results.pass) { + trailer += "\nok\n" + } + this.trailer = trailer + } + if (this.trailer) this.write(this.trailer) + this.writable = false + this.emit("end", null, this.count, this.ok) +} + +function encodeResult (res, count, diag) { + if (typeof res === "string") { + res = res.split(/\r?\n/).map(function (l) { + if (!l.trim()) return l.trim() + return "# " + l + }).join("\n") + if (res.substr(-1) !== "\n") res += "\n" + return res + } + + if (!!process.env.TAP_NODIAG) diag = false + else if (!!process.env.TAP_DIAG) diag = true + else if (diag === undefined) diag = !res.ok + + var output = "" + res.name = res.name && res.name.trim() + output += ( !res.ok ? "not " : "") + "ok " + count + + ( !res.name ? "" + : " " + res.name.replace(/[\r\n]/, " ") ) + + ( res.skip ? " # SKIP" + : res.todo ? " # TODO" + : "" ) + + "\n" + + if (!diag) return output + var d = {} + , dc = 0 + Object.keys(res).filter(function (k) { + return k !== "ok" && k !== "name" && k !== "id" + }).forEach(function (k) { + dc ++ + d[k] = res[k] + }) + //console.error(d, "about to encode") + if (dc > 0) output += " ---"+yamlish.encode(d)+"\n ...\n" + return output +} diff --git a/node_modules/nodeunit/nodelint.cfg b/node_modules/nodeunit/nodelint.cfg new file mode 100644 index 0000000..d6a3aad --- /dev/null +++ b/node_modules/nodeunit/nodelint.cfg @@ -0,0 +1,7 @@ +//See: http://www.jslint.com/lint.html#options +var options = { + //white: false, // if false, strict whitespace rules should be enforced. + indent: 4, + onevar: false, + vars: true // allow multiple var statement per function. +}; diff --git a/node_modules/nodeunit/package.json b/node_modules/nodeunit/package.json new file mode 100644 index 0000000..d1d8e0b --- /dev/null +++ b/node_modules/nodeunit/package.json @@ -0,0 +1,67 @@ +{ "name": "nodeunit" +, "description": "Easy unit testing for node.js and the browser." +, "maintainers": + [ { "name": "Caolan McMahon" + , "web": "https://github.com/caolan" + } + ] +, "contributors" : + [ { "name": "Romain Beauxis" + , "web": "https://github.com/toots" + } + , { "name": "Alex Gorbatchev" + , "web": "https://github.com/alexgorbatchev" + } + , { "name": "Alex Wolfe" + , "web": "https://github.com/alexkwolfe" + } + , { "name": "Carl Fürstenberg" + , "web": "https://github.com/azatoth" + } + , { "name": "Gerad Suyderhoud" + , "web": "https://github.com/gerad" + } + , { "name": "Kadir Pekel" + , "web": "https://github.com/coffeemate" + } + , { "name": "Oleg Efimov" + , "web": "https://github.com/Sannis" + } + , { "name": "Orlando Vazquez" + , "web": "https://github.com/orlandov" + } + , { "name": "Ryan Dahl" + , "web": "https://github.com/ry" + } + , { "name": "Sam Stephenson" + , "web": "https://github.com/sstephenson" + } + , { "name": "Thomas Mayfield" + , "web": "https://github.com/thegreatape" + } + , { "name": "Elijah Insua ", + "web": "http://tmpvar.com" + } + ] +, "version": "0.7.3" +, "repository" : + { "type" : "git" + , "url" : "http://github.com/caolan/nodeunit.git" + } +, "devDependencies": + { "uglify-js": ">=1.1.0" + , "should" : ">=0.4.2" + } +, "bugs" : { "url" : "http://github.com/caolan/nodeunit/issues" } +, "licenses" : + [ { "type" : "MIT" + , "url" : "http://github.com/caolan/nodeunit/raw/master/LICENSE" + } + ] +, "directories" : { "lib": "./lib", "doc" : "./doc", "man" : "./man1" } +, "bin" : { "nodeunit" : "./bin/nodeunit" } +, "dependencies" : + { "tap-assert": ">=0.0.9" + , "tap-producer": ">=0.0.1" + } +} diff --git a/node_modules/nodeunit/share/junit.xml.ejs b/node_modules/nodeunit/share/junit.xml.ejs new file mode 100644 index 0000000..c1db5bb --- /dev/null +++ b/node_modules/nodeunit/share/junit.xml.ejs @@ -0,0 +1,19 @@ + +<% for (var i=0; i < suites.length; i++) { %> + <% var suite=suites[i]; %> + + <% for (var j=0; j < suite.testcases.length; j++) { %> + <% var testcase=suites[i].testcases[j]; %> + + <% if (testcase.failure) { %> + + <% if (testcase.failure.backtrace) { %><%= testcase.failure.backtrace %><% } %> + + <% } %> + + <% } %> + +<% } %> diff --git a/node_modules/nodeunit/share/license.js b/node_modules/nodeunit/share/license.js new file mode 100644 index 0000000..f0f326f --- /dev/null +++ b/node_modules/nodeunit/share/license.js @@ -0,0 +1,11 @@ +/*! + * Nodeunit + * https://github.com/caolan/nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + * + * json2.js + * http://www.JSON.org/json2.js + * Public Domain. + * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + */ diff --git a/node_modules/nodeunit/share/nodeunit.css b/node_modules/nodeunit/share/nodeunit.css new file mode 100644 index 0000000..274434a --- /dev/null +++ b/node_modules/nodeunit/share/nodeunit.css @@ -0,0 +1,70 @@ +/*! + * Styles taken from qunit.css + */ + +h1#nodeunit-header, h1.nodeunit-header { + padding: 15px; + font-size: large; + background-color: #06b; + color: white; + font-family: 'trebuchet ms', verdana, arial; + margin: 0; +} + +h1#nodeunit-header a { + color: white; +} + +h2#nodeunit-banner { + height: 2em; + border-bottom: 1px solid white; + background-color: #eee; + margin: 0; + font-family: 'trebuchet ms', verdana, arial; +} +h2#nodeunit-banner.pass { + background-color: green; +} +h2#nodeunit-banner.fail { + background-color: red; +} + +h2#nodeunit-userAgent, h2.nodeunit-userAgent { + padding: 10px; + background-color: #eee; + color: black; + margin: 0; + font-size: small; + font-weight: normal; + font-family: 'trebuchet ms', verdana, arial; + font-size: 10pt; +} + +div#nodeunit-testrunner-toolbar { + background: #eee; + border-top: 1px solid black; + padding: 10px; + font-family: 'trebuchet ms', verdana, arial; + margin: 0; + font-size: 10pt; +} + +ol#nodeunit-tests { + font-family: 'trebuchet ms', verdana, arial; + font-size: 10pt; +} +ol#nodeunit-tests li strong { + cursor:pointer; +} +ol#nodeunit-tests .pass { + color: green; +} +ol#nodeunit-tests .fail { + color: red; +} + +p#nodeunit-testresult { + margin-left: 1em; + font-size: 10pt; + font-family: 'trebuchet ms', verdana, arial; +} diff --git a/node_modules/nodeunit/test.js b/node_modules/nodeunit/test.js new file mode 100644 index 0000000..a36d56c --- /dev/null +++ b/node_modules/nodeunit/test.js @@ -0,0 +1,8 @@ +var Buffer = require('buffer').Buffer; + +exports.de = function (test) { + var a = new Buffer('foo'); + var b = new Buffer('foo'); + test.deepEqual(a, b); + test.done(); +}; diff --git a/node_modules/nodeunit/test/fixtures/coffee/mock_coffee_module.coffee b/node_modules/nodeunit/test/fixtures/coffee/mock_coffee_module.coffee new file mode 100644 index 0000000..a1c069b --- /dev/null +++ b/node_modules/nodeunit/test/fixtures/coffee/mock_coffee_module.coffee @@ -0,0 +1,4 @@ +j = 0 +j += i for i in [0..5] + +exports.name = "mock_coffee_#{j}" diff --git a/node_modules/nodeunit/test/fixtures/dir/mock_module3.js b/node_modules/nodeunit/test/fixtures/dir/mock_module3.js new file mode 100644 index 0000000..3021776 --- /dev/null +++ b/node_modules/nodeunit/test/fixtures/dir/mock_module3.js @@ -0,0 +1 @@ +exports.name = 'mock_module3'; diff --git a/node_modules/nodeunit/test/fixtures/dir/mock_module4.js b/node_modules/nodeunit/test/fixtures/dir/mock_module4.js new file mode 100644 index 0000000..876f9ca --- /dev/null +++ b/node_modules/nodeunit/test/fixtures/dir/mock_module4.js @@ -0,0 +1 @@ +exports.name = 'mock_module4'; diff --git a/node_modules/nodeunit/test/fixtures/mock_module1.js b/node_modules/nodeunit/test/fixtures/mock_module1.js new file mode 100644 index 0000000..4c093ad --- /dev/null +++ b/node_modules/nodeunit/test/fixtures/mock_module1.js @@ -0,0 +1 @@ +exports.name = 'mock_module1'; diff --git a/node_modules/nodeunit/test/fixtures/mock_module2.js b/node_modules/nodeunit/test/fixtures/mock_module2.js new file mode 100644 index 0000000..a63d012 --- /dev/null +++ b/node_modules/nodeunit/test/fixtures/mock_module2.js @@ -0,0 +1 @@ +exports.name = 'mock_module2'; diff --git a/node_modules/nodeunit/test/fixtures/raw_jscode1.js b/node_modules/nodeunit/test/fixtures/raw_jscode1.js new file mode 100644 index 0000000..2ef7115 --- /dev/null +++ b/node_modules/nodeunit/test/fixtures/raw_jscode1.js @@ -0,0 +1,3 @@ +function hello_world(arg) { + return "_" + arg + "_"; +} diff --git a/node_modules/nodeunit/test/fixtures/raw_jscode2.js b/node_modules/nodeunit/test/fixtures/raw_jscode2.js new file mode 100644 index 0000000..55a764e --- /dev/null +++ b/node_modules/nodeunit/test/fixtures/raw_jscode2.js @@ -0,0 +1,3 @@ +function get_a_variable() { + return typeof a_variable; +} diff --git a/node_modules/nodeunit/test/fixtures/raw_jscode3.js b/node_modules/nodeunit/test/fixtures/raw_jscode3.js new file mode 100644 index 0000000..1fd1e78 --- /dev/null +++ b/node_modules/nodeunit/test/fixtures/raw_jscode3.js @@ -0,0 +1 @@ +var t=t?t+1:1; diff --git a/node_modules/nodeunit/test/test-base.js b/node_modules/nodeunit/test/test-base.js new file mode 100644 index 0000000..5335046 --- /dev/null +++ b/node_modules/nodeunit/test/test-base.js @@ -0,0 +1,239 @@ +/* + * This module is not a plain nodeunit test suite, but instead uses the + * assert module to ensure a basic level of functionality is present, + * allowing the rest of the tests to be written using nodeunit itself. + * + * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. + * Only code on that line will be removed, its mostly to avoid requiring code + * that is node specific + */ + +var assert = require('assert'), // @REMOVE_LINE_FOR_BROWSER + async = require('../deps/async'), // @REMOVE_LINE_FOR_BROWSER + nodeunit = require('../lib/nodeunit'); // @REMOVE_LINE_FOR_BROWSER + + +// NOT A TEST - util function to make testing faster. +// retries the assertion until it passes or the timeout is reached, +// at which point it throws the assertion error +var waitFor = function (fn, timeout, callback, start) { + start = start || new Date().getTime(); + callback = callback || function () {}; + try { + fn(); + callback(); + } + catch (e) { + if (e instanceof assert.AssertionError) { + var now = new Date().getTime(); + if (now - start >= timeout) { + throw e; + } + else { + async.nextTick(function () { + waitFor(fn, timeout, callback, start); + }); + } + } + else { + throw e; + } + } +}; + + +// TESTS: + +// Are exported tests actually run? - store completed tests in this variable +// for checking later +var tests_called = {}; + +// most basic test that should run, the tests_called object is tested +// at the end of this module to ensure the tests were actually run by nodeunit +exports.testCalled = function (test) { + tests_called.testCalled = true; + test.done(); +}; + +// generates test functions for nodeunit assertions +var makeTest = function (method, args_pass, args_fail) { + return function (test) { + var test1_called = false; + var test2_called = false; + + // test pass + nodeunit.runTest( + 'testname', + function (test) { + test[method].apply(test, args_pass); + test.done(); + }, + {testDone: function (name, assertions) { + assert.equal(assertions.length, 1); + assert.equal(assertions.failures(), 0); + }}, + function () { + test1_called = true; + } + ); + + // test failure + nodeunit.runTest( + 'testname', + function (test) { + test[method].apply(test, args_fail); + test.done(); + }, + {testDone: function (name, assertions) { + assert.equal(assertions.length, 1); + assert.equal(assertions.failures(), 1); + }}, + function () { + test2_called = true; + } + ); + + // ensure tests were run + waitFor(function () { + assert.ok(test1_called); + assert.ok(test2_called); + tests_called[method] = true; + }, 500, test.done); + }; +}; + +// ensure basic assertions are working: +exports.testOk = makeTest('ok', [true], [false]); +exports.testEquals = makeTest('equals', [1, 1], [1, 2]); +exports.testSame = makeTest('same', + [{test: 'test'}, {test: 'test'}], + [{test: 'test'}, {monkey: 'penguin'}] +); + +// from the assert module: +exports.testEqual = makeTest('equal', [1, 1], [1, 2]); +exports.testNotEqual = makeTest('notEqual', [1, 2], [1, 1]); +exports.testDeepEqual = makeTest('deepEqual', + [{one: 1}, {one: 1}], [{one: 1}, {two: 2}] +); +exports.testNotDeepEqual = makeTest('notDeepEqual', + [{one: 1}, {two: 2}], [{one: 1}, {one: 1}] +); +exports.testStrictEqual = makeTest('strictEqual', [1, 1], [1, true]); +exports.testNotStrictEqual = makeTest('notStrictEqual', [true, 1], [1, 1]); +exports.testThrows = makeTest('throws', + [function () { + throw new Error('test'); + }], + [function () { + return; + }] +); +exports.testThrowsWithReGex = makeTest('throws', + [function () { + throw new Error('test'); + }, /test/], + [function () { + throw new Error('test'); + }, /fail/] +); +exports.testThrowsWithErrorValidation = makeTest('throws', + [function () { + throw new Error('test'); + }, function(err) { + return true; + }], + [function () { + throw new Error('test'); + }, function(err) { + return false; + }] +); +exports.testDoesNotThrows = makeTest('doesNotThrow', + [function () { + return; + }], + [function () { + throw new Error('test'); + }] +); +exports.testIfError = makeTest('ifError', [false], [new Error('test')]); + + +exports.testExpect = function (test) { + var test1_called = false, + test2_called = false, + test3_called = false; + + // correct number of tests run + nodeunit.runTest( + 'testname', + function (test) { + test.expect(2); + test.ok(true); + test.ok(true); + test.done(); + }, + {testDone: function (name, assertions) { + test.equals(assertions.length, 2); + test.equals(assertions.failures(), 0); + }}, + function () { + test1_called = true; + } + ); + + // no tests run + nodeunit.runTest( + 'testname', + function (test) { + test.expect(2); + test.done(); + }, + {testDone: function (name, assertions) { + test.equals(assertions.length, 1); + test.equals(assertions.failures(), 1); + }}, + function () { + test2_called = true; + } + ); + + // incorrect number of tests run + nodeunit.runTest( + 'testname', + function (test) { + test.expect(2); + test.ok(true); + test.ok(true); + test.ok(true); + test.done(); + }, + {testDone: function (name, assertions) { + test.equals(assertions.length, 4); + test.equals(assertions.failures(), 1); + }}, + function () { + test3_called = true; + } + ); + + // ensure callbacks fired + waitFor(function () { + assert.ok(test1_called); + assert.ok(test2_called); + assert.ok(test3_called); + tests_called.expect = true; + }, 1000, test.done); +}; + + +// tests are async, so wait for them to be called +waitFor(function () { + assert.ok(tests_called.testCalled); + assert.ok(tests_called.ok); + assert.ok(tests_called.equals); + assert.ok(tests_called.same); + assert.ok(tests_called.expect); +}, 10000); diff --git a/node_modules/nodeunit/test/test-bettererrors.js b/node_modules/nodeunit/test/test-bettererrors.js new file mode 100644 index 0000000..d20ca24 --- /dev/null +++ b/node_modules/nodeunit/test/test-bettererrors.js @@ -0,0 +1,71 @@ +/* + * Test utils.betterErrors. utils.betterErrors should provide sensible error messages even when the error does not + * contain expected, actual or operator. + */ +var assert = require("../lib/assert"); +var should = require("should"); +var types = require("../lib/types"); +var util = require('util'); +var utils = require("../lib/utils"); + +function betterErrorStringFromError(error) { + var assertion = types.assertion({error: error}); + var better = utils.betterErrors(assertion); + return better.error.stack.toString(); +} + +function performBasicChecks(betterErrorString) { + betterErrorString.should.include("AssertionError"); + betterErrorString.should.include("test-bettererrors"); + betterErrorString.should.not.include("undefined"); +} + +/** + * Control test. Provide an AssertionError that contains actual, expected operator values. + * @param test the test object from nodeunit + */ +exports.testEqual = function (test) { + try { + assert.equal(true, false); + } catch (error) { + var betterErrorString = betterErrorStringFromError(error); + performBasicChecks(betterErrorString); + betterErrorString.should.include("true"); + betterErrorString.should.include("false"); + betterErrorString.should.include("=="); + test.done(); + } +}; + +/** + * Test an AssertionError that does not contain actual, expected or operator values. + * @param test the test object from nodeunit + */ +exports.testAssertThrows = function (test) { + try { + assert.throws(function () { + }); + } catch (error) { + var betterErrorString = betterErrorStringFromError(error); + performBasicChecks(betterErrorString); + test.done(); + } +}; + +/** + * Test with an error that is not an AssertionError. + * @param test the test object from nodeunit + */ +exports.testNonAssertionError = function (test) { + try { + throw new Error("test error"); + } catch (error) { + var betterErrorString = betterErrorStringFromError(error); + betterErrorString.should.not.include("AssertionError"); + betterErrorString.should.include("Error"); + betterErrorString.should.include("test error"); + betterErrorString.should.include("test-bettererrors"); + betterErrorString.should.not.include("undefined"); + test.done(); + } +}; diff --git a/node_modules/nodeunit/test/test-failing-callbacks.js b/node_modules/nodeunit/test/test-failing-callbacks.js new file mode 100644 index 0000000..08f7eb5 --- /dev/null +++ b/node_modules/nodeunit/test/test-failing-callbacks.js @@ -0,0 +1,114 @@ +var nodeunit = require('../lib/nodeunit'); + + +exports.testFailingLog = function (test) { + test.expect(3); + + // this is meant to bubble to the top, and will be ignored for the purposes + // of testing: + var ignored_error = new Error('ignore this callback error'); + var err_handler = function (err) { + if (err && err.message !== ignored_error.message) { + throw err; + } + }; + process.addListener('uncaughtException', err_handler); + + // A failing callback should not affect the test outcome + var testfn = function (test) { + test.ok(true, 'test.ok'); + test.done(); + }; + nodeunit.runTest('testname', testfn, { + log: function (assertion) { + test.ok(true, 'log called'); + throw ignored_error; + }, + testDone: function (name, assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 1, 'total'); + process.removeListener('uncaughtException', err_handler); + } + }, test.done); +}; + +exports.testFailingTestDone = function (test) { + test.expect(2); + + var ignored_error = new Error('ignore this callback error'); + var err_handler = function (err) { + if (err && err.message !== ignored_error.message) { + throw err; + } + }; + process.addListener('uncaughtException', err_handler); + + // A failing callback should not affect the test outcome + var testfn = function (test) { + test.done(); + }; + nodeunit.runTest('testname', testfn, { + log: function (assertion) { + test.ok(false, 'log should not be called'); + }, + testDone: function (name, assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 0, 'total'); + process.nextTick(function () { + process.removeListener('uncaughtException', err_handler); + test.done(); + }); + throw ignored_error; + } + }, function () {}); +}; + +exports.testAssertionObj = function (test) { + test.expect(4); + var testfn = function (test) { + test.ok(true, 'ok true'); + test.done(); + }; + nodeunit.runTest('testname', testfn, { + log: function (assertion) { + test.ok(assertion.passed() === true, 'assertion.passed'); + test.ok(assertion.failed() === false, 'assertion.failed'); + }, + testDone: function (name, assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 1, 'total'); + } + }, test.done); +}; + +exports.testLogOptional = function (test) { + test.expect(2); + var testfn = function (test) { + test.ok(true, 'ok true'); + test.done(); + }; + nodeunit.runTest('testname', testfn, { + testDone: function (name, assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 1, 'total'); + } + }, test.done); +}; + +exports.testExpectWithFailure = function (test) { + test.expect(3); + var testfn = function (test) { + test.expect(1); + test.ok(false, 'test.ok'); + test.done(); + }; + nodeunit.runTest('testname', testfn, { + log: function (assertion) { + test.equals(assertion.method, 'ok', 'assertion.method'); + }, + testDone: function (name, assertions) { + test.equals(assertions.failures(), 1, 'failures'); + test.equals(assertions.length, 1, 'total'); + } + }, test.done); +}; diff --git a/node_modules/nodeunit/test/test-httputil.js b/node_modules/nodeunit/test/test-httputil.js new file mode 100644 index 0000000..e5ee25c --- /dev/null +++ b/node_modules/nodeunit/test/test-httputil.js @@ -0,0 +1,55 @@ +var nodeunit = require('../lib/nodeunit'); +var httputil = require('../lib/utils').httputil; + +exports.testHttpUtilBasics = function (test) { + + test.expect(6); + + httputil(function (req, resp) { + test.equal(req.method, 'PUT'); + test.equal(req.url, '/newpair'); + test.equal(req.headers.foo, 'bar'); + + resp.writeHead(500, {'content-type': 'text/plain'}); + resp.end('failed'); + }, function (server, client) { + client.fetch('PUT', '/newpair', {'foo': 'bar'}, function (resp) { + test.equal(resp.statusCode, 500); + test.equal(resp.headers['content-type'], 'text/plain'); + test.equal(resp.body, 'failed'); + + server.close(); + test.done(); + }); + }); +}; + +exports.testHttpUtilJsonHandling = function (test) { + + test.expect(9); + + httputil(function (req, resp) { + test.equal(req.method, 'GET'); + test.equal(req.url, '/'); + test.equal(req.headers.foo, 'bar'); + + var testdata = {foo1: 'bar', foo2: 'baz'}; + + resp.writeHead(200, {'content-type': 'application/json'}); + resp.end(JSON.stringify(testdata)); + + }, function (server, client) { + client.fetch('GET', '/', {'foo': 'bar'}, function (resp) { + test.equal(resp.statusCode, 200); + test.equal(resp.headers['content-type'], 'application/json'); + + test.ok(resp.bodyAsObject); + test.equal(typeof resp.bodyAsObject, 'object'); + test.equal(resp.bodyAsObject.foo1, 'bar'); + test.equal(resp.bodyAsObject.foo2, 'baz'); + + server.close(); + test.done(); + }); + }); +}; diff --git a/node_modules/nodeunit/test/test-runfiles.js b/node_modules/nodeunit/test/test-runfiles.js new file mode 100644 index 0000000..ce1a4cd --- /dev/null +++ b/node_modules/nodeunit/test/test-runfiles.js @@ -0,0 +1,214 @@ +var assert = require('assert'), + fs = require('fs'), + path = require('path'), + nodeunit = require('../lib/nodeunit'); + + +var setup = function (fn) { + return function (test) { + process.chdir(__dirname); + var env = { + mock_module1: require(__dirname + '/fixtures/mock_module1'), + mock_module2: require(__dirname + '/fixtures/mock_module2'), + mock_module3: require(__dirname + '/fixtures/dir/mock_module3'), + mock_module4: require(__dirname + '/fixtures/dir/mock_module4') + }; + fn.call(env, test); + }; +}; + + +exports.testRunFiles = setup(function (test) { + test.expect(24); + var runModule_copy = nodeunit.runModule; + + var runModule_calls = []; + var modules = []; + + var opts = { + moduleStart: function () { + return 'moduleStart'; + }, + testDone: function () { + return 'testDone'; + }, + testStart: function () { + return 'testStart'; + }, + log: function () { + return 'log'; + }, + done: function (assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 4, 'length'); + test.ok(typeof assertions.duration === "number"); + + var called_with = function (name) { + return runModule_calls.some(function (m) { + return m.name === name; + }); + }; + test.ok(called_with('mock_module1'), 'mock_module1 ran'); + test.ok(called_with('mock_module2'), 'mock_module2 ran'); + test.ok(called_with('mock_module3'), 'mock_module3 ran'); + test.ok(called_with('mock_module4'), 'mock_module4 ran'); + test.equals(runModule_calls.length, 4); + + nodeunit.runModule = runModule_copy; + test.done(); + } + }; + + nodeunit.runModule = function (name, mod, options, callback) { + test.equals(options.testDone, opts.testDone); + test.equals(options.testStart, opts.testStart); + test.equals(options.log, opts.log); + test.ok(typeof name === "string"); + runModule_calls.push(mod); + var m = [{failed: function () { + return false; + }}]; + modules.push(m); + callback(null, m); + }; + + nodeunit.runFiles( + [__dirname + '/fixtures/mock_module1.js', + __dirname + '/fixtures/mock_module2.js', + __dirname + '/fixtures/dir'], + opts + ); +}); + +exports.testRunFilesEmpty = function (test) { + test.expect(3); + nodeunit.runFiles([], { + moduleStart: function () { + test.ok(false, 'should not be called'); + }, + testDone: function () { + test.ok(false, 'should not be called'); + }, + testStart: function () { + test.ok(false, 'should not be called'); + }, + log: function () { + test.ok(false, 'should not be called'); + }, + done: function (assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 0, 'length'); + test.ok(typeof assertions.duration === "number"); + test.done(); + } + }); +}; + + +exports.testEmptyDir = function (test) { + var dir2 = __dirname + '/fixtures/dir2'; + + // git doesn't like empty directories, so we have to create one + path.exists(dir2, function (exists) { + if (!exists) { + fs.mkdirSync(dir2, 0777); + } + + // runFiles on empty directory: + nodeunit.runFiles([dir2], { + moduleStart: function () { + test.ok(false, 'should not be called'); + }, + testDone: function () { + test.ok(false, 'should not be called'); + }, + testStart: function () { + test.ok(false, 'should not be called'); + }, + log: function () { + test.ok(false, 'should not be called'); + }, + done: function (assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 0, 'length'); + test.ok(typeof assertions.duration === "number"); + test.done(); + } + }); + }); +}; + + +var CoffeeScript; +try { + CoffeeScript = require('coffee-script'); +} catch (e) { +} + +if (CoffeeScript) { + exports.testCoffeeScript = function (test) { + process.chdir(__dirname); + var env = { + mock_coffee_module: require(__dirname + + '/fixtures/coffee/mock_coffee_module') + }; + + test.expect(9); + var runModule_copy = nodeunit.runModule; + + var runModule_calls = []; + var modules = []; + + var opts = { + moduleStart: function () { + return 'moduleStart'; + }, + testDone: function () { + return 'testDone'; + }, + testStart: function () { + return 'testStart'; + }, + log: function () { + return 'log'; + }, + done: function (assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 1, 'length'); + test.ok(typeof assertions.duration === "number"); + + var called_with = function (name) { + return runModule_calls.some(function (m) { + return m.name === name; + }); + }; + test.ok( + called_with('mock_coffee_15'), + 'mock_coffee_module ran' + ); + test.equals(runModule_calls.length, 1); + + nodeunit.runModule = runModule_copy; + test.done(); + } + }; + + nodeunit.runModule = function (name, mod, options, callback) { + test.equals(options.testDone, opts.testDone); + test.equals(options.testStart, opts.testStart); + test.equals(options.log, opts.log); + test.ok(typeof name === "string"); + runModule_calls.push(mod); + var m = [{failed: function () { + return false; + }}]; + modules.push(m); + callback(null, m); + }; + + nodeunit.runFiles( + [__dirname + 'fixtures/coffee/mock_coffee_module.coffee'], + opts + ); + }; +} diff --git a/node_modules/nodeunit/test/test-runmodule.js b/node_modules/nodeunit/test/test-runmodule.js new file mode 100644 index 0000000..19fe5c7 --- /dev/null +++ b/node_modules/nodeunit/test/test-runmodule.js @@ -0,0 +1,177 @@ +/* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. + * Only code on that line will be removed, its mostly to avoid requiring code + * that is node specific + */ + +var nodeunit = require('../lib/nodeunit'); // @REMOVE_LINE_FOR_BROWSER + + +exports.testRunModule = function (test) { + test.expect(11); + var call_order = []; + var testmodule = { + test1: function (test) { + call_order.push('test1'); + test.ok(true, 'ok true'); + test.done(); + }, + test2: function (test) { + call_order.push('test2'); + test.ok(false, 'ok false'); + test.ok(false, 'ok false'); + test.done(); + }, + test3: function (test) { + call_order.push('test3'); + test.done(); + } + }; + nodeunit.runModule('testmodule', testmodule, { + log: function (assertion) { + call_order.push('log'); + }, + testStart: function (name) { + call_order.push('testStart'); + test.ok( + name.toString() === 'test1' || + name.toString() === 'test2' || + name.toString() === 'test3', + 'testStart called with test name ' + ); + }, + testDone: function (name, assertions) { + call_order.push('testDone'); + test.ok( + name.toString() === 'test1' || + name.toString() === 'test2' || + name.toString() === 'test3', + 'testDone called with test name' + ); + }, + moduleDone: function (name, assertions) { + call_order.push('moduleDone'); + test.equals(assertions.length, 3); + test.equals(assertions.failures(), 2); + test.equals(name, 'testmodule'); + test.ok(typeof assertions.duration === "number"); + test.same(call_order, [ + 'testStart', 'test1', 'log', 'testDone', + 'testStart', 'test2', 'log', 'log', 'testDone', + 'testStart', 'test3', 'testDone', + 'moduleDone' + ]); + } + }, test.done); +}; + + +exports.testRunModuleTestSpec = function (test) { + test.expect(6); + var call_order = []; + var testmodule = { + test1: function (test) { + test.ok(true, 'ok true'); + test.done(); + }, + test2: function (test) { + call_order.push('test2'); + test.ok(false, 'ok false'); + test.ok(false, 'ok false'); + test.done(); + }, + test3: function (test) { + test.done(); + } + }; + nodeunit.runModule('testmodule', testmodule, { + testspec: "test2", + log: function (assertion) { + call_order.push('log'); + }, + testStart: function (name) { + call_order.push('testStart'); + test.equals( + name,'test2', + 'testStart called with test name ' + ); + }, + testDone: function (name, assertions) { + call_order.push('testDone'); + test.equal( + name, 'test2', + 'testDone called with test name' + ); + }, + moduleDone: function (name, assertions) { + call_order.push('moduleDone'); + test.equals(assertions.length, 2); + test.equals(name, 'testmodule'); + test.ok(typeof assertions.duration === "number"); + test.same(call_order, [ + 'testStart', 'test2', 'log', 'log', 'testDone', + 'moduleDone' + ]); + } + }, test.done); +}; + +exports.testRunModuleEmpty = function (test) { + nodeunit.runModule('module with no exports', {}, { + log: function (assertion) { + test.ok(false, 'log should not be called'); + }, + testStart: function (name) { + test.ok(false, 'testStart should not be called'); + }, + testDone: function (name, assertions) { + test.ok(false, 'testDone should not be called'); + }, + moduleDone: function (name, assertions) { + test.equals(assertions.length, 0); + test.equals(assertions.failures(), 0); + test.equals(name, 'module with no exports'); + test.ok(typeof assertions.duration === "number"); + } + }, test.done); +}; + + +exports.testNestedTests = function (test) { + var call_order = []; + var m = { + test1: function (test) { + test.done(); + }, + suite: { + t1: function (test) { + test.done(); + }, + t2: function (test) { + test.done(); + }, + another_suite: { + t3: function (test) { + test.done(); + } + } + } + }; + nodeunit.runModule('modulename', m, { + testStart: function (name) { + call_order.push(['testStart'].concat(name)); + }, + testDone: function (name, assertions) { + call_order.push(['testDone'].concat(name)); + } + }, function () { + test.same(call_order, [ + ['testStart', 'test1'], ['testDone', 'test1'], + ['testStart', 'suite', 't1'], ['testDone', 'suite', 't1'], + ['testStart', 'suite', 't2'], ['testDone', 'suite', 't2'], + ['testStart', 'suite', 'another_suite', 't3'], + ['testDone', 'suite', 'another_suite', 't3'] + ]); + test.done(); + }); +}; diff --git a/node_modules/nodeunit/test/test-runtest.js b/node_modules/nodeunit/test/test-runtest.js new file mode 100644 index 0000000..8fc3d52 --- /dev/null +++ b/node_modules/nodeunit/test/test-runtest.js @@ -0,0 +1,46 @@ +/* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. + * Only code on that line will be removed, its mostly to avoid requiring code + * that is node specific + */ + +var nodeunit = require('../lib/nodeunit'); // @REMOVE_LINE_FOR_BROWSER + + +exports.testArgs = function (test) { + test.ok(test.expect instanceof Function, 'test.expect'); + test.ok(test.done instanceof Function, 'test.done'); + test.ok(test.ok instanceof Function, 'test.ok'); + test.ok(test.same instanceof Function, 'test.same'); + test.ok(test.equals instanceof Function, 'test.equals'); + test.done(); +}; + +exports.testDoneCallback = function (test) { + test.expect(4); + nodeunit.runTest('testname', exports.testArgs, { + testDone: function (name, assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 5, 'length'); + test.ok(typeof assertions.duration === "number"); + test.equals(name, 'testname'); + } + }, test.done); +}; + +exports.testThrowError = function (test) { + test.expect(3); + var err = new Error('test'); + var testfn = function (test) { + throw err; + }; + nodeunit.runTest('testname', testfn, { + log: function (assertion) { + test.same(assertion.error, err, 'assertion.error'); + }, + testDone: function (name, assertions) { + test.equals(assertions.failures(), 1); + test.equals(assertions.length, 1); + } + }, test.done); +}; diff --git a/node_modules/nodeunit/test/test-sandbox.js b/node_modules/nodeunit/test/test-sandbox.js new file mode 100644 index 0000000..1b249d7 --- /dev/null +++ b/node_modules/nodeunit/test/test-sandbox.js @@ -0,0 +1,31 @@ +var nodeunit = require('../lib/nodeunit'); +var sandbox = require('../lib/utils').sandbox; +var testCase = nodeunit.testCase; + +exports.testSimpleSandbox = function (test) { + var raw_jscode1 = sandbox(__dirname + '/fixtures/raw_jscode1.js'); + test.equal(raw_jscode1.hello_world('foo'), '_foo_', 'evaluation ok'); + test.done(); +}; + +exports.testSandboxContext = function (test) { + var a_variable = 42; // should not be visible in the sandbox + var raw_jscode2 = sandbox(__dirname + '/fixtures/raw_jscode2.js'); + a_variable = 42; // again for the win + test.equal( + raw_jscode2.get_a_variable(), + 'undefined', + 'the variable should not be defined' + ); + test.done(); +}; + +exports.testSandboxMultiple = function (test) { + var raw_jscode3 = sandbox([ + __dirname + '/fixtures/raw_jscode3.js', + __dirname + '/fixtures/raw_jscode3.js', + __dirname + '/fixtures/raw_jscode3.js' + ]); + test.equal(raw_jscode3.t, 3, 'two files loaded'); + test.done(); +}; diff --git a/node_modules/nodeunit/test/test-testcase-legacy.js b/node_modules/nodeunit/test/test-testcase-legacy.js new file mode 100644 index 0000000..1dfd9a7 --- /dev/null +++ b/node_modules/nodeunit/test/test-testcase-legacy.js @@ -0,0 +1,257 @@ +/* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. + * Only code on that line will be removed, its mostly to avoid requiring code + * that is node specific + */ + +var nodeunit = require('../lib/nodeunit'); // @REMOVE_LINE_FOR_BROWSER +var testCase = nodeunit.testCase; + +exports.testTestCase = function (test) { + test.expect(7); + var call_order = []; + var s = testCase({ + setUp: function (callback) { + call_order.push('setUp'); + test.equals(this.one, undefined); + this.one = 1; + callback(); + }, + tearDown: function (callback) { + call_order.push('tearDown'); + test.ok(true, 'tearDown called'); + callback(); + }, + test1: function (t) { + call_order.push('test1'); + test.equals(this.one, 1); + this.one = 2; + t.done(); + }, + test2: function (t) { + call_order.push('test2'); + test.equals(this.one, 1); + t.done(); + } + }); + nodeunit.runSuite(null, s, {}, function () { + test.same(call_order, [ + 'setUp', 'test1', 'tearDown', + 'setUp', 'test2', 'tearDown' + ]); + test.done(); + }); +}; + +exports.tearDownAfterError = function (test) { + test.expect(1); + var s = testCase({ + tearDown: function (callback) { + test.ok(true, 'tearDown called'); + callback(); + }, + test: function (t) { + throw new Error('some error'); + } + }); + nodeunit.runSuite(null, s, {}, function () { + test.done(); + }); +}; + +exports.catchSetUpError = function (test) { + test.expect(2); + var test_error = new Error('test error'); + var s = testCase({ + setUp: function (callback) { + throw test_error; + }, + test: function (t) { + test.ok(false, 'test function should not be called'); + t.done(); + } + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 1); + test.equal(assertions[0].error, test_error); + test.done(); + }); +}; + +exports.setUpErrorCallback = function (test) { + test.expect(2); + var test_error = new Error('test error'); + var s = testCase({ + setUp: function (callback) { + callback(test_error); + }, + test: function (t) { + test.ok(false, 'test function should not be called'); + t.done(); + } + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 1); + test.equal(assertions[0].error, test_error); + test.done(); + }); +}; + +exports.catchTearDownError = function (test) { + test.expect(2); + var test_error = new Error('test error'); + var s = testCase({ + tearDown: function (callback) { + throw test_error; + }, + test: function (t) { + t.done(); + } + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 1); + test.equal(assertions[0].error, test_error); + test.done(); + }); +}; + +exports.tearDownErrorCallback = function (test) { + test.expect(2); + var test_error = new Error('test error'); + var s = testCase({ + tearDown: function (callback) { + callback(test_error); + }, + test: function (t) { + t.done(); + } + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 1); + test.equal(assertions[0].error, test_error); + test.done(); + }); +}; + +exports.testErrorAndtearDownError = function (test) { + test.expect(3); + var error1 = new Error('test error one'); + var error2 = new Error('test error two'); + var s = testCase({ + tearDown: function (callback) { + callback(error2); + }, + test: function (t) { + t.done(error1); + } + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 2); + test.equal(assertions[0].error, error1); + test.equal(assertions[1].error, error2); + test.done(); + }); +}; + +exports.testCaseGroups = function (test) { + var call_order = []; + var s = testCase({ + setUp: function (callback) { + call_order.push('setUp'); + callback(); + }, + tearDown: function (callback) { + call_order.push('tearDown'); + callback(); + }, + test1: function (test) { + call_order.push('test1'); + test.done(); + }, + group1: { + test2: function (test) { + call_order.push('group1.test2'); + test.done(); + } + } + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.same(call_order, [ + 'setUp', + 'test1', + 'tearDown', + 'setUp', + 'group1.test2', + 'tearDown' + ]); + test.done(); + }); +}; + +exports.nestedTestCases = function (test) { + var call_order = []; + var s = testCase({ + setUp: function (callback) { + call_order.push('setUp'); + callback(); + }, + tearDown: function (callback) { + call_order.push('tearDown'); + callback(); + }, + test1: function (test) { + call_order.push('test1'); + test.done(); + }, + group1: testCase({ + setUp: function (callback) { + call_order.push('group1.setUp'); + callback(); + }, + tearDown: function (callback) { + call_order.push('group1.tearDown'); + callback(); + }, + test2: function (test) { + call_order.push('group1.test2'); + test.done(); + } + }) + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.same(call_order, [ + 'setUp', + 'test1', + 'tearDown', + 'setUp', + 'group1.setUp', + 'group1.test2', + 'group1.tearDown', + 'tearDown' + ]); + test.done(); + }); +}; + +exports.deepNestedTestCases = function (test) { + var val = 'foo'; + var s = testCase({ + setUp: function (callback) { + val = 'bar'; + callback(); + }, + group1: testCase({ + test: testCase({ + test2: function (test) { + test.equal(val, 'bar'); + test.done(); + } + }) + }) + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.ok(!assertions[0].failed()); + test.equal(assertions.length, 1); + test.done(); + }); +}; diff --git a/node_modules/nodeunit/test/test-testcase.js b/node_modules/nodeunit/test/test-testcase.js new file mode 100644 index 0000000..5d33b0b --- /dev/null +++ b/node_modules/nodeunit/test/test-testcase.js @@ -0,0 +1,256 @@ +/* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. + * Only code on that line will be removed, its mostly to avoid requiring code + * that is node specific + */ + +var nodeunit = require('../lib/nodeunit'); // @REMOVE_LINE_FOR_BROWSER + +exports.testTestCase = function (test) { + test.expect(7); + var call_order = []; + var s = { + setUp: function (callback) { + call_order.push('setUp'); + test.equals(this.one, undefined, 'in setUp, this.one not set'); + this.one = 1; + callback(); + }, + tearDown: function (callback) { + call_order.push('tearDown'); + test.ok(true, 'tearDown called'); + callback(); + }, + test1: function (t) { + call_order.push('test1'); + test.equals(this.one, 1, 'in test1, this.one is 1'); + this.one = 2; + t.done(); + }, + test2: function (t) { + call_order.push('test2'); + test.equals(this.one, 1, 'in test2, this.one is still 1'); + t.done(); + } + }; + nodeunit.runSuite(null, s, {}, function () { + test.same(call_order, [ + 'setUp', 'test1', 'tearDown', + 'setUp', 'test2', 'tearDown' + ]); + test.done(); + }); +}; + +exports.tearDownAfterError = function (test) { + test.expect(1); + var s = { + tearDown: function (callback) { + test.ok(true, 'tearDown called'); + callback(); + }, + test: function (t) { + throw new Error('some error'); + } + }; + nodeunit.runSuite(null, s, {}, function () { + test.done(); + }); +}; + +exports.catchSetUpError = function (test) { + test.expect(2); + var test_error = new Error('test error'); + var s = { + setUp: function (callback) { + throw test_error; + }, + test: function (t) { + test.ok(false, 'test function should not be called'); + t.done(); + } + }; + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 1); + test.equal(assertions[0].error, test_error); + test.done(); + }); +}; + +exports.setUpErrorCallback = function (test) { + test.expect(2); + var test_error = new Error('test error'); + var s = { + setUp: function (callback) { + callback(test_error); + }, + test: function (t) { + test.ok(false, 'test function should not be called'); + t.done(); + } + }; + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 1); + test.equal(assertions[0].error, test_error); + test.done(); + }); +}; + +exports.catchTearDownError = function (test) { + test.expect(2); + var test_error = new Error('test error'); + var s = { + tearDown: function (callback) { + throw test_error; + }, + test: function (t) { + t.done(); + } + }; + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 1); + test.equal(assertions[0].error, test_error); + test.done(); + }); +}; + +exports.tearDownErrorCallback = function (test) { + test.expect(2); + var test_error = new Error('test error'); + var s = { + tearDown: function (callback) { + callback(test_error); + }, + test: function (t) { + t.done(); + } + }; + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 1); + test.equal(assertions[0].error, test_error); + test.done(); + }); +}; + +exports.testErrorAndtearDownError = function (test) { + test.expect(3); + var error1 = new Error('test error one'); + var error2 = new Error('test error two'); + var s = { + tearDown: function (callback) { + callback(error2); + }, + test: function (t) { + t.done(error1); + } + }; + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 2); + test.equal(assertions[0].error, error1); + test.equal(assertions[1].error, error2); + test.done(); + }); +}; + +exports.testCaseGroups = function (test) { + var call_order = []; + var s = { + setUp: function (callback) { + call_order.push('setUp'); + callback(); + }, + tearDown: function (callback) { + call_order.push('tearDown'); + callback(); + }, + test1: function (test) { + call_order.push('test1'); + test.done(); + }, + group1: { + test2: function (test) { + call_order.push('group1.test2'); + test.done(); + } + } + }; + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.same(call_order, [ + 'setUp', + 'test1', + 'tearDown', + 'setUp', + 'group1.test2', + 'tearDown' + ]); + test.done(); + }); +}; + +exports.nestedTestCases = function (test) { + var call_order = []; + var s = { + setUp: function (callback) { + call_order.push('setUp'); + callback(); + }, + tearDown: function (callback) { + call_order.push('tearDown'); + callback(); + }, + test1: function (test) { + call_order.push('test1'); + test.done(); + }, + group1: { + setUp: function (callback) { + call_order.push('group1.setUp'); + callback(); + }, + tearDown: function (callback) { + call_order.push('group1.tearDown'); + callback(); + }, + test2: function (test) { + call_order.push('group1.test2'); + test.done(); + } + } + }; + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.same(call_order, [ + 'setUp', + 'test1', + 'tearDown', + 'setUp', + 'group1.setUp', + 'group1.test2', + 'group1.tearDown', + 'tearDown' + ]); + test.done(); + }); +}; + +exports.deepNestedTestCases = function (test) { + var val = 'foo'; + var s = { + setUp: function (callback) { + val = 'bar'; + callback(); + }, + group1: { + test: { + test2: function (test) { + test.equal(val, 'bar'); + test.done(); + } + } + } + }; + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.ok(!assertions[0].failed()); + test.equal(assertions.length, 1); + test.done(); + }); +}; diff --git a/node_modules/nodeunit/test/test.html b/node_modules/nodeunit/test/test.html new file mode 100644 index 0000000..e0826de --- /dev/null +++ b/node_modules/nodeunit/test/test.html @@ -0,0 +1,28 @@ + + + Nodeunit Test Suite + + + + + + + + + + +

Nodeunit Test Suite

+ + + diff --git a/node_modules/underscore/.npmignore b/node_modules/underscore/.npmignore new file mode 100644 index 0000000..2ce2684 --- /dev/null +++ b/node_modules/underscore/.npmignore @@ -0,0 +1,3 @@ +test/ +Rakefile +docs/ \ No newline at end of file diff --git a/node_modules/underscore/LICENSE b/node_modules/underscore/LICENSE new file mode 100644 index 0000000..61d28c0 --- /dev/null +++ b/node_modules/underscore/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2009-2012 Jeremy Ashkenas, DocumentCloud + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/underscore/README.md b/node_modules/underscore/README.md new file mode 100644 index 0000000..a6564a2 --- /dev/null +++ b/node_modules/underscore/README.md @@ -0,0 +1,19 @@ + __ + /\ \ __ + __ __ ___ \_\ \ __ _ __ ____ ___ ___ _ __ __ /\_\ ____ + /\ \/\ \ /' _ `\ /'_ \ /'__`\/\ __\/ ,__\ / ___\ / __`\/\ __\/'__`\ \/\ \ /',__\ + \ \ \_\ \/\ \/\ \/\ \ \ \/\ __/\ \ \//\__, `\/\ \__//\ \ \ \ \ \//\ __/ __ \ \ \/\__, `\ + \ \____/\ \_\ \_\ \___,_\ \____\\ \_\\/\____/\ \____\ \____/\ \_\\ \____\/\_\ _\ \ \/\____/ + \/___/ \/_/\/_/\/__,_ /\/____/ \/_/ \/___/ \/____/\/___/ \/_/ \/____/\/_//\ \_\ \/___/ + \ \____/ + \/___/ + +Underscore.js is a utility-belt library for JavaScript that provides +support for the usual functional suspects (each, map, reduce, filter...) +without extending any core JavaScript objects. + +For Docs, License, Tests, and pre-packed downloads, see: +http://documentcloud.github.com/underscore/ + +Many thanks to our contributors: +https://github.com/documentcloud/underscore/contributors diff --git a/node_modules/underscore/index.html b/node_modules/underscore/index.html new file mode 100644 index 0000000..52c9671 --- /dev/null +++ b/node_modules/underscore/index.html @@ -0,0 +1,1975 @@ + + + + + + Underscore.js + + + + +
+ +
+ +

+ Underscore.js +

+ +

+ Underscore is a + utility-belt library for JavaScript that provides a lot of the + functional programming support that you would expect in + Prototype.js + (or Ruby), + but without extending any of the built-in JavaScript objects. It's the + tie to go along with jQuery's tux, + and Backbone.js's suspenders. +

+ +

+ Underscore provides 60-odd functions that support both the usual + functional suspects: map, select, invoke — + as well as more specialized helpers: function binding, javascript + templating, deep equality testing, and so on. It delegates to built-in + functions, if present, so modern browsers will use the + native implementations of forEach, map, reduce, + filter, every, some and indexOf. +

+ +

+ A complete Test & Benchmark Suite + is included for your perusal. +

+ +

+ You may also read through the annotated source code. +

+ +

+ The project is + hosted on GitHub. + You can report bugs and discuss features on the + issues page, + on Freenode in the #documentcloud channel, + or send tweets to @documentcloud. +

+ +

+ Underscore is an open-source component of DocumentCloud. +

+ +

Downloads (Right-click, and use "Save As")

+ + + + + + + + + + +
Development Version (1.3.1)34kb, Uncompressed with Comments
Production Version (1.3.1)< 4kb, Minified and Gzipped
+ +
Upgrade warning: version 1.3.0 removes AMD (RequireJS) support.
+ +
+ +

Collection Functions (Arrays or Objects)

+ +

+ each_.each(list, iterator, [context]) + Alias: forEach +
+ Iterates over a list of elements, yielding each in turn to an iterator + function. The iterator is bound to the context object, if one is + passed. Each invocation of iterator is called with three arguments: + (element, index, list). If list is a JavaScript object, iterator's + arguments will be (value, key, list). Delegates to the native + forEach function if it exists. +

+
+_.each([1, 2, 3], function(num){ alert(num); });
+=> alerts each number in turn...
+_.each({one : 1, two : 2, three : 3}, function(num, key){ alert(num); });
+=> alerts each number in turn...
+ +

+ map_.map(list, iterator, [context]) + Alias: collect +
+ Produces a new array of values by mapping each value in list + through a transformation function (iterator). If the native map method + exists, it will be used instead. If list is a JavaScript object, + iterator's arguments will be (value, key, list). +

+
+_.map([1, 2, 3], function(num){ return num * 3; });
+=> [3, 6, 9]
+_.map({one : 1, two : 2, three : 3}, function(num, key){ return num * 3; });
+=> [3, 6, 9]
+ +

+ reduce_.reduce(list, iterator, memo, [context]) + Aliases: inject, foldl +
+ Also known as inject and foldl, reduce boils down a + list of values into a single value. Memo is the initial state + of the reduction, and each successive step of it should be returned by + iterator. +

+
+var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
+=> 6
+
+ +

+ reduceRight_.reduceRight(list, iterator, memo, [context]) + Alias: foldr +
+ The right-associative version of reduce. Delegates to the + JavaScript 1.8 version of reduceRight, if it exists. Foldr + is not as useful in JavaScript as it would be in a language with lazy + evaluation. +

+
+var list = [[0, 1], [2, 3], [4, 5]];
+var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
+=> [4, 5, 2, 3, 0, 1]
+
+ +

+ find_.find(list, iterator, [context]) + Alias: detect +
+ Looks through each value in the list, returning the first one that + passes a truth test (iterator). The function returns as + soon as it finds an acceptable element, and doesn't traverse the + entire list. +

+
+var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
+=> 2
+
+ +

+ filter_.filter(list, iterator, [context]) + Alias: select +
+ Looks through each value in the list, returning an array of all + the values that pass a truth test (iterator). Delegates to the + native filter method, if it exists. +

+
+var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
+=> [2, 4, 6]
+
+ +

+ reject_.reject(list, iterator, [context]) +
+ Returns the values in list without the elements that the truth + test (iterator) passes. The opposite of filter. +

+
+var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
+=> [1, 3, 5]
+
+ +

+ all_.all(list, iterator, [context]) + Alias: every +
+ Returns true if all of the values in the list pass the iterator + truth test. Delegates to the native method every, if present. +

+
+_.all([true, 1, null, 'yes'], _.identity);
+=> false
+
+ +

+ any_.any(list, [iterator], [context]) + Alias: some +
+ Returns true if any of the values in the list pass the + iterator truth test. Short-circuits and stops traversing the list + if a true element is found. Delegates to the native method some, + if present. +

+
+_.any([null, 0, 'yes', false]);
+=> true
+
+ +

+ include_.include(list, value) + Alias: contains +
+ Returns true if the value is present in the list, using + === to test equality. Uses indexOf internally, if list + is an Array. +

+
+_.include([1, 2, 3], 3);
+=> true
+
+ +

+ invoke_.invoke(list, methodName, [*arguments]) +
+ Calls the method named by methodName on each value in the list. + Any extra arguments passed to invoke will be forwarded on to the + method invocation. +

+
+_.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
+=> [[1, 5, 7], [1, 2, 3]]
+
+ +

+ pluck_.pluck(list, propertyName) +
+ A convenient version of what is perhaps the most common use-case for + map: extracting a list of property values. +

+
+var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
+_.pluck(stooges, 'name');
+=> ["moe", "larry", "curly"]
+
+ +

+ max_.max(list, [iterator], [context]) +
+ Returns the maximum value in list. If iterator is passed, + it will be used on each value to generate the criterion by which the + value is ranked. +

+
+var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
+_.max(stooges, function(stooge){ return stooge.age; });
+=> {name : 'curly', age : 60};
+
+ +

+ min_.min(list, [iterator], [context]) +
+ Returns the minimum value in list. If iterator is passed, + it will be used on each value to generate the criterion by which the + value is ranked. +

+
+var numbers = [10, 5, 100, 2, 1000];
+_.min(numbers);
+=> 2
+
+ +

+ sortBy_.sortBy(list, iterator, [context]) +
+ Returns a sorted copy of list, ranked in ascending order by the + results of running each value through iterator. +

+
+_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
+=> [5, 4, 6, 3, 1, 2]
+
+ +

+ groupBy_.groupBy(list, iterator) +
+ Splits a collection into sets, grouped by the result of running each + value through iterator. If iterator is a string instead of + a function, groups by the property named by iterator on each of + the values. +

+
+_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });
+=> {1: [1.3], 2: [2.1, 2.4]}
+
+_.groupBy(['one', 'two', 'three'], 'length');
+=> {3: ["one", "two"], 5: ["three"]}
+
+ +

+ sortedIndex_.sortedIndex(list, value, [iterator]) +
+ Uses a binary search to determine the index at which the value + should be inserted into the list in order to maintain the list's + sorted order. If an iterator is passed, it will be used to compute + the sort ranking of each value. +

+
+_.sortedIndex([10, 20, 30, 40, 50], 35);
+=> 3
+
+ +

+ shuffle_.shuffle(list) +
+ Returns a shuffled copy of the list, using a version of the + Fisher-Yates shuffle. +

+
+_.shuffle([1, 2, 3, 4, 5, 6]);
+=> [4, 1, 6, 3, 5, 2]
+
+ +

+ toArray_.toArray(list) +
+ Converts the list (anything that can be iterated over), into a + real Array. Useful for transmuting the arguments object. +

+
+(function(){ return _.toArray(arguments).slice(0); })(1, 2, 3);
+=> [1, 2, 3]
+
+ +

+ size_.size(list) +
+ Return the number of values in the list. +

+
+_.size({one : 1, two : 2, three : 3});
+=> 3
+
+ +

Array Functions

+ +

+ Note: All array functions will also work on the arguments object. +

+ +

+ first_.first(array, [n]) + Alias: head +
+ Returns the first element of an array. Passing n will + return the first n elements of the array. +

+
+_.first([5, 4, 3, 2, 1]);
+=> 5
+
+ +

+ initial_.initial(array, [n]) +
+ Returns everything but the last entry of the array. Especially useful on + the arguments object. Pass n to exclude the last n elements + from the result. +

+
+_.initial([5, 4, 3, 2, 1]);
+=> [5, 4, 3, 2]
+
+ +

+ last_.last(array, [n]) +
+ Returns the last element of an array. Passing n will return + the last n elements of the array. +

+
+_.last([5, 4, 3, 2, 1]);
+=> 1
+
+ +

+ rest_.rest(array, [index]) + Alias: tail +
+ Returns the rest of the elements in an array. Pass an index + to return the values of the array from that index onward. +

+
+_.rest([5, 4, 3, 2, 1]);
+=> [4, 3, 2, 1]
+
+ +

+ compact_.compact(array) +
+ Returns a copy of the array with all falsy values removed. + In JavaScript, false, null, 0, "", + undefined and NaN are all falsy. +

+
+_.compact([0, 1, false, 2, '', 3]);
+=> [1, 2, 3]
+
+ +

+ flatten_.flatten(array, [shallow]) +
+ Flattens a nested array (the nesting can be to any depth). If you + pass shallow, the array will only be flattened a single level. +

+
+_.flatten([1, [2], [3, [[4]]]]);
+=> [1, 2, 3, 4];
+
+_.flatten([1, [2], [3, [[4]]]], true);
+=> [1, 2, 3, [[4]]];
+
+ +

+ without_.without(array, [*values]) +
+ Returns a copy of the array with all instances of the values + removed. === is used for the equality test. +

+
+_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
+=> [2, 3, 4]
+
+ +

+ union_.union(*arrays) +
+ Computes the union of the passed-in arrays: the list of unique items, + in order, that are present in one or more of the arrays. +

+
+_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
+=> [1, 2, 3, 101, 10]
+
+ +

+ intersection_.intersection(*arrays) +
+ Computes the list of values that are the intersection of all the arrays. + Each value in the result is present in each of the arrays. +

+
+_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
+=> [1, 2]
+
+ +

+ difference_.difference(array, *others) +
+ Similar to without, but returns the values from array that + are not present in the other arrays. +

+
+_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
+=> [1, 3, 4]
+
+ +

+ uniq_.uniq(array, [isSorted], [iterator]) + Alias: unique +
+ Produces a duplicate-free version of the array, using === to test + object equality. If you know in advance that the array is sorted, + passing true for isSorted will run a much faster algorithm. + If you want to compute unique items based on a transformation, pass an + iterator function. +

+
+_.uniq([1, 2, 1, 3, 1, 4]);
+=> [1, 2, 3, 4]
+
+ +

+ zip_.zip(*arrays) +
+ Merges together the values of each of the arrays with the + values at the corresponding position. Useful when you have separate + data sources that are coordinated through matching array indexes. + If you're working with a matrix of nested arrays, zip.apply + can transpose the matrix in a similar fashion. +

+
+_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
+=> [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]
+
+ +

+ indexOf_.indexOf(array, value, [isSorted]) +
+ Returns the index at which value can be found in the array, + or -1 if value is not present in the array. Uses the native + indexOf function unless it's missing. If you're working with a + large array, and you know that the array is already sorted, pass true + for isSorted to use a faster binary search. +

+
+_.indexOf([1, 2, 3], 2);
+=> 1
+
+ +

+ lastIndexOf_.lastIndexOf(array, value) +
+ Returns the index of the last occurrence of value in the array, + or -1 if value is not present. Uses the native lastIndexOf + function if possible. +

+
+_.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
+=> 4
+
+ +

+ range_.range([start], stop, [step]) +
+ A function to create flexibly-numbered lists of integers, handy for + each and map loops. start, if omitted, defaults + to 0; step defaults to 1. Returns a list of integers + from start to stop, incremented (or decremented) by step, + exclusive. +

+
+_.range(10);
+=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+_.range(1, 11);
+=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+_.range(0, 30, 5);
+=> [0, 5, 10, 15, 20, 25]
+_.range(0, -10, -1);
+=> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
+_.range(0);
+=> []
+
+ +

Function (uh, ahem) Functions

+ +

+ bind_.bind(function, object, [*arguments]) +
+ Bind a function to an object, meaning that whenever + the function is called, the value of this will be the object. + Optionally, bind arguments to the function to pre-fill them, + also known as partial application. +

+
+var func = function(greeting){ return greeting + ': ' + this.name };
+func = _.bind(func, {name : 'moe'}, 'hi');
+func();
+=> 'hi: moe'
+
+ +

+ bindAll_.bindAll(object, [*methodNames]) +
+ Binds a number of methods on the object, specified by + methodNames, to be run in the context of that object whenever they + are invoked. Very handy for binding functions that are going to be used + as event handlers, which would otherwise be invoked with a fairly useless + this. If no methodNames are provided, all of the object's + function properties will be bound to it. +

+
+var buttonView = {
+  label   : 'underscore',
+  onClick : function(){ alert('clicked: ' + this.label); },
+  onHover : function(){ console.log('hovering: ' + this.label); }
+};
+_.bindAll(buttonView);
+jQuery('#underscore_button').bind('click', buttonView.onClick);
+=> When the button is clicked, this.label will have the correct value...
+
+ +

+ memoize_.memoize(function, [hashFunction]) +
+ Memoizes a given function by caching the computed result. Useful + for speeding up slow-running computations. If passed an optional + hashFunction, it will be used to compute the hash key for storing + the result, based on the arguments to the original function. The default + hashFunction just uses the first argument to the memoized function + as the key. +

+
+var fibonacci = _.memoize(function(n) {
+  return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
+});
+
+ +

+ delay_.delay(function, wait, [*arguments]) +
+ Much like setTimeout, invokes function after wait + milliseconds. If you pass the optional arguments, they will be + forwarded on to the function when it is invoked. +

+
+var log = _.bind(console.log, console);
+_.delay(log, 1000, 'logged later');
+=> 'logged later' // Appears after one second.
+
+ +

+ defer_.defer(function) +
+ Defers invoking the function until the current call stack has cleared, + similar to using setTimeout with a delay of 0. Useful for performing + expensive computations or HTML rendering in chunks without blocking the UI thread + from updating. +

+
+_.defer(function(){ alert('deferred'); });
+// Returns from the function before the alert runs.
+
+ +

+ throttle_.throttle(function, wait) +
+ Creates and returns a new, throttled version of the passed function, + that, when invoked repeatedly, will only actually call the original function + at most once per every wait + milliseconds. Useful for rate-limiting events that occur faster than you + can keep up with. +

+
+var throttled = _.throttle(updatePosition, 100);
+$(window).scroll(throttled);
+
+ +

+ debounce_.debounce(function, wait) +
+ Creates and returns a new debounced version of the passed function that + will postpone its execution until after + wait milliseconds have elapsed since the last time it + was invoked. Useful for implementing behavior that should only happen + after the input has stopped arriving. For example: rendering a + preview of a Markdown comment, recalculating a layout after the window + has stopped being resized, and so on. +

+
+var lazyLayout = _.debounce(calculateLayout, 300);
+$(window).resize(lazyLayout);
+
+ +

+ once_.once(function) +
+ Creates a version of the function that can only be called one time. + Repeated calls to the modified function will have no effect, returning + the value from the original call. Useful for initialization functions, + instead of having to set a boolean flag and then check it later. +

+
+var initialize = _.once(createApplication);
+initialize();
+initialize();
+// Application is only created once.
+
+ +

+ after_.after(count, function) +
+ Creates a version of the function that will only be run after first + being called count times. Useful for grouping asynchronous responses, + where you want to be sure that all the async calls have finished, before + proceeding. +

+
+var renderNotes = _.after(notes.length, render);
+_.each(notes, function(note) {
+  note.asyncSave({success: renderNotes}); 
+});
+// renderNotes is run once, after all notes have saved.
+
+ +

+ wrap_.wrap(function, wrapper) +
+ Wraps the first function inside of the wrapper function, + passing it as the first argument. This allows the wrapper to + execute code before and after the function runs, adjust the arguments, + and execute it conditionally. +

+
+var hello = function(name) { return "hello: " + name; };
+hello = _.wrap(hello, function(func) {
+  return "before, " + func("moe") + ", after";
+});
+hello();
+=> 'before, hello: moe, after'
+
+ +

+ compose_.compose(*functions) +
+ Returns the composition of a list of functions, where each function + consumes the return value of the function that follows. In math terms, + composing the functions f(), g(), and h() produces + f(g(h())). +

+
+var greet    = function(name){ return "hi: " + name; };
+var exclaim  = function(statement){ return statement + "!"; };
+var welcome = _.compose(exclaim, greet);
+welcome('moe');
+=> 'hi: moe!'
+
+ +

Object Functions

+ +

+ keys_.keys(object) +
+ Retrieve all the names of the object's properties. +

+
+_.keys({one : 1, two : 2, three : 3});
+=> ["one", "two", "three"]
+
+ +

+ values_.values(object) +
+ Return all of the values of the object's properties. +

+
+_.values({one : 1, two : 2, three : 3});
+=> [1, 2, 3]
+
+ +

+ functions_.functions(object) + Alias: methods +
+ Returns a sorted list of the names of every method in an object — + that is to say, the name of every function property of the object. +

+
+_.functions(_);
+=> ["all", "any", "bind", "bindAll", "clone", "compact", "compose" ...
+
+ +

+ extend_.extend(destination, *sources) +
+ Copy all of the properties in the source objects over to the + destination object. It's in-order, so the last source will override + properties of the same name in previous arguments. +

+
+_.extend({name : 'moe'}, {age : 50});
+=> {name : 'moe', age : 50}
+
+ +

+ defaults_.defaults(object, *defaults) +
+ Fill in missing properties in object with default values from the + defaults objects. As soon as the property is filled, further defaults + will have no effect. +

+
+var iceCream = {flavor : "chocolate"};
+_.defaults(iceCream, {flavor : "vanilla", sprinkles : "lots"});
+=> {flavor : "chocolate", sprinkles : "lots"}
+
+ +

+ clone_.clone(object) +
+ Create a shallow-copied clone of the object. Any nested objects + or arrays will be copied by reference, not duplicated. +

+
+_.clone({name : 'moe'});
+=> {name : 'moe'};
+
+ +

+ tap_.tap(object, interceptor) +
+ Invokes interceptor with the object, and then returns object. + The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain. +

+
+_.chain([1,2,3,200])
+  .filter(function(num) { return num % 2 == 0; })
+  .tap(console.log)
+  .map(function(num) { return num * num })
+  .value();
+=> [2, 200]
+=> [4, 40000]
+
+ +

+ has_.has(object, key) +
+ Does the object contain the given key? Identical to + object.hasOwnProperty(key), but uses a safe reference to the + hasOwnProperty function, in case it's been + overridden accidentally. +

+
+_.has({a: 1, b: 2, c: 3}, "b");
+=> true
+
+ +

+ isEqual_.isEqual(object, other) +
+ Performs an optimized deep comparison between the two objects, to determine + if they should be considered equal. +

+
+var moe   = {name : 'moe', luckyNumbers : [13, 27, 34]};
+var clone = {name : 'moe', luckyNumbers : [13, 27, 34]};
+moe == clone;
+=> false
+_.isEqual(moe, clone);
+=> true
+
+ +

+ isEmpty_.isEmpty(object) +
+ Returns true if object contains no values. +

+
+_.isEmpty([1, 2, 3]);
+=> false
+_.isEmpty({});
+=> true
+
+ +

+ isElement_.isElement(object) +
+ Returns true if object is a DOM element. +

+
+_.isElement(jQuery('body')[0]);
+=> true
+
+ +

+ isArray_.isArray(object) +
+ Returns true if object is an Array. +

+
+(function(){ return _.isArray(arguments); })();
+=> false
+_.isArray([1,2,3]);
+=> true
+
+ +

+ isArguments_.isArguments(object) +
+ Returns true if object is an Arguments object. +

+
+(function(){ return _.isArguments(arguments); })(1, 2, 3);
+=> true
+_.isArguments([1,2,3]);
+=> false
+
+ +

+ isFunction_.isFunction(object) +
+ Returns true if object is a Function. +

+
+_.isFunction(alert);
+=> true
+
+ +

+ isString_.isString(object) +
+ Returns true if object is a String. +

+
+_.isString("moe");
+=> true
+
+ +

+ isNumber_.isNumber(object) +
+ Returns true if object is a Number (including NaN). +

+
+_.isNumber(8.4 * 5);
+=> true
+
+ +

+ isBoolean_.isBoolean(object) +
+ Returns true if object is either true or false. +

+
+_.isBoolean(null);
+=> false
+
+ +

+ isDate_.isDate(object) +
+ Returns true if object is a Date. +

+
+_.isDate(new Date());
+=> true
+
+ +

+ isRegExp_.isRegExp(object) +
+ Returns true if object is a RegExp. +

+
+_.isRegExp(/moe/);
+=> true
+
+ +

+ isNaN_.isNaN(object) +
+ Returns true if object is NaN.
Note: this is not + the same as the native isNaN function, which will also return + true if the variable is undefined. +

+
+_.isNaN(NaN);
+=> true
+isNaN(undefined);
+=> true
+_.isNaN(undefined);
+=> false
+
+ +

+ isNull_.isNull(object) +
+ Returns true if the value of object is null. +

+
+_.isNull(null);
+=> true
+_.isNull(undefined);
+=> false
+
+ +

+ isUndefined_.isUndefined(variable) +
+ Returns true if variable is undefined. +

+
+_.isUndefined(window.missingVariable);
+=> true
+
+ +

Utility Functions

+ +

+ noConflict_.noConflict() +
+ Give control of the "_" variable back to its previous owner. Returns + a reference to the Underscore object. +

+
+var underscore = _.noConflict();
+ +

+ identity_.identity(value) +
+ Returns the same value that is used as the argument. In math: + f(x) = x
+ This function looks useless, but is used throughout Underscore as + a default iterator. +

+
+var moe = {name : 'moe'};
+moe === _.identity(moe);
+=> true
+ +

+ times_.times(n, iterator) +
+ Invokes the given iterator function n times. +

+
+_(3).times(function(){ genie.grantWish(); });
+ +

+ mixin_.mixin(object) +
+ Allows you to extend Underscore with your own utility functions. Pass + a hash of {name: function} definitions to have your functions + added to the Underscore object, as well as the OOP wrapper. +

+
+_.mixin({
+  capitalize : function(string) {
+    return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase();
+  }
+});
+_("fabio").capitalize();
+=> "Fabio"
+
+ +

+ uniqueId_.uniqueId([prefix]) +
+ Generate a globally-unique id for client-side models or DOM elements + that need one. If prefix is passed, the id will be appended to it. +

+
+_.uniqueId('contact_');
+=> 'contact_104'
+ +

+ escape_.escape(string) +
+ Escapes a string for insertion into HTML, replacing + &, <, >, ", ', and / characters. +

+
+_.escape('Curly, Larry & Moe');
+=> "Curly, Larry &amp; Moe"
+ +

+ template_.template(templateString, [context]) +
+ Compiles JavaScript templates into functions that can be evaluated + for rendering. Useful for rendering complicated bits of HTML from JSON + data sources. Template functions can both interpolate variables, using
+ <%= … %>, as well as execute arbitrary JavaScript code, with + <% … %>. If you wish to interpolate a value, and have + it be HTML-escaped, use <%- … %> When you evaluate a template function, pass in a + context object that has properties corresponding to the template's free + variables. If you're writing a one-off, you can pass the context + object as the second parameter to template in order to render + immediately instead of returning a template function. +

+
+var compiled = _.template("hello: <%= name %>");
+compiled({name : 'moe'});
+=> "hello: moe"
+
+var list = "<% _.each(people, function(name) { %> <li><%= name %></li> <% }); %>";
+_.template(list, {people : ['moe', 'curly', 'larry']});
+=> "<li>moe</li><li>curly</li><li>larry</li>"
+
+var template = _.template("<b><%- value %></b>");
+template({value : '<script>'});
+=> "<b>&lt;script&gt;</b>"
+ +

+ You can also use print from within JavaScript code. This is + sometimes more convenient than using <%= ... %>. +

+ +
+var compiled = _.template("<% print('Hello ' + epithet); %>");
+compiled({epithet: "stooge"});
+=> "Hello stooge."
+ +

+ If ERB-style delimiters aren't your cup of tea, you can change Underscore's + template settings to use different symbols to set off interpolated code. + Define an interpolate regex to match expressions that should be + interpolated verbatim, an escape regex to match expressions that should + be inserted after being HTML escaped, and an evaluate regex to match + expressions that should be evaluated without insertion into the resulting + string. You may define or omit any combination of the three. + For example, to perform + Mustache.js + style templating: +

+ +
+_.templateSettings = {
+  interpolate : /\{\{(.+?)\}\}/g
+};
+
+var template = _.template("Hello {{ name }}!");
+template({name : "Mustache"});
+=> "Hello Mustache!"
+ + +

Chaining

+ +

+ You can use Underscore in either an object-oriented or a functional style, + depending on your preference. The following two lines of code are + identical ways to double a list of numbers. +

+ +
+_.map([1, 2, 3], function(n){ return n * 2; });
+_([1, 2, 3]).map(function(n){ return n * 2; });
+ +

+ Using the object-oriented style allows you to chain together methods. Calling + chain on a wrapped object will cause all future method calls to + return wrapped objects as well. When you've finished the computation, + use value to retrieve the final value. Here's an example of chaining + together a map/flatten/reduce, in order to get the word count of + every word in a song. +

+ +
+var lyrics = [
+  {line : 1, words : "I'm a lumberjack and I'm okay"},
+  {line : 2, words : "I sleep all night and I work all day"},
+  {line : 3, words : "He's a lumberjack and he's okay"},
+  {line : 4, words : "He sleeps all night and he works all day"}
+];
+
+_.chain(lyrics)
+  .map(function(line) { return line.words.split(' '); })
+  .flatten()
+  .reduce(function(counts, word) {
+    counts[word] = (counts[word] || 0) + 1;
+    return counts;
+}, {}).value();
+
+=> {lumberjack : 2, all : 4, night : 2 ... }
+ +

+ In addition, the + Array prototype's methods + are proxied through the chained Underscore object, so you can slip a + reverse or a push into your chain, and continue to + modify the array. +

+ +

+ chain_.chain(obj) +
+ Returns a wrapped object. Calling methods on this object will continue + to return wrapped objects until value is used. +

+
+var stooges = [{name : 'curly', age : 25}, {name : 'moe', age : 21}, {name : 'larry', age : 23}];
+var youngest = _.chain(stooges)
+  .sortBy(function(stooge){ return stooge.age; })
+  .map(function(stooge){ return stooge.name + ' is ' + stooge.age; })
+  .first()
+  .value();
+=> "moe is 21"
+
+ +

+ value_(obj).value() +
+ Extracts the value of a wrapped object. +

+
+_([1, 2, 3]).value();
+=> [1, 2, 3]
+
+ + + +

+ Underscore.lua, + a Lua port of the functions that are applicable in both languages. + Includes OOP-wrapping and chaining. + The source is + available on GitHub. +

+ +

+ Underscore.php, + a PHP port of the functions that are applicable in both languages. + Includes OOP-wrapping and chaining. + The source is + available on GitHub. +

+ +

+ Underscore-perl, + a Perl port of many of the Underscore.js functions, + aimed at on Perl hashes and arrays, also + available on GitHub. +

+ +

+ Underscore.string, + an Underscore extension that adds functions for string-manipulation: + trim, startsWith, contains, capitalize, + reverse, sprintf, and more. +

+ +

+ Ruby's Enumerable module. +

+ +

+ Prototype.js, which provides + JavaScript with collection functions in the manner closest to Ruby's Enumerable. +

+ +

+ Oliver Steele's + Functional JavaScript, + which includes comprehensive higher-order function support as well as string lambdas. +

+ +

+ Michael Aufreiter's Data.js, + a data manipulation + persistence library for JavaScript. +

+ +

+ Python's itertools. +

+ +

Change Log

+ +

+ 1.3.1Jan. 23, 2012
+

    +
  • + Added an _.has function, as a safer way to use hasOwnProperty. +
  • +
  • + Added _.collect as an alias for _.map. Smalltalkers, rejoice. +
  • +
  • + Reverted an old change so that _.extend will correctly copy + over keys with undefined values again. +
  • +
  • + Bugfix to stop escaping slashes within interpolations in _.template. +
  • +
+

+ +

+ 1.3.0Jan. 11, 2012
+

    +
  • + Removed AMD (RequireJS) support from Underscore. If you'd like to use + Underscore with RequireJS, you can load it as a normal script, wrap + or patch your copy, or download a forked version. +
  • +
+

+ +

+ 1.2.4Jan. 4, 2012
+

    +
  • + You now can (and probably should) write _.chain(list) + instead of _(list).chain(). +
  • +
  • + Fix for escaped characters in Underscore templates, and for supporting + customizations of _.templateSettings that only define one or + two of the required regexes. +
  • +
  • + Fix for passing an array as the first argument to an _.wrap'd function. +
  • +
  • + Improved compatibility with ClojureScript, which adds a call + function to String.prototype. +
  • +
+

+ +

+ 1.2.3Dec. 7, 2011
+

    +
  • + Dynamic scope is now preserved for compiled _.template functions, + so you can use the value of this if you like. +
  • +
  • + Sparse array support of _.indexOf, _.lastIndexOf. +
  • +
  • + Both _.reduce and _.reduceRight can now be passed an + explicitly undefined value. (There's no reason why you'd + want to do this.) +
  • +
+

+ +

+ 1.2.2Nov. 14, 2011
+

    +
  • + Continued tweaks to _.isEqual semantics. Now JS primitives are + considered equivalent to their wrapped versions, and arrays are compared + by their numeric properties only (#351). +
  • +
  • + _.escape no longer tries to be smart about not double-escaping + already-escaped HTML entities. Now it just escapes regardless (#350). +
  • +
  • + In _.template, you may now leave semicolons out of evaluated + statements if you wish: <% }) %> (#369). +
  • +
  • + _.after(callback, 0) will now trigger the callback immediately, + making "after" easier to use with asynchronous APIs (#366). +
  • +
+

+ +

+ 1.2.1Oct. 24, 2011
+

    +
  • + Several important bug fixes for _.isEqual, which should now + do better on mutated Arrays, and on non-Array objects with + length properties. (#329) +
  • +
  • + jrburke contributed Underscore exporting for AMD module loaders, + and tonylukasavage for Appcelerator Titanium. + (#335, #338) +
  • +
  • + You can now _.groupBy(list, 'property') as a shortcut for + grouping values by a particular common property. +
  • +
  • + _.throttle'd functions now fire immediately upon invocation, + and are rate-limited thereafter (#170, #266). +
  • +
  • + Most of the _.is[Type] checks no longer ducktype. +
  • +
  • + The _.bind function now also works on constructors, a-la + ES5 ... but you would never want to use _.bind on a + constructor function. +
  • +
  • + _.clone no longer wraps non-object types in Objects. +
  • +
  • + _.find and _.filter are now the preferred names for + _.detect and _.select. +
  • +
+

+ +

+ 1.2.0Oct. 5, 2011
+

    +
  • + The _.isEqual function now + supports true deep equality comparisons, with checks for cyclic structures, + thanks to Kit Cambridge. +
  • +
  • + Underscore templates now support HTML escaping interpolations, using + <%- ... %> syntax. +
  • +
  • + Ryan Tenney contributed _.shuffle, which uses a modified + Fisher-Yates to give you a shuffled copy of an array. +
  • +
  • + _.uniq can now be passed an optional iterator, to determine by + what criteria an object should be considered unique. +
  • +
  • + _.last now takes an optional argument which will return the last + N elements of the list. +
  • +
  • + A new _.initial function was added, as a mirror of _.rest, + which returns all the initial values of a list (except the last N). +
  • +
+

+ +

+ 1.1.7July 13, 2011
+ Added _.groupBy, which aggregates a collection into groups of like items. + Added _.union and _.difference, to complement the + (re-named) _.intersection. + Various improvements for support of sparse arrays. + _.toArray now returns a clone, if directly passed an array. + _.functions now also returns the names of functions that are present + in the prototype chain. +

+ +

+ 1.1.6April 18, 2011
+ Added _.after, which will return a function that only runs after + first being called a specified number of times. + _.invoke can now take a direct function reference. + _.every now requires an iterator function to be passed, which + mirrors the ECMA5 API. + _.extend no longer copies keys when the value is undefined. + _.bind now errors when trying to bind an undefined value. +

+ +

+ 1.1.5Mar 20, 2011
+ Added an _.defaults function, for use merging together JS objects + representing default options. + Added an _.once function, for manufacturing functions that should + only ever execute a single time. + _.bind now delegates to the native ECMAScript 5 version, + where available. + _.keys now throws an error when used on non-Object values, as in + ECMAScript 5. + Fixed a bug with _.keys when used over sparse arrays. +

+ +

+ 1.1.4Jan 9, 2011
+ Improved compliance with ES5's Array methods when passing null + as a value. _.wrap now correctly sets this for the + wrapped function. _.indexOf now takes an optional flag for + finding the insertion index in an array that is guaranteed to already + be sorted. Avoiding the use of .callee, to allow _.isArray + to work properly in ES5's strict mode. +

+ +

+ 1.1.3Dec 1, 2010
+ In CommonJS, Underscore may now be required with just:
+ var _ = require("underscore"). + Added _.throttle and _.debounce functions. + Removed _.breakLoop, in favor of an ECMA5-style un-break-able + each implementation — this removes the try/catch, and you'll now have + better stack traces for exceptions that are thrown within an Underscore iterator. + Improved the isType family of functions for better interoperability + with Internet Explorer host objects. + _.template now correctly escapes backslashes in templates. + Improved _.reduce compatibility with the ECMA5 version: + if you don't pass an initial value, the first item in the collection is used. + _.each no longer returns the iterated collection, for improved + consistency with ES5's forEach. +

+ +

+ 1.1.2
+ Fixed _.contains, which was mistakenly pointing at + _.intersect instead of _.include, like it should + have been. Added _.unique as an alias for _.uniq. +

+ +

+ 1.1.1
+ Improved the speed of _.template, and its handling of multiline + interpolations. Ryan Tenney contributed optimizations to many Underscore + functions. An annotated version of the source code is now available. +

+ +

+ 1.1.0
+ The method signature of _.reduce has been changed to match + the ECMAScript 5 signature, instead of the Ruby/Prototype.js version. + This is a backwards-incompatible change. _.template may now be + called with no arguments, and preserves whitespace. _.contains + is a new alias for _.include. +

+ +

+ 1.0.4
+ Andri Möll contributed the _.memoize + function, which can be used to speed up expensive repeated computations + by caching the results. +

+ +

+ 1.0.3
+ Patch that makes _.isEqual return false if any property + of the compared object has a NaN value. Technically the correct + thing to do, but of questionable semantics. Watch out for NaN comparisons. +

+ +

+ 1.0.2
+ Fixes _.isArguments in recent versions of Opera, which have + arguments objects as real Arrays. +

+ +

+ 1.0.1
+ Bugfix for _.isEqual, when comparing two objects with the same + number of undefined keys, but with different names. +

+ +

+ 1.0.0
+ Things have been stable for many months now, so Underscore is now + considered to be out of beta, at 1.0. Improvements since 0.6 + include _.isBoolean, and the ability to have _.extend + take multiple source objects. +

+ +

+ 0.6.0
+ Major release. Incorporates a number of + Mile Frawley's refactors for + safer duck-typing on collection functions, and cleaner internals. A new + _.mixin method that allows you to extend Underscore with utility + functions of your own. Added _.times, which works the same as in + Ruby or Prototype.js. Native support for ECMAScript 5's Array.isArray, + and Object.keys. +

+ +

+ 0.5.8
+ Fixed Underscore's collection functions to work on + NodeLists and + HTMLCollections + once more, thanks to + Justin Tulloss. +

+ +

+ 0.5.7
+ A safer implementation of _.isArguments, and a + faster _.isNumber,
thanks to + Jed Schmidt. +

+ +

+ 0.5.6
+ Customizable delimiters for _.template, contributed by + Noah Sloan. +

+ +

+ 0.5.5
+ Fix for a bug in MobileSafari's OOP-wrapper, with the arguments object. +

+ +

+ 0.5.4
+ Fix for multiple single quotes within a template string for + _.template. See: + Rick Strahl's blog post. +

+ +

+ 0.5.2
+ New implementations of isArray, isDate, isFunction, + isNumber, isRegExp, and isString, thanks to + a suggestion from + Robert Kieffer. + Instead of doing Object#toString + comparisons, they now check for expected properties, which is less safe, + but more than an order of magnitude faster. Most other Underscore + functions saw minor speed improvements as a result. + Evgeniy Dolzhenko + contributed _.tap, + similar to Ruby 1.9's, + which is handy for injecting side effects (like logging) into chained calls. +

+ +

+ 0.5.1
+ Added an _.isArguments function. Lots of little safety checks + and optimizations contributed by + Noah Sloan and + Andri Möll. +

+ +

+ 0.5.0
+ [API Changes] _.bindAll now takes the context object as + its first parameter. If no method names are passed, all of the context + object's methods are bound to it, enabling chaining and easier binding. + _.functions now takes a single argument and returns the names + of its Function properties. Calling _.functions(_) will get you + the previous behavior. + Added _.isRegExp so that isEqual can now test for RegExp equality. + All of the "is" functions have been shrunk down into a single definition. + Karl Guertin contributed patches. +

+ +

+ 0.4.7
+ Added isDate, isNaN, and isNull, for completeness. + Optimizations for isEqual when checking equality between Arrays + or Dates. _.keys is now 25%–2X faster (depending on your + browser) which speeds up the functions that rely on it, such as _.each. +

+ +

+ 0.4.6
+ Added the range function, a port of the + Python + function of the same name, for generating flexibly-numbered lists + of integers. Original patch contributed by + Kirill Ishanov. +

+ +

+ 0.4.5
+ Added rest for Arrays and arguments objects, and aliased + first as head, and rest as tail, + thanks to Luke Sutton's patches. + Added tests ensuring that all Underscore Array functions also work on + arguments objects. +

+ +

+ 0.4.4
+ Added isString, and isNumber, for consistency. Fixed + _.isEqual(NaN, NaN) to return true (which is debatable). +

+ +

+ 0.4.3
+ Started using the native StopIteration object in browsers that support it. + Fixed Underscore setup for CommonJS environments. +

+ +

+ 0.4.2
+ Renamed the unwrapping function to value, for clarity. +

+ +

+ 0.4.1
+ Chained Underscore objects now support the Array prototype methods, so + that you can perform the full range of operations on a wrapped array + without having to break your chain. Added a breakLoop method + to break in the middle of any Underscore iteration. Added an + isEmpty function that works on arrays and objects. +

+ +

+ 0.4.0
+ All Underscore functions can now be called in an object-oriented style, + like so: _([1, 2, 3]).map(...);. Original patch provided by + Marc-André Cournoyer. + Wrapped objects can be chained through multiple + method invocations. A functions method + was added, providing a sorted list of all the functions in Underscore. +

+ +

+ 0.3.3
+ Added the JavaScript 1.8 function reduceRight. Aliased it + as foldr, and aliased reduce as foldl. +

+ +

+ 0.3.2
+ Now runs on stock Rhino + interpreters with: load("underscore.js"). + Added identity as a utility function. +

+ +

+ 0.3.1
+ All iterators are now passed in the original collection as their third + argument, the same as JavaScript 1.6's forEach. Iterating over + objects is now called with (value, key, collection), for details + see _.each. +

+ +

+ 0.3.0
+ Added Dmitry Baranovskiy's + comprehensive optimizations, merged in + Kris Kowal's patches to make Underscore + CommonJS and + Narwhal compliant. +

+ +

+ 0.2.0
+ Added compose and lastIndexOf, renamed inject to + reduce, added aliases for inject, filter, + every, some, and forEach. +

+ +

+ 0.1.1
+ Added noConflict, so that the "Underscore" object can be assigned to + other variables. +

+ +

+ 0.1.0
+ Initial release of Underscore.js. +

+ +

+ + A DocumentCloud Project + +

+ +
+ +
+ + + + + + diff --git a/node_modules/underscore/index.js b/node_modules/underscore/index.js new file mode 100644 index 0000000..2cf0ca5 --- /dev/null +++ b/node_modules/underscore/index.js @@ -0,0 +1 @@ +module.exports = require('./underscore'); diff --git a/node_modules/underscore/package.json b/node_modules/underscore/package.json new file mode 100644 index 0000000..4a2e3ca --- /dev/null +++ b/node_modules/underscore/package.json @@ -0,0 +1,10 @@ +{ + "name" : "underscore", + "description" : "JavaScript's functional programming helper library.", + "homepage" : "http://documentcloud.github.com/underscore/", + "keywords" : ["util", "functional", "server", "client", "browser"], + "author" : "Jeremy Ashkenas ", + "repository" : {"type": "git", "url": "git://github.com/documentcloud/underscore.git"}, + "main" : "underscore.js", + "version" : "1.3.1" +} diff --git a/node_modules/underscore/raw/underscore.psd b/node_modules/underscore/raw/underscore.psd new file mode 100644 index 0000000000000000000000000000000000000000..73ad2d7c8eebce69b4f46f31c0a1a8c2d523bc0d GIT binary patch literal 215540 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 literal 0 HcmV?d00001 diff --git a/node_modules/underscore/underscore-min.js b/node_modules/underscore/underscore-min.js new file mode 100644 index 0000000..5b55f32 --- /dev/null +++ b/node_modules/underscore/underscore-min.js @@ -0,0 +1,31 @@ +// Underscore.js 1.3.1 +// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore +(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source== +c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c, +h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each= +b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e2;a== +null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect= +function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e= +e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck= +function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;bd?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a, +c,d){d||(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}}; +b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments, +1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)}; +b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"}; +b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a), +function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+ +u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]= +function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain= +true;return this};m.prototype.value=function(){return this._wrapped}}).call(this); diff --git a/node_modules/underscore/underscore.js b/node_modules/underscore/underscore.js new file mode 100644 index 0000000..208d4cd --- /dev/null +++ b/node_modules/underscore/underscore.js @@ -0,0 +1,999 @@ +// Underscore.js 1.3.1 +// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore + +(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `global` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Establish the object that gets returned to break out of a loop iteration. + var breaker = {}; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var slice = ArrayProto.slice, + unshift = ArrayProto.unshift, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeForEach = ArrayProto.forEach, + nativeMap = ArrayProto.map, + nativeReduce = ArrayProto.reduce, + nativeReduceRight = ArrayProto.reduceRight, + nativeFilter = ArrayProto.filter, + nativeEvery = ArrayProto.every, + nativeSome = ArrayProto.some, + nativeIndexOf = ArrayProto.indexOf, + nativeLastIndexOf = ArrayProto.lastIndexOf, + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { return new wrapper(obj); }; + + // Export the Underscore object for **Node.js**, with + // backwards-compatibility for the old `require()` API. If we're in + // the browser, add `_` as a global object via a string identifier, + // for Closure Compiler "advanced" mode. + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else { + root['_'] = _; + } + + // Current version. + _.VERSION = '1.3.1'; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles objects with the built-in `forEach`, arrays, and raw objects. + // Delegates to **ECMAScript 5**'s native `forEach` if available. + var each = _.each = _.forEach = function(obj, iterator, context) { + if (obj == null) return; + if (nativeForEach && obj.forEach === nativeForEach) { + obj.forEach(iterator, context); + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; + } + } else { + for (var key in obj) { + if (_.has(obj, key)) { + if (iterator.call(context, obj[key], key, obj) === breaker) return; + } + } + } + }; + + // Return the results of applying the iterator to each element. + // Delegates to **ECMAScript 5**'s native `map` if available. + _.map = _.collect = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); + each(obj, function(value, index, list) { + results[results.length] = iterator.call(context, value, index, list); + }); + if (obj.length === +obj.length) results.length = obj.length; + return results; + }; + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. + _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduce && obj.reduce === nativeReduce) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); + } + each(obj, function(value, index, list) { + if (!initial) { + memo = value; + initial = true; + } else { + memo = iterator.call(context, memo, value, index, list); + } + }); + if (!initial) throw new TypeError('Reduce of empty array with no initial value'); + return memo; + }; + + // The right-associative version of reduce, also known as `foldr`. + // Delegates to **ECMAScript 5**'s native `reduceRight` if available. + _.reduceRight = _.foldr = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); + } + var reversed = _.toArray(obj).reverse(); + if (context && !initial) iterator = _.bind(iterator, context); + return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator); + }; + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, iterator, context) { + var result; + any(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) { + result = value; + return true; + } + }); + return result; + }; + + // Return all the elements that pass a truth test. + // Delegates to **ECMAScript 5**'s native `filter` if available. + // Aliased as `select`. + _.filter = _.select = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); + each(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + each(obj, function(value, index, list) { + if (!iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Determine whether all of the elements match a truth test. + // Delegates to **ECMAScript 5**'s native `every` if available. + // Aliased as `all`. + _.every = _.all = function(obj, iterator, context) { + var result = true; + if (obj == null) return result; + if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); + each(obj, function(value, index, list) { + if (!(result = result && iterator.call(context, value, index, list))) return breaker; + }); + return result; + }; + + // Determine if at least one element in the object matches a truth test. + // Delegates to **ECMAScript 5**'s native `some` if available. + // Aliased as `any`. + var any = _.some = _.any = function(obj, iterator, context) { + iterator || (iterator = _.identity); + var result = false; + if (obj == null) return result; + if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); + each(obj, function(value, index, list) { + if (result || (result = iterator.call(context, value, index, list))) return breaker; + }); + return !!result; + }; + + // Determine if a given value is included in the array or object using `===`. + // Aliased as `contains`. + _.include = _.contains = function(obj, target) { + var found = false; + if (obj == null) return found; + if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; + found = any(obj, function(value) { + return value === target; + }); + return found; + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + return _.map(obj, function(value) { + return (_.isFunction(method) ? method || value : value[method]).apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, function(value){ return value[key]; }); + }; + + // Return the maximum element or (element-based computation). + _.max = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); + if (!iterator && _.isEmpty(obj)) return -Infinity; + var result = {computed : -Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed >= result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj); + if (!iterator && _.isEmpty(obj)) return Infinity; + var result = {computed : Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed < result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Shuffle an array. + _.shuffle = function(obj) { + var shuffled = [], rand; + each(obj, function(value, index, list) { + if (index == 0) { + shuffled[0] = value; + } else { + rand = Math.floor(Math.random() * (index + 1)); + shuffled[index] = shuffled[rand]; + shuffled[rand] = value; + } + }); + return shuffled; + }; + + // Sort the object's values by a criterion produced by an iterator. + _.sortBy = function(obj, iterator, context) { + return _.pluck(_.map(obj, function(value, index, list) { + return { + value : value, + criteria : iterator.call(context, value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }), 'value'); + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = function(obj, val) { + var result = {}; + var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; + each(obj, function(value, index) { + var key = iterator(value, index); + (result[key] || (result[key] = [])).push(value); + }); + return result; + }; + + // Use a comparator function to figure out at what index an object should + // be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iterator) { + iterator || (iterator = _.identity); + var low = 0, high = array.length; + while (low < high) { + var mid = (low + high) >> 1; + iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; + } + return low; + }; + + // Safely convert anything iterable into a real, live array. + _.toArray = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) return iterable.toArray(); + if (_.isArray(iterable)) return slice.call(iterable); + if (_.isArguments(iterable)) return slice.call(iterable); + return _.values(iterable); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + return _.toArray(obj).length; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head`. The **guard** check allows it to work + // with `_.map`. + _.first = _.head = function(array, n, guard) { + return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; + }; + + // Returns everything but the last entry of the array. Especcialy useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. The **guard** check allows it to work with + // `_.map`. + _.initial = function(array, n, guard) { + return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); + }; + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. The **guard** check allows it to work with `_.map`. + _.last = function(array, n, guard) { + if ((n != null) && !guard) { + return slice.call(array, Math.max(array.length - n, 0)); + } else { + return array[array.length - 1]; + } + }; + + // Returns everything but the first entry of the array. Aliased as `tail`. + // Especially useful on the arguments object. Passing an **index** will return + // the rest of the values in the array from that index onward. The **guard** + // check allows it to work with `_.map`. + _.rest = _.tail = function(array, index, guard) { + return slice.call(array, (index == null) || guard ? 1 : index); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, function(value){ return !!value; }); + }; + + // Return a completely flattened version of an array. + _.flatten = function(array, shallow) { + return _.reduce(array, function(memo, value) { + if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value)); + memo[memo.length] = value; + return memo; + }, []); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iterator) { + var initial = iterator ? _.map(array, iterator) : array; + var result = []; + _.reduce(initial, function(memo, el, i) { + if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) { + memo[memo.length] = el; + result[result.length] = array[i]; + } + return memo; + }, []); + return result; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(_.flatten(arguments, true)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. (Aliased as "intersect" for back-compat.) + _.intersection = _.intersect = function(array) { + var rest = slice.call(arguments, 1); + return _.filter(_.uniq(array), function(item) { + return _.every(rest, function(other) { + return _.indexOf(other, item) >= 0; + }); + }); + }; + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + _.difference = function(array) { + var rest = _.flatten(slice.call(arguments, 1)); + return _.filter(array, function(value){ return !_.include(rest, value); }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + var args = slice.call(arguments); + var length = _.max(_.pluck(args, 'length')); + var results = new Array(length); + for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); + return results; + }; + + // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), + // we need this function. Return the position of the first occurrence of an + // item in an array, or -1 if the item is not included in the array. + // Delegates to **ECMAScript 5**'s native `indexOf` if available. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = function(array, item, isSorted) { + if (array == null) return -1; + var i, l; + if (isSorted) { + i = _.sortedIndex(array, item); + return array[i] === item ? i : -1; + } + if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); + for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i; + return -1; + }; + + // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. + _.lastIndexOf = function(array, item) { + if (array == null) return -1; + if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); + var i = array.length; + while (i--) if (i in array && array[i] === item) return i; + return -1; + }; + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (arguments.length <= 1) { + stop = start || 0; + start = 0; + } + step = arguments[2] || 1; + + var len = Math.max(Math.ceil((stop - start) / step), 0); + var idx = 0; + var range = new Array(len); + + while(idx < len) { + range[idx++] = start; + start += step; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Reusable constructor function for prototype setting. + var ctor = function(){}; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Binding with arguments is also known as `curry`. + // Delegates to **ECMAScript 5**'s native `Function.bind` if available. + // We check for `func.bind` first, to fail fast when `func` is undefined. + _.bind = function bind(func, context) { + var bound, args; + if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError; + args = slice.call(arguments, 2); + return bound = function() { + if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); + ctor.prototype = func.prototype; + var self = new ctor; + var result = func.apply(self, args.concat(slice.call(arguments))); + if (Object(result) === result) return result; + return self; + }; + }; + + // Bind all of an object's methods to that object. Useful for ensuring that + // all callbacks defined on an object belong to it. + _.bindAll = function(obj) { + var funcs = slice.call(arguments, 1); + if (funcs.length == 0) funcs = _.functions(obj); + each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memo = {}; + hasher || (hasher = _.identity); + return function() { + var key = hasher.apply(this, arguments); + return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); + }; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ return func.apply(func, args); }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = function(func) { + return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); + }; + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. + _.throttle = function(func, wait) { + var context, args, timeout, throttling, more; + var whenDone = _.debounce(function(){ more = throttling = false; }, wait); + return function() { + context = this; args = arguments; + var later = function() { + timeout = null; + if (more) func.apply(context, args); + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + func.apply(context, args); + } + whenDone(); + throttling = true; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. + _.debounce = function(func, wait) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + func.apply(context, args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = function(func) { + var ran = false, memo; + return function() { + if (ran) return memo; + ran = true; + return memo = func.apply(this, arguments); + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return function() { + var args = [func].concat(slice.call(arguments, 0)); + return wrapper.apply(this, args); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var funcs = arguments; + return function() { + var args = arguments; + for (var i = funcs.length - 1; i >= 0; i--) { + args = [funcs[i].apply(this, args)]; + } + return args[0]; + }; + }; + + // Returns a function that will only be executed after being called N times. + _.after = function(times, func) { + if (times <= 0) return func(); + return function() { + if (--times < 1) { return func.apply(this, arguments); } + }; + }; + + // Object Functions + // ---------------- + + // Retrieve the names of an object's properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = nativeKeys || function(obj) { + if (obj !== Object(obj)) throw new TypeError('Invalid object'); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + return _.map(obj, _.identity); + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Fill in a given object with default properties. + _.defaults = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (obj[prop] == null) obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Internal recursive comparison function. + function eq(a, b, stack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. + if (a === b) return a !== 0 || 1 / a == 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a._chain) a = a._wrapped; + if (b._chain) b = b._wrapped; + // Invoke a custom `isEqual` method if one is provided. + if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b); + if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a); + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className != toString.call(b)) return false; + switch (className) { + // Strings, numbers, dates, and booleans are compared by value. + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return a == String(b); + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for + // other numeric values. + return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a == +b; + // RegExps are compared by their source patterns and flags. + case '[object RegExp]': + return a.source == b.source && + a.global == b.global && + a.multiline == b.multiline && + a.ignoreCase == b.ignoreCase; + } + if (typeof a != 'object' || typeof b != 'object') return false; + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + var length = stack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (stack[length] == a) return true; + } + // Add the first object to the stack of traversed objects. + stack.push(a); + var size = 0, result = true; + // Recursively compare objects and arrays. + if (className == '[object Array]') { + // Compare array lengths to determine if a deep comparison is necessary. + size = a.length; + result = size == b.length; + if (result) { + // Deep compare the contents, ignoring non-numeric properties. + while (size--) { + // Ensure commutative equality for sparse arrays. + if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break; + } + } + } else { + // Objects with different constructors are not equivalent. + if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false; + // Deep compare objects. + for (var key in a) { + if (_.has(a, key)) { + // Count the expected number of properties. + size++; + // Deep compare each member. + if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break; + } + } + // Ensure that both objects contain the same number of properties. + if (result) { + for (key in b) { + if (_.has(b, key) && !(size--)) break; + } + result = !size; + } + } + // Remove the first object from the stack of traversed objects. + stack.pop(); + return result; + } + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b, []); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; + for (var key in obj) if (_.has(obj, key)) return false; + return true; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType == 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) == '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + return obj === Object(obj); + }; + + // Is a given variable an arguments object? + _.isArguments = function(obj) { + return toString.call(obj) == '[object Arguments]'; + }; + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return !!(obj && _.has(obj, 'callee')); + }; + } + + // Is a given value a function? + _.isFunction = function(obj) { + return toString.call(obj) == '[object Function]'; + }; + + // Is a given value a string? + _.isString = function(obj) { + return toString.call(obj) == '[object String]'; + }; + + // Is a given value a number? + _.isNumber = function(obj) { + return toString.call(obj) == '[object Number]'; + }; + + // Is the given value `NaN`? + _.isNaN = function(obj) { + // `NaN` is the only value for which `===` is not reflexive. + return obj !== obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; + }; + + // Is a given value a date? + _.isDate = function(obj) { + return toString.call(obj) == '[object Date]'; + }; + + // Is the given value a regular expression? + _.isRegExp = function(obj) { + return toString.call(obj) == '[object RegExp]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Has own property? + _.has = function(obj, key) { + return hasOwnProperty.call(obj, key); + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iterators. + _.identity = function(value) { + return value; + }; + + // Run a function **n** times. + _.times = function (n, iterator, context) { + for (var i = 0; i < n; i++) iterator.call(context, i); + }; + + // Escape a string for HTML interpolation. + _.escape = function(string) { + return (''+string).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/'); + }; + + // Add your own custom functions to the Underscore object, ensuring that + // they're correctly added to the OOP wrapper as well. + _.mixin = function(obj) { + each(_.functions(obj), function(name){ + addToWrapper(name, _[name] = obj[name]); + }); + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = idCounter++; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /.^/; + + // Within an interpolation, evaluation, or escaping, remove HTML escaping + // that had been previously added. + var unescape = function(code) { + return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'"); + }; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(str, data) { + var c = _.templateSettings; + var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + + 'with(obj||{}){__p.push(\'' + + str.replace(/\\/g, '\\\\') + .replace(/'/g, "\\'") + .replace(c.escape || noMatch, function(match, code) { + return "',_.escape(" + unescape(code) + "),'"; + }) + .replace(c.interpolate || noMatch, function(match, code) { + return "'," + unescape(code) + ",'"; + }) + .replace(c.evaluate || noMatch, function(match, code) { + return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('"; + }) + .replace(/\r/g, '\\r') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + + "');}return __p.join('');"; + var func = new Function('obj', '_', tmpl); + if (data) return func(data, _); + return function(data) { + return func.call(this, data, _); + }; + }; + + // Add a "chain" function, which will delegate to the wrapper. + _.chain = function(obj) { + return _(obj).chain(); + }; + + // The OOP Wrapper + // --------------- + + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + var wrapper = function(obj) { this._wrapped = obj; }; + + // Expose `wrapper.prototype` as `_.prototype` + _.prototype = wrapper.prototype; + + // Helper function to continue chaining intermediate results. + var result = function(obj, chain) { + return chain ? _(obj).chain() : obj; + }; + + // A method to easily add functions to the OOP wrapper. + var addToWrapper = function(name, func) { + wrapper.prototype[name] = function() { + var args = slice.call(arguments); + unshift.call(args, this._wrapped); + return result(func.apply(_, args), this._chain); + }; + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + var wrapped = this._wrapped; + method.apply(wrapped, arguments); + var length = wrapped.length; + if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0]; + return result(wrapped, this._chain); + }; + }); + + // Add all accessor Array functions to the wrapper. + each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + return result(method.apply(this._wrapped, arguments), this._chain); + }; + }); + + // Start chaining a wrapped Underscore object. + wrapper.prototype.chain = function() { + this._chain = true; + return this; + }; + + // Extracts the result from a wrapped and chained object. + wrapper.prototype.value = function() { + return this._wrapped; + }; + +}).call(this); diff --git a/package.json b/package.json new file mode 100644 index 0000000..3f3ff8f --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "author": "Greg Melton", + "name": "casio", + "description": "ODM for Cassandra", + "version": "0.0.0", + "homepage": "https://github.com/studybreak/casio", + "repository": { + "type": "git", + "url": "git://github.com/studybreak/casio.git" + }, + "scripts": { + "test": "./test/testsuite.sh" + }, + "engines": { + "node": "~0.6.7" + }, + "dependencies": { + "async": "0.1.16", + "cassandra-client": "0.8.2", + "underscore": "1.3.1" + }, + "devDependencies": { + "nodeunit": "0.7.3" + }, + "optionalDependencies": {}, + "licenses" : + [ { "type" : "MIT", "url" : "http://github.com/studybreak/casio/raw/master/LICENSE"}] +} diff --git a/test/keyspaces/casio.cql b/test/keyspaces/casio.cql new file mode 100644 index 0000000..e7b9b4b --- /dev/null +++ b/test/keyspaces/casio.cql @@ -0,0 +1,29 @@ +DROP KEYSPACE casio; + +CREATE KEYSPACE casio WITH + strategy_class=SimpleStrategy AND + strategy_options:replication_factor=3; + +USE casio; + +CREATE COLUMNFAMILY User ( + userId text PRIMARY KEY, + name text, + first_name text, + last_name text, + email text, + birthday text, + gender text, + is_admin boolean, + visits int, + visited_at timestamp, + created_at timestamp, + updated_at timestamp +) WITH default_validation=text AND comparator=text; +CREATE INDEX UserEmail ON User (email); + +CREATE COLUMNFAMILY Vote ( + KEY text PRIMARY KEY, + up counter, + down counter +) WITH default_validation=counter AND comparator=text; \ No newline at end of file diff --git a/test/model/index.js b/test/model/index.js new file mode 100644 index 0000000..227000c --- /dev/null +++ b/test/model/index.js @@ -0,0 +1,3 @@ +exports.User = require('./user').User; +exports.UserShort = require('./user').UserShort; +exports.Vote = require('./vote').Vote; \ No newline at end of file diff --git a/test/model/user.js b/test/model/user.js new file mode 100644 index 0000000..47cb092 --- /dev/null +++ b/test/model/user.js @@ -0,0 +1,79 @@ +var Casio = require('../../').Casio; + +var options = { + + host:'127.0.0.1', + port:9160, + keyspace:'casio', + use_bigints: true, + consistency:{ + select:'ONE', + insert:'ONE', + update:'ONE', + delete:'ONE' + } +} + +var User = Casio.model('User', options); + +User.connect(function(err, results){ + console.log('client connected'); + if (err) console.log(err); + if (results) console.log(results); + +}); + +User.property('userId', String, { + primary:true +}); + +User.property('name', String, {}); +User.property('first_name', String, {}); +User.property('last_name', String, {}); +User.property('email', String, {}); +User.property('birthday', String, {}); +User.property('gender', String, {}); +User.property('visits', Number, {}); +User.property('is_admin', Boolean, { + default:false +}); +User.property('created_at', Date, {}); +User.property('updated_at', Date, {}); + +User.classMethods({ + something:function(){ + return "this is something;" + } +}); + +User.instanceMethods({ + hello:function(){ + return 'Hello, ' + this.first_name + ' ' + this.last_name + ' (' + this.email + ')'; + } +}); + + +////////////////////////////////////// +exports.User = User +////////////////////////////////////// +// short version of user +function UserShort(props){ + this._type = 'UserShort'; + + for(p in props){ + this[p] = props[p]; + } +} + +UserShort.prototype = { + _type:null, + first_name:null, + last_name:null +} +UserShort.prototype.hello = function(){ + return 'Hello, ' + this.first_name + ' ' + this.last_name ; +} + +////////////////////////////////////// +exports.UserShort = UserShort +////////////////////////////////////// \ No newline at end of file diff --git a/test/model/vote.js b/test/model/vote.js new file mode 100644 index 0000000..ff6031b --- /dev/null +++ b/test/model/vote.js @@ -0,0 +1,33 @@ +var Casio = require('../../').Casio; + +var options = { + + host:'127.0.0.1', + port:9160, + keyspace:'casio', + use_bigints: true, + consistency:{ + select:'ONE', + insert:'ONE', + update:'ONE', + delete:'ONE' + } +} + +var Vote = Casio.model('Vote', options); + +Vote.connect(function(err, results){ + console.log('client connected'); + if (err) console.log(err); + if (results) console.log(results); +}); + +Vote.property('key', String, { + primary:true +}); +Vote.property('up', Casio.types.BigInteger, {}); +Vote.property('down', Casio.types.BigInteger, {}); + +////////////////////////////////////// +exports.Vote = Vote +////////////////////////////////////// \ No newline at end of file diff --git a/test/rebuild.js b/test/rebuild.js new file mode 100644 index 0000000..1ed128a --- /dev/null +++ b/test/rebuild.js @@ -0,0 +1,143 @@ +var util = require('util'); +var async = require('async'); +var _ = require('underscore'); +var Cassandra = require('cassandra-client'); +var ColumnFamilyDef = Cassandra.CfDef; +var KeyspaceDef = Cassandra.KsDef; +var ColumnDef = Cassandra.ColumnDef; + +///////////////////////// +Cassandra.System.prototype.dropKeyspace = function(ksDef, callback){ + this.q.put(function(con) { + con.thriftCli.system_drop_keyspace(ksDef, callback); + }); + this.emit('checkq'); +} + +///////////////////////// +var KEYSPACE = 'casio'; +///////////////////////// + +//// load the keyspaces file up... +var cql_file = require('fs').readFileSync(__dirname + '/keyspaces/casio.cql', 'utf8') + +var statements = []; +var system_statements=[]; + +var system_cmds = ['DROP KEYSPACE', 'CREATE KEYSPACE', 'USE'] + +_.each(cql_file.split(';\n'), function(st){ + st = st.replace(/\n|\t/g, ''); + + var sys_cmd = false; + _.each(system_cmds, function(cmd){ + if (st.indexOf(cmd) > -1) { + sys_cmd = true; + } + }) + if (sys_cmd) { + if (st.indexOf('USE') == -1) system_statements.push(st); + } else { + statements.push(st); + } +}) + +// console.log(system_statements) +// console.log(statements) +var sys = new Cassandra.System('127.0.0.1:9160'); + +var system = new Cassandra.Connection({ + host:'127.0.0.1', + port:9160, + keyspace:'system' +}); + +var keyspace = new Cassandra.Connection({ + host:'127.0.0.1', + port:9160, + keyspace:'casio' +}); + +system.connect(function(err){ + if (err) console.log(err); + run(); +}) + +function run(){ + // prepare all the system statements... + // drop keyspace, create keyspace, etc. + + var order = []; + _.each(system_statements, function(cql){ + order.push(function(next){ + system.execute(cql, [], function(err, results){ + console.log(cql) + if (err) { + console.log('ERROR:', err); + throw new Error(err) + } + next(); + }) + }); + }) + + // connect to the keyspace now we've created it... + order.push(function(next){ + keyspace.connect(function(err){ + if (err) { + console.log('ERROR:', err); + throw new Error(err) + } + next(); + }) + }) + + _.each(statements, function(cql){ + order.push(function(next){ + keyspace.execute(cql, [], function(err, results){ + console.log(cql) + if (err) { + console.log('ERROR:', err); + throw new Error(err) + } + next(); + }) + }); + }) + + order.push(function(next){ + sys.describeKeyspace(KEYSPACE, function(err, ksDef) { + console.log("Keyspace", util.inspect(ksDef, true, null, true)) + next(); + }); + + }) + + + // if (err) console.log(err); + // if (results) { + // console.log("Added keyspace", util.inspect(casio, true, null, true)) + // console.log(results); + // } + // next(); + + async.series(order, function(err, results){ + // console.log(err, results) + process.exit(0); + }) +} +exports.run = run; + +// add keyspace +// order.push(function(next){ +// system.addKeyspace(casio, function(err, results){ +// if (err) console.log(err); +// if (results) { +// console.log("Added keyspace", util.inspect(casio, true, null, true)) +// console.log(results); +// } +// next(); +// }) +// }); + + diff --git a/test/test-casio.js b/test/test-casio.js new file mode 100644 index 0000000..a5091fa --- /dev/null +++ b/test/test-casio.js @@ -0,0 +1,241 @@ +var Casio = require('../').Casio; +var Cassandra = require('cassandra-client'); +var model = require('./model'); +var _ = require('underscore') +var async = require('async'); + + +////////////////////////////// +var now = new Date().getTime() +var USER = new model.User({ + userId: new Date().getTime() + '-' + new Cassandra.UUID().toString(), + name:'Dirty Harry ' + now, + first_name:'Dirty', + last_name:'Harry ' + now, + birthday:'06/19/1974', + gender:'M', + state:'CA', + email:'dirty@hairy.com', + visits:0, + is_admin: true +}); + +////////////////////////////// + +function checkClient(){ + var total=0, connected=0; + for (var name in model){ + isConnected = model[name].prototype._clientConnected; + if (isConnected !== undefined){ + total++; + if(isConnected !== null) connected++; + } + } + console.log('Clients connected:', connected, '/', total); +} + +exports.setUp = function(callback){ + // give the clients time to connect; + setTimeout(function(){ + USER.create(function(err, results){ + if (err) { + console.log(err); + throw new Error(err) + } + callback() + }) + }, 100) +} + + +exports.tearDown = function (callback) { + // clean up + setTimeout(function(){ + process.exit(0); + }, 2000); + callback(); +} + +exports.test_user_something= function(test){ + // test the class method was attached + test.equal(model.User.something(), 'this is something;') + test.done(); +} + +exports.test_user_find=function(test){ + async.series([ + function(next){ + model.User.find({ + // columns:'full_name, birth_year', + // where:['key = :key', {key:1}], + where:['email = :email', {email:'dirty@hairy.com'}], + // start:1, + // limit:10 + }, function(err, users){ + if (err) { + console.log(err); + throw new Error(err); + } + if (users) { + console.log('--- Users ---') + console.log(users); + } + next(); + }) + }, + function(next){ + model.User.find({ + columns: ['first_name', 'last_name'], + where: ['email = :email', {email:'dirty@hairy.com'}], + as: model.UserShort + }, function(err, users){ + if (err) { + console.log(err); + throw new Error(err); + } + if (users) { + console.log('--- Users as UserShort ---') + console.log(users); + } + next(); + }) + + } + ], function(err, results){ + + test.done() + }) +} + +exports.test_user_get=function (test){ + + // Test the setUp user creation here... + test.strictEqual(USER.created_at.getTime(), USER.updated_at.getTime()) + + async.series([ + + function(next){ + + // get the user we created during setUp... + model.User.get(USER.userId, function(err, user){ + if (err) console.log(err); + if (user) { + console.log('--- User---') + console.log(user); + + // test booleans + test.equal(USER.is_admin, true) + test.equal(USER._props.is_admin, true) + + // test instance method was properly set + test.strictEqual(USER.hello(), 'Hello, ' + USER.first_name + ' ' + USER.last_name + ' (' + USER.email + ')'); + } + next(); + }); + + }, + function(next){ + + // get the short version of the user we created during setUp... + model.User.get({ + userId: USER.userId, + columns:['first_name', 'last_name'], + as: model.UserShort, + }, function(err, userShort){ + if (err) console.log(err); + if (userShort){ + console.log('--- UserShort ---') + console.log(userShort); + console.log(userShort.hello()) + }; + next(); + }); + + } + ], function(err, results){ + test.done(); + }) +} + +// function test_create_indicies(){ +// User.createIndicies(); +// } + +exports.test_vote_create = function(test){ + + // var vote = model.Vote(); + var key = USER.userId; + var vote; + var order = []; + + var i64 = 18446744073709551616; + var i32 = 9007199254740992; + + // var bigint = new Casio.types.BigInteger(i64.toString()) + // console.log(bigint.toString(), i64.toString()) + + var up = i32; //10; + var down = i32; + + // test static incr method + order.push(function(next){ + model.Vote.incr(key, 'up', up, function(err, results){ + next(); + }) + }) + + // test static decr method + order.push(function(next){ + model.Vote.decr(key, 'down', down, function(err, results){ + next(); + }) + }) + + // test the above was set properly + order.push(function(next){ + model.Vote.get(key, function(err, results){ + vote = results; + + console.log('---Vote---'); + console.log(vote); + + test.equal(vote.up, up) + test.equal(vote.down, -(down)) + + next(); + }) + }) + order.push(function(next){ + vote.incr('up', function(err, results){ + vote.decr('down', function(err, results){ + + setTimeout(next, 1000); + + }) + }) + }) + // test the above was set properly + order.push(function(next){ + model.Vote.get(key, function(err, results){ + // vote = results; + + console.log('---Vote2---'); + console.log(results); + + // test.equal(results.up, up + 1) + // test.equal(results.down, -(down)) + + next(); + }) + }) + + + async.series(order, function(err, results){ + test.done(); + }) + + +} + + + diff --git a/test/testsuite.sh b/test/testsuite.sh new file mode 100755 index 0000000..3fd5e99 --- /dev/null +++ b/test/testsuite.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +node test/rebuild.js +node node_modules/nodeunit/bin/nodeunit test/test-casio.js $@ \ No newline at end of file