Updating npm externals
authorJack Allnutt <m2ys4u@Gmail.com>
Sat, 17 Sep 2011 14:01:44 +0000 (15:01 +0100)
committerJack Allnutt <m2ys4u@Gmail.com>
Sat, 17 Sep 2011 14:01:44 +0000 (15:01 +0100)
432 files changed:
node/app.js
node/node_modules/___uglify-js.npm/package/.gitignore [deleted file]
node/node_modules/___uglify-js.npm/package/README.html [deleted file]
node/node_modules/___uglify-js.npm/package/README.org [deleted file]
node/node_modules/___uglify-js.npm/package/bin/uglifyjs [deleted file]
node/node_modules/___uglify-js.npm/package/docstyle.css [deleted file]
node/node_modules/___uglify-js.npm/package/lib/parse-js.js [deleted file]
node/node_modules/___uglify-js.npm/package/lib/process.js [deleted file]
node/node_modules/___uglify-js.npm/package/lib/squeeze-more.js [deleted file]
node/node_modules/___uglify-js.npm/package/package.json [deleted file]
node/node_modules/___uglify-js.npm/package/test/beautify.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/testparser.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array1.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array2.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array3.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array4.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/assignment.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/concatstring.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/const.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/empty-blocks.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/forstatement.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/if.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/ifreturn.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/ifreturn2.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue10.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue11.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue13.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue14.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue16.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue17.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue20.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue21.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue25.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue27.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue28.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue29.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue30.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue34.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue4.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue48.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue50.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue53.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue54.1.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue68.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue69.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue9.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/mangle.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/strict-equals.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/var.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/with.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array1.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array2.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array3.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array4.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/assignment.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/concatstring.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/const.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/empty-blocks.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/forstatement.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/if.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/ifreturn.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/ifreturn2.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue10.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue11.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue13.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue14.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue16.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue17.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue20.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue21.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue25.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue27.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue28.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue29.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue30.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue34.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue4.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue48.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue50.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue53.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue54.1.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue68.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue69.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue9.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/mangle.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/strict-equals.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/var.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/compress/test/with.js [deleted file]
node/node_modules/___uglify-js.npm/package/test/unit/scripts.js [deleted file]
node/node_modules/___uglify-js.npm/package/tmp/instrument.js [deleted file]
node/node_modules/___uglify-js.npm/package/tmp/instrument2.js [deleted file]
node/node_modules/___uglify-js.npm/package/uglify-js.js [deleted file]
node/node_modules/jade/History.md
node/node_modules/jade/Makefile
node/node_modules/jade/Readme.md
node/node_modules/jade/benchmarks/common.js [deleted file]
node/node_modules/jade/benchmarks/ejs.js [deleted file]
node/node_modules/jade/benchmarks/ejs/.gitignore [deleted file]
node/node_modules/jade/benchmarks/ejs/.gitmodules [deleted file]
node/node_modules/jade/benchmarks/ejs/History.md [deleted file]
node/node_modules/jade/benchmarks/ejs/Makefile [deleted file]
node/node_modules/jade/benchmarks/ejs/Readme.md [deleted file]
node/node_modules/jade/benchmarks/ejs/benchmark.js [deleted file]
node/node_modules/jade/benchmarks/ejs/examples/list.ejs [deleted file]
node/node_modules/jade/benchmarks/ejs/examples/list.js [deleted file]
node/node_modules/jade/benchmarks/ejs/index.js [deleted file]
node/node_modules/jade/benchmarks/ejs/lib/ejs.js [deleted file]
node/node_modules/jade/benchmarks/ejs/lib/filters.js [deleted file]
node/node_modules/jade/benchmarks/ejs/lib/utils.js [deleted file]
node/node_modules/jade/benchmarks/ejs/package.json [deleted file]
node/node_modules/jade/benchmarks/ejs/test/ejs.test.js [deleted file]
node/node_modules/jade/benchmarks/example-self.jade [deleted file]
node/node_modules/jade/benchmarks/example.ejs [deleted file]
node/node_modules/jade/benchmarks/example.haml [deleted file]
node/node_modules/jade/benchmarks/example.jade [deleted file]
node/node_modules/jade/benchmarks/example2.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/CHANGELOG.markdown [deleted file]
node/node_modules/jade/benchmarks/haml-js/LICENSE [deleted file]
node/node_modules/jade/benchmarks/haml-js/README.markdown [deleted file]
node/node_modules/jade/benchmarks/haml-js/lib/haml.js [deleted file]
node/node_modules/jade/benchmarks/haml-js/package.json [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/alt_attribs.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/alt_attribs.html [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/div_nesting.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/div_nesting.html [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/doctype.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/doctype.html [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/embedded_code.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/embedded_code.html [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/embedded_code.js [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/foreach.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/foreach.html [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/foreach.js [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/meta.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/meta.html [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/nanline.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/nanline.html [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/nested_context.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/nested_context.html [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/nested_context.js [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/no_self_close_div.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/no_self_close_div.html [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/non-string-attribs.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/non-string-attribs.html [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/script_css.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/script_css.html [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/self_close.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/self_close.html [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/self_close.js [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/standard.haml [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/standard.html [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/standard.js [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/test-commonjs.js [deleted file]
node/node_modules/jade/benchmarks/haml-js/test/test.js [deleted file]
node/node_modules/jade/benchmarks/haml.js [deleted file]
node/node_modules/jade/benchmarks/haml/.gitmodules [deleted file]
node/node_modules/jade/benchmarks/haml/.ignore [deleted file]
node/node_modules/jade/benchmarks/haml/History.md [deleted file]
node/node_modules/jade/benchmarks/haml/Makefile [deleted file]
node/node_modules/jade/benchmarks/haml/Readme.md [deleted file]
node/node_modules/jade/benchmarks/haml/benchmarks/page.haml [deleted file]
node/node_modules/jade/benchmarks/haml/benchmarks/run.js [deleted file]
node/node_modules/jade/benchmarks/haml/examples/example.js [deleted file]
node/node_modules/jade/benchmarks/haml/examples/page.haml [deleted file]
node/node_modules/jade/benchmarks/haml/index.js [deleted symlink]
node/node_modules/jade/benchmarks/haml/lib/haml.js [deleted file]
node/node_modules/jade/benchmarks/haml/package.json [deleted file]
node/node_modules/jade/benchmarks/haml/seed.yml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/class.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/class.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/classes.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/classes.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.index.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.index.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.non-enumerable.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.non-enumerable.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.escape.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.escape.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.if.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.if.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.nested.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/code.nested.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.conditional.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.conditional.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.tag.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.tag.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.complex.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.complex.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/context.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/context.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/cr.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/cr.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/crlf.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/crlf.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.case.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.case.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/error.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/escape.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/escape.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/feed.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/feed.xml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.whitespace.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.whitespace.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.javascript.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.javascript.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.plain.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.plain.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/html.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/html.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/id.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/id.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/issue.#10.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/issue.#10.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/issue.#8.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/issue.#8.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/literals.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/literals.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/namespace.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/namespace.tag.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/namespace.tag.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/namespace.xml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/nesting.complex.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/nesting.complex.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/nesting.simple.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/nesting.simple.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/newlines.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/newlines.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.bools.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.bools.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.escape.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.escape.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.class.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.class.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.classes.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.classes.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.no-escape.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.no-escape.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.complex.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.complex.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.empty.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.empty.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.escape.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.escape.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.self-close.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.self-close.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.simple.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.simple.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.complex.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.complex.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/trailing-indent.haml [deleted file]
node/node_modules/jade/benchmarks/haml/spec/fixtures/trailing-indent.html [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/images/bg.png [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/images/hr.png [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/images/loading.gif [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/images/sprites.bg.png [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/images/sprites.png [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/images/vr.png [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/jspec.css [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/jspec.growl.js [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/jspec.jquery.js [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/jspec.js [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/jspec.nodejs.js [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/jspec.shell.js [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/jspec.timers.js [deleted file]
node/node_modules/jade/benchmarks/haml/spec/lib/jspec.xhr.js [deleted file]
node/node_modules/jade/benchmarks/haml/spec/node.js [deleted file]
node/node_modules/jade/benchmarks/haml/spec/unit/spec.helper.js [deleted file]
node/node_modules/jade/benchmarks/haml/spec/unit/spec.js [deleted file]
node/node_modules/jade/benchmarks/haml2.js [deleted file]
node/node_modules/jade/benchmarks/jade-self.js [deleted file]
node/node_modules/jade/benchmarks/jade.js [deleted file]
node/node_modules/jade/bin/jade
node/node_modules/jade/examples/includes/head.jade
node/node_modules/jade/examples/includes/scripts.jade [new file with mode: 0644]
node/node_modules/jade/examples/includes/style.css [new file with mode: 0644]
node/node_modules/jade/jade.js
node/node_modules/jade/jade.min.js
node/node_modules/jade/lib/compiler.js
node/node_modules/jade/lib/jade.js
node/node_modules/jade/lib/lexer.js
node/node_modules/jade/lib/nodes/index.js
node/node_modules/jade/lib/nodes/literal.js [new file with mode: 0644]
node/node_modules/jade/lib/parser.js
node/node_modules/jade/lib/runtime.js [new file with mode: 0644]
node/node_modules/jade/package.json
node/node_modules/jade/runtime.js [new file with mode: 0644]
node/node_modules/jade/runtime.min.js [new file with mode: 0644]
node/node_modules/jade/support/benchmark.js [new file with mode: 0644]
node/node_modules/jade/support/foot.js [new file with mode: 0644]
node/node_modules/jade/support/head.js [new file with mode: 0644]
node/node_modules/jade/test/filters.test.js
node/node_modules/jade/test/jade.test.js
node/node_modules/node-static/lib/node-static.js
node/node_modules/node-static/package.json
node/node_modules/socket.io-client/History.md
node/node_modules/socket.io-client/Makefile
node/node_modules/socket.io-client/bin/builder.js
node/node_modules/socket.io-client/dist/socket.io.js
node/node_modules/socket.io-client/dist/socket.io.min.js
node/node_modules/socket.io-client/lib/io.js
node/node_modules/socket.io-client/lib/parser.js
node/node_modules/socket.io-client/lib/socket.js
node/node_modules/socket.io-client/lib/transport.js
node/node_modules/socket.io-client/lib/transports/flashsocket.js
node/node_modules/socket.io-client/lib/transports/htmlfile.js
node/node_modules/socket.io-client/lib/transports/jsonp-polling.js
node/node_modules/socket.io-client/lib/transports/websocket.js
node/node_modules/socket.io-client/lib/transports/xhr-polling.js
node/node_modules/socket.io-client/lib/transports/xhr.js
node/node_modules/socket.io-client/lib/util.js
node/node_modules/socket.io-client/package.json
node/node_modules/socket.io-client/support/should.js [new file with mode: 0644]
node/node_modules/socket.io-client/support/test-runner/app.js [new file with mode: 0644]
node/node_modules/socket.io-client/support/test-runner/index.jade [new file with mode: 0644]
node/node_modules/socket.io-client/support/test-runner/public/javascript/jquery.js [new file with mode: 0644]
node/node_modules/socket.io-client/support/test-runner/public/javascript/runner.js [new file with mode: 0644]
node/node_modules/socket.io-client/support/test-runner/public/javascript/script.js [new file with mode: 0644]
node/node_modules/socket.io-client/support/test-runner/public/stylesheets/main.css [new file with mode: 0644]
node/node_modules/socket.io-client/support/test-runner/public/stylesheets/main.styl [new file with mode: 0644]
node/node_modules/socket.io-client/test/node/builder.test.js
node/node_modules/socket.io-client/test/parser.test.js
node/node_modules/socket.io-client/test/socket.test.js
node/node_modules/socket.io-client/test/util.test.js
node/node_modules/socket.io/History.md
node/node_modules/socket.io/Makefile
node/node_modules/socket.io/Readme.md
node/node_modules/socket.io/TODO [deleted file]
node/node_modules/socket.io/examples/chat/app.js [new file with mode: 0644]
node/node_modules/socket.io/examples/chat/index.jade [new file with mode: 0644]
node/node_modules/socket.io/examples/chat/package.json [new file with mode: 0644]
node/node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl [new file with mode: 0644]
node/node_modules/socket.io/examples/chat/public/stylesheets/style.css [new file with mode: 0644]
node/node_modules/socket.io/examples/chat/public/stylesheets/style.styl [new file with mode: 0644]
node/node_modules/socket.io/examples/irc-output/app.js [new file with mode: 0644]
node/node_modules/socket.io/examples/irc-output/index.jade [new file with mode: 0644]
node/node_modules/socket.io/examples/irc-output/irc.js [new file with mode: 0644]
node/node_modules/socket.io/examples/irc-output/package.json [moved from node/node_modules/socket.io/new-old/package.json with 72% similarity]
node/node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl [new file with mode: 0644]
node/node_modules/socket.io/lib/manager.js
node/node_modules/socket.io/lib/namespace.js
node/node_modules/socket.io/lib/parser.js
node/node_modules/socket.io/lib/socket.io.js
node/node_modules/socket.io/lib/socket.js
node/node_modules/socket.io/lib/stores/redis.js
node/node_modules/socket.io/lib/transport.js
node/node_modules/socket.io/lib/transports/flashsocket.js
node/node_modules/socket.io/lib/transports/http.js
node/node_modules/socket.io/lib/transports/jsonp-polling.js
node/node_modules/socket.io/lib/transports/websocket.js
node/node_modules/socket.io/lib/transports/websocket/default.js [new file with mode: 0644]
node/node_modules/socket.io/lib/transports/websocket/hybi-07-12.js [new file with mode: 0644]
node/node_modules/socket.io/lib/transports/websocket/index.js [new file with mode: 0644]
node/node_modules/socket.io/lib/util.js
node/node_modules/socket.io/new-old/app.js [deleted file]
node/node_modules/socket.io/new-old/index.jade [deleted file]
node/node_modules/socket.io/new-old/layout.jade [deleted file]
node/node_modules/socket.io/new-old/public/js/main.js [deleted file]
node/node_modules/socket.io/package.json
node/node_modules/socket.io/support/node-websocket-client/LICENSE [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/Makefile [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/README.md [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/examples/client-unix.js [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/examples/client.js [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/examples/server-unix.js [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/lib/websocket.js [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/package.json [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/test/test-basic.js [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/test/test-client-close.js [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/test/test-readonly-attrs.js [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/test/test-ready-state.js [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/test/test-server-close.js [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/test/test-unix-send-fd.js [new file with mode: 0644]
node/node_modules/socket.io/support/node-websocket-client/test/test-unix-sockets.js [new file with mode: 0644]
node/node_modules/socket.io/test/common.js [new file with mode: 0644]
node/node_modules/socket.io/test/fixtures/cert.crt [new file with mode: 0644]
node/node_modules/socket.io/test/fixtures/key.key [new file with mode: 0644]
node/node_modules/socket.io/test/io.test.js [new file with mode: 0644]
node/node_modules/socket.io/test/leaks/socket.leaktest.js [new file with mode: 0644]
node/node_modules/socket.io/test/manager.test.js [new file with mode: 0644]
node/node_modules/socket.io/test/namespace.test.js [new file with mode: 0644]
node/node_modules/socket.io/test/parser.test.js [new file with mode: 0644]
node/node_modules/socket.io/test/socket.js [new file with mode: 0644]
node/node_modules/socket.io/test/stores.memory.test.js [new file with mode: 0644]
node/node_modules/socket.io/test/stores.redis.test.js [new file with mode: 0644]
node/node_modules/socket.io/test/transports.flashsocket.test.js [new file with mode: 0644]
node/node_modules/socket.io/test/transports.htmlfile.test.js [new file with mode: 0644]
node/node_modules/socket.io/test/transports.jsonp-polling.test.js [new file with mode: 0644]
node/node_modules/socket.io/test/transports.websocket.hybi07-12.parser.test.js [new file with mode: 0644]
node/node_modules/socket.io/test/transports.websocket.test.js [new file with mode: 0644]
node/node_modules/socket.io/test/transports.xhr-polling.test.js [new file with mode: 0644]
node/node_modules/uglify-js/README.html
node/node_modules/uglify-js/README.org
node/node_modules/uglify-js/bin/uglifyjs [changed mode: 0644->0755]
node/node_modules/uglify-js/lib/object-ast.js [new file with mode: 0644]
node/node_modules/uglify-js/lib/parse-js.js
node/node_modules/uglify-js/lib/process.js
node/node_modules/uglify-js/lib/squeeze-more.js
node/node_modules/uglify-js/package.json
node/node_modules/uglify-js/test/beautify.js [changed mode: 0644->0755]
node/node_modules/uglify-js/test/testparser.js [changed mode: 0644->0755]
node/node_modules/uglify-js/test/unit/compress/expected/empty-blocks.js
node/node_modules/uglify-js/test/unit/compress/expected/ifreturn2.js
node/node_modules/uglify-js/test/unit/compress/expected/issue68.js
node/node_modules/uglify-js/test/unit/compress/expected/with.js
node/node_modules/uglify-js/test/unit/scripts.js
node/node_modules/uglify-js/tmp/hoist.js [new file with mode: 0644]
node/node_modules/uglify-js/tmp/test.js [new file with mode: 0755]
node/npm-debug.log [deleted file]

index 6243647a8e87f94503e210e2082d35bb7b8ac1cc..b3206411d7485f5facd9d80329baf79993353984 100644 (file)
@@ -596,9 +596,12 @@ this.httpHandler = function (request, response) {
                 }
                 response.end();
             } else {
-                kiwi.jade.renderFile(__dirname + '/client/index.html.jade', { locals: { "touchscreen": touchscreen, "debug": debug, "server_set": server_set, "server": server, "nick": nick, "agent": agent, "config": kiwi.config }}, function (err, html) {
+                fs.readFile(__dirname + '/client/index.html.jade', 'utf8', function (err, str) {
+                    var html, hash2;
                     if (!err) {
-                        var hash2 = crypto.createHash('md5').update(html).digest('base64');
+                        html = kiwi.jade.compile(str)({ "touchscreen": touchscreen, "debug": debug, "server_set": server_set, "server": server, "nick": nick, "agent": agent, "config": kiwi.config });
+                        console.log(typeof html, html);
+                        hash2 = crypto.createHash('md5').update(html).digest('base64');
                         kiwi.cache.html[hash] = {"html": html, "hash": hash2};
                         if (request.headers['if-none-match'] === hash2) {
                             response.statusCode = 304;
diff --git a/node/node_modules/___uglify-js.npm/package/.gitignore b/node/node_modules/___uglify-js.npm/package/.gitignore
deleted file mode 100644 (file)
index d97eaa0..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-.DS_Store
-.tmp*~
-*.local.*
-.pinf-*
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/README.html b/node/node_modules/___uglify-js.npm/package/README.html
deleted file mode 100644 (file)
index 8bc5da6..0000000
+++ /dev/null
@@ -1,835 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-               "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml"
-lang="en" xml:lang="en">
-<head>
-<title>UglifyJS -- a JavaScript parser/compressor/beautifier</title>
-<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
-<meta name="generator" content="Org-mode"/>
-<meta name="generated" content="2011-07-14 12:50:31 EEST"/>
-<meta name="author" content="Mihai Bazon"/>
-<meta name="description" content="a JavaScript parser/compressor/beautifier in JavaScript"/>
-<meta name="keywords" content="javascript, js, parser, compiler, compressor, mangle, minify, minifier"/>
-<style type="text/css">
- <!--/*--><![CDATA[/*><!--*/
-  html { font-family: Times, serif; font-size: 12pt; }
-  .title  { text-align: center; }
-  .todo   { color: red; }
-  .done   { color: green; }
-  .tag    { background-color: #add8e6; font-weight:normal }
-  .target { }
-  .timestamp { color: #bebebe; }
-  .timestamp-kwd { color: #5f9ea0; }
-  p.verse { margin-left: 3% }
-  pre {
-       border: 1pt solid #AEBDCC;
-       background-color: #F3F5F7;
-       padding: 5pt;
-       font-family: courier, monospace;
-        font-size: 90%;
-        overflow:auto;
-  }
-  table { border-collapse: collapse; }
-  td, th { vertical-align: top; }
-  dt { font-weight: bold; }
-  div.figure { padding: 0.5em; }
-  div.figure p { text-align: center; }
-  textarea { overflow-x: auto; }
-  .linenr { font-size:smaller }
-  .code-highlighted {background-color:#ffff00;}
-  .org-info-js_info-navigation { border-style:none; }
-  #org-info-js_console-label { font-size:10px; font-weight:bold;
-                               white-space:nowrap; }
-  .org-info-js_search-highlight {background-color:#ffff00; color:#000000;
-                                 font-weight:bold; }
-  /*]]>*/-->
-</style>
-<link rel="stylesheet" type="text/css" href="docstyle.css" />
-<script type="text/javascript">
-<!--/*--><![CDATA[/*><!--*/
- function CodeHighlightOn(elem, id)
- {
-   var target = document.getElementById(id);
-   if(null != target) {
-     elem.cacheClassElem = elem.className;
-     elem.cacheClassTarget = target.className;
-     target.className = "code-highlighted";
-     elem.className   = "code-highlighted";
-   }
- }
- function CodeHighlightOff(elem, id)
- {
-   var target = document.getElementById(id);
-   if(elem.cacheClassElem)
-     elem.className = elem.cacheClassElem;
-   if(elem.cacheClassTarget)
-     target.className = elem.cacheClassTarget;
- }
-/*]]>*///-->
-</script>
-
-</head>
-<body>
-<div id="content">
-
-<h1 class="title">UglifyJS &ndash; a JavaScript parser/compressor/beautifier</h1>
-
-
-<div id="table-of-contents">
-<h2>Table of Contents</h2>
-<div id="text-table-of-contents">
-<ul>
-<li><a href="#sec-1">1 UglifyJS &mdash; a JavaScript parser/compressor/beautifier </a>
-<ul>
-<li><a href="#sec-1_1">1.1 Unsafe transformations </a>
-<ul>
-<li><a href="#sec-1_1_1">1.1.1 Calls involving the global Array constructor </a></li>
-</ul>
-</li>
-<li><a href="#sec-1_2">1.2 Install (NPM) </a></li>
-<li><a href="#sec-1_3">1.3 Install latest code from GitHub </a></li>
-<li><a href="#sec-1_4">1.4 Usage </a>
-<ul>
-<li><a href="#sec-1_4_1">1.4.1 API </a></li>
-<li><a href="#sec-1_4_2">1.4.2 Beautifier shortcoming &ndash; no more comments </a></li>
-</ul>
-</li>
-<li><a href="#sec-1_5">1.5 Compression &ndash; how good is it? </a></li>
-<li><a href="#sec-1_6">1.6 Bugs? </a></li>
-<li><a href="#sec-1_7">1.7 Links </a></li>
-<li><a href="#sec-1_8">1.8 License </a></li>
-</ul>
-</li>
-</ul>
-</div>
-</div>
-
-<div id="outline-container-1" class="outline-2">
-<h2 id="sec-1"><span class="section-number-2">1</span> UglifyJS &mdash; a JavaScript parser/compressor/beautifier </h2>
-<div class="outline-text-2" id="text-1">
-
-
-<p>
-This package implements a general-purpose JavaScript
-parser/compressor/beautifier toolkit.  It is developed on <a href="http://nodejs.org/">NodeJS</a>, but it
-should work on any JavaScript platform supporting the CommonJS module system
-(and if your platform of choice doesn't support CommonJS, you can easily
-implement it, or discard the <code>exports.*</code> lines from UglifyJS sources).
-</p>
-<p>
-The tokenizer/parser generates an abstract syntax tree from JS code.  You
-can then traverse the AST to learn more about the code, or do various
-manipulations on it.  This part is implemented in <a href="../lib/parse-js.js">parse-js.js</a> and it's a
-port to JavaScript of the excellent <a href="http://marijn.haverbeke.nl/parse-js/">parse-js</a> Common Lisp library from <a href="http://marijn.haverbeke.nl/">Marijn Haverbeke</a>.
-</p>
-<p>
-( See <a href="http://github.com/mishoo/cl-uglify-js">cl-uglify-js</a> if you're looking for the Common Lisp version of
-UglifyJS. )
-</p>
-<p>
-The second part of this package, implemented in <a href="../lib/process.js">process.js</a>, inspects and
-manipulates the AST generated by the parser to provide the following:
-</p>
-<ul>
-<li>
-ability to re-generate JavaScript code from the AST.  Optionally
-indented&mdash;you can use this if you want to “beautify” a program that has
-been compressed, so that you can inspect the source.  But you can also run
-our code generator to print out an AST without any whitespace, so you
-achieve compression as well.
-
-</li>
-<li>
-shorten variable names (usually to single characters).  Our mangler will
-analyze the code and generate proper variable names, depending on scope
-and usage, and is smart enough to deal with globals defined elsewhere, or
-with <code>eval()</code> calls or <code>with{}</code> statements.  In short, if <code>eval()</code> or
-<code>with{}</code> are used in some scope, then all variables in that scope and any
-variables in the parent scopes will remain unmangled, and any references
-to such variables remain unmangled as well.
-
-</li>
-<li>
-various small optimizations that may lead to faster code but certainly
-lead to smaller code.  Where possible, we do the following:
-
-<ul>
-<li>
-foo["bar"]  ==&gt;  foo.bar
-
-</li>
-<li>
-remove block brackets <code>{}</code>
-
-</li>
-<li>
-join consecutive var declarations:
-var a = 10; var b = 20; ==&gt; var a=10,b=20;
-
-</li>
-<li>
-resolve simple constant expressions: 1 +2 * 3 ==&gt; 7.  We only do the
-replacement if the result occupies less bytes; for example 1/3 would
-translate to 0.333333333333, so in this case we don't replace it.
-
-</li>
-<li>
-consecutive statements in blocks are merged into a sequence; in many
-cases, this leaves blocks with a single statement, so then we can remove
-the block brackets.
-
-</li>
-<li>
-various optimizations for IF statements:
-
-<ul>
-<li>
-if (foo) bar(); else baz(); ==&gt; foo?bar():baz();
-</li>
-<li>
-if (!foo) bar(); else baz(); ==&gt; foo?baz():bar();
-</li>
-<li>
-if (foo) bar(); ==&gt; foo&amp;&amp;bar();
-</li>
-<li>
-if (!foo) bar(); ==&gt; foo||bar();
-</li>
-<li>
-if (foo) return bar(); else return baz(); ==&gt; return foo?bar():baz();
-</li>
-<li>
-if (foo) return bar(); else something(); ==&gt; {if(foo)return bar();something()}
-
-</li>
-</ul>
-</li>
-<li>
-remove some unreachable code and warn about it (code that follows a
-<code>return</code>, <code>throw</code>, <code>break</code> or <code>continue</code> statement, except
-function/variable declarations).
-</li>
-</ul>
-</li>
-</ul>
-
-
-
-</div>
-
-<div id="outline-container-1_1" class="outline-3">
-<h3 id="sec-1_1"><span class="section-number-3">1.1</span> <span class="target">Unsafe transformations</span>  </h3>
-<div class="outline-text-3" id="text-1_1">
-
-
-<p>
-UglifyJS tries its best to achieve great compression while leaving the
-semantics of the code intact.  In general, if your code logic is broken by
-UglifyJS then it's a bug in UglifyJS and you should report it and I should
-fix it. :-)
-</p>
-<p>
-However, I opted to include the following potentially unsafe transformations
-as default behavior.  Discussion is welcome, if you have ideas of how to
-handle this better, or any objections to these optimizations, please let me
-know.
-</p>
-
-</div>
-
-<div id="outline-container-1_1_1" class="outline-4">
-<h4 id="sec-1_1_1"><span class="section-number-4">1.1.1</span> Calls involving the global Array constructor </h4>
-<div class="outline-text-4" id="text-1_1_1">
-
-
-<p>
-The following transformations occur:
-</p>
-
-
-
-<pre class="src src-js"><span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(1, 2, 3, 4)  =&gt; [1,2,3,4]
-Array(a, b, c)         =&gt; [a,b,c]
-<span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(5)           =&gt; Array(5)
-<span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(a)           =&gt; Array(a)
-</pre>
-
-
-
-<p>
-These are all safe if the Array name isn't redefined.  JavaScript does allow
-one to globally redefine Array (and pretty much everything, in fact) but I
-personally don't see why would anyone do that.
-</p>
-<p>
-UglifyJS does handle the case where Array is redefined locally, or even
-globally but with a <code>function</code> or <code>var</code> declaration.  Therefore, in the
-following cases UglifyJS <b>doesn't touch</b> calls or instantiations of Array:
-</p>
-
-
-
-<pre class="src src-js"><span style="color: #00008b;">// </span><span style="color: #00008b;">case 1.  globally declared variable
-</span>  <span style="color: #8b0000;">var</span> <span style="color: #8b008b;">Array</span>;
-  <span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(1, 2, 3);
-  Array(a, b);
-
-  <span style="color: #00008b;">// </span><span style="color: #00008b;">or (can be declared later)
-</span>  <span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(1, 2, 3);
-  <span style="color: #8b0000;">var</span> <span style="color: #8b008b;">Array</span>;
-
-  <span style="color: #00008b;">// </span><span style="color: #00008b;">or (can be a function)
-</span>  <span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(1, 2, 3);
-  <span style="color: #8b0000;">function</span> <span style="color: #8b2323;">Array</span>() { ... }
-
-<span style="color: #00008b;">// </span><span style="color: #00008b;">case 2.  declared in a function
-</span>  (<span style="color: #8b0000;">function</span>(){
-    a = <span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(1, 2, 3);
-    b = Array(5, 6);
-    <span style="color: #8b0000;">var</span> <span style="color: #8b008b;">Array</span>;
-  })();
-
-  <span style="color: #00008b;">// </span><span style="color: #00008b;">or
-</span>  (<span style="color: #8b0000;">function</span>(<span style="color: #8b008b;">Array</span>){
-    <span style="color: #8b0000;">return</span> Array(5, 6, 7);
-  })();
-
-  <span style="color: #00008b;">// </span><span style="color: #00008b;">or
-</span>  (<span style="color: #8b0000;">function</span>(){
-    <span style="color: #8b0000;">return</span> <span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(1, 2, 3, 4);
-    <span style="color: #8b0000;">function</span> <span style="color: #8b2323;">Array</span>() { ... }
-  })();
-
-  <span style="color: #00008b;">// </span><span style="color: #00008b;">etc.
-</span></pre>
-
-
-
-</div>
-</div>
-
-</div>
-
-<div id="outline-container-1_2" class="outline-3">
-<h3 id="sec-1_2"><span class="section-number-3">1.2</span> Install (NPM) </h3>
-<div class="outline-text-3" id="text-1_2">
-
-
-<p>
-UglifyJS is now available through NPM &mdash; <code>npm install uglify-js</code> should do
-the job.
-</p>
-</div>
-
-</div>
-
-<div id="outline-container-1_3" class="outline-3">
-<h3 id="sec-1_3"><span class="section-number-3">1.3</span> Install latest code from GitHub </h3>
-<div class="outline-text-3" id="text-1_3">
-
-
-
-
-
-<pre class="src src-sh"><span style="color: #00008b;">## </span><span style="color: #00008b;">clone the repository
-</span>mkdir -p /where/you/wanna/put/it
-<span style="color: #cd0000;">cd</span> /where/you/wanna/put/it
-git clone git://github.com/mishoo/UglifyJS.git
-
-<span style="color: #00008b;">## </span><span style="color: #00008b;">make the module available to Node
-</span>mkdir -p ~/.node_libraries/
-<span style="color: #cd0000;">cd</span> ~/.node_libraries/
-ln -s /where/you/wanna/put/it/UglifyJS/uglify-js.js
-
-<span style="color: #00008b;">## </span><span style="color: #00008b;">and if you want the CLI script too:
-</span>mkdir -p ~/bin
-<span style="color: #cd0000;">cd</span> ~/bin
-ln -s /where/you/wanna/put/it/UglifyJS/bin/uglifyjs
-  <span style="color: #00008b;"># </span><span style="color: #00008b;">(then add ~/bin to your $PATH if it's not there already)
-</span></pre>
-
-
-
-</div>
-
-</div>
-
-<div id="outline-container-1_4" class="outline-3">
-<h3 id="sec-1_4"><span class="section-number-3">1.4</span> Usage </h3>
-<div class="outline-text-3" id="text-1_4">
-
-
-<p>
-There is a command-line tool that exposes the functionality of this library
-for your shell-scripting needs:
-</p>
-
-
-
-<pre class="src src-sh">uglifyjs [ options... ] [ filename ]
-</pre>
-
-
-
-<p>
-<code>filename</code> should be the last argument and should name the file from which
-to read the JavaScript code.  If you don't specify it, it will read code
-from STDIN.
-</p>
-<p>
-Supported options:
-</p>
-<ul>
-<li>
-<code>-b</code> or <code>--beautify</code> &mdash; output indented code; when passed, additional
-options control the beautifier:
-
-<ul>
-<li>
-<code>-i N</code> or <code>--indent N</code> &mdash; indentation level (number of spaces)
-
-</li>
-<li>
-<code>-q</code> or <code>--quote-keys</code> &mdash; quote keys in literal objects (by default,
-only keys that cannot be identifier names will be quotes).
-
-</li>
-</ul>
-</li>
-<li>
-<code>--ascii</code> &mdash; pass this argument to encode non-ASCII characters as
-<code>\uXXXX</code> sequences.  By default UglifyJS won't bother to do it and will
-output Unicode characters instead.  (the output is always encoded in UTF8,
-but if you pass this option you'll only get ASCII).
-
-</li>
-<li>
-<code>-nm</code> or <code>--no-mangle</code> &mdash; don't mangle variable names
-
-</li>
-<li>
-<code>-ns</code> or <code>--no-squeeze</code> &mdash; don't call <code>ast_squeeze()</code> (which does various
-optimizations that result in smaller, less readable code).
-
-</li>
-<li>
-<code>-mt</code> or <code>--mangle-toplevel</code> &mdash; mangle names in the toplevel scope too
-(by default we don't do this).
-
-</li>
-<li>
-<code>--no-seqs</code> &mdash; when <code>ast_squeeze()</code> is called (thus, unless you pass
-<code>--no-squeeze</code>) it will reduce consecutive statements in blocks into a
-sequence.  For example, "a = 10; b = 20; foo();" will be written as
-"a=10,b=20,foo();".  In various occasions, this allows us to discard the
-block brackets (since the block becomes a single statement).  This is ON
-by default because it seems safe and saves a few hundred bytes on some
-libs that I tested it on, but pass <code>--no-seqs</code> to disable it.
-
-</li>
-<li>
-<code>--no-dead-code</code> &mdash; by default, UglifyJS will remove code that is
-obviously unreachable (code that follows a <code>return</code>, <code>throw</code>, <code>break</code> or
-<code>continue</code> statement and is not a function/variable declaration).  Pass
-this option to disable this optimization.
-
-</li>
-<li>
-<code>-nc</code> or <code>--no-copyright</code> &mdash; by default, <code>uglifyjs</code> will keep the initial
-comment tokens in the generated code (assumed to be copyright information
-etc.).  If you pass this it will discard it.
-
-</li>
-<li>
-<code>-o filename</code> or <code>--output filename</code> &mdash; put the result in <code>filename</code>.  If
-this isn't given, the result goes to standard output (or see next one).
-
-</li>
-<li>
-<code>--overwrite</code> &mdash; if the code is read from a file (not from STDIN) and you
-pass <code>--overwrite</code> then the output will be written in the same file.
-
-</li>
-<li>
-<code>--ast</code> &mdash; pass this if you want to get the Abstract Syntax Tree instead
-of JavaScript as output.  Useful for debugging or learning more about the
-internals.
-
-</li>
-<li>
-<code>-v</code> or <code>--verbose</code> &mdash; output some notes on STDERR (for now just how long
-each operation takes).
-
-</li>
-<li>
-<code>--extra</code> &mdash; enable additional optimizations that have not yet been
-extensively tested.  These might, or might not, break your code.  If you
-find a bug using this option, please report a test case.
-
-</li>
-<li>
-<code>--unsafe</code> &mdash; enable other additional optimizations that are known to be
-unsafe in some contrived situations, but could still be generally useful.
-For now only this:
-
-<ul>
-<li>
-foo.toString()  ==&gt;  foo+""
-
-</li>
-</ul>
-</li>
-<li>
-<code>--max-line-len</code> (default 32K characters) &mdash; add a newline after around
-32K characters.  I've seen both FF and Chrome croak when all the code was
-on a single line of around 670K.  Pass &ndash;max-line-len 0 to disable this
-safety feature.
-
-</li>
-<li>
-<code>--reserved-names</code> &mdash; some libraries rely on certain names to be used, as
-pointed out in issue #92 and #81, so this option allow you to exclude such
-names from the mangler.  For example, to keep names <code>require</code> and <code>$super</code>
-intact you'd specify &ndash;reserved-names "require,$super".
-
-</li>
-<li>
-<code>--inline-script</code> &ndash; when you want to include the output literally in an
-HTML <code>&lt;script&gt;</code> tag you can use this option to prevent <code>&lt;/script</code> from
-showing up in the output.
-</li>
-</ul>
-
-
-
-</div>
-
-<div id="outline-container-1_4_1" class="outline-4">
-<h4 id="sec-1_4_1"><span class="section-number-4">1.4.1</span> API </h4>
-<div class="outline-text-4" id="text-1_4_1">
-
-
-<p>
-To use the library from JavaScript, you'd do the following (example for
-NodeJS):
-</p>
-
-
-
-<pre class="src src-js"><span style="color: #8b0000;">var</span> <span style="color: #8b008b;">jsp</span> = require(<span style="color: #008b00;">"uglify-js"</span>).parser;
-<span style="color: #8b0000;">var</span> <span style="color: #8b008b;">pro</span> = require(<span style="color: #008b00;">"uglify-js"</span>).uglify;
-
-<span style="color: #8b0000;">var</span> <span style="color: #8b008b;">orig_code</span> = <span style="color: #008b00;">"... JS code here"</span>;
-<span style="color: #8b0000;">var</span> <span style="color: #8b008b;">ast</span> = jsp.parse(orig_code); <span style="color: #00008b;">// </span><span style="color: #00008b;">parse code and get the initial AST
-</span>ast = pro.ast_mangle(ast); <span style="color: #00008b;">// </span><span style="color: #00008b;">get a new AST with mangled names
-</span>ast = pro.ast_squeeze(ast); <span style="color: #00008b;">// </span><span style="color: #00008b;">get an AST with compression optimizations
-</span><span style="color: #8b0000;">var</span> <span style="color: #8b008b;">final_code</span> = pro.gen_code(ast); <span style="color: #00008b;">// </span><span style="color: #00008b;">compressed code here
-</span></pre>
-
-
-
-<p>
-The above performs the full compression that is possible right now.  As you
-can see, there are a sequence of steps which you can apply.  For example if
-you want compressed output but for some reason you don't want to mangle
-variable names, you would simply skip the line that calls
-<code>pro.ast_mangle(ast)</code>.
-</p>
-<p>
-Some of these functions take optional arguments.  Here's a description:
-</p>
-<ul>
-<li>
-<code>jsp.parse(code, strict_semicolons)</code> &ndash; parses JS code and returns an AST.
-<code>strict_semicolons</code> is optional and defaults to <code>false</code>.  If you pass
-<code>true</code> then the parser will throw an error when it expects a semicolon and
-it doesn't find it.  For most JS code you don't want that, but it's useful
-if you want to strictly sanitize your code.
-
-</li>
-<li>
-<code>pro.ast_mangle(ast, options)</code> &ndash; generates a new AST containing mangled
-(compressed) variable and function names.  It supports the following
-options:
-
-<ul>
-<li>
-<code>toplevel</code> &ndash; mangle toplevel names (by default we don't touch them).
-</li>
-<li>
-<code>except</code> &ndash; an array of names to exclude from compression.
-
-</li>
-</ul>
-</li>
-<li>
-<code>pro.ast_squeeze(ast, options)</code> &ndash; employs further optimizations designed
-to reduce the size of the code that <code>gen_code</code> would generate from the
-AST.  Returns a new AST.  <code>options</code> can be a hash; the supported options
-are:
-
-<ul>
-<li>
-<code>make_seqs</code> (default true) which will cause consecutive statements in a
-block to be merged using the "sequence" (comma) operator
-
-</li>
-<li>
-<code>dead_code</code> (default true) which will remove unreachable code.
-
-</li>
-</ul>
-</li>
-<li>
-<code>pro.gen_code(ast, options)</code> &ndash; generates JS code from the AST.  By
-default it's minified, but using the <code>options</code> argument you can get nicely
-formatted output.  <code>options</code> is, well, optional :-) and if you pass it it
-must be an object and supports the following properties (below you can see
-the default values):
-
-<ul>
-<li>
-<code>beautify: false</code> &ndash; pass <code>true</code> if you want indented output
-</li>
-<li>
-<code>indent_start: 0</code> (only applies when <code>beautify</code> is <code>true</code>) &ndash; initial
-indentation in spaces
-</li>
-<li>
-<code>indent_level: 4</code> (only applies when <code>beautify</code> is <code>true</code>) --
-indentation level, in spaces (pass an even number)
-</li>
-<li>
-<code>quote_keys: false</code> &ndash; if you pass <code>true</code> it will quote all keys in
-literal objects
-</li>
-<li>
-<code>space_colon: false</code> (only applies when <code>beautify</code> is <code>true</code>) &ndash; wether
-to put a space before the colon in object literals
-</li>
-<li>
-<code>ascii_only: false</code> &ndash; pass <code>true</code> if you want to encode non-ASCII
-characters as <code>\uXXXX</code>.
-</li>
-<li>
-<code>inline_script: false</code> &ndash; pass <code>true</code> to escape occurrences of
-<code>&lt;/script</code> in strings
-</li>
-</ul>
-</li>
-</ul>
-
-
-</div>
-
-</div>
-
-<div id="outline-container-1_4_2" class="outline-4">
-<h4 id="sec-1_4_2"><span class="section-number-4">1.4.2</span> Beautifier shortcoming &ndash; no more comments </h4>
-<div class="outline-text-4" id="text-1_4_2">
-
-
-<p>
-The beautifier can be used as a general purpose indentation tool.  It's
-useful when you want to make a minified file readable.  One limitation,
-though, is that it discards all comments, so you don't really want to use it
-to reformat your code, unless you don't have, or don't care about, comments.
-</p>
-<p>
-In fact it's not the beautifier who discards comments &mdash; they are dumped at
-the parsing stage, when we build the initial AST.  Comments don't really
-make sense in the AST, and while we could add nodes for them, it would be
-inconvenient because we'd have to add special rules to ignore them at all
-the processing stages.
-</p>
-</div>
-</div>
-
-</div>
-
-<div id="outline-container-1_5" class="outline-3">
-<h3 id="sec-1_5"><span class="section-number-3">1.5</span> Compression &ndash; how good is it? </h3>
-<div class="outline-text-3" id="text-1_5">
-
-
-<p>
-(XXX: this is somewhat outdated.  On the jQuery source code we beat Closure
-by 168 bytes (560 after gzip) and by many seconds.)
-</p>
-<p>
-There are a few popular JS minifiers nowadays &ndash; the two most well known
-being the GoogleClosure (GCL) compiler and the YUI compressor.  For some
-reason they are both written in Java.  I didn't really hope to beat any of
-them, but finally I did &ndash; UglifyJS compresses better than the YUI
-compressor, and safer than GoogleClosure.
-</p>
-<p>
-I tested it on two big libraries.  <a href="http://www.dynarchlib.com/">DynarchLIB</a> is my own, and it's big enough
-to contain probably all the JavaScript tricks known to mankind.  <a href="http://jquery.com/">jQuery</a> is
-definitely the most popular JavaScript library (to some people, it's a
-synonym to JavaScript itself).
-</p>
-<p>
-I cannot swear that there are no bugs in the generated codes, but they
-appear to work fine.
-</p>
-<p>
-Compression results:
-</p>
-<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
-<caption></caption>
-<colgroup><col align="left" /><col align="right" /><col align="right" /><col align="left" /><col align="left" />
-</colgroup>
-<thead>
-<tr><th scope="col">Library</th><th scope="col">Orig. size</th><th scope="col">UglifyJS</th><th scope="col">YUI</th><th scope="col">GCL</th></tr>
-</thead>
-<tbody>
-<tr><td>DynarchLIB</td><td>636896</td><td>241441</td><td>246452 (+5011)</td><td>240439 (-1002) (buggy)</td></tr>
-<tr><td>jQuery</td><td>163855</td><td>72006</td><td>79702  (+7696)</td><td>71858   (-148)</td></tr>
-</tbody>
-</table>
-
-
-<p>
-UglifyJS is the fastest to run.  On my laptop UglifyJS takes 1.35s for
-DynarchLIB, while YUI takes 2.7s and GCL takes 6.5s.
-</p>
-<p>
-GoogleClosure does a lot of smart ass optimizations.  I had to strive really
-hard to get close to it.  It should be possible to even beat it, but then
-again, GCL has a gazillion lines of code and runs terribly slow, so I'm not
-sure it worths spending the effort to save a few bytes.  Also, GCL doesn't
-cope with <code>eval()</code> or <code>with{}</code> &ndash; it just dumps a warning and proceeds to
-mangle names anyway; my DynarchLIB compiled with it is buggy because of
-this.
-</p>
-<p>
-UglifyJS consists of ~1100 lines of code for the tokenizer/parser, and ~1100
-lines for the compressor and code generator.  That should make it very
-maintainable and easily extensible, so I would say it has a good place in
-this field and it's bound to become the de-facto standard JS minifier.  And
-I shall rule the world. :-) Use it, and <b>spread the word</b>!
-</p>
-</div>
-
-</div>
-
-<div id="outline-container-1_6" class="outline-3">
-<h3 id="sec-1_6"><span class="section-number-3">1.6</span> Bugs? </h3>
-<div class="outline-text-3" id="text-1_6">
-
-
-<p>
-Unfortunately, for the time being there is no automated test suite.  But I
-ran the compressor manually on non-trivial code, and then I tested that the
-generated code works as expected.  A few hundred times.
-</p>
-<p>
-DynarchLIB was started in times when there was no good JS minifier.
-Therefore I was quite religious about trying to write short code manually,
-and as such DL contains a lot of syntactic hacks<sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup> such as “foo == bar ?  a
-= 10 : b = 20”, though the more readable version would clearly be to use
-“if/else”.
-</p>
-<p>
-Since the parser/compressor runs fine on DL and jQuery, I'm quite confident
-that it's solid enough for production use.  If you can identify any bugs,
-I'd love to hear about them (<a href="http://groups.google.com/group/uglifyjs">use the Google Group</a> or email me directly).
-</p>
-</div>
-
-</div>
-
-<div id="outline-container-1_7" class="outline-3">
-<h3 id="sec-1_7"><span class="section-number-3">1.7</span> Links </h3>
-<div class="outline-text-3" id="text-1_7">
-
-
-<ul>
-<li>
-Project at GitHub: <a href="http://github.com/mishoo/UglifyJS">http://github.com/mishoo/UglifyJS</a>
-</li>
-<li>
-Google Group: <a href="http://groups.google.com/group/uglifyjs">http://groups.google.com/group/uglifyjs</a>
-</li>
-<li>
-Common Lisp JS parser: <a href="http://marijn.haverbeke.nl/parse-js/">http://marijn.haverbeke.nl/parse-js/</a>
-</li>
-<li>
-JS-to-Lisp compiler: <a href="http://github.com/marijnh/js">http://github.com/marijnh/js</a>
-</li>
-<li>
-Common Lisp JS uglifier: <a href="http://github.com/mishoo/cl-uglify-js">http://github.com/mishoo/cl-uglify-js</a>
-</li>
-</ul>
-
-
-</div>
-
-</div>
-
-<div id="outline-container-1_8" class="outline-3">
-<h3 id="sec-1_8"><span class="section-number-3">1.8</span> License </h3>
-<div class="outline-text-3" id="text-1_8">
-
-
-<p>
-UglifyJS is released under the BSD license:
-</p>
-
-
-
-<pre class="example">Copyright 2010 (c) Mihai Bazon &lt;mihai.bazon@gmail.com&gt;
-Based on parse-js (http://marijn.haverbeke.nl/parse-js/).
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-    * Redistributions of source code must retain the above
-      copyright notice, this list of conditions and the following
-      disclaimer.
-
-    * Redistributions in binary form must reproduce the above
-      copyright notice, this list of conditions and the following
-      disclaimer in the documentation and/or other materials
-      provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
-</pre>
-
-
-
-
-</div>
-</div>
-</div>
-<div id="footnotes">
-<h2 class="footnotes">Footnotes: </h2>
-<div id="text-footnotes">
-<p class="footnote"><sup><a class="footnum" name="fn.1" href="#fnr.1">1</a></sup> I even reported a few bugs and suggested some fixes in the original
-<a href="http://marijn.haverbeke.nl/parse-js/">parse-js</a> library, and Marijn pushed fixes literally in minutes.
-</p>
-</div>
-</div>
-<div id="postamble">
-<p class="author"> Author: Mihai Bazon
-</p>
-<p class="date"> Date: 2011-07-14 12:50:31 EEST</p>
-<p class="creator">HTML generated by org-mode 7.01trans in emacs 23</p>
-</div>
-</div>
-</body>
-</html>
diff --git a/node/node_modules/___uglify-js.npm/package/README.org b/node/node_modules/___uglify-js.npm/package/README.org
deleted file mode 100644 (file)
index f0ae354..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-#+TITLE: UglifyJS -- a JavaScript parser/compressor/beautifier
-#+KEYWORDS: javascript, js, parser, compiler, compressor, mangle, minify, minifier
-#+DESCRIPTION: a JavaScript parser/compressor/beautifier in JavaScript
-#+STYLE: <link rel="stylesheet" type="text/css" href="docstyle.css" />
-#+AUTHOR: Mihai Bazon
-#+EMAIL: mihai.bazon@gmail.com
-
-* UglifyJS --- a JavaScript parser/compressor/beautifier
-
-This package implements a general-purpose JavaScript
-parser/compressor/beautifier toolkit.  It is developed on [[http://nodejs.org/][NodeJS]], but it
-should work on any JavaScript platform supporting the CommonJS module system
-(and if your platform of choice doesn't support CommonJS, you can easily
-implement it, or discard the =exports.*= lines from UglifyJS sources).
-
-The tokenizer/parser generates an abstract syntax tree from JS code.  You
-can then traverse the AST to learn more about the code, or do various
-manipulations on it.  This part is implemented in [[../lib/parse-js.js][parse-js.js]] and it's a
-port to JavaScript of the excellent [[http://marijn.haverbeke.nl/parse-js/][parse-js]] Common Lisp library from [[http://marijn.haverbeke.nl/][Marijn
-Haverbeke]].
-
-( See [[http://github.com/mishoo/cl-uglify-js][cl-uglify-js]] if you're looking for the Common Lisp version of
-UglifyJS. )
-
-The second part of this package, implemented in [[../lib/process.js][process.js]], inspects and
-manipulates the AST generated by the parser to provide the following:
-
-- ability to re-generate JavaScript code from the AST.  Optionally
-  indented---you can use this if you want to “beautify” a program that has
-  been compressed, so that you can inspect the source.  But you can also run
-  our code generator to print out an AST without any whitespace, so you
-  achieve compression as well.
-
-- shorten variable names (usually to single characters).  Our mangler will
-  analyze the code and generate proper variable names, depending on scope
-  and usage, and is smart enough to deal with globals defined elsewhere, or
-  with =eval()= calls or =with{}= statements.  In short, if =eval()= or
-  =with{}= are used in some scope, then all variables in that scope and any
-  variables in the parent scopes will remain unmangled, and any references
-  to such variables remain unmangled as well.
-
-- various small optimizations that may lead to faster code but certainly
-  lead to smaller code.  Where possible, we do the following:
-
-  - foo["bar"]  ==>  foo.bar
-
-  - remove block brackets ={}=
-
-  - join consecutive var declarations:
-    var a = 10; var b = 20; ==> var a=10,b=20;
-
-  - resolve simple constant expressions: 1 +2 * 3 ==> 7.  We only do the
-    replacement if the result occupies less bytes; for example 1/3 would
-    translate to 0.333333333333, so in this case we don't replace it.
-
-  - consecutive statements in blocks are merged into a sequence; in many
-    cases, this leaves blocks with a single statement, so then we can remove
-    the block brackets.
-
-  - various optimizations for IF statements:
-
-    - if (foo) bar(); else baz(); ==> foo?bar():baz();
-    - if (!foo) bar(); else baz(); ==> foo?baz():bar();
-    - if (foo) bar(); ==> foo&&bar();
-    - if (!foo) bar(); ==> foo||bar();
-    - if (foo) return bar(); else return baz(); ==> return foo?bar():baz();
-    - if (foo) return bar(); else something(); ==> {if(foo)return bar();something()}
-
-  - remove some unreachable code and warn about it (code that follows a
-    =return=, =throw=, =break= or =continue= statement, except
-    function/variable declarations).
-
-** <<Unsafe transformations>>
-
-UglifyJS tries its best to achieve great compression while leaving the
-semantics of the code intact.  In general, if your code logic is broken by
-UglifyJS then it's a bug in UglifyJS and you should report it and I should
-fix it. :-)
-
-However, I opted to include the following potentially unsafe transformations
-as default behavior.  Discussion is welcome, if you have ideas of how to
-handle this better, or any objections to these optimizations, please let me
-know.
-
-*** Calls involving the global Array constructor
-
-The following transformations occur:
-
-#+BEGIN_SRC js
-new Array(1, 2, 3, 4)  => [1,2,3,4]
-Array(a, b, c)         => [a,b,c]
-new Array(5)           => Array(5)
-new Array(a)           => Array(a)
-#+END_SRC
-
-These are all safe if the Array name isn't redefined.  JavaScript does allow
-one to globally redefine Array (and pretty much everything, in fact) but I
-personally don't see why would anyone do that.
-
-UglifyJS does handle the case where Array is redefined locally, or even
-globally but with a =function= or =var= declaration.  Therefore, in the
-following cases UglifyJS *doesn't touch* calls or instantiations of Array:
-
-#+BEGIN_SRC js
-// case 1.  globally declared variable
-  var Array;
-  new Array(1, 2, 3);
-  Array(a, b);
-
-  // or (can be declared later)
-  new Array(1, 2, 3);
-  var Array;
-
-  // or (can be a function)
-  new Array(1, 2, 3);
-  function Array() { ... }
-
-// case 2.  declared in a function
-  (function(){
-    a = new Array(1, 2, 3);
-    b = Array(5, 6);
-    var Array;
-  })();
-
-  // or
-  (function(Array){
-    return Array(5, 6, 7);
-  })();
-
-  // or
-  (function(){
-    return new Array(1, 2, 3, 4);
-    function Array() { ... }
-  })();
-
-  // etc.
-#+END_SRC
-
-** Install (NPM)
-
-UglifyJS is now available through NPM --- =npm install uglify-js= should do
-the job.
-
-** Install latest code from GitHub
-
-#+BEGIN_SRC sh
-## clone the repository
-mkdir -p /where/you/wanna/put/it
-cd /where/you/wanna/put/it
-git clone git://github.com/mishoo/UglifyJS.git
-
-## make the module available to Node
-mkdir -p ~/.node_libraries/
-cd ~/.node_libraries/
-ln -s /where/you/wanna/put/it/UglifyJS/uglify-js.js
-
-## and if you want the CLI script too:
-mkdir -p ~/bin
-cd ~/bin
-ln -s /where/you/wanna/put/it/UglifyJS/bin/uglifyjs
-  # (then add ~/bin to your $PATH if it's not there already)
-#+END_SRC
-
-** Usage
-
-There is a command-line tool that exposes the functionality of this library
-for your shell-scripting needs:
-
-#+BEGIN_SRC sh
-uglifyjs [ options... ] [ filename ]
-#+END_SRC
-
-=filename= should be the last argument and should name the file from which
-to read the JavaScript code.  If you don't specify it, it will read code
-from STDIN.
-
-Supported options:
-
-- =-b= or =--beautify= --- output indented code; when passed, additional
-  options control the beautifier:
-
-  - =-i N= or =--indent N= --- indentation level (number of spaces)
-
-  - =-q= or =--quote-keys= --- quote keys in literal objects (by default,
-    only keys that cannot be identifier names will be quotes).
-
-- =--ascii= --- pass this argument to encode non-ASCII characters as
-  =\uXXXX= sequences.  By default UglifyJS won't bother to do it and will
-  output Unicode characters instead.  (the output is always encoded in UTF8,
-  but if you pass this option you'll only get ASCII).
-
-- =-nm= or =--no-mangle= --- don't mangle variable names
-
-- =-ns= or =--no-squeeze= --- don't call =ast_squeeze()= (which does various
-  optimizations that result in smaller, less readable code).
-
-- =-mt= or =--mangle-toplevel= --- mangle names in the toplevel scope too
-  (by default we don't do this).
-
-- =--no-seqs= --- when =ast_squeeze()= is called (thus, unless you pass
-  =--no-squeeze=) it will reduce consecutive statements in blocks into a
-  sequence.  For example, "a = 10; b = 20; foo();" will be written as
-  "a=10,b=20,foo();".  In various occasions, this allows us to discard the
-  block brackets (since the block becomes a single statement).  This is ON
-  by default because it seems safe and saves a few hundred bytes on some
-  libs that I tested it on, but pass =--no-seqs= to disable it.
-
-- =--no-dead-code= --- by default, UglifyJS will remove code that is
-  obviously unreachable (code that follows a =return=, =throw=, =break= or
-  =continue= statement and is not a function/variable declaration).  Pass
-  this option to disable this optimization.
-
-- =-nc= or =--no-copyright= --- by default, =uglifyjs= will keep the initial
-  comment tokens in the generated code (assumed to be copyright information
-  etc.).  If you pass this it will discard it.
-
-- =-o filename= or =--output filename= --- put the result in =filename=.  If
-  this isn't given, the result goes to standard output (or see next one).
-
-- =--overwrite= --- if the code is read from a file (not from STDIN) and you
-  pass =--overwrite= then the output will be written in the same file.
-
-- =--ast= --- pass this if you want to get the Abstract Syntax Tree instead
-  of JavaScript as output.  Useful for debugging or learning more about the
-  internals.
-
-- =-v= or =--verbose= --- output some notes on STDERR (for now just how long
-  each operation takes).
-
-- =--extra= --- enable additional optimizations that have not yet been
-  extensively tested.  These might, or might not, break your code.  If you
-  find a bug using this option, please report a test case.
-
-- =--unsafe= --- enable other additional optimizations that are known to be
-  unsafe in some contrived situations, but could still be generally useful.
-  For now only this:
-
-  - foo.toString()  ==>  foo+""
-
-- =--max-line-len= (default 32K characters) --- add a newline after around
-  32K characters.  I've seen both FF and Chrome croak when all the code was
-  on a single line of around 670K.  Pass --max-line-len 0 to disable this
-  safety feature.
-
-- =--reserved-names= --- some libraries rely on certain names to be used, as
-  pointed out in issue #92 and #81, so this option allow you to exclude such
-  names from the mangler.  For example, to keep names =require= and =$super=
-  intact you'd specify --reserved-names "require,$super".
-
-- =--inline-script= -- when you want to include the output literally in an
-  HTML =<script>= tag you can use this option to prevent =</script= from
-  showing up in the output.
-
-*** API
-
-To use the library from JavaScript, you'd do the following (example for
-NodeJS):
-
-#+BEGIN_SRC js
-var jsp = require("uglify-js").parser;
-var pro = require("uglify-js").uglify;
-
-var orig_code = "... JS code here";
-var ast = jsp.parse(orig_code); // parse code and get the initial AST
-ast = pro.ast_mangle(ast); // get a new AST with mangled names
-ast = pro.ast_squeeze(ast); // get an AST with compression optimizations
-var final_code = pro.gen_code(ast); // compressed code here
-#+END_SRC
-
-The above performs the full compression that is possible right now.  As you
-can see, there are a sequence of steps which you can apply.  For example if
-you want compressed output but for some reason you don't want to mangle
-variable names, you would simply skip the line that calls
-=pro.ast_mangle(ast)=.
-
-Some of these functions take optional arguments.  Here's a description:
-
-- =jsp.parse(code, strict_semicolons)= -- parses JS code and returns an AST.
-  =strict_semicolons= is optional and defaults to =false=.  If you pass
-  =true= then the parser will throw an error when it expects a semicolon and
-  it doesn't find it.  For most JS code you don't want that, but it's useful
-  if you want to strictly sanitize your code.
-
-- =pro.ast_mangle(ast, options)= -- generates a new AST containing mangled
-  (compressed) variable and function names.  It supports the following
-  options:
-
-  - =toplevel= -- mangle toplevel names (by default we don't touch them).
-  - =except= -- an array of names to exclude from compression.
-
-- =pro.ast_squeeze(ast, options)= -- employs further optimizations designed
-  to reduce the size of the code that =gen_code= would generate from the
-  AST.  Returns a new AST.  =options= can be a hash; the supported options
-  are:
-
-  - =make_seqs= (default true) which will cause consecutive statements in a
-    block to be merged using the "sequence" (comma) operator
-
-  - =dead_code= (default true) which will remove unreachable code.
-
-- =pro.gen_code(ast, options)= -- generates JS code from the AST.  By
-  default it's minified, but using the =options= argument you can get nicely
-  formatted output.  =options= is, well, optional :-) and if you pass it it
-  must be an object and supports the following properties (below you can see
-  the default values):
-
-  - =beautify: false= -- pass =true= if you want indented output
-  - =indent_start: 0= (only applies when =beautify= is =true=) -- initial
-    indentation in spaces
-  - =indent_level: 4= (only applies when =beautify= is =true=) --
-    indentation level, in spaces (pass an even number)
-  - =quote_keys: false= -- if you pass =true= it will quote all keys in
-    literal objects
-  - =space_colon: false= (only applies when =beautify= is =true=) -- wether
-    to put a space before the colon in object literals
-  - =ascii_only: false= -- pass =true= if you want to encode non-ASCII
-    characters as =\uXXXX=.
-  - =inline_script: false= -- pass =true= to escape occurrences of
-    =</script= in strings
-
-*** Beautifier shortcoming -- no more comments
-
-The beautifier can be used as a general purpose indentation tool.  It's
-useful when you want to make a minified file readable.  One limitation,
-though, is that it discards all comments, so you don't really want to use it
-to reformat your code, unless you don't have, or don't care about, comments.
-
-In fact it's not the beautifier who discards comments --- they are dumped at
-the parsing stage, when we build the initial AST.  Comments don't really
-make sense in the AST, and while we could add nodes for them, it would be
-inconvenient because we'd have to add special rules to ignore them at all
-the processing stages.
-
-** Compression -- how good is it?
-
-(XXX: this is somewhat outdated.  On the jQuery source code we beat Closure
-by 168 bytes (560 after gzip) and by many seconds.)
-
-There are a few popular JS minifiers nowadays -- the two most well known
-being the GoogleClosure (GCL) compiler and the YUI compressor.  For some
-reason they are both written in Java.  I didn't really hope to beat any of
-them, but finally I did -- UglifyJS compresses better than the YUI
-compressor, and safer than GoogleClosure.
-
-I tested it on two big libraries.  [[http://www.dynarchlib.com/][DynarchLIB]] is my own, and it's big enough
-to contain probably all the JavaScript tricks known to mankind.  [[http://jquery.com/][jQuery]] is
-definitely the most popular JavaScript library (to some people, it's a
-synonym to JavaScript itself).
-
-I cannot swear that there are no bugs in the generated codes, but they
-appear to work fine.
-
-Compression results:
-
-| Library    | Orig. size | UglifyJS | YUI            | GCL                    |
-|------------+------------+----------+----------------+------------------------|
-| DynarchLIB |     636896 |   241441 | 246452 (+5011) | 240439 (-1002) (buggy) |
-| jQuery     |     163855 |    72006 | 79702  (+7696) | 71858   (-148)         |
-
-UglifyJS is the fastest to run.  On my laptop UglifyJS takes 1.35s for
-DynarchLIB, while YUI takes 2.7s and GCL takes 6.5s.
-
-GoogleClosure does a lot of smart ass optimizations.  I had to strive really
-hard to get close to it.  It should be possible to even beat it, but then
-again, GCL has a gazillion lines of code and runs terribly slow, so I'm not
-sure it worths spending the effort to save a few bytes.  Also, GCL doesn't
-cope with =eval()= or =with{}= -- it just dumps a warning and proceeds to
-mangle names anyway; my DynarchLIB compiled with it is buggy because of
-this.
-
-UglifyJS consists of ~1100 lines of code for the tokenizer/parser, and ~1100
-lines for the compressor and code generator.  That should make it very
-maintainable and easily extensible, so I would say it has a good place in
-this field and it's bound to become the de-facto standard JS minifier.  And
-I shall rule the world. :-) Use it, and *spread the word*!
-
-** Bugs?
-
-Unfortunately, for the time being there is no automated test suite.  But I
-ran the compressor manually on non-trivial code, and then I tested that the
-generated code works as expected.  A few hundred times.
-
-DynarchLIB was started in times when there was no good JS minifier.
-Therefore I was quite religious about trying to write short code manually,
-and as such DL contains a lot of syntactic hacks[1] such as “foo == bar ?  a
-= 10 : b = 20”, though the more readable version would clearly be to use
-“if/else”.
-
-Since the parser/compressor runs fine on DL and jQuery, I'm quite confident
-that it's solid enough for production use.  If you can identify any bugs,
-I'd love to hear about them ([[http://groups.google.com/group/uglifyjs][use the Google Group]] or email me directly).
-
-[1] I even reported a few bugs and suggested some fixes in the original
-    [[http://marijn.haverbeke.nl/parse-js/][parse-js]] library, and Marijn pushed fixes literally in minutes.
-
-** Links
-
-- Project at GitHub: [[http://github.com/mishoo/UglifyJS][http://github.com/mishoo/UglifyJS]]
-- Google Group: [[http://groups.google.com/group/uglifyjs][http://groups.google.com/group/uglifyjs]]
-- Common Lisp JS parser: [[http://marijn.haverbeke.nl/parse-js/][http://marijn.haverbeke.nl/parse-js/]]
-- JS-to-Lisp compiler: [[http://github.com/marijnh/js][http://github.com/marijnh/js]]
-- Common Lisp JS uglifier: [[http://github.com/mishoo/cl-uglify-js][http://github.com/mishoo/cl-uglify-js]]
-
-** License
-
-UglifyJS is released under the BSD license:
-
-#+BEGIN_EXAMPLE
-Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
-Based on parse-js (http://marijn.haverbeke.nl/parse-js/).
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-    * Redistributions of source code must retain the above
-      copyright notice, this list of conditions and the following
-      disclaimer.
-
-    * Redistributions in binary form must reproduce the above
-      copyright notice, this list of conditions and the following
-      disclaimer in the documentation and/or other materials
-      provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
-OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
-THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-#+END_EXAMPLE
diff --git a/node/node_modules/___uglify-js.npm/package/bin/uglifyjs b/node/node_modules/___uglify-js.npm/package/bin/uglifyjs
deleted file mode 100644 (file)
index 3a23be8..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-#! /usr/bin/env node
-// -*- js -*-
-
-global.sys = require(/^v0\.[012]/.test(process.version) ? "sys" : "util");
-var fs = require("fs");
-var uglify = require("uglify-js"), // symlink ~/.node_libraries/uglify-js.js to ../uglify-js.js
-    jsp = uglify.parser,
-    pro = uglify.uglify;
-
-var options = {
-        ast: false,
-        mangle: true,
-        mangle_toplevel: false,
-        squeeze: true,
-        make_seqs: true,
-        dead_code: true,
-        verbose: false,
-        show_copyright: true,
-        out_same_file: false,
-        max_line_length: 32 * 1024,
-        unsafe: false,
-        reserved_names: null,
-        defines: { },
-        codegen_options: {
-                ascii_only: false,
-                beautify: false,
-                indent_level: 4,
-                indent_start: 0,
-                quote_keys: false,
-                space_colon: false,
-                inline_script: false
-        },
-        make: false,
-        output: true            // stdout
-};
-
-var args = jsp.slice(process.argv, 2);
-var filename;
-
-out: while (args.length > 0) {
-        var v = args.shift();
-        switch (v) {
-            case "-b":
-            case "--beautify":
-                options.codegen_options.beautify = true;
-                break;
-            case "-i":
-            case "--indent":
-                options.codegen_options.indent_level = args.shift();
-                break;
-            case "-q":
-            case "--quote-keys":
-                options.codegen_options.quote_keys = true;
-                break;
-            case "-mt":
-            case "--mangle-toplevel":
-                options.mangle_toplevel = true;
-                break;
-            case "--no-mangle":
-            case "-nm":
-                options.mangle = false;
-                break;
-            case "--no-squeeze":
-            case "-ns":
-                options.squeeze = false;
-                break;
-            case "--no-seqs":
-                options.make_seqs = false;
-                break;
-            case "--no-dead-code":
-                options.dead_code = false;
-                break;
-            case "--no-copyright":
-            case "-nc":
-                options.show_copyright = false;
-                break;
-            case "-o":
-            case "--output":
-                options.output = args.shift();
-                break;
-            case "--overwrite":
-                options.out_same_file = true;
-                break;
-            case "-v":
-            case "--verbose":
-                options.verbose = true;
-                break;
-            case "--ast":
-                options.ast = true;
-                break;
-            case "--unsafe":
-                options.unsafe = true;
-                break;
-            case "--max-line-len":
-                options.max_line_length = parseInt(args.shift(), 10);
-                break;
-            case "--reserved-names":
-                options.reserved_names = args.shift().split(",");
-                break;
-            case "-d":
-            case "--define":
-                 var defarg = args.shift();
-                 try {
-                     var defsym = function(sym) {
-                             // KEYWORDS_ATOM doesn't include NaN or Infinity - should we check
-                             // for them too ?? We don't check reserved words and the like as the
-                             // define values are only substituted AFTER parsing
-                             if (jsp.KEYWORDS_ATOM.hasOwnProperty(sym)) {
-                                 throw "Don't define values for inbuilt constant '"+sym+"'";
-                             }
-                             return sym;
-                         },
-                         defval = function(v) {
-                             if (v.match(/^"(.*)"$/) || v.match(/^'(.*)'$/)) {
-                                 return [ "string", RegExp.$1 ];
-                             }
-                             else if (!isNaN(parseFloat(v))) {
-                                 return [ "num", parseFloat(v) ];
-                             }
-                             else if (v.match(/^[a-z\$_][a-z\$_0-9]*$/i)) {
-                                 return [ "name", v ];
-                             }
-                             else if (!v.match(/"/)) {
-                                 return [ "string", v ];
-                             }
-                             else if (!v.match(/'/)) {
-                                 return [ "string", v ];
-                             }
-                             throw "Can't understand the specified value: "+v;
-                         };
-                     if (defarg.match(/^([a-z_\$][a-z_\$0-9]*)(=(.*))?$/i)) {
-                         var sym = defsym(RegExp.$1),
-                             val = RegExp.$2 ? defval(RegExp.$2.substr(1)) : [ 'name', 'true' ];
-                         options.defines[sym] = val;
-                     }
-                     else {
-                         throw "The --define option expects SYMBOL[=value]";
-                     }
-                 } catch(ex) {
-                     sys.print("ERROR: In option --define "+defarg+"\n"+ex+"\n");
-                     process.exit(1);
-                 }
-                 break;
-            case "--define-from-module":
-                var defmodarg = args.shift(),
-                    defmodule = require(defmodarg),
-                    sym,
-                    val;
-                for (sym in defmodule) {
-                    if (defmodule.hasOwnProperty(sym)) {
-                        options.defines[sym] = function(val) {
-                            if (typeof val == "string")
-                                return [ "string", val ];
-                            if (typeof val == "number")
-                                return [ "num", val ];
-                            if (val === true)
-                                return [ 'name', 'true' ];
-                            if (val === false)
-                                return [ 'name', 'false' ];
-                            if (val === null)
-                                return [ 'name', 'null' ];
-                            if (val === undefined)
-                                return [ 'name', 'undefined' ];
-                            sys.print("ERROR: In option --define-from-module "+defmodarg+"\n");
-                            sys.print("ERROR: Unknown object type for: "+sym+"="+val+"\n");
-                            process.exit(1);
-                            return null;
-                        }(defmodule[sym]);
-                    }
-                }
-                break;
-            case "--ascii":
-                options.codegen_options.ascii_only = true;
-                break;
-            case "--make":
-                options.make = true;
-                break;
-            case "--inline-script":
-                options.codegen_options.inline_script = true;
-                break;
-            default:
-                filename = v;
-                break out;
-        }
-}
-
-if (options.verbose) {
-        pro.set_logger(function(msg){
-                sys.debug(msg);
-        });
-}
-
-jsp.set_logger(function(msg){
-        sys.debug(msg);
-});
-
-if (options.make) {
-        options.out_same_file = false; // doesn't make sense in this case
-        var makefile = JSON.parse(fs.readFileSync(filename || "Makefile.uglify.js").toString());
-        output(makefile.files.map(function(file){
-                var code = fs.readFileSync(file.name);
-                if (file.module) {
-                        code = "!function(exports, global){global = this;\n" + code + "\n;this." + file.module + " = exports;}({})";
-                }
-                else if (file.hide) {
-                        code = "(function(){" + code + "}());";
-                }
-                return squeeze_it(code);
-        }).join("\n"));
-}
-else if (filename) {
-        fs.readFile(filename, "utf8", function(err, text){
-                if (err) throw err;
-                output(squeeze_it(text));
-        });
-}
-else {
-        var stdin = process.openStdin();
-        stdin.setEncoding("utf8");
-        var text = "";
-        stdin.on("data", function(chunk){
-                text += chunk;
-        });
-        stdin.on("end", function() {
-                output(squeeze_it(text));
-        });
-}
-
-function output(text) {
-        var out;
-        if (options.out_same_file && filename)
-                options.output = filename;
-        if (options.output === true) {
-                out = process.stdout;
-        } else {
-                out = fs.createWriteStream(options.output, {
-                        flags: "w",
-                        encoding: "utf8",
-                        mode: 0644
-                });
-        }
-        out.write(text);
-        if (options.output !== true) {
-                out.end();
-        }
-};
-
-// --------- main ends here.
-
-function show_copyright(comments) {
-        var ret = "";
-        for (var i = 0; i < comments.length; ++i) {
-                var c = comments[i];
-                if (c.type == "comment1") {
-                        ret += "//" + c.value + "\n";
-                } else {
-                        ret += "/*" + c.value + "*/";
-                }
-        }
-        return ret;
-};
-
-function squeeze_it(code) {
-        var result = "";
-        if (options.show_copyright) {
-                var tok = jsp.tokenizer(code), c;
-                c = tok();
-                result += show_copyright(c.comments_before);
-        }
-        try {
-                var ast = time_it("parse", function(){ return jsp.parse(code); });
-                if (options.mangle) ast = time_it("mangle", function(){
-                        return pro.ast_mangle(ast, {
-                                toplevel: options.mangle_toplevel,
-                                defines: options.defines,
-                                except: options.reserved_names
-                        });
-                });
-                if (options.squeeze) ast = time_it("squeeze", function(){
-                        ast = pro.ast_squeeze(ast, {
-                                make_seqs  : options.make_seqs,
-                                dead_code  : options.dead_code,
-                                keep_comps : !options.unsafe
-                        });
-                        if (options.unsafe)
-                                ast = pro.ast_squeeze_more(ast);
-                        return ast;
-                });
-                if (options.ast)
-                        return sys.inspect(ast, null, null);
-                result += time_it("generate", function(){ return pro.gen_code(ast, options.codegen_options) });
-                if (!options.codegen_options.beautify && options.max_line_length) {
-                        result = time_it("split", function(){ return pro.split_lines(result, options.max_line_length) });
-                }
-                return result;
-        } catch(ex) {
-                sys.debug(ex.stack);
-                sys.debug(sys.inspect(ex));
-                sys.debug(JSON.stringify(ex));
-        }
-};
-
-function time_it(name, cont) {
-        if (!options.verbose)
-                return cont();
-        var t1 = new Date().getTime();
-        try { return cont(); }
-        finally { sys.debug("// " + name + ": " + ((new Date().getTime() - t1) / 1000).toFixed(3) + " sec."); }
-};
diff --git a/node/node_modules/___uglify-js.npm/package/docstyle.css b/node/node_modules/___uglify-js.npm/package/docstyle.css
deleted file mode 100644 (file)
index 412481f..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-html { font-family: "Lucida Grande","Trebuchet MS",sans-serif; font-size: 12pt; }
-body { max-width: 60em; }
-.title  { text-align: center; }
-.todo   { color: red; }
-.done   { color: green; }
-.tag    { background-color:lightblue; font-weight:normal }
-.target { }
-.timestamp { color: grey }
-.timestamp-kwd { color: CadetBlue }
-p.verse { margin-left: 3% }
-pre {
-  border: 1pt solid #AEBDCC;
-  background-color: #F3F5F7;
-  padding: 5pt;
-  font-family: monospace;
-  font-size: 90%;
-  overflow:auto;
-}
-pre.src {
-  background-color: #eee; color: #112; border: 1px solid #000;
-}
-table { border-collapse: collapse; }
-td, th { vertical-align: top; }
-dt { font-weight: bold; }
-div.figure { padding: 0.5em; }
-div.figure p { text-align: center; }
-.linenr { font-size:smaller }
-.code-highlighted {background-color:#ffff00;}
-.org-info-js_info-navigation { border-style:none; }
-#org-info-js_console-label { font-size:10px; font-weight:bold;
-  white-space:nowrap; }
-.org-info-js_search-highlight {background-color:#ffff00; color:#000000;
-  font-weight:bold; }
-
-sup {
-  vertical-align: baseline;
-  position: relative;
-  top: -0.5em;
-  font-size: 80%;
-}
-
-sup a:link, sup a:visited {
-  text-decoration: none;
-  color: #c00;
-}
-
-sup a:before { content: "["; color: #999; }
-sup a:after { content: "]"; color: #999; }
-
-h1.title { border-bottom: 4px solid #000; padding-bottom: 5px; margin-bottom: 2em; }
-
-#postamble {
-  color: #777;
-  font-size: 90%;
-  padding-top: 1em; padding-bottom: 1em; border-top: 1px solid #999;
-  margin-top: 2em;
-  padding-left: 2em;
-  padding-right: 2em;
-  text-align: right;
-}
-
-#postamble p { margin: 0; }
-
-#footnotes { border-top: 1px solid #000; }
-
-h1 { font-size: 200% }
-h2 { font-size: 175% }
-h3 { font-size: 150% }
-h4 { font-size: 125% }
-
-h1, h2, h3, h4 { font-family: "Bookman",Georgia,"Times New Roman",serif; font-weight: normal; }
-
-@media print {
-  html { font-size: 11pt; }
-}
diff --git a/node/node_modules/___uglify-js.npm/package/lib/parse-js.js b/node/node_modules/___uglify-js.npm/package/lib/parse-js.js
deleted file mode 100644 (file)
index 70bf999..0000000
+++ /dev/null
@@ -1,1340 +0,0 @@
-/***********************************************************************
-
-  A JavaScript tokenizer / parser / beautifier / compressor.
-
-  This version is suitable for Node.js.  With minimal changes (the
-  exports stuff) it should work on any JS platform.
-
-  This file contains the tokenizer/parser.  It is a port to JavaScript
-  of parse-js [1], a JavaScript parser library written in Common Lisp
-  by Marijn Haverbeke.  Thank you Marijn!
-
-  [1] http://marijn.haverbeke.nl/parse-js/
-
-  Exported functions:
-
-    - tokenizer(code) -- returns a function.  Call the returned
-      function to fetch the next token.
-
-    - parse(code) -- returns an AST of the given JavaScript code.
-
-  -------------------------------- (C) ---------------------------------
-
-                           Author: Mihai Bazon
-                         <mihai.bazon@gmail.com>
-                       http://mihai.bazon.net/blog
-
-  Distributed under the BSD license:
-
-    Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
-    Based on parse-js (http://marijn.haverbeke.nl/parse-js/).
-
-    Redistribution and use in source and binary forms, with or without
-    modification, are permitted provided that the following conditions
-    are met:
-
-        * Redistributions of source code must retain the above
-          copyright notice, this list of conditions and the following
-          disclaimer.
-
-        * Redistributions in binary form must reproduce the above
-          copyright notice, this list of conditions and the following
-          disclaimer in the documentation and/or other materials
-          provided with the distribution.
-
-    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
-    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
-
- ***********************************************************************/
-
-/* -----[ Tokenizer (constants) ]----- */
-
-var KEYWORDS = array_to_hash([
-        "break",
-        "case",
-        "catch",
-        "const",
-        "continue",
-        "default",
-        "delete",
-        "do",
-        "else",
-        "finally",
-        "for",
-        "function",
-        "if",
-        "in",
-        "instanceof",
-        "new",
-        "return",
-        "switch",
-        "throw",
-        "try",
-        "typeof",
-        "var",
-        "void",
-        "while",
-        "with"
-]);
-
-var RESERVED_WORDS = array_to_hash([
-        "abstract",
-        "boolean",
-        "byte",
-        "char",
-        "class",
-        "debugger",
-        "double",
-        "enum",
-        "export",
-        "extends",
-        "final",
-        "float",
-        "goto",
-        "implements",
-        "import",
-        "int",
-        "interface",
-        "long",
-        "native",
-        "package",
-        "private",
-        "protected",
-        "public",
-        "short",
-        "static",
-        "super",
-        "synchronized",
-        "throws",
-        "transient",
-        "volatile"
-]);
-
-var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([
-        "return",
-        "new",
-        "delete",
-        "throw",
-        "else",
-        "case"
-]);
-
-var KEYWORDS_ATOM = array_to_hash([
-        "false",
-        "null",
-        "true",
-        "undefined"
-]);
-
-var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^"));
-
-var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
-var RE_OCT_NUMBER = /^0[0-7]+$/;
-var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
-
-var OPERATORS = array_to_hash([
-        "in",
-        "instanceof",
-        "typeof",
-        "new",
-        "void",
-        "delete",
-        "++",
-        "--",
-        "+",
-        "-",
-        "!",
-        "~",
-        "&",
-        "|",
-        "^",
-        "*",
-        "/",
-        "%",
-        ">>",
-        "<<",
-        ">>>",
-        "<",
-        ">",
-        "<=",
-        ">=",
-        "==",
-        "===",
-        "!=",
-        "!==",
-        "?",
-        "=",
-        "+=",
-        "-=",
-        "/=",
-        "*=",
-        "%=",
-        ">>=",
-        "<<=",
-        ">>>=",
-        "|=",
-        "^=",
-        "&=",
-        "&&",
-        "||"
-]);
-
-var WHITESPACE_CHARS = array_to_hash(characters(" \u00a0\n\r\t\f\v\u200b"));
-
-var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:"));
-
-var PUNC_CHARS = array_to_hash(characters("[]{}(),;:"));
-
-var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy"));
-
-/* -----[ Tokenizer ]----- */
-
-// regexps adapted from http://xregexp.com/plugins/#unicode
-var UNICODE = {
-        letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
-        non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
-        space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
-        connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
-};
-
-function is_letter(ch) {
-        return UNICODE.letter.test(ch);
-};
-
-function is_digit(ch) {
-        ch = ch.charCodeAt(0);
-        return ch >= 48 && ch <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9
-};
-
-function is_alphanumeric_char(ch) {
-        return is_digit(ch) || is_letter(ch);
-};
-
-function is_unicode_combining_mark(ch) {
-        return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
-};
-
-function is_unicode_connector_punctuation(ch) {
-        return UNICODE.connector_punctuation.test(ch);
-};
-
-function is_identifier_start(ch) {
-        return ch == "$" || ch == "_" || is_letter(ch);
-};
-
-function is_identifier_char(ch) {
-        return is_identifier_start(ch)
-                || is_unicode_combining_mark(ch)
-                || is_digit(ch)
-                || is_unicode_connector_punctuation(ch)
-                || ch == "\u200c" // zero-width non-joiner <ZWNJ>
-                || ch == "\u200d" // zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
-        ;
-};
-
-function parse_js_number(num) {
-        if (RE_HEX_NUMBER.test(num)) {
-                return parseInt(num.substr(2), 16);
-        } else if (RE_OCT_NUMBER.test(num)) {
-                return parseInt(num.substr(1), 8);
-        } else if (RE_DEC_NUMBER.test(num)) {
-                return parseFloat(num);
-        }
-};
-
-function JS_Parse_Error(message, line, col, pos) {
-        this.message = message;
-        this.line = line;
-        this.col = col;
-        this.pos = pos;
-        try {
-                ({})();
-        } catch(ex) {
-                this.stack = ex.stack;
-        };
-};
-
-JS_Parse_Error.prototype.toString = function() {
-        return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
-};
-
-function js_error(message, line, col, pos) {
-        throw new JS_Parse_Error(message, line, col, pos);
-};
-
-function is_token(token, type, val) {
-        return token.type == type && (val == null || token.value == val);
-};
-
-var EX_EOF = {};
-
-function tokenizer($TEXT) {
-
-        var S = {
-                text            : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''),
-                pos             : 0,
-                tokpos          : 0,
-                line            : 0,
-                tokline         : 0,
-                col             : 0,
-                tokcol          : 0,
-                newline_before  : false,
-                regex_allowed   : false,
-                comments_before : []
-        };
-
-        function peek() { return S.text.charAt(S.pos); };
-
-        function next(signal_eof) {
-                var ch = S.text.charAt(S.pos++);
-                if (signal_eof && !ch)
-                        throw EX_EOF;
-                if (ch == "\n") {
-                        S.newline_before = true;
-                        ++S.line;
-                        S.col = 0;
-                } else {
-                        ++S.col;
-                }
-                return ch;
-        };
-
-        function eof() {
-                return !S.peek();
-        };
-
-        function find(what, signal_eof) {
-                var pos = S.text.indexOf(what, S.pos);
-                if (signal_eof && pos == -1) throw EX_EOF;
-                return pos;
-        };
-
-        function start_token() {
-                S.tokline = S.line;
-                S.tokcol = S.col;
-                S.tokpos = S.pos;
-        };
-
-        function token(type, value, is_comment) {
-                S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) ||
-                                   (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) ||
-                                   (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value)));
-                var ret = {
-                        type  : type,
-                        value : value,
-                        line  : S.tokline,
-                        col   : S.tokcol,
-                        pos   : S.tokpos,
-                        nlb   : S.newline_before
-                };
-                if (!is_comment) {
-                        ret.comments_before = S.comments_before;
-                        S.comments_before = [];
-                }
-                S.newline_before = false;
-                return ret;
-        };
-
-        function skip_whitespace() {
-                while (HOP(WHITESPACE_CHARS, peek()))
-                        next();
-        };
-
-        function read_while(pred) {
-                var ret = "", ch = peek(), i = 0;
-                while (ch && pred(ch, i++)) {
-                        ret += next();
-                        ch = peek();
-                }
-                return ret;
-        };
-
-        function parse_error(err) {
-                js_error(err, S.tokline, S.tokcol, S.tokpos);
-        };
-
-        function read_num(prefix) {
-                var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
-                var num = read_while(function(ch, i){
-                        if (ch == "x" || ch == "X") {
-                                if (has_x) return false;
-                                return has_x = true;
-                        }
-                        if (!has_x && (ch == "E" || ch == "e")) {
-                                if (has_e) return false;
-                                return has_e = after_e = true;
-                        }
-                        if (ch == "-") {
-                                if (after_e || (i == 0 && !prefix)) return true;
-                                return false;
-                        }
-                        if (ch == "+") return after_e;
-                        after_e = false;
-                        if (ch == ".") {
-                                if (!has_dot && !has_x)
-                                        return has_dot = true;
-                                return false;
-                        }
-                        return is_alphanumeric_char(ch);
-                });
-                if (prefix)
-                        num = prefix + num;
-                var valid = parse_js_number(num);
-                if (!isNaN(valid)) {
-                        return token("num", valid);
-                } else {
-                        parse_error("Invalid syntax: " + num);
-                }
-        };
-
-        function read_escaped_char() {
-                var ch = next(true);
-                switch (ch) {
-                    case "n" : return "\n";
-                    case "r" : return "\r";
-                    case "t" : return "\t";
-                    case "b" : return "\b";
-                    case "v" : return "\v";
-                    case "f" : return "\f";
-                    case "0" : return "\0";
-                    case "x" : return String.fromCharCode(hex_bytes(2));
-                    case "u" : return String.fromCharCode(hex_bytes(4));
-                    default  : return ch;
-                }
-        };
-
-        function hex_bytes(n) {
-                var num = 0;
-                for (; n > 0; --n) {
-                        var digit = parseInt(next(true), 16);
-                        if (isNaN(digit))
-                                parse_error("Invalid hex-character pattern in string");
-                        num = (num << 4) | digit;
-                }
-                return num;
-        };
-
-        function read_string() {
-                return with_eof_error("Unterminated string constant", function(){
-                        var quote = next(), ret = "";
-                        for (;;) {
-                                var ch = next(true);
-                                if (ch == "\\") {
-                                        // read OctalEscapeSequence (XXX: deprecated if "strict mode")
-                                        // https://github.com/mishoo/UglifyJS/issues/178
-                                        var octal_len = 0, first = null;
-                                        ch = read_while(function(ch){
-                                                if (ch >= "0" && ch <= "7") {
-                                                        if (!first) {
-                                                                first = ch;
-                                                                return ++octal_len;
-                                                        }
-                                                        else if (first <= "3" && octal_len <= 2) return ++octal_len;
-                                                        else if (first >= "4" && octal_len <= 1) return ++octal_len;
-                                                }
-                                                return false;
-                                        });
-                                        if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8));
-                                        else ch = read_escaped_char();
-                                }
-                                else if (ch == quote) break;
-                                ret += ch;
-                        }
-                        return token("string", ret);
-                });
-        };
-
-        function read_line_comment() {
-                next();
-                var i = find("\n"), ret;
-                if (i == -1) {
-                        ret = S.text.substr(S.pos);
-                        S.pos = S.text.length;
-                } else {
-                        ret = S.text.substring(S.pos, i);
-                        S.pos = i;
-                }
-                return token("comment1", ret, true);
-        };
-
-        function read_multiline_comment() {
-                next();
-                return with_eof_error("Unterminated multiline comment", function(){
-                        var i = find("*/", true),
-                            text = S.text.substring(S.pos, i),
-                            tok = token("comment2", text, true);
-                        S.pos = i + 2;
-                        S.line += text.split("\n").length - 1;
-                        S.newline_before = text.indexOf("\n") >= 0;
-
-                        // https://github.com/mishoo/UglifyJS/issues/#issue/100
-                        if (/^@cc_on/i.test(text)) {
-                                warn("WARNING: at line " + S.line);
-                                warn("*** Found \"conditional comment\": " + text);
-                                warn("*** UglifyJS DISCARDS ALL COMMENTS.  This means your code might no longer work properly in Internet Explorer.");
-                        }
-
-                        return tok;
-                });
-        };
-
-        function read_name() {
-                var backslash = false, name = "", ch;
-                while ((ch = peek()) != null) {
-                        if (!backslash) {
-                                if (ch == "\\") backslash = true, next();
-                                else if (is_identifier_char(ch)) name += next();
-                                else break;
-                        }
-                        else {
-                                if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
-                                ch = read_escaped_char();
-                                if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
-                                name += ch;
-                                backslash = false;
-                        }
-                }
-                return name;
-        };
-
-        function read_regexp() {
-                return with_eof_error("Unterminated regular expression", function(){
-                        var prev_backslash = false, regexp = "", ch, in_class = false;
-                        while ((ch = next(true))) if (prev_backslash) {
-                                regexp += "\\" + ch;
-                                prev_backslash = false;
-                        } else if (ch == "[") {
-                                in_class = true;
-                                regexp += ch;
-                        } else if (ch == "]" && in_class) {
-                                in_class = false;
-                                regexp += ch;
-                        } else if (ch == "/" && !in_class) {
-                                break;
-                        } else if (ch == "\\") {
-                                prev_backslash = true;
-                        } else {
-                                regexp += ch;
-                        }
-                        var mods = read_name();
-                        return token("regexp", [ regexp, mods ]);
-                });
-        };
-
-        function read_operator(prefix) {
-                function grow(op) {
-                        if (!peek()) return op;
-                        var bigger = op + peek();
-                        if (HOP(OPERATORS, bigger)) {
-                                next();
-                                return grow(bigger);
-                        } else {
-                                return op;
-                        }
-                };
-                return token("operator", grow(prefix || next()));
-        };
-
-        function handle_slash() {
-                next();
-                var regex_allowed = S.regex_allowed;
-                switch (peek()) {
-                    case "/":
-                        S.comments_before.push(read_line_comment());
-                        S.regex_allowed = regex_allowed;
-                        return next_token();
-                    case "*":
-                        S.comments_before.push(read_multiline_comment());
-                        S.regex_allowed = regex_allowed;
-                        return next_token();
-                }
-                return S.regex_allowed ? read_regexp() : read_operator("/");
-        };
-
-        function handle_dot() {
-                next();
-                return is_digit(peek())
-                        ? read_num(".")
-                        : token("punc", ".");
-        };
-
-        function read_word() {
-                var word = read_name();
-                return !HOP(KEYWORDS, word)
-                        ? token("name", word)
-                        : HOP(OPERATORS, word)
-                        ? token("operator", word)
-                        : HOP(KEYWORDS_ATOM, word)
-                        ? token("atom", word)
-                        : token("keyword", word);
-        };
-
-        function with_eof_error(eof_error, cont) {
-                try {
-                        return cont();
-                } catch(ex) {
-                        if (ex === EX_EOF) parse_error(eof_error);
-                        else throw ex;
-                }
-        };
-
-        function next_token(force_regexp) {
-                if (force_regexp)
-                        return read_regexp();
-                skip_whitespace();
-                start_token();
-                var ch = peek();
-                if (!ch) return token("eof");
-                if (is_digit(ch)) return read_num();
-                if (ch == '"' || ch == "'") return read_string();
-                if (HOP(PUNC_CHARS, ch)) return token("punc", next());
-                if (ch == ".") return handle_dot();
-                if (ch == "/") return handle_slash();
-                if (HOP(OPERATOR_CHARS, ch)) return read_operator();
-                if (ch == "\\" || is_identifier_start(ch)) return read_word();
-                parse_error("Unexpected character '" + ch + "'");
-        };
-
-        next_token.context = function(nc) {
-                if (nc) S = nc;
-                return S;
-        };
-
-        return next_token;
-
-};
-
-/* -----[ Parser (constants) ]----- */
-
-var UNARY_PREFIX = array_to_hash([
-        "typeof",
-        "void",
-        "delete",
-        "--",
-        "++",
-        "!",
-        "~",
-        "-",
-        "+"
-]);
-
-var UNARY_POSTFIX = array_to_hash([ "--", "++" ]);
-
-var ASSIGNMENT = (function(a, ret, i){
-        while (i < a.length) {
-                ret[a[i]] = a[i].substr(0, a[i].length - 1);
-                i++;
-        }
-        return ret;
-})(
-        ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="],
-        { "=": true },
-        0
-);
-
-var PRECEDENCE = (function(a, ret){
-        for (var i = 0, n = 1; i < a.length; ++i, ++n) {
-                var b = a[i];
-                for (var j = 0; j < b.length; ++j) {
-                        ret[b[j]] = n;
-                }
-        }
-        return ret;
-})(
-        [
-                ["||"],
-                ["&&"],
-                ["|"],
-                ["^"],
-                ["&"],
-                ["==", "===", "!=", "!=="],
-                ["<", ">", "<=", ">=", "in", "instanceof"],
-                [">>", "<<", ">>>"],
-                ["+", "-"],
-                ["*", "/", "%"]
-        ],
-        {}
-);
-
-var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
-
-var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
-
-/* -----[ Parser ]----- */
-
-function NodeWithToken(str, start, end) {
-        this.name = str;
-        this.start = start;
-        this.end = end;
-};
-
-NodeWithToken.prototype.toString = function() { return this.name; };
-
-function parse($TEXT, exigent_mode, embed_tokens) {
-
-        var S = {
-                input       : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT,
-                token       : null,
-                prev        : null,
-                peeked      : null,
-                in_function : 0,
-                in_loop     : 0,
-                labels      : []
-        };
-
-        S.token = next();
-
-        function is(type, value) {
-                return is_token(S.token, type, value);
-        };
-
-        function peek() { return S.peeked || (S.peeked = S.input()); };
-
-        function next() {
-                S.prev = S.token;
-                if (S.peeked) {
-                        S.token = S.peeked;
-                        S.peeked = null;
-                } else {
-                        S.token = S.input();
-                }
-                return S.token;
-        };
-
-        function prev() {
-                return S.prev;
-        };
-
-        function croak(msg, line, col, pos) {
-                var ctx = S.input.context();
-                js_error(msg,
-                         line != null ? line : ctx.tokline,
-                         col != null ? col : ctx.tokcol,
-                         pos != null ? pos : ctx.tokpos);
-        };
-
-        function token_error(token, msg) {
-                croak(msg, token.line, token.col);
-        };
-
-        function unexpected(token) {
-                if (token == null)
-                        token = S.token;
-                token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
-        };
-
-        function expect_token(type, val) {
-                if (is(type, val)) {
-                        return next();
-                }
-                token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type);
-        };
-
-        function expect(punc) { return expect_token("punc", punc); };
-
-        function can_insert_semicolon() {
-                return !exigent_mode && (
-                        S.token.nlb || is("eof") || is("punc", "}")
-                );
-        };
-
-        function semicolon() {
-                if (is("punc", ";")) next();
-                else if (!can_insert_semicolon()) unexpected();
-        };
-
-        function as() {
-                return slice(arguments);
-        };
-
-        function parenthesised() {
-                expect("(");
-                var ex = expression();
-                expect(")");
-                return ex;
-        };
-
-        function add_tokens(str, start, end) {
-                return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end);
-        };
-
-        function maybe_embed_tokens(parser) {
-                if (embed_tokens) return function() {
-                        var start = S.token;
-                        var ast = parser.apply(this, arguments);
-                        ast[0] = add_tokens(ast[0], start, prev());
-                        return ast;
-                };
-                else return parser;
-        };
-
-        var statement = maybe_embed_tokens(function() {
-                if (is("operator", "/")) {
-                        S.peeked = null;
-                        S.token = S.input(true); // force regexp
-                }
-                switch (S.token.type) {
-                    case "num":
-                    case "string":
-                    case "regexp":
-                    case "operator":
-                    case "atom":
-                        return simple_statement();
-
-                    case "name":
-                        return is_token(peek(), "punc", ":")
-                                ? labeled_statement(prog1(S.token.value, next, next))
-                                : simple_statement();
-
-                    case "punc":
-                        switch (S.token.value) {
-                            case "{":
-                                return as("block", block_());
-                            case "[":
-                            case "(":
-                                return simple_statement();
-                            case ";":
-                                next();
-                                return as("block");
-                            default:
-                                unexpected();
-                        }
-
-                    case "keyword":
-                        switch (prog1(S.token.value, next)) {
-                            case "break":
-                                return break_cont("break");
-
-                            case "continue":
-                                return break_cont("continue");
-
-                            case "debugger":
-                                semicolon();
-                                return as("debugger");
-
-                            case "do":
-                                return (function(body){
-                                        expect_token("keyword", "while");
-                                        return as("do", prog1(parenthesised, semicolon), body);
-                                })(in_loop(statement));
-
-                            case "for":
-                                return for_();
-
-                            case "function":
-                                return function_(true);
-
-                            case "if":
-                                return if_();
-
-                            case "return":
-                                if (S.in_function == 0)
-                                        croak("'return' outside of function");
-                                return as("return",
-                                          is("punc", ";")
-                                          ? (next(), null)
-                                          : can_insert_semicolon()
-                                          ? null
-                                          : prog1(expression, semicolon));
-
-                            case "switch":
-                                return as("switch", parenthesised(), switch_block_());
-
-                            case "throw":
-                                return as("throw", prog1(expression, semicolon));
-
-                            case "try":
-                                return try_();
-
-                            case "var":
-                                return prog1(var_, semicolon);
-
-                            case "const":
-                                return prog1(const_, semicolon);
-
-                            case "while":
-                                return as("while", parenthesised(), in_loop(statement));
-
-                            case "with":
-                                return as("with", parenthesised(), statement());
-
-                            default:
-                                unexpected();
-                        }
-                }
-        });
-
-        function labeled_statement(label) {
-                S.labels.push(label);
-                var start = S.token, stat = statement();
-                if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0]))
-                        unexpected(start);
-                S.labels.pop();
-                return as("label", label, stat);
-        };
-
-        function simple_statement() {
-                return as("stat", prog1(expression, semicolon));
-        };
-
-        function break_cont(type) {
-                var name;
-                if (!can_insert_semicolon()) {
-                        name = is("name") ? S.token.value : null;
-                }
-                if (name != null) {
-                        next();
-                        if (!member(name, S.labels))
-                                croak("Label " + name + " without matching loop or statement");
-                }
-                else if (S.in_loop == 0)
-                        croak(type + " not inside a loop or switch");
-                semicolon();
-                return as(type, name);
-        };
-
-        function for_() {
-                expect("(");
-                var init = null;
-                if (!is("punc", ";")) {
-                        init = is("keyword", "var")
-                                ? (next(), var_(true))
-                                : expression(true, true);
-                        if (is("operator", "in"))
-                                return for_in(init);
-                }
-                return regular_for(init);
-        };
-
-        function regular_for(init) {
-                expect(";");
-                var test = is("punc", ";") ? null : expression();
-                expect(";");
-                var step = is("punc", ")") ? null : expression();
-                expect(")");
-                return as("for", init, test, step, in_loop(statement));
-        };
-
-        function for_in(init) {
-                var lhs = init[0] == "var" ? as("name", init[1][0]) : init;
-                next();
-                var obj = expression();
-                expect(")");
-                return as("for-in", init, lhs, obj, in_loop(statement));
-        };
-
-        var function_ = maybe_embed_tokens(function(in_statement) {
-                var name = is("name") ? prog1(S.token.value, next) : null;
-                if (in_statement && !name)
-                        unexpected();
-                expect("(");
-                return as(in_statement ? "defun" : "function",
-                          name,
-                          // arguments
-                          (function(first, a){
-                                  while (!is("punc", ")")) {
-                                          if (first) first = false; else expect(",");
-                                          if (!is("name")) unexpected();
-                                          a.push(S.token.value);
-                                          next();
-                                  }
-                                  next();
-                                  return a;
-                          })(true, []),
-                          // body
-                          (function(){
-                                  ++S.in_function;
-                                  var loop = S.in_loop;
-                                  S.in_loop = 0;
-                                  var a = block_();
-                                  --S.in_function;
-                                  S.in_loop = loop;
-                                  return a;
-                          })());
-        });
-
-        function if_() {
-                var cond = parenthesised(), body = statement(), belse;
-                if (is("keyword", "else")) {
-                        next();
-                        belse = statement();
-                }
-                return as("if", cond, body, belse);
-        };
-
-        function block_() {
-                expect("{");
-                var a = [];
-                while (!is("punc", "}")) {
-                        if (is("eof")) unexpected();
-                        a.push(statement());
-                }
-                next();
-                return a;
-        };
-
-        var switch_block_ = curry(in_loop, function(){
-                expect("{");
-                var a = [], cur = null;
-                while (!is("punc", "}")) {
-                        if (is("eof")) unexpected();
-                        if (is("keyword", "case")) {
-                                next();
-                                cur = [];
-                                a.push([ expression(), cur ]);
-                                expect(":");
-                        }
-                        else if (is("keyword", "default")) {
-                                next();
-                                expect(":");
-                                cur = [];
-                                a.push([ null, cur ]);
-                        }
-                        else {
-                                if (!cur) unexpected();
-                                cur.push(statement());
-                        }
-                }
-                next();
-                return a;
-        });
-
-        function try_() {
-                var body = block_(), bcatch, bfinally;
-                if (is("keyword", "catch")) {
-                        next();
-                        expect("(");
-                        if (!is("name"))
-                                croak("Name expected");
-                        var name = S.token.value;
-                        next();
-                        expect(")");
-                        bcatch = [ name, block_() ];
-                }
-                if (is("keyword", "finally")) {
-                        next();
-                        bfinally = block_();
-                }
-                if (!bcatch && !bfinally)
-                        croak("Missing catch/finally blocks");
-                return as("try", body, bcatch, bfinally);
-        };
-
-        function vardefs(no_in) {
-                var a = [];
-                for (;;) {
-                        if (!is("name"))
-                                unexpected();
-                        var name = S.token.value;
-                        next();
-                        if (is("operator", "=")) {
-                                next();
-                                a.push([ name, expression(false, no_in) ]);
-                        } else {
-                                a.push([ name ]);
-                        }
-                        if (!is("punc", ","))
-                                break;
-                        next();
-                }
-                return a;
-        };
-
-        function var_(no_in) {
-                return as("var", vardefs(no_in));
-        };
-
-        function const_() {
-                return as("const", vardefs());
-        };
-
-        function new_() {
-                var newexp = expr_atom(false), args;
-                if (is("punc", "(")) {
-                        next();
-                        args = expr_list(")");
-                } else {
-                        args = [];
-                }
-                return subscripts(as("new", newexp, args), true);
-        };
-
-        var expr_atom = maybe_embed_tokens(function(allow_calls) {
-                if (is("operator", "new")) {
-                        next();
-                        return new_();
-                }
-                if (is("punc")) {
-                        switch (S.token.value) {
-                            case "(":
-                                next();
-                                return subscripts(prog1(expression, curry(expect, ")")), allow_calls);
-                            case "[":
-                                next();
-                                return subscripts(array_(), allow_calls);
-                            case "{":
-                                next();
-                                return subscripts(object_(), allow_calls);
-                        }
-                        unexpected();
-                }
-                if (is("keyword", "function")) {
-                        next();
-                        return subscripts(function_(false), allow_calls);
-                }
-                if (HOP(ATOMIC_START_TOKEN, S.token.type)) {
-                        var atom = S.token.type == "regexp"
-                                ? as("regexp", S.token.value[0], S.token.value[1])
-                                : as(S.token.type, S.token.value);
-                        return subscripts(prog1(atom, next), allow_calls);
-                }
-                unexpected();
-        });
-
-        function expr_list(closing, allow_trailing_comma, allow_empty) {
-                var first = true, a = [];
-                while (!is("punc", closing)) {
-                        if (first) first = false; else expect(",");
-                        if (allow_trailing_comma && is("punc", closing)) break;
-                        if (is("punc", ",") && allow_empty) {
-                                a.push([ "atom", "undefined" ]);
-                        } else {
-                                a.push(expression(false));
-                        }
-                }
-                next();
-                return a;
-        };
-
-        function array_() {
-                return as("array", expr_list("]", !exigent_mode, true));
-        };
-
-        function object_() {
-                var first = true, a = [];
-                while (!is("punc", "}")) {
-                        if (first) first = false; else expect(",");
-                        if (!exigent_mode && is("punc", "}"))
-                                // allow trailing comma
-                                break;
-                        var type = S.token.type;
-                        var name = as_property_name();
-                        if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) {
-                                a.push([ as_name(), function_(false), name ]);
-                        } else {
-                                expect(":");
-                                a.push([ name, expression(false) ]);
-                        }
-                }
-                next();
-                return as("object", a);
-        };
-
-        function as_property_name() {
-                switch (S.token.type) {
-                    case "num":
-                    case "string":
-                        return prog1(S.token.value, next);
-                }
-                return as_name();
-        };
-
-        function as_name() {
-                switch (S.token.type) {
-                    case "name":
-                    case "operator":
-                    case "keyword":
-                    case "atom":
-                        return prog1(S.token.value, next);
-                    default:
-                        unexpected();
-                }
-        };
-
-        function subscripts(expr, allow_calls) {
-                if (is("punc", ".")) {
-                        next();
-                        return subscripts(as("dot", expr, as_name()), allow_calls);
-                }
-                if (is("punc", "[")) {
-                        next();
-                        return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls);
-                }
-                if (allow_calls && is("punc", "(")) {
-                        next();
-                        return subscripts(as("call", expr, expr_list(")")), true);
-                }
-                return expr;
-        };
-
-        function maybe_unary(allow_calls) {
-                if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) {
-                        return make_unary("unary-prefix",
-                                          prog1(S.token.value, next),
-                                          maybe_unary(allow_calls));
-                }
-                var val = expr_atom(allow_calls);
-                while (is("operator") && HOP(UNARY_POSTFIX, S.token.value) && !S.token.nlb) {
-                        val = make_unary("unary-postfix", S.token.value, val);
-                        next();
-                }
-                return val;
-        };
-
-        function make_unary(tag, op, expr) {
-                if ((op == "++" || op == "--") && !is_assignable(expr))
-                        croak("Invalid use of " + op + " operator");
-                return as(tag, op, expr);
-        };
-
-        function expr_op(left, min_prec, no_in) {
-                var op = is("operator") ? S.token.value : null;
-                if (op && op == "in" && no_in) op = null;
-                var prec = op != null ? PRECEDENCE[op] : null;
-                if (prec != null && prec > min_prec) {
-                        next();
-                        var right = expr_op(maybe_unary(true), prec, no_in);
-                        return expr_op(as("binary", op, left, right), min_prec, no_in);
-                }
-                return left;
-        };
-
-        function expr_ops(no_in) {
-                return expr_op(maybe_unary(true), 0, no_in);
-        };
-
-        function maybe_conditional(no_in) {
-                var expr = expr_ops(no_in);
-                if (is("operator", "?")) {
-                        next();
-                        var yes = expression(false);
-                        expect(":");
-                        return as("conditional", expr, yes, expression(false, no_in));
-                }
-                return expr;
-        };
-
-        function is_assignable(expr) {
-                if (!exigent_mode) return true;
-                switch (expr[0]) {
-                    case "dot":
-                    case "sub":
-                    case "new":
-                    case "call":
-                        return true;
-                    case "name":
-                        return expr[1] != "this";
-                }
-        };
-
-        function maybe_assign(no_in) {
-                var left = maybe_conditional(no_in), val = S.token.value;
-                if (is("operator") && HOP(ASSIGNMENT, val)) {
-                        if (is_assignable(left)) {
-                                next();
-                                return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in));
-                        }
-                        croak("Invalid assignment");
-                }
-                return left;
-        };
-
-        var expression = maybe_embed_tokens(function(commas, no_in) {
-                if (arguments.length == 0)
-                        commas = true;
-                var expr = maybe_assign(no_in);
-                if (commas && is("punc", ",")) {
-                        next();
-                        return as("seq", expr, expression(true, no_in));
-                }
-                return expr;
-        });
-
-        function in_loop(cont) {
-                try {
-                        ++S.in_loop;
-                        return cont();
-                } finally {
-                        --S.in_loop;
-                }
-        };
-
-        return as("toplevel", (function(a){
-                while (!is("eof"))
-                        a.push(statement());
-                return a;
-        })([]));
-
-};
-
-/* -----[ Utilities ]----- */
-
-function curry(f) {
-        var args = slice(arguments, 1);
-        return function() { return f.apply(this, args.concat(slice(arguments))); };
-};
-
-function prog1(ret) {
-        if (ret instanceof Function)
-                ret = ret();
-        for (var i = 1, n = arguments.length; --n > 0; ++i)
-                arguments[i]();
-        return ret;
-};
-
-function array_to_hash(a) {
-        var ret = {};
-        for (var i = 0; i < a.length; ++i)
-                ret[a[i]] = true;
-        return ret;
-};
-
-function slice(a, start) {
-        return Array.prototype.slice.call(a, start == null ? 0 : start);
-};
-
-function characters(str) {
-        return str.split("");
-};
-
-function member(name, array) {
-        for (var i = array.length; --i >= 0;)
-                if (array[i] === name)
-                        return true;
-        return false;
-};
-
-function HOP(obj, prop) {
-        return Object.prototype.hasOwnProperty.call(obj, prop);
-};
-
-var warn = function() {};
-
-/* -----[ Exports ]----- */
-
-exports.tokenizer = tokenizer;
-exports.parse = parse;
-exports.slice = slice;
-exports.curry = curry;
-exports.member = member;
-exports.array_to_hash = array_to_hash;
-exports.PRECEDENCE = PRECEDENCE;
-exports.KEYWORDS_ATOM = KEYWORDS_ATOM;
-exports.RESERVED_WORDS = RESERVED_WORDS;
-exports.KEYWORDS = KEYWORDS;
-exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN;
-exports.OPERATORS = OPERATORS;
-exports.is_alphanumeric_char = is_alphanumeric_char;
-exports.set_logger = function(logger) {
-        warn = logger;
-};
diff --git a/node/node_modules/___uglify-js.npm/package/lib/process.js b/node/node_modules/___uglify-js.npm/package/lib/process.js
deleted file mode 100644 (file)
index 775e305..0000000
+++ /dev/null
@@ -1,1774 +0,0 @@
-/***********************************************************************
-
-  A JavaScript tokenizer / parser / beautifier / compressor.
-
-  This version is suitable for Node.js.  With minimal changes (the
-  exports stuff) it should work on any JS platform.
-
-  This file implements some AST processors.  They work on data built
-  by parse-js.
-
-  Exported functions:
-
-    - ast_mangle(ast, options) -- mangles the variable/function names
-      in the AST.  Returns an AST.
-
-    - ast_squeeze(ast) -- employs various optimizations to make the
-      final generated code even smaller.  Returns an AST.
-
-    - gen_code(ast, options) -- generates JS code from the AST.  Pass
-      true (or an object, see the code for some options) as second
-      argument to get "pretty" (indented) code.
-
-  -------------------------------- (C) ---------------------------------
-
-                           Author: Mihai Bazon
-                         <mihai.bazon@gmail.com>
-                       http://mihai.bazon.net/blog
-
-  Distributed under the BSD license:
-
-    Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
-
-    Redistribution and use in source and binary forms, with or without
-    modification, are permitted provided that the following conditions
-    are met:
-
-        * Redistributions of source code must retain the above
-          copyright notice, this list of conditions and the following
-          disclaimer.
-
-        * Redistributions in binary form must reproduce the above
-          copyright notice, this list of conditions and the following
-          disclaimer in the documentation and/or other materials
-          provided with the distribution.
-
-    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
-    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
-
- ***********************************************************************/
-
-var jsp = require("./parse-js"),
-    slice = jsp.slice,
-    member = jsp.member,
-    PRECEDENCE = jsp.PRECEDENCE,
-    OPERATORS = jsp.OPERATORS;
-
-/* -----[ helper for AST traversal ]----- */
-
-function ast_walker(ast) {
-        function _vardefs(defs) {
-                return [ this[0], MAP(defs, function(def){
-                        var a = [ def[0] ];
-                        if (def.length > 1)
-                                a[1] = walk(def[1]);
-                        return a;
-                }) ];
-        };
-        function _block(statements) {
-                var out = [ this[0] ];
-                if (statements != null)
-                        out.push(MAP(statements, walk));
-                return out;
-        };
-        var walkers = {
-                "string": function(str) {
-                        return [ this[0], str ];
-                },
-                "num": function(num) {
-                        return [ this[0], num ];
-                },
-                "name": function(name) {
-                        return [ this[0], name ];
-                },
-                "toplevel": function(statements) {
-                        return [ this[0], MAP(statements, walk) ];
-                },
-                "block": _block,
-                "splice": _block,
-                "var": _vardefs,
-                "const": _vardefs,
-                "try": function(t, c, f) {
-                        return [
-                                this[0],
-                                MAP(t, walk),
-                                c != null ? [ c[0], MAP(c[1], walk) ] : null,
-                                f != null ? MAP(f, walk) : null
-                        ];
-                },
-                "throw": function(expr) {
-                        return [ this[0], walk(expr) ];
-                },
-                "new": function(ctor, args) {
-                        return [ this[0], walk(ctor), MAP(args, walk) ];
-                },
-                "switch": function(expr, body) {
-                        return [ this[0], walk(expr), MAP(body, function(branch){
-                                return [ branch[0] ? walk(branch[0]) : null,
-                                         MAP(branch[1], walk) ];
-                        }) ];
-                },
-                "break": function(label) {
-                        return [ this[0], label ];
-                },
-                "continue": function(label) {
-                        return [ this[0], label ];
-                },
-                "conditional": function(cond, t, e) {
-                        return [ this[0], walk(cond), walk(t), walk(e) ];
-                },
-                "assign": function(op, lvalue, rvalue) {
-                        return [ this[0], op, walk(lvalue), walk(rvalue) ];
-                },
-                "dot": function(expr) {
-                        return [ this[0], walk(expr) ].concat(slice(arguments, 1));
-                },
-                "call": function(expr, args) {
-                        return [ this[0], walk(expr), MAP(args, walk) ];
-                },
-                "function": function(name, args, body) {
-                        return [ this[0], name, args.slice(), MAP(body, walk) ];
-                },
-                "defun": function(name, args, body) {
-                        return [ this[0], name, args.slice(), MAP(body, walk) ];
-                },
-                "if": function(conditional, t, e) {
-                        return [ this[0], walk(conditional), walk(t), walk(e) ];
-                },
-                "for": function(init, cond, step, block) {
-                        return [ this[0], walk(init), walk(cond), walk(step), walk(block) ];
-                },
-                "for-in": function(vvar, key, hash, block) {
-                        return [ this[0], walk(vvar), walk(key), walk(hash), walk(block) ];
-                },
-                "while": function(cond, block) {
-                        return [ this[0], walk(cond), walk(block) ];
-                },
-                "do": function(cond, block) {
-                        return [ this[0], walk(cond), walk(block) ];
-                },
-                "return": function(expr) {
-                        return [ this[0], walk(expr) ];
-                },
-                "binary": function(op, left, right) {
-                        return [ this[0], op, walk(left), walk(right) ];
-                },
-                "unary-prefix": function(op, expr) {
-                        return [ this[0], op, walk(expr) ];
-                },
-                "unary-postfix": function(op, expr) {
-                        return [ this[0], op, walk(expr) ];
-                },
-                "sub": function(expr, subscript) {
-                        return [ this[0], walk(expr), walk(subscript) ];
-                },
-                "object": function(props) {
-                        return [ this[0], MAP(props, function(p){
-                                return p.length == 2
-                                        ? [ p[0], walk(p[1]) ]
-                                        : [ p[0], walk(p[1]), p[2] ]; // get/set-ter
-                        }) ];
-                },
-                "regexp": function(rx, mods) {
-                        return [ this[0], rx, mods ];
-                },
-                "array": function(elements) {
-                        return [ this[0], MAP(elements, walk) ];
-                },
-                "stat": function(stat) {
-                        return [ this[0], walk(stat) ];
-                },
-                "seq": function() {
-                        return [ this[0] ].concat(MAP(slice(arguments), walk));
-                },
-                "label": function(name, block) {
-                        return [ this[0], name, walk(block) ];
-                },
-                "with": function(expr, block) {
-                        return [ this[0], walk(expr), walk(block) ];
-                },
-                "atom": function(name) {
-                        return [ this[0], name ];
-                }
-        };
-
-        var user = {};
-        var stack = [];
-        function walk(ast) {
-                if (ast == null)
-                        return null;
-                try {
-                        stack.push(ast);
-                        var type = ast[0];
-                        var gen = user[type];
-                        if (gen) {
-                                var ret = gen.apply(ast, ast.slice(1));
-                                if (ret != null)
-                                        return ret;
-                        }
-                        gen = walkers[type];
-                        return gen.apply(ast, ast.slice(1));
-                } finally {
-                        stack.pop();
-                }
-        };
-
-        function with_walkers(walkers, cont){
-                var save = {}, i;
-                for (i in walkers) if (HOP(walkers, i)) {
-                        save[i] = user[i];
-                        user[i] = walkers[i];
-                }
-                var ret = cont();
-                for (i in save) if (HOP(save, i)) {
-                        if (!save[i]) delete user[i];
-                        else user[i] = save[i];
-                }
-                return ret;
-        };
-
-        return {
-                walk: walk,
-                with_walkers: with_walkers,
-                parent: function() {
-                        return stack[stack.length - 2]; // last one is current node
-                },
-                stack: function() {
-                        return stack;
-                }
-        };
-};
-
-/* -----[ Scope and mangling ]----- */
-
-function Scope(parent) {
-        this.names = {};        // names defined in this scope
-        this.mangled = {};      // mangled names (orig.name => mangled)
-        this.rev_mangled = {};  // reverse lookup (mangled => orig.name)
-        this.cname = -1;        // current mangled name
-        this.refs = {};         // names referenced from this scope
-        this.uses_with = false; // will become TRUE if with() is detected in this or any subscopes
-        this.uses_eval = false; // will become TRUE if eval() is detected in this or any subscopes
-        this.parent = parent;   // parent scope
-        this.children = [];     // sub-scopes
-        if (parent) {
-                this.level = parent.level + 1;
-                parent.children.push(this);
-        } else {
-                this.level = 0;
-        }
-};
-
-var base54 = (function(){
-        var DIGITS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_";
-        return function(num) {
-                var ret = "";
-                do {
-                        ret = DIGITS.charAt(num % 54) + ret;
-                        num = Math.floor(num / 54);
-                } while (num > 0);
-                return ret;
-        };
-})();
-
-Scope.prototype = {
-        has: function(name) {
-                for (var s = this; s; s = s.parent)
-                        if (HOP(s.names, name))
-                                return s;
-        },
-        has_mangled: function(mname) {
-                for (var s = this; s; s = s.parent)
-                        if (HOP(s.rev_mangled, mname))
-                                return s;
-        },
-        toJSON: function() {
-                return {
-                        names: this.names,
-                        uses_eval: this.uses_eval,
-                        uses_with: this.uses_with
-                };
-        },
-
-        next_mangled: function() {
-                // we must be careful that the new mangled name:
-                //
-                // 1. doesn't shadow a mangled name from a parent
-                //    scope, unless we don't reference the original
-                //    name from this scope OR from any sub-scopes!
-                //    This will get slow.
-                //
-                // 2. doesn't shadow an original name from a parent
-                //    scope, in the event that the name is not mangled
-                //    in the parent scope and we reference that name
-                //    here OR IN ANY SUBSCOPES!
-                //
-                // 3. doesn't shadow a name that is referenced but not
-                //    defined (possibly global defined elsewhere).
-                for (;;) {
-                        var m = base54(++this.cname), prior;
-
-                        // case 1.
-                        prior = this.has_mangled(m);
-                        if (prior && this.refs[prior.rev_mangled[m]] === prior)
-                                continue;
-
-                        // case 2.
-                        prior = this.has(m);
-                        if (prior && prior !== this && this.refs[m] === prior && !prior.has_mangled(m))
-                                continue;
-
-                        // case 3.
-                        if (HOP(this.refs, m) && this.refs[m] == null)
-                                continue;
-
-                        // I got "do" once. :-/
-                        if (!is_identifier(m))
-                                continue;
-
-                        return m;
-                }
-        },
-        set_mangle: function(name, m) {
-                this.rev_mangled[m] = name;
-                return this.mangled[name] = m;
-        },
-        get_mangled: function(name, newMangle) {
-                if (this.uses_eval || this.uses_with) return name; // no mangle if eval or with is in use
-                var s = this.has(name);
-                if (!s) return name; // not in visible scope, no mangle
-                if (HOP(s.mangled, name)) return s.mangled[name]; // already mangled in this scope
-                if (!newMangle) return name;                      // not found and no mangling requested
-                return s.set_mangle(name, s.next_mangled());
-        },
-        define: function(name) {
-                if (name != null)
-                        return this.names[name] = name;
-        }
-};
-
-function ast_add_scope(ast) {
-
-        var current_scope = null;
-        var w = ast_walker(), walk = w.walk;
-        var having_eval = [];
-
-        function with_new_scope(cont) {
-                current_scope = new Scope(current_scope);
-                var ret = current_scope.body = cont();
-                ret.scope = current_scope;
-                current_scope = current_scope.parent;
-                return ret;
-        };
-
-        function define(name) {
-                return current_scope.define(name);
-        };
-
-        function reference(name) {
-                current_scope.refs[name] = true;
-        };
-
-        function _lambda(name, args, body) {
-                var is_defun = this[0] == "defun";
-                return [ this[0], is_defun ? define(name) : name, args, with_new_scope(function(){
-                        if (!is_defun) define(name);
-                        MAP(args, define);
-                        return MAP(body, walk);
-                })];
-        };
-
-        return with_new_scope(function(){
-                // process AST
-                var ret = w.with_walkers({
-                        "function": _lambda,
-                        "defun": _lambda,
-                        "with": function(expr, block) {
-                                for (var s = current_scope; s; s = s.parent)
-                                        s.uses_with = true;
-                        },
-                        "var": function(defs) {
-                                MAP(defs, function(d){ define(d[0]) });
-                        },
-                        "const": function(defs) {
-                                MAP(defs, function(d){ define(d[0]) });
-                        },
-                        "try": function(t, c, f) {
-                                if (c != null) return [
-                                        this[0],
-                                        MAP(t, walk),
-                                        [ define(c[0]), MAP(c[1], walk) ],
-                                        f != null ? MAP(f, walk) : null
-                                ];
-                        },
-                        "name": function(name) {
-                                if (name == "eval")
-                                        having_eval.push(current_scope);
-                                reference(name);
-                        }
-                }, function(){
-                        return walk(ast);
-                });
-
-                // the reason why we need an additional pass here is
-                // that names can be used prior to their definition.
-
-                // scopes where eval was detected and their parents
-                // are marked with uses_eval, unless they define the
-                // "eval" name.
-                MAP(having_eval, function(scope){
-                        if (!scope.has("eval")) while (scope) {
-                                scope.uses_eval = true;
-                                scope = scope.parent;
-                        }
-                });
-
-                // for referenced names it might be useful to know
-                // their origin scope.  current_scope here is the
-                // toplevel one.
-                function fixrefs(scope, i) {
-                        // do children first; order shouldn't matter
-                        for (i = scope.children.length; --i >= 0;)
-                                fixrefs(scope.children[i]);
-                        for (i in scope.refs) if (HOP(scope.refs, i)) {
-                                // find origin scope and propagate the reference to origin
-                                for (var origin = scope.has(i), s = scope; s; s = s.parent) {
-                                        s.refs[i] = origin;
-                                        if (s === origin) break;
-                                }
-                        }
-                };
-                fixrefs(current_scope);
-
-                return ret;
-        });
-
-};
-
-/* -----[ mangle names ]----- */
-
-function ast_mangle(ast, options) {
-        var w = ast_walker(), walk = w.walk, scope;
-        options = options || {};
-
-        function get_mangled(name, newMangle) {
-                if (!options.toplevel && !scope.parent) return name; // don't mangle toplevel
-                if (options.except && member(name, options.except))
-                        return name;
-                return scope.get_mangled(name, newMangle);
-        };
-
-        function get_define(name) {
-                if (options.defines) {
-                        // we always lookup a defined symbol for the current scope FIRST, so declared
-                        // vars trump a DEFINE symbol, but if no such var is found, then match a DEFINE value
-                        if (!scope.has(name)) {
-                                if (HOP(options.defines, name)) {
-                                        return options.defines[name];
-                                }
-                        }
-                        return null;
-                }
-        };
-
-        function _lambda(name, args, body) {
-                var is_defun = this[0] == "defun", extra;
-                if (name) {
-                        if (is_defun) name = get_mangled(name);
-                        else {
-                                extra = {};
-                                if (!(scope.uses_eval || scope.uses_with))
-                                        name = extra[name] = scope.next_mangled();
-                                else
-                                        extra[name] = name;
-                        }
-                }
-                body = with_scope(body.scope, function(){
-                        args = MAP(args, function(name){ return get_mangled(name) });
-                        return MAP(body, walk);
-                }, extra);
-                return [ this[0], name, args, body ];
-        };
-
-        function with_scope(s, cont, extra) {
-                var _scope = scope;
-                scope = s;
-                if (extra) for (var i in extra) if (HOP(extra, i)) {
-                        s.set_mangle(i, extra[i]);
-                }
-                for (var i in s.names) if (HOP(s.names, i)) {
-                        get_mangled(i, true);
-                }
-                var ret = cont();
-                ret.scope = s;
-                scope = _scope;
-                return ret;
-        };
-
-        function _vardefs(defs) {
-                return [ this[0], MAP(defs, function(d){
-                        return [ get_mangled(d[0]), walk(d[1]) ];
-                }) ];
-        };
-
-        return w.with_walkers({
-                "function": _lambda,
-                "defun": function() {
-                        // move function declarations to the top when
-                        // they are not in some block.
-                        var ast = _lambda.apply(this, arguments);
-                        switch (w.parent()[0]) {
-                            case "toplevel":
-                            case "function":
-                            case "defun":
-                                return MAP.at_top(ast);
-                        }
-                        return ast;
-                },
-                "var": _vardefs,
-                "const": _vardefs,
-                "name": function(name) {
-                        return get_define(name) || [ this[0], get_mangled(name) ];
-                },
-                "try": function(t, c, f) {
-                        return [ this[0],
-                                 MAP(t, walk),
-                                 c != null ? [ get_mangled(c[0]), MAP(c[1], walk) ] : null,
-                                 f != null ? MAP(f, walk) : null ];
-                },
-                "toplevel": function(body) {
-                        var self = this;
-                        return with_scope(self.scope, function(){
-                                return [ self[0], MAP(body, walk) ];
-                        });
-                }
-        }, function() {
-                return walk(ast_add_scope(ast));
-        });
-};
-
-/* -----[
-   - compress foo["bar"] into foo.bar,
-   - remove block brackets {} where possible
-   - join consecutive var declarations
-   - various optimizations for IFs:
-     - if (cond) foo(); else bar();  ==>  cond?foo():bar();
-     - if (cond) foo();  ==>  cond&&foo();
-     - if (foo) return bar(); else return baz();  ==> return foo?bar():baz(); // also for throw
-     - if (foo) return bar(); else something();  ==> {if(foo)return bar();something()}
-   ]----- */
-
-var warn = function(){};
-
-function best_of(ast1, ast2) {
-        return gen_code(ast1).length > gen_code(ast2[0] == "stat" ? ast2[1] : ast2).length ? ast2 : ast1;
-};
-
-function last_stat(b) {
-        if (b[0] == "block" && b[1] && b[1].length > 0)
-                return b[1][b[1].length - 1];
-        return b;
-}
-
-function aborts(t) {
-        if (t) {
-                t = last_stat(t);
-                if (t[0] == "return" || t[0] == "break" || t[0] == "continue" || t[0] == "throw")
-                        return true;
-        }
-};
-
-function boolean_expr(expr) {
-        return ( (expr[0] == "unary-prefix"
-                  && member(expr[1], [ "!", "delete" ])) ||
-
-                 (expr[0] == "binary"
-                  && member(expr[1], [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ])) ||
-
-                 (expr[0] == "binary"
-                  && member(expr[1], [ "&&", "||" ])
-                  && boolean_expr(expr[2])
-                  && boolean_expr(expr[3])) ||
-
-                 (expr[0] == "conditional"
-                  && boolean_expr(expr[2])
-                  && boolean_expr(expr[3])) ||
-
-                 (expr[0] == "assign"
-                  && expr[1] === true
-                  && boolean_expr(expr[3])) ||
-
-                 (expr[0] == "seq"
-                  && boolean_expr(expr[expr.length - 1]))
-               );
-};
-
-function make_conditional(c, t, e) {
-    var make_real_conditional = function() {
-        if (c[0] == "unary-prefix" && c[1] == "!") {
-            return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ];
-        } else {
-            return e ? [ "conditional", c, t, e ] : [ "binary", "&&", c, t ];
-        }
-    };
-    // shortcut the conditional if the expression has a constant value
-    return when_constant(c, function(ast, val){
-        warn_unreachable(val ? e : t);
-        return          (val ? t : e);
-    }, make_real_conditional);
-};
-
-function empty(b) {
-        return !b || (b[0] == "block" && (!b[1] || b[1].length == 0));
-};
-
-function is_string(node) {
-        return (node[0] == "string" ||
-                node[0] == "unary-prefix" && node[1] == "typeof" ||
-                node[0] == "binary" && node[1] == "+" &&
-                (is_string(node[2]) || is_string(node[3])));
-};
-
-var when_constant = (function(){
-
-        var $NOT_CONSTANT = {};
-
-        // this can only evaluate constant expressions.  If it finds anything
-        // not constant, it throws $NOT_CONSTANT.
-        function evaluate(expr) {
-                switch (expr[0]) {
-                    case "string":
-                    case "num":
-                        return expr[1];
-                    case "name":
-                    case "atom":
-                        switch (expr[1]) {
-                            case "true": return true;
-                            case "false": return false;
-                        }
-                        break;
-                    case "unary-prefix":
-                        switch (expr[1]) {
-                            case "!": return !evaluate(expr[2]);
-                            case "typeof": return typeof evaluate(expr[2]);
-                            case "~": return ~evaluate(expr[2]);
-                            case "-": return -evaluate(expr[2]);
-                            case "+": return +evaluate(expr[2]);
-                        }
-                        break;
-                    case "binary":
-                        var left = expr[2], right = expr[3];
-                        switch (expr[1]) {
-                            case "&&"         : return evaluate(left) &&         evaluate(right);
-                            case "||"         : return evaluate(left) ||         evaluate(right);
-                            case "|"          : return evaluate(left) |          evaluate(right);
-                            case "&"          : return evaluate(left) &          evaluate(right);
-                            case "^"          : return evaluate(left) ^          evaluate(right);
-                            case "+"          : return evaluate(left) +          evaluate(right);
-                            case "*"          : return evaluate(left) *          evaluate(right);
-                            case "/"          : return evaluate(left) /          evaluate(right);
-                            case "-"          : return evaluate(left) -          evaluate(right);
-                            case "<<"         : return evaluate(left) <<         evaluate(right);
-                            case ">>"         : return evaluate(left) >>         evaluate(right);
-                            case ">>>"        : return evaluate(left) >>>        evaluate(right);
-                            case "=="         : return evaluate(left) ==         evaluate(right);
-                            case "==="        : return evaluate(left) ===        evaluate(right);
-                            case "!="         : return evaluate(left) !=         evaluate(right);
-                            case "!=="        : return evaluate(left) !==        evaluate(right);
-                            case "<"          : return evaluate(left) <          evaluate(right);
-                            case "<="         : return evaluate(left) <=         evaluate(right);
-                            case ">"          : return evaluate(left) >          evaluate(right);
-                            case ">="         : return evaluate(left) >=         evaluate(right);
-                            case "in"         : return evaluate(left) in         evaluate(right);
-                            case "instanceof" : return evaluate(left) instanceof evaluate(right);
-                        }
-                }
-                throw $NOT_CONSTANT;
-        };
-
-        return function(expr, yes, no) {
-                try {
-                        var val = evaluate(expr), ast;
-                        switch (typeof val) {
-                            case "string": ast =  [ "string", val ]; break;
-                            case "number": ast =  [ "num", val ]; break;
-                            case "boolean": ast =  [ "name", String(val) ]; break;
-                            default: throw new Error("Can't handle constant of type: " + (typeof val));
-                        }
-                        return yes.call(expr, ast, val);
-                } catch(ex) {
-                        if (ex === $NOT_CONSTANT) {
-                                if (expr[0] == "binary"
-                                    && (expr[1] == "===" || expr[1] == "!==")
-                                    && ((is_string(expr[2]) && is_string(expr[3]))
-                                        || (boolean_expr(expr[2]) && boolean_expr(expr[3])))) {
-                                        expr[1] = expr[1].substr(0, 2);
-                                }
-                                else if (no && expr[0] == "binary"
-                                         && (expr[1] == "||" || expr[1] == "&&")) {
-                                    // the whole expression is not constant but the lval may be...
-                                    try {
-                                        var lval = evaluate(expr[2]);
-                                        expr = ((expr[1] == "&&" && (lval ? expr[3] : lval))    ||
-                                                (expr[1] == "||" && (lval ? lval    : expr[3])) ||
-                                                expr);
-                                    } catch(ex2) {
-                                        // IGNORE... lval is not constant
-                                    }
-                                }
-                                return no ? no.call(expr, expr) : null;
-                        }
-                        else throw ex;
-                }
-        };
-
-})();
-
-function warn_unreachable(ast) {
-        if (!empty(ast))
-                warn("Dropping unreachable code: " + gen_code(ast, true));
-};
-
-function prepare_ifs(ast) {
-        var w = ast_walker(), walk = w.walk;
-        // In this first pass, we rewrite ifs which abort with no else with an
-        // if-else.  For example:
-        //
-        // if (x) {
-        //     blah();
-        //     return y;
-        // }
-        // foobar();
-        //
-        // is rewritten into:
-        //
-        // if (x) {
-        //     blah();
-        //     return y;
-        // } else {
-        //     foobar();
-        // }
-        function redo_if(statements) {
-                statements = MAP(statements, walk);
-
-                for (var i = 0; i < statements.length; ++i) {
-                        var fi = statements[i];
-                        if (fi[0] != "if") continue;
-
-                        if (fi[3] && walk(fi[3])) continue;
-
-                        var t = walk(fi[2]);
-                        if (!aborts(t)) continue;
-
-                        var conditional = walk(fi[1]);
-
-                        var e_body = statements.slice(i + 1);
-                        var e;
-                        if (e_body.length == 1) e = e_body[0];
-                        else e = [ "block", e_body ];
-
-                        var ret = statements.slice(0, i).concat([ [
-                                fi[0],          // "if"
-                                conditional,    // conditional
-                                t,              // then
-                                e               // else
-                        ] ]);
-
-                        return redo_if(ret);
-                }
-
-                return statements;
-        };
-
-        function redo_if_lambda(name, args, body) {
-                body = redo_if(body);
-                return [ this[0], name, args.slice(), body ];
-        };
-
-        function redo_if_block(statements) {
-                var out = [ this[0] ];
-                if (statements != null)
-                        out.push(redo_if(statements));
-                return out;
-        };
-
-        return w.with_walkers({
-                "defun": redo_if_lambda,
-                "function": redo_if_lambda,
-                "block": redo_if_block,
-                "splice": redo_if_block,
-                "toplevel": function(statements) {
-                        return [ this[0], redo_if(statements) ];
-                },
-                "try": function(t, c, f) {
-                        return [
-                                this[0],
-                                redo_if(t),
-                                c != null ? [ c[0], redo_if(c[1]) ] : null,
-                                f != null ? redo_if(f) : null
-                        ];
-                }
-        }, function() {
-                return walk(ast);
-        });
-};
-
-function ast_squeeze(ast, options) {
-        options = defaults(options, {
-                make_seqs   : true,
-                dead_code   : true,
-                keep_comps  : true,
-                no_warnings : false
-        });
-
-        var w = ast_walker(), walk = w.walk, scope;
-
-        function negate(c) {
-                var not_c = [ "unary-prefix", "!", c ];
-                switch (c[0]) {
-                    case "unary-prefix":
-                        return c[1] == "!" && boolean_expr(c[2]) ? c[2] : not_c;
-                    case "seq":
-                        c = slice(c);
-                        c[c.length - 1] = negate(c[c.length - 1]);
-                        return c;
-                    case "conditional":
-                        return best_of(not_c, [ "conditional", c[1], negate(c[2]), negate(c[3]) ]);
-                    case "binary":
-                        var op = c[1], left = c[2], right = c[3];
-                        if (!options.keep_comps) switch (op) {
-                            case "<="  : return [ "binary", ">", left, right ];
-                            case "<"   : return [ "binary", ">=", left, right ];
-                            case ">="  : return [ "binary", "<", left, right ];
-                            case ">"   : return [ "binary", "<=", left, right ];
-                        }
-                        switch (op) {
-                            case "=="  : return [ "binary", "!=", left, right ];
-                            case "!="  : return [ "binary", "==", left, right ];
-                            case "===" : return [ "binary", "!==", left, right ];
-                            case "!==" : return [ "binary", "===", left, right ];
-                            case "&&"  : return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]);
-                            case "||"  : return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]);
-                        }
-                        break;
-                }
-                return not_c;
-        };
-
-        function with_scope(s, cont) {
-                var _scope = scope;
-                scope = s;
-                var ret = cont();
-                ret.scope = s;
-                scope = _scope;
-                return ret;
-        };
-
-        function rmblock(block) {
-                if (block != null && block[0] == "block" && block[1]) {
-                        if (block[1].length == 1)
-                                block = block[1][0];
-                        else if (block[1].length == 0)
-                                block = [ "block" ];
-                }
-                return block;
-        };
-
-        function _lambda(name, args, body) {
-                var is_defun = this[0] == "defun";
-                body = with_scope(body.scope, function(){
-                        var ret = tighten(MAP(body, walk), "lambda");
-                        if (!is_defun && name && !HOP(scope.refs, name))
-                                name = null;
-                        return ret;
-                });
-                return [ this[0], name, args, body ];
-        };
-
-        // we get here for blocks that have been already transformed.
-        // this function does a few things:
-        // 1. discard useless blocks
-        // 2. join consecutive var declarations
-        // 3. remove obviously dead code
-        // 4. transform consecutive statements using the comma operator
-        // 5. if block_type == "lambda" and it detects constructs like if(foo) return ... - rewrite like if (!foo) { ... }
-        function tighten(statements, block_type) {
-                statements = statements.reduce(function(a, stat){
-                        if (stat[0] == "block") {
-                                if (stat[1]) {
-                                        a.push.apply(a, stat[1]);
-                                }
-                        } else {
-                                a.push(stat);
-                        }
-                        return a;
-                }, []);
-
-                statements = (function(a, prev){
-                        statements.forEach(function(cur){
-                                if (prev && ((cur[0] == "var" && prev[0] == "var") ||
-                                             (cur[0] == "const" && prev[0] == "const"))) {
-                                        prev[1] = prev[1].concat(cur[1]);
-                                } else {
-                                        a.push(cur);
-                                        prev = cur;
-                                }
-                        });
-                        return a;
-                })([]);
-
-                if (options.dead_code) statements = (function(a, has_quit){
-                        statements.forEach(function(st){
-                                if (has_quit) {
-                                        if (member(st[0], [ "function", "defun" , "var", "const" ])) {
-                                                a.push(st);
-                                        }
-                                        else if (!options.no_warnings)
-                                                warn_unreachable(st);
-                                }
-                                else {
-                                        a.push(st);
-                                        if (member(st[0], [ "return", "throw", "break", "continue" ]))
-                                                has_quit = true;
-                                }
-                        });
-                        return a;
-                })([]);
-
-                if (options.make_seqs) statements = (function(a, prev) {
-                        statements.forEach(function(cur){
-                                if (prev && prev[0] == "stat" && cur[0] == "stat") {
-                                        prev[1] = [ "seq", prev[1], cur[1] ];
-                                } else {
-                                        a.push(cur);
-                                        prev = cur;
-                                }
-                        });
-                        return a;
-                })([]);
-
-                if (block_type == "lambda") statements = (function(i, a, stat){
-                        while (i < statements.length) {
-                                stat = statements[i++];
-                                if (stat[0] == "if" && !stat[3]) {
-                                        if (stat[2][0] == "return" && stat[2][1] == null) {
-                                                a.push(make_if(negate(stat[1]), [ "block", statements.slice(i) ]));
-                                                break;
-                                        }
-                                        var last = last_stat(stat[2]);
-                                        if (last[0] == "return" && last[1] == null) {
-                                                a.push(make_if(stat[1], [ "block", stat[2][1].slice(0, -1) ], [ "block", statements.slice(i) ]));
-                                                break;
-                                        }
-                                }
-                                a.push(stat);
-                        }
-                        return a;
-                })(0, []);
-
-                return statements;
-        };
-
-        function make_if(c, t, e) {
-                return when_constant(c, function(ast, val){
-                        if (val) {
-                                warn_unreachable(e);
-                                return t;
-                        } else {
-                                warn_unreachable(t);
-                                return e;
-                        }
-                }, function() {
-                        return make_real_if(c, t, e);
-                });
-        };
-
-        function make_real_if(c, t, e) {
-                c = walk(c);
-                t = walk(t);
-                e = walk(e);
-
-                if (empty(t)) {
-                        c = negate(c);
-                        t = e;
-                        e = null;
-                } else if (empty(e)) {
-                        e = null;
-                } else {
-                        // if we have both else and then, maybe it makes sense to switch them?
-                        (function(){
-                                var a = gen_code(c);
-                                var n = negate(c);
-                                var b = gen_code(n);
-                                if (b.length < a.length) {
-                                        var tmp = t;
-                                        t = e;
-                                        e = tmp;
-                                        c = n;
-                                }
-                        })();
-                }
-                if (empty(e) && empty(t))
-                        return [ "stat", c ];
-                var ret = [ "if", c, t, e ];
-                if (t[0] == "if" && empty(t[3]) && empty(e)) {
-                        ret = best_of(ret, walk([ "if", [ "binary", "&&", c, t[1] ], t[2] ]));
-                }
-                else if (t[0] == "stat") {
-                        if (e) {
-                                if (e[0] == "stat") {
-                                        ret = best_of(ret, [ "stat", make_conditional(c, t[1], e[1]) ]);
-                                }
-                        }
-                        else {
-                                ret = best_of(ret, [ "stat", make_conditional(c, t[1]) ]);
-                        }
-                }
-                else if (e && t[0] == e[0] && (t[0] == "return" || t[0] == "throw") && t[1] && e[1]) {
-                        ret = best_of(ret, [ t[0], make_conditional(c, t[1], e[1] ) ]);
-                }
-                else if (e && aborts(t)) {
-                        ret = [ [ "if", c, t ] ];
-                        if (e[0] == "block") {
-                                if (e[1]) ret = ret.concat(e[1]);
-                        }
-                        else {
-                                ret.push(e);
-                        }
-                        ret = walk([ "block", ret ]);
-                }
-                else if (t && aborts(e)) {
-                        ret = [ [ "if", negate(c), e ] ];
-                        if (t[0] == "block") {
-                                if (t[1]) ret = ret.concat(t[1]);
-                        } else {
-                                ret.push(t);
-                        }
-                        ret = walk([ "block", ret ]);
-                }
-                return ret;
-        };
-
-        function _do_while(cond, body) {
-                return when_constant(cond, function(cond, val){
-                        if (!val) {
-                                warn_unreachable(body);
-                                return [ "block" ];
-                        } else {
-                                return [ "for", null, null, null, walk(body) ];
-                        }
-                });
-        };
-
-        ast = prepare_ifs(ast);
-        ast = ast_add_scope(ast);
-
-        return w.with_walkers({
-                "sub": function(expr, subscript) {
-                        if (subscript[0] == "string") {
-                                var name = subscript[1];
-                                if (is_identifier(name))
-                                        return [ "dot", walk(expr), name ];
-                                else if (/^[1-9][0-9]*$/.test(name) || name === "0")
-                                        return [ "sub", walk(expr), [ "num", parseInt(name, 10) ] ];
-                        }
-                },
-                "if": make_if,
-                "toplevel": function(body) {
-                        return [ "toplevel", with_scope(this.scope, function(){
-                                return tighten(MAP(body, walk));
-                        }) ];
-                },
-                "switch": function(expr, body) {
-                        var last = body.length - 1;
-                        return [ "switch", walk(expr), MAP(body, function(branch, i){
-                                var block = tighten(MAP(branch[1], walk));
-                                if (i == last && block.length > 0) {
-                                        var node = block[block.length - 1];
-                                        if (node[0] == "break" && !node[1])
-                                                block.pop();
-                                }
-                                return [ branch[0] ? walk(branch[0]) : null, block ];
-                        }) ];
-                },
-                "function": _lambda,
-                "defun": _lambda,
-                "block": function(body) {
-                        if (body) return rmblock([ "block", tighten(MAP(body, walk)) ]);
-                },
-                "binary": function(op, left, right) {
-                        return when_constant([ "binary", op, walk(left), walk(right) ], function yes(c){
-                                return best_of(walk(c), this);
-                        }, function no() {
-                                return this;
-                        });
-                },
-                "conditional": function(c, t, e) {
-                        return make_conditional(walk(c), walk(t), walk(e));
-                },
-                "try": function(t, c, f) {
-                        return [
-                                "try",
-                                tighten(MAP(t, walk)),
-                                c != null ? [ c[0], tighten(MAP(c[1], walk)) ] : null,
-                                f != null ? tighten(MAP(f, walk)) : null
-                        ];
-                },
-                "unary-prefix": function(op, expr) {
-                        expr = walk(expr);
-                        var ret = [ "unary-prefix", op, expr ];
-                        if (op == "!")
-                                ret = best_of(ret, negate(expr));
-                        return when_constant(ret, function(ast, val){
-                                return walk(ast); // it's either true or false, so minifies to !0 or !1
-                        }, function() { return ret });
-                },
-                "name": function(name) {
-                        switch (name) {
-                            case "true": return [ "unary-prefix", "!", [ "num", 0 ]];
-                            case "false": return [ "unary-prefix", "!", [ "num", 1 ]];
-                        }
-                },
-                "new": function(ctor, args) {
-                        if (ctor[0] == "name" && ctor[1] == "Array" && !scope.has("Array")) {
-                                if (args.length != 1) {
-                                        return [ "array", args ];
-                                } else {
-                                        return [ "call", [ "name", "Array" ], args ];
-                                }
-                        }
-                },
-                "call": function(expr, args) {
-                        if (expr[0] == "name" && expr[1] == "Array" && args.length != 1 && !scope.has("Array")) {
-                                return [ "array", args ];
-                        }
-                },
-                "while": _do_while
-        }, function() {
-                return walk(ast);
-        });
-};
-
-/* -----[ re-generate code from the AST ]----- */
-
-var DOT_CALL_NO_PARENS = jsp.array_to_hash([
-        "name",
-        "array",
-        "object",
-        "string",
-        "dot",
-        "sub",
-        "call",
-        "regexp"
-]);
-
-function make_string(str, ascii_only) {
-        var dq = 0, sq = 0;
-        str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029]/g, function(s){
-                switch (s) {
-                    case "\\": return "\\\\";
-                    case "\b": return "\\b";
-                    case "\f": return "\\f";
-                    case "\n": return "\\n";
-                    case "\r": return "\\r";
-                    case "\t": return "\\t";
-                    case "\u2028": return "\\u2028";
-                    case "\u2029": return "\\u2029";
-                    case '"': ++dq; return '"';
-                    case "'": ++sq; return "'";
-                }
-                return s;
-        });
-        if (ascii_only) str = to_ascii(str);
-        if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'";
-        else return '"' + str.replace(/\x22/g, '\\"') + '"';
-};
-
-function to_ascii(str) {
-        return str.replace(/[\u0080-\uffff]/g, function(ch) {
-                var code = ch.charCodeAt(0).toString(16);
-                while (code.length < 4) code = "0" + code;
-                return "\\u" + code;
-        });
-};
-
-var SPLICE_NEEDS_BRACKETS = jsp.array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]);
-
-function gen_code(ast, options) {
-        options = defaults(options, {
-                indent_start : 0,
-                indent_level : 4,
-                quote_keys   : false,
-                space_colon  : false,
-                beautify     : false,
-                ascii_only   : false,
-                inline_script: false
-        });
-        var beautify = !!options.beautify;
-        var indentation = 0,
-            newline = beautify ? "\n" : "",
-            space = beautify ? " " : "";
-
-        function encode_string(str) {
-                var ret = make_string(str, options.ascii_only);
-                if (options.inline_script)
-                        ret = ret.replace(/<\x2fscript([>/\t\n\f\r ])/gi, "<\\/script$1");
-                return ret;
-        };
-
-        function make_name(name) {
-                name = name.toString();
-                if (options.ascii_only)
-                        name = to_ascii(name);
-                return name;
-        };
-
-        function indent(line) {
-                if (line == null)
-                        line = "";
-                if (beautify)
-                        line = repeat_string(" ", options.indent_start + indentation * options.indent_level) + line;
-                return line;
-        };
-
-        function with_indent(cont, incr) {
-                if (incr == null) incr = 1;
-                indentation += incr;
-                try { return cont.apply(null, slice(arguments, 1)); }
-                finally { indentation -= incr; }
-        };
-
-        function add_spaces(a) {
-                if (beautify)
-                        return a.join(" ");
-                var b = [];
-                for (var i = 0; i < a.length; ++i) {
-                        var next = a[i + 1];
-                        b.push(a[i]);
-                        if (next &&
-                            ((/[a-z0-9_\x24]$/i.test(a[i].toString()) && /^[a-z0-9_\x24]/i.test(next.toString())) ||
-                             (/[\+\-]$/.test(a[i].toString()) && /^[\+\-]/.test(next.toString())))) {
-                                b.push(" ");
-                        }
-                }
-                return b.join("");
-        };
-
-        function add_commas(a) {
-                return a.join("," + space);
-        };
-
-        function parenthesize(expr) {
-                var gen = make(expr);
-                for (var i = 1; i < arguments.length; ++i) {
-                        var el = arguments[i];
-                        if ((el instanceof Function && el(expr)) || expr[0] == el)
-                                return "(" + gen + ")";
-                }
-                return gen;
-        };
-
-        function best_of(a) {
-                if (a.length == 1) {
-                        return a[0];
-                }
-                if (a.length == 2) {
-                        var b = a[1];
-                        a = a[0];
-                        return a.length <= b.length ? a : b;
-                }
-                return best_of([ a[0], best_of(a.slice(1)) ]);
-        };
-
-        function needs_parens(expr) {
-                if (expr[0] == "function" || expr[0] == "object") {
-                        // dot/call on a literal function requires the
-                        // function literal itself to be parenthesized
-                        // only if it's the first "thing" in a
-                        // statement.  This means that the parent is
-                        // "stat", but it could also be a "seq" and
-                        // we're the first in this "seq" and the
-                        // parent is "stat", and so on.  Messy stuff,
-                        // but it worths the trouble.
-                        var a = slice($stack), self = a.pop(), p = a.pop();
-                        while (p) {
-                                if (p[0] == "stat") return true;
-                                if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) ||
-                                    ((p[0] == "binary" || p[0] == "assign" || p[0] == "unary-postfix") && p[2] === self)) {
-                                        self = p;
-                                        p = a.pop();
-                                } else {
-                                        return false;
-                                }
-                        }
-                }
-                return !HOP(DOT_CALL_NO_PARENS, expr[0]);
-        };
-
-        function make_num(num) {
-                var str = num.toString(10), a = [ str.replace(/^0\./, ".") ], m;
-                if (Math.floor(num) === num) {
-                        a.push("0x" + num.toString(16).toLowerCase(), // probably pointless
-                               "0" + num.toString(8)); // same.
-                        if ((m = /^(.*?)(0+)$/.exec(num))) {
-                                a.push(m[1] + "e" + m[2].length);
-                        }
-                } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) {
-                        a.push(m[2] + "e-" + (m[1].length + m[2].length),
-                               str.substr(str.indexOf(".")));
-                }
-                return best_of(a);
-        };
-
-        var generators = {
-                "string": encode_string,
-                "num": make_num,
-                "name": make_name,
-                "toplevel": function(statements) {
-                        return make_block_statements(statements)
-                                .join(newline + newline);
-                },
-                "splice": function(statements) {
-                        var parent = $stack[$stack.length - 2][0];
-                        if (HOP(SPLICE_NEEDS_BRACKETS, parent)) {
-                                // we need block brackets in this case
-                                return make_block.apply(this, arguments);
-                        } else {
-                                return MAP(make_block_statements(statements, true),
-                                           function(line, i) {
-                                                   // the first line is already indented
-                                                   return i > 0 ? indent(line) : line;
-                                           }).join(newline);
-                        }
-                },
-                "block": make_block,
-                "var": function(defs) {
-                        return "var " + add_commas(MAP(defs, make_1vardef)) + ";";
-                },
-                "const": function(defs) {
-                        return "const " + add_commas(MAP(defs, make_1vardef)) + ";";
-                },
-                "try": function(tr, ca, fi) {
-                        var out = [ "try", make_block(tr) ];
-                        if (ca) out.push("catch", "(" + ca[0] + ")", make_block(ca[1]));
-                        if (fi) out.push("finally", make_block(fi));
-                        return add_spaces(out);
-                },
-                "throw": function(expr) {
-                        return add_spaces([ "throw", make(expr) ]) + ";";
-                },
-                "new": function(ctor, args) {
-                        args = args.length > 0 ? "(" + add_commas(MAP(args, make)) + ")" : "";
-                        return add_spaces([ "new", parenthesize(ctor, "seq", "binary", "conditional", "assign", function(expr){
-                                var w = ast_walker(), has_call = {};
-                                try {
-                                        w.with_walkers({
-                                                "call": function() { throw has_call },
-                                                "function": function() { return this }
-                                        }, function(){
-                                                w.walk(expr);
-                                        });
-                                } catch(ex) {
-                                        if (ex === has_call)
-                                                return true;
-                                        throw ex;
-                                }
-                        }) + args ]);
-                },
-                "switch": function(expr, body) {
-                        return add_spaces([ "switch", "(" + make(expr) + ")", make_switch_block(body) ]);
-                },
-                "break": function(label) {
-                        var out = "break";
-                        if (label != null)
-                                out += " " + make_name(label);
-                        return out + ";";
-                },
-                "continue": function(label) {
-                        var out = "continue";
-                        if (label != null)
-                                out += " " + make_name(label);
-                        return out + ";";
-                },
-                "conditional": function(co, th, el) {
-                        return add_spaces([ parenthesize(co, "assign", "seq", "conditional"), "?",
-                                            parenthesize(th, "seq"), ":",
-                                            parenthesize(el, "seq") ]);
-                },
-                "assign": function(op, lvalue, rvalue) {
-                        if (op && op !== true) op += "=";
-                        else op = "=";
-                        return add_spaces([ make(lvalue), op, parenthesize(rvalue, "seq") ]);
-                },
-                "dot": function(expr) {
-                        var out = make(expr), i = 1;
-                        if (expr[0] == "num") {
-                                if (!/\./.test(expr[1]))
-                                        out += ".";
-                        } else if (needs_parens(expr))
-                                out = "(" + out + ")";
-                        while (i < arguments.length)
-                                out += "." + make_name(arguments[i++]);
-                        return out;
-                },
-                "call": function(func, args) {
-                        var f = make(func);
-                        if (needs_parens(func))
-                                f = "(" + f + ")";
-                        return f + "(" + add_commas(MAP(args, function(expr){
-                                return parenthesize(expr, "seq");
-                        })) + ")";
-                },
-                "function": make_function,
-                "defun": make_function,
-                "if": function(co, th, el) {
-                        var out = [ "if", "(" + make(co) + ")", el ? make_then(th) : make(th) ];
-                        if (el) {
-                                out.push("else", make(el));
-                        }
-                        return add_spaces(out);
-                },
-                "for": function(init, cond, step, block) {
-                        var out = [ "for" ];
-                        init = (init != null ? make(init) : "").replace(/;*\s*$/, ";" + space);
-                        cond = (cond != null ? make(cond) : "").replace(/;*\s*$/, ";" + space);
-                        step = (step != null ? make(step) : "").replace(/;*\s*$/, "");
-                        var args = init + cond + step;
-                        if (args == "; ; ") args = ";;";
-                        out.push("(" + args + ")", make(block));
-                        return add_spaces(out);
-                },
-                "for-in": function(vvar, key, hash, block) {
-                        return add_spaces([ "for", "(" +
-                                            (vvar ? make(vvar).replace(/;+$/, "") : make(key)),
-                                            "in",
-                                            make(hash) + ")", make(block) ]);
-                },
-                "while": function(condition, block) {
-                        return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]);
-                },
-                "do": function(condition, block) {
-                        return add_spaces([ "do", make(block), "while", "(" + make(condition) + ")" ]) + ";";
-                },
-                "return": function(expr) {
-                        var out = [ "return" ];
-                        if (expr != null) out.push(make(expr));
-                        return add_spaces(out) + ";";
-                },
-                "binary": function(operator, lvalue, rvalue) {
-                        var left = make(lvalue), right = make(rvalue);
-                        // XXX: I'm pretty sure other cases will bite here.
-                        //      we need to be smarter.
-                        //      adding parens all the time is the safest bet.
-                        if (member(lvalue[0], [ "assign", "conditional", "seq" ]) ||
-                            lvalue[0] == "binary" && PRECEDENCE[operator] > PRECEDENCE[lvalue[1]]) {
-                                left = "(" + left + ")";
-                        }
-                        if (member(rvalue[0], [ "assign", "conditional", "seq" ]) ||
-                            rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] &&
-                            !(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) {
-                                right = "(" + right + ")";
-                        }
-                        else if (!beautify && options.inline_script && (operator == "<" || operator == "<<")
-                                 && rvalue[0] == "regexp" && /^script/i.test(rvalue[1])) {
-                                right = " " + right;
-                        }
-                        return add_spaces([ left, operator, right ]);
-                },
-                "unary-prefix": function(operator, expr) {
-                        var val = make(expr);
-                        if (!(expr[0] == "num" || (expr[0] == "unary-prefix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr)))
-                                val = "(" + val + ")";
-                        return operator + (jsp.is_alphanumeric_char(operator.charAt(0)) ? " " : "") + val;
-                },
-                "unary-postfix": function(operator, expr) {
-                        var val = make(expr);
-                        if (!(expr[0] == "num" || (expr[0] == "unary-postfix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr)))
-                                val = "(" + val + ")";
-                        return val + operator;
-                },
-                "sub": function(expr, subscript) {
-                        var hash = make(expr);
-                        if (needs_parens(expr))
-                                hash = "(" + hash + ")";
-                        return hash + "[" + make(subscript) + "]";
-                },
-                "object": function(props) {
-                        if (props.length == 0)
-                                return "{}";
-                        return "{" + newline + with_indent(function(){
-                                return MAP(props, function(p){
-                                        if (p.length == 3) {
-                                                // getter/setter.  The name is in p[0], the arg.list in p[1][2], the
-                                                // body in p[1][3] and type ("get" / "set") in p[2].
-                                                return indent(make_function(p[0], p[1][2], p[1][3], p[2]));
-                                        }
-                                        var key = p[0], val = make(p[1]);
-                                        if (options.quote_keys) {
-                                                key = encode_string(key);
-                                        } else if ((typeof key == "number" || !beautify && +key + "" == key)
-                                                   && parseFloat(key) >= 0) {
-                                                key = make_num(+key);
-                                        } else if (!is_identifier(key)) {
-                                                key = encode_string(key);
-                                        }
-                                        return indent(add_spaces(beautify && options.space_colon
-                                                                 ? [ key, ":", val ]
-                                                                 : [ key + ":", val ]));
-                                }).join("," + newline);
-                        }) + newline + indent("}");
-                },
-                "regexp": function(rx, mods) {
-                        return "/" + rx + "/" + mods;
-                },
-                "array": function(elements) {
-                        if (elements.length == 0) return "[]";
-                        return add_spaces([ "[", add_commas(MAP(elements, function(el){
-                                if (!beautify && el[0] == "atom" && el[1] == "undefined") return "";
-                                return parenthesize(el, "seq");
-                        })), "]" ]);
-                },
-                "stat": function(stmt) {
-                        return make(stmt).replace(/;*\s*$/, ";");
-                },
-                "seq": function() {
-                        return add_commas(MAP(slice(arguments), make));
-                },
-                "label": function(name, block) {
-                        return add_spaces([ make_name(name), ":", make(block) ]);
-                },
-                "with": function(expr, block) {
-                        return add_spaces([ "with", "(" + make(expr) + ")", make(block) ]);
-                },
-                "atom": function(name) {
-                        return make_name(name);
-                }
-        };
-
-        // The squeezer replaces "block"-s that contain only a single
-        // statement with the statement itself; technically, the AST
-        // is correct, but this can create problems when we output an
-        // IF having an ELSE clause where the THEN clause ends in an
-        // IF *without* an ELSE block (then the outer ELSE would refer
-        // to the inner IF).  This function checks for this case and
-        // adds the block brackets if needed.
-        function make_then(th) {
-                if (th[0] == "do") {
-                        // https://github.com/mishoo/UglifyJS/issues/#issue/57
-                        // IE croaks with "syntax error" on code like this:
-                        //     if (foo) do ... while(cond); else ...
-                        // we need block brackets around do/while
-                        return make([ "block", [ th ]]);
-                }
-                var b = th;
-                while (true) {
-                        var type = b[0];
-                        if (type == "if") {
-                                if (!b[3])
-                                        // no else, we must add the block
-                                        return make([ "block", [ th ]]);
-                                b = b[3];
-                        }
-                        else if (type == "while" || type == "do") b = b[2];
-                        else if (type == "for" || type == "for-in") b = b[4];
-                        else break;
-                }
-                return make(th);
-        };
-
-        function make_function(name, args, body, keyword) {
-                var out = keyword || "function";
-                if (name) {
-                        out += " " + make_name(name);
-                }
-                out += "(" + add_commas(MAP(args, make_name)) + ")";
-                return add_spaces([ out, make_block(body) ]);
-        };
-
-        function make_block_statements(statements, noindent) {
-                for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) {
-                        var stat = statements[i];
-                        var code = make(stat);
-                        if (code != ";") {
-                                if (!beautify && i == last) {
-                                        if ((stat[0] == "while" && empty(stat[2])) ||
-                                            (member(stat[0], [ "for", "for-in"] ) && empty(stat[4])) ||
-                                            (stat[0] == "if" && empty(stat[2]) && !stat[3]) ||
-                                            (stat[0] == "if" && stat[3] && empty(stat[3]))) {
-                                                code = code.replace(/;*\s*$/, ";");
-                                        } else {
-                                                code = code.replace(/;+\s*$/, "");
-                                        }
-                                }
-                                a.push(code);
-                        }
-                }
-                return noindent ? a : MAP(a, indent);
-        };
-
-        function make_switch_block(body) {
-                var n = body.length;
-                if (n == 0) return "{}";
-                return "{" + newline + MAP(body, function(branch, i){
-                        var has_body = branch[1].length > 0, code = with_indent(function(){
-                                return indent(branch[0]
-                                              ? add_spaces([ "case", make(branch[0]) + ":" ])
-                                              : "default:");
-                        }, 0.5) + (has_body ? newline + with_indent(function(){
-                                return make_block_statements(branch[1]).join(newline);
-                        }) : "");
-                        if (!beautify && has_body && i < n - 1)
-                                code += ";";
-                        return code;
-                }).join(newline) + newline + indent("}");
-        };
-
-        function make_block(statements) {
-                if (!statements) return ";";
-                if (statements.length == 0) return "{}";
-                return "{" + newline + with_indent(function(){
-                        return make_block_statements(statements).join(newline);
-                }) + newline + indent("}");
-        };
-
-        function make_1vardef(def) {
-                var name = def[0], val = def[1];
-                if (val != null)
-                        name = add_spaces([ make_name(name), "=", parenthesize(val, "seq") ]);
-                return name;
-        };
-
-        var $stack = [];
-
-        function make(node) {
-                var type = node[0];
-                var gen = generators[type];
-                if (!gen)
-                        throw new Error("Can't find generator for \"" + type + "\"");
-                $stack.push(node);
-                var ret = gen.apply(type, node.slice(1));
-                $stack.pop();
-                return ret;
-        };
-
-        return make(ast);
-};
-
-function split_lines(code, max_line_length) {
-        var splits = [ 0 ];
-        jsp.parse(function(){
-                var next_token = jsp.tokenizer(code);
-                var last_split = 0;
-                var prev_token;
-                function current_length(tok) {
-                        return tok.pos - last_split;
-                };
-                function split_here(tok) {
-                        last_split = tok.pos;
-                        splits.push(last_split);
-                };
-                function custom(){
-                        var tok = next_token.apply(this, arguments);
-                        out: {
-                                if (prev_token) {
-                                        if (prev_token.type == "keyword") break out;
-                                }
-                                if (current_length(tok) > max_line_length) {
-                                        switch (tok.type) {
-                                            case "keyword":
-                                            case "atom":
-                                            case "name":
-                                            case "punc":
-                                                split_here(tok);
-                                                break out;
-                                        }
-                                }
-                        }
-                        prev_token = tok;
-                        return tok;
-                };
-                custom.context = function() {
-                        return next_token.context.apply(this, arguments);
-                };
-                return custom;
-        }());
-        return splits.map(function(pos, i){
-                return code.substring(pos, splits[i + 1] || code.length);
-        }).join("\n");
-};
-
-/* -----[ Utilities ]----- */
-
-function repeat_string(str, i) {
-        if (i <= 0) return "";
-        if (i == 1) return str;
-        var d = repeat_string(str, i >> 1);
-        d += d;
-        if (i & 1) d += str;
-        return d;
-};
-
-function defaults(args, defs) {
-        var ret = {};
-        if (args === true)
-                args = {};
-        for (var i in defs) if (HOP(defs, i)) {
-                ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
-        }
-        return ret;
-};
-
-function is_identifier(name) {
-        return /^[a-z_$][a-z0-9_$]*$/i.test(name)
-                && name != "this"
-                && !HOP(jsp.KEYWORDS_ATOM, name)
-                && !HOP(jsp.RESERVED_WORDS, name)
-                && !HOP(jsp.KEYWORDS, name);
-};
-
-function HOP(obj, prop) {
-        return Object.prototype.hasOwnProperty.call(obj, prop);
-};
-
-// some utilities
-
-var MAP;
-
-(function(){
-        MAP = function(a, f, o) {
-                var ret = [];
-                for (var i = 0; i < a.length; ++i) {
-                        var val = f.call(o, a[i], i);
-                        if (val instanceof AtTop) ret.unshift(val.v);
-                        else ret.push(val);
-                }
-                return ret;
-        };
-        MAP.at_top = function(val) { return new AtTop(val) };
-        function AtTop(val) { this.v = val };
-})();
-
-/* -----[ Exports ]----- */
-
-exports.ast_walker = ast_walker;
-exports.ast_mangle = ast_mangle;
-exports.ast_squeeze = ast_squeeze;
-exports.gen_code = gen_code;
-exports.ast_add_scope = ast_add_scope;
-exports.set_logger = function(logger) { warn = logger };
-exports.make_string = make_string;
-exports.split_lines = split_lines;
-exports.MAP = MAP;
-
-// keep this last!
-exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more;
diff --git a/node/node_modules/___uglify-js.npm/package/lib/squeeze-more.js b/node/node_modules/___uglify-js.npm/package/lib/squeeze-more.js
deleted file mode 100644 (file)
index 12380af..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-var jsp = require("./parse-js"),
-    pro = require("./process"),
-    slice = jsp.slice,
-    member = jsp.member,
-    PRECEDENCE = jsp.PRECEDENCE,
-    OPERATORS = jsp.OPERATORS;
-
-function ast_squeeze_more(ast) {
-        var w = pro.ast_walker(), walk = w.walk;
-        return w.with_walkers({
-                "call": function(expr, args) {
-                        if (expr[0] == "dot" && expr[2] == "toString" && args.length == 0) {
-                                // foo.toString()  ==>  foo+""
-                                return [ "binary", "+", expr[1], [ "string", "" ]];
-                        }
-                }
-        }, function() {
-                return walk(ast);
-        });
-};
-
-exports.ast_squeeze_more = ast_squeeze_more;
diff --git a/node/node_modules/___uglify-js.npm/package/package.json b/node/node_modules/___uglify-js.npm/package/package.json
deleted file mode 100644 (file)
index 49eaddc..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-        "name"    : "uglify-js",
-
-        "author"  : {
-                "name"  : "Mihai Bazon",
-                "email" : "mihai.bazon@gmail.com",
-                "url"   : "http://mihai.bazon.net/blog"
-        },
-
-        "version" : "1.0.6",
-
-        "main"    : "./uglify-js.js",
-
-        "bin"     : {
-                "uglifyjs" : "./bin/uglifyjs"
-        },
-
-        "repository": {
-                "type": "git",
-                "url": "git@github.com:mishoo/UglifyJS.git"
-        }
-}
diff --git a/node/node_modules/___uglify-js.npm/package/test/beautify.js b/node/node_modules/___uglify-js.npm/package/test/beautify.js
deleted file mode 100644 (file)
index f19369e..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#! /usr/bin/env node
-
-global.sys = require("sys");
-var fs = require("fs");
-
-var jsp = require("../lib/parse-js");
-var pro = require("../lib/process");
-
-var filename = process.argv[2];
-fs.readFile(filename, "utf8", function(err, text){
-        try {
-                var ast = time_it("parse", function(){ return jsp.parse(text); });
-                ast = time_it("mangle", function(){ return pro.ast_mangle(ast); });
-                ast = time_it("squeeze", function(){ return pro.ast_squeeze(ast); });
-                var gen = time_it("generate", function(){ return pro.gen_code(ast, false); });
-                sys.puts(gen);
-        } catch(ex) {
-                sys.debug(ex.stack);
-                sys.debug(sys.inspect(ex));
-                sys.debug(JSON.stringify(ex));
-        }
-});
-
-function time_it(name, cont) {
-        var t1 = new Date().getTime();
-        try { return cont(); }
-        finally { sys.debug("// " + name + ": " + ((new Date().getTime() - t1) / 1000).toFixed(3) + " sec."); }
-};
diff --git a/node/node_modules/___uglify-js.npm/package/test/testparser.js b/node/node_modules/___uglify-js.npm/package/test/testparser.js
deleted file mode 100644 (file)
index c16d9a3..0000000
+++ /dev/null
@@ -1,402 +0,0 @@
-#! /usr/bin/env node
-
-var parseJS = require("../lib/parse-js");
-var sys = require("sys");
-
-// write debug in a very straightforward manner
-var debug = function(){
-        sys.log(Array.prototype.slice.call(arguments).join(', '));
-};
-
-ParserTestSuite(function(i, input, desc){
-       try {
-               parseJS.parse(input);
-               debug("ok " + i + ": " + desc);
-       } catch(e){
-               debug("FAIL " + i + " " + desc + " (" + e + ")");
-       }
-});
-
-function ParserTestSuite(callback){
-       var inps = [
-               ["var abc;", "Regular variable statement w/o assignment"],
-               ["var abc = 5;", "Regular variable statement with assignment"],
-               ["/* */;", "Multiline comment"],
-               ['/** **/;', 'Double star multiline comment'],
-               ["var f = function(){;};", "Function expression in var assignment"],
-               ['hi; // moo\n;', 'single line comment'],
-               ['var varwithfunction;', 'Dont match keywords as substrings'], // difference between `var withsomevar` and `"str"` (local search and lits)
-               ['a + b;', 'addition'],
-               ["'a';", 'single string literal'],
-               ["'a\\n';", 'single string literal with escaped return'],
-               ['"a";', 'double string literal'],
-               ['"a\\n";', 'double string literal with escaped return'],
-               ['"var";', 'string is a keyword'],
-               ['"variable";', 'string starts with a keyword'],
-               ['"somevariable";', 'string contains a keyword'],
-               ['"somevar";', 'string ends with a keyword'],
-               ['500;', 'int literal'],
-               ['500.;', 'float literal w/o decimals'],
-               ['500.432;', 'float literal with decimals'],
-               ['.432432;', 'float literal w/o int'],
-               ['(a,b,c);', 'parens and comma'],
-               ['[1,2,abc];', 'array literal'],
-               ['var o = {a:1};', 'object literal unquoted key'],
-               ['var o = {"b":2};', 'object literal quoted key'], // opening curly may not be at the start of a statement...
-               ['var o = {c:c};', 'object literal keyname is identifier'],
-               ['var o = {a:1,"b":2,c:c};', 'object literal combinations'],
-               ['var x;\nvar y;', 'two lines'],
-               ['var x;\nfunction n(){; }', 'function def'],
-               ['var x;\nfunction n(abc){; }', 'function def with arg'],
-               ['var x;\nfunction n(abc, def){ ;}', 'function def with args'],
-               ['function n(){ "hello"; }', 'function def with body'],
-               ['/a/;', 'regex literal'],
-               ['/a/b;', 'regex literal with flag'],
-               ['/a/ / /b/;', 'regex div regex'],
-               ['a/b/c;', 'triple division looks like regex'],
-               ['+function(){/regex/;};', 'regex at start of function body'],
-               // http://code.google.com/p/es-lab/source/browse/trunk/tests/parser/parsertests.js?r=86
-               // http://code.google.com/p/es-lab/source/browse/trunk/tests/parser/parsertests.js?r=430
-
-               // first tests for the lexer, should also parse as program (when you append a semi)
-
-               // comments
-               ['//foo!@#^&$1234\nbar;', 'single line comment'],
-               ['/* abcd!@#@$* { } && null*/;', 'single line multi line comment'],
-               ['/*foo\nbar*/;','multi line comment'],
-               ['/*x*x*/;','multi line comment with *'],
-               ['/**/;','empty comment'],
-               // identifiers
-               ["x;",'1 identifier'],
-               ["_x;",'2 identifier'],
-               ["xyz;",'3 identifier'],
-               ["$x;",'4 identifier'],
-               ["x$;",'5 identifier'],
-               ["_;",'6 identifier'],
-               ["x5;",'7 identifier'],
-               ["x_y;",'8 identifier'],
-               ["x+5;",'9 identifier'],
-               ["xyz123;",'10 identifier'],
-               ["x1y1z1;",'11 identifier'],
-               ["foo\\u00D8bar;",'12 identifier unicode escape'],
-               //["foo�bar;",'13 identifier unicode embedded (might fail)'],
-               // numbers
-               ["5;", '1 number'],
-               ["5.5;", '2 number'],
-               ["0;", '3 number'],
-               ["0.0;", '4 number'],
-               ["0.001;", '5 number'],
-               ["1.e2;", '6 number'],
-               ["1.e-2;", '7 number'],
-               ["1.E2;", '8 number'],
-               ["1.E-2;", '9 number'],
-               [".5;", '10 number'],
-               [".5e3;", '11 number'],
-               [".5e-3;", '12 number'],
-               ["0.5e3;", '13 number'],
-               ["55;", '14 number'],
-               ["123;", '15 number'],
-               ["55.55;", '16 number'],
-               ["55.55e10;", '17 number'],
-               ["123.456;", '18 number'],
-               ["1+e;", '20 number'],
-               ["0x01;", '22 number'],
-               ["0XCAFE;", '23 number'],
-               ["0x12345678;", '24 number'],
-               ["0x1234ABCD;", '25 number'],
-               ["0x0001;", '26 number'],
-               // strings
-               ["\"foo\";", '1 string'],
-               ["\'foo\';", '2 string'],
-               ["\"x\";", '3 string'],
-               ["\'\';", '4 string'],
-               ["\"foo\\tbar\";", '5 string'],
-               ["\"!@#$%^&*()_+{}[]\";", '6 string'],
-               ["\"/*test*/\";", '7 string'],
-               ["\"//test\";", '8 string'],
-               ["\"\\\\\";", '9 string'],
-               ["\"\\u0001\";", '10 string'],
-               ["\"\\uFEFF\";", '11 string'],
-               ["\"\\u10002\";", '12 string'],
-               ["\"\\x55\";", '13 string'],
-               ["\"\\x55a\";", '14 string'],
-               ["\"a\\\\nb\";", '15 string'],
-               ['";"', '16 string: semi in a string'],
-               ['"a\\\nb";', '17 string: line terminator escape'],
-               // literals
-               ["null;", "null"],
-               ["true;", "true"],
-               ["false;", "false"],
-               // regex
-               ["/a/;", "1 regex"],
-               ["/abc/;", "2 regex"],
-               ["/abc[a-z]*def/g;", "3 regex"],
-               ["/\\b/;", "4 regex"],
-               ["/[a-zA-Z]/;", "5 regex"],
-
-               // program tests (for as far as they havent been covered above)
-
-               // regexp
-               ["/foo(.*)/g;", "another regexp"],
-               // arrays
-               ["[];", "1 array"],
-               ["[   ];", "2 array"],
-               ["[1];", "3 array"],
-               ["[1,2];", "4 array"],
-               ["[1,2,,];", "5 array"],
-               ["[1,2,3];", "6 array"],
-               ["[1,2,3,,,];", "7 array"],
-               // objects
-               ["{};", "1 object"],
-               ["({x:5});", "2 object"],
-               ["({x:5,y:6});", "3 object"],
-               ["({x:5,});", "4 object"],
-               ["({if:5});", "5 object"],
-               ["({ get x() {42;} });", "6 object"],
-               ["({ set y(a) {1;} });", "7 object"],
-               // member expression
-               ["o.m;", "1 member expression"],
-               ["o['m'];", "2 member expression"],
-               ["o['n']['m'];", "3 member expression"],
-               ["o.n.m;", "4 member expression"],
-               ["o.if;", "5 member expression"],
-               // call and invoke expressions
-               ["f();", "1 call/invoke expression"],
-               ["f(x);", "2 call/invoke expression"],
-               ["f(x,y);", "3 call/invoke expression"],
-               ["o.m();", "4 call/invoke expression"],
-               ["o['m'];", "5 call/invoke expression"],
-               ["o.m(x);", "6 call/invoke expression"],
-               ["o['m'](x);", "7 call/invoke expression"],
-               ["o.m(x,y);", "8 call/invoke expression"],
-               ["o['m'](x,y);", "9 call/invoke expression"],
-               ["f(x)(y);", "10 call/invoke expression"],
-               ["f().x;", "11 call/invoke expression"],
-
-               // eval
-               ["eval('x');", "1 eval"],
-               ["(eval)('x');", "2 eval"],
-               ["(1,eval)('x');", "3 eval"],
-               ["eval(x,y);", "4 eval"],
-               // new expression
-               ["new f();", "1 new expression"],
-               ["new o;", "2 new expression"],
-               ["new o.m;", "3 new expression"],
-               ["new o.m(x);", "4 new expression"],
-               ["new o.m(x,y);", "5 new expression"],
-               // prefix/postfix
-               ["++x;", "1 pre/postfix"],
-               ["x++;", "2 pre/postfix"],
-               ["--x;", "3 pre/postfix"],
-               ["x--;", "4 pre/postfix"],
-               ["x ++;", "5 pre/postfix"],
-               ["x /* comment */ ++;", "6 pre/postfix"],
-               ["++ /* comment */ x;", "7 pre/postfix"],
-               // unary operators
-               ["delete x;", "1 unary operator"],
-               ["void x;", "2 unary operator"],
-               ["+ x;", "3 unary operator"],
-               ["-x;", "4 unary operator"],
-               ["~x;", "5 unary operator"],
-               ["!x;", "6 unary operator"],
-               // meh
-               ["new Date++;", "new date ++"],
-               ["+x++;", " + x ++"],
-               // expression expressions
-               ["1 * 2;", "1 expression expressions"],
-               ["1 / 2;", "2 expression expressions"],
-               ["1 % 2;", "3 expression expressions"],
-               ["1 + 2;", "4 expression expressions"],
-               ["1 - 2;", "5 expression expressions"],
-               ["1 << 2;", "6 expression expressions"],
-               ["1 >>> 2;", "7 expression expressions"],
-               ["1 >> 2;", "8 expression expressions"],
-               ["1 * 2 + 3;", "9 expression expressions"],
-               ["(1+2)*3;", "10 expression expressions"],
-               ["1*(2+3);", "11 expression expressions"],
-               ["x<y;", "12 expression expressions"],
-               ["x>y;", "13 expression expressions"],
-               ["x<=y;", "14 expression expressions"],
-               ["x>=y;", "15 expression expressions"],
-               ["x instanceof y;", "16 expression expressions"],
-               ["x in y;", "17 expression expressions"],
-               ["x&y;", "18 expression expressions"],
-               ["x^y;", "19 expression expressions"],
-               ["x|y;", "20 expression expressions"],
-               ["x+y<z;", "21 expression expressions"],
-               ["x<y+z;", "22 expression expressions"],
-               ["x+y+z;", "23 expression expressions"],
-               ["x+y<z;", "24 expression expressions"],
-               ["x<y+z;", "25 expression expressions"],
-               ["x&y|z;", "26 expression expressions"],
-               ["x&&y;", "27 expression expressions"],
-               ["x||y;", "28 expression expressions"],
-               ["x&&y||z;", "29 expression expressions"],
-               ["x||y&&z;", "30 expression expressions"],
-               ["x<y?z:w;", "31 expression expressions"],
-               // assignment
-               ["x >>>= y;", "1 assignment"],
-               ["x <<= y;", "2 assignment"],
-               ["x = y;", "3 assignment"],
-               ["x += y;", "4 assignment"],
-               ["x /= y;", "5 assignment"],
-               // comma
-               ["x, y;", "comma"],
-               // block
-               ["{};", "1 block"],
-               ["{x;};", "2 block"],
-               ["{x;y;};", "3 block"],
-               // vars
-               ["var x;", "1 var"],
-               ["var x,y;", "2 var"],
-               ["var x=1,y=2;", "3 var"],
-               ["var x,y=2;", "4 var"],
-               // empty
-               [";", "1 empty"],
-               ["\n;", "2 empty"],
-               // expression statement
-               ["x;", "1 expression statement"],
-               ["5;", "2 expression statement"],
-               ["1+2;", "3 expression statement"],
-               // if
-               ["if (c) x; else y;", "1 if statement"],
-               ["if (c) x;", "2 if statement"],
-               ["if (c) {} else {};", "3 if statement"],
-               ["if (c1) if (c2) s1; else s2;", "4 if statement"],
-               // while
-               ["do s; while (e);", "1 while statement"],
-               ["do { s; } while (e);", "2 while statement"],
-               ["while (e) s;", "3 while statement"],
-               ["while (e) { s; };", "4 while statement"],
-               // for
-               ["for (;;) ;", "1 for statement"],
-               ["for (;c;x++) x;", "2 for statement"],
-               ["for (i;i<len;++i){};", "3 for statement"],
-               ["for (var i=0;i<len;++i) {};", "4 for statement"],
-               ["for (var i=0,j=0;;){};", "5 for statement"],
-               //["for (x in b; c; u) {};", "6 for statement"],
-               ["for ((x in b); c; u) {};", "7 for statement"],
-               ["for (x in a);", "8 for statement"],
-               ["for (var x in a){};", "9 for statement"],
-               ["for (var x=5 in a) {};", "10 for statement"],
-               ["for (var x = a in b in c) {};", "11 for statement"],
-               ["for (var x=function(){a+b;}; a<b; ++i) some;", "11 for statement, testing for parsingForHeader reset with the function"],
-               ["for (var x=function(){for (x=0; x<15; ++x) alert(foo); }; a<b; ++i) some;", "11 for statement, testing for parsingForHeader reset with the function"],
-               // flow statements
-               ["while(1){ continue; }", "1 flow statement"],
-               ["label: while(1){ continue label; }", "2 flow statement"],
-               ["while(1){ break; }", "3 flow statement"],
-               ["somewhere: while(1){ break somewhere; }", "4 flow statement"],
-               ["while(1){ continue /* comment */ ; }", "5 flow statement"],
-               ["while(1){ continue \n; }", "6 flow statement"],
-               ["(function(){ return; })()", "7 flow statement"],
-               ["(function(){ return 0; })()", "8 flow statement"],
-               ["(function(){ return 0 + \n 1; })()", "9 flow statement"],
-               // with
-               ["with (e) s;", "with statement"],
-               // switch
-               ["switch (e) { case x: s; };", "1 switch statement"],
-               ["switch (e) { case x: s1;s2; default: s3; case y: s4; };", "2 switch statement"],
-               ["switch (e) { default: s1; case x: s2; case y: s3; };", "3 switch statement"],
-               ["switch (e) { default: s; };", "4 switch statement"],
-               ["switch (e) { case x: s1; case y: s2; };", "5 switch statement"],
-               // labels
-               ["foo : x;", " flow statement"],
-               // throw
-               ["throw x;", "1 throw statement"],
-               ["throw x\n;", "2 throw statement"],
-               // try catch finally
-               ["try { s1; } catch (e) { s2; };", "1 trycatchfinally statement"],
-               ["try { s1; } finally { s2; };", "2 trycatchfinally statement"],
-               ["try { s1; } catch (e) { s2; } finally { s3; };", "3 trycatchfinally statement"],
-               // debugger
-               ["debugger;", "debuger statement"],
-               // function decl
-               ["function f(x) { e; return x; };", "1 function declaration"],
-               ["function f() { x; y; };", "2 function declaration"],
-               ["function f(x,y) { var z; return x; };", "3 function declaration"],
-               // function exp
-               ["(function f(x) { return x; });", "1 function expression"],
-               ["(function empty() {;});", "2 function expression"],
-               ["(function empty() {;});", "3 function expression"],
-               ["(function (x) {; });", "4 function expression"],
-               // program
-               ["var x; function f(){;}; null;", "1 program"],
-               [";;", "2 program"],
-               ["{ x; y; z; }", "3 program"],
-               ["function f(){ function g(){;}};", "4 program"],
-               ["x;\n/*foo*/\n ;", "5 program"],
-
-               // asi
-               ["foo: while(1){ continue \n foo; }", "1 asi"],
-               ["foo: while(1){ break \n foo; }", "2 asi"],
-               ["(function(){ return\nfoo; })()", "3 asi"],
-               ["var x; { 1 \n 2 } 3", "4 asi"],
-               ["ab     /* hi */\ncd", "5 asi"],
-               ["ab/*\n*/cd", "6 asi (multi line multilinecomment counts as eol)"],
-               ["foo: while(1){ continue /* wtf \n busta */ foo; }", "7 asi illegal with multi line comment"],
-               ["function f() { s }", "8 asi"],
-               ["function f() { return }", "9 asi"],
-
-               // use strict
-                // XXX: some of these should actually fail?
-                //      no support for "use strict" yet...
-               ['"use strict"; \'bla\'\n; foo;', "1 directive"],
-               ['(function() { "use strict"; \'bla\';\n foo; });', "2 directive"],
-               ['"use\\n strict";', "3 directive"],
-               ['foo; "use strict";', "4 directive"],
-
-               // tests from http://es5conform.codeplex.com/
-
-               ['"use strict"; var o = { eval: 42};', "8.7.2-3-1-s: the use of eval as property name is allowed"],
-               ['({foo:0,foo:1});', 'Duplicate property name allowed in not strict mode'],
-               ['function foo(a,a){}', 'Duplicate parameter name allowed in not strict mode'],
-               ['(function foo(eval){})', 'Eval allowed as parameter name in non strict mode'],
-               ['(function foo(arguments){})', 'Arguments allowed as parameter name in non strict mode'],
-
-               // empty programs
-
-               ['', '1 Empty program'],
-               ['// test', '2 Empty program'],
-               ['//test\n', '3 Empty program'],
-               ['\n// test', '4 Empty program'],
-               ['\n// test\n', '5 Empty program'],
-               ['/* */', '6 Empty program'],
-               ['/*\ns,fd\n*/', '7 Empty program'],
-               ['/*\ns,fd\n*/\n', '8 Empty program'],
-               ['      ', '9 Empty program'],
-               ['  /*\nsmeh*/  \n   ', '10 Empty program'],
-
-               // trailing whitespace
-
-               ['a  ', '1 Trailing whitespace'],
-               ['a /* something */', '2 Trailing whitespace'],
-               ['a\n   // hah', '3 Trailing whitespace'],
-               ['/abc/de//f', '4 Trailing whitespace'],
-               ['/abc/de/*f*/\n        ', '5 Trailing whitespace'],
-
-               // things the parser tripped over at one point or the other (prevents regression bugs)
-               ['for (x;function(){ a\nb };z) x;', 'for header with function body forcing ASI'],
-               ['c=function(){return;return};', 'resetting noAsi after literal'],
-               ['d\nd()', 'asi exception causing token overflow'],
-               ['for(;;){x=function(){}}', 'function expression in a for header'],
-               ['for(var k;;){}', 'parser failing due to ASI accepting the incorrect "for" rule'],
-               ['({get foo(){ }})', 'getter with empty function body'],
-               ['\nreturnr', 'eol causes return statement to ignore local search requirement'],
-               [' / /', '1 whitespace before regex causes regex to fail?'],
-               ['/ // / /', '2 whitespace before regex causes regex to fail?'],
-               ['/ / / / /', '3 whitespace before regex causes regex to fail?'],
-
-               ['\n\t// Used for trimming whitespace\n\ttrimLeft = /^\\s+/;\n\ttrimRight = /\\s+$/;\t\n','turned out this didnt crash (the test below did), but whatever.'],
-               ['/[\\/]/;', 'escaped forward slash inside class group (would choke on fwd slash)'],
-               ['/[/]/;', 'also broke but is valid in es5 (not es3)'],
-               ['({get:5});','get property name thats not a getter'],
-               ['({set:5});','set property name thats not a setter'],
-               ['l !== "px" && (d.style(h, c, (k || 1) + l), j = (k || 1) / f.cur() * j, d.style(h, c, j + l)), i[1] && (k = (i[1] === "-=" ? -1 : 1) * k + j), f.custom(j, k, l)', 'this choked regex/div at some point'],
-               ['(/\'/g, \'\\\\\\\'\') + "\'";', 'the sequence of escaped characters confused the tokenizer']
-       ];
-
-       for (var i=0; i<inps.length; ++i) {
-               callback(i, inps[i][0], inps[i][1]);
-       };
-};
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array1.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array1.js
deleted file mode 100644 (file)
index 7b09176..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[],Array(1),[1,2,3]
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array2.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array2.js
deleted file mode 100644 (file)
index 05eba19..0000000
+++ /dev/null
@@ -1 +0,0 @@
-(function(){var a=function(){};return new a(1,2,3,4)})()
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array3.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array3.js
deleted file mode 100644 (file)
index 82f4f4d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-(function(){function a(){}return new a(1,2,3,4)})()
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array4.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array4.js
deleted file mode 100644 (file)
index 4b7b0f1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-(function(){function a(){}(function(){return new a(1,2,3)})()})()
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/assignment.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/assignment.js
deleted file mode 100644 (file)
index ab626d3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-a=1,b=a,c=1,d=b,e=d,longname=2;if(longname+1){x=3;if(x)var z=7}z=1,y=1,x=1,g+=1,h=g,++i,j=i,i++,j=i+17
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/concatstring.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/concatstring.js
deleted file mode 100644 (file)
index 3a4ee10..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a=a+"a"+"b"+1+c,b=a+"c"+"ds"+123+c,c=a+"c"+123+d+"ds"+c
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/const.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/const.js
deleted file mode 100644 (file)
index cef74d7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a=13,b=1/3
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/empty-blocks.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/empty-blocks.js
deleted file mode 100644 (file)
index a8e876c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-function mak(){for(;;);}function foo(){while(bar());}function bar(){return--x}var x=5
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/forstatement.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/forstatement.js
deleted file mode 100644 (file)
index fc47411..0000000
+++ /dev/null
@@ -1 +0,0 @@
-a=func(),b=z;for(a++;i<10;i++)alert(i);var z=1;g=2;for(;i<10;i++)alert(i);var a=2;for(var i=1;i<10;i++)alert(i)
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/if.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/if.js
deleted file mode 100644 (file)
index 236993c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a=1;a==1?a=2:a=17
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/ifreturn.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/ifreturn.js
deleted file mode 100644 (file)
index c5c32dd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-function a(a){return a==1?2:17}
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/ifreturn2.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/ifreturn2.js
deleted file mode 100644 (file)
index 92a6ac2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-function y(a){return typeof a=="object"?a:null}function x(a){return typeof a=="object"?a:a===42?0:a*2}
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue10.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue10.js
deleted file mode 100644 (file)
index 1de52af..0000000
+++ /dev/null
@@ -1 +0,0 @@
-function f(){var a;return(a="a")?a:a}f()
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue11.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue11.js
deleted file mode 100644 (file)
index 876bd0a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-new(A,B),new(A||B),new(X?A:B)
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue13.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue13.js
deleted file mode 100644 (file)
index 295ee69..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a=/^(?:(\w+):)?(?:\/\/(?:(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#])(?::(\d))?)?(..?$|(?:[^?#\/]\/))([^?#]*)(?:\?([^#]))?(?:#(.))?/
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue14.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue14.js
deleted file mode 100644 (file)
index 1ca8eef..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"}
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue16.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue16.js
deleted file mode 100644 (file)
index 2094828..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a=3250441966
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue17.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue17.js
deleted file mode 100644 (file)
index 339bce4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a=function(b){b(),a()}
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue20.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue20.js
deleted file mode 100644 (file)
index a21935c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-a:1
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue21.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue21.js
deleted file mode 100644 (file)
index fa83bdc..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a=0;switch(a){case 0:a++}
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue25.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue25.js
deleted file mode 100644 (file)
index 3ee9533..0000000
+++ /dev/null
@@ -1 +0,0 @@
-label1:{label2:break label2;console.log(1)}
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue27.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue27.js
deleted file mode 100644 (file)
index b1154d1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-(a?b:c)?d:e
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue28.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue28.js
deleted file mode 100644 (file)
index 5c0c914..0000000
+++ /dev/null
@@ -1 +0,0 @@
-o={".5":.5},o={.5:.5},o={.5:.5}
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue29.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue29.js
deleted file mode 100644 (file)
index eaaa1cb..0000000
+++ /dev/null
@@ -1 +0,0 @@
-result=function(){return 1}()
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue30.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue30.js
deleted file mode 100644 (file)
index 27610b5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a=8,b=4,c=4
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue34.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue34.js
deleted file mode 100644 (file)
index a9dd7d4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a={};a["this"]=1,a.that=2
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue4.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue4.js
deleted file mode 100644 (file)
index 1fee33d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a=2e3,b=.002,c=2e-5
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue48.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue48.js
deleted file mode 100644 (file)
index 5e8abcd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var s,i;s="",i=0
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue50.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue50.js
deleted file mode 100644 (file)
index 1974186..0000000
+++ /dev/null
@@ -1 +0,0 @@
-function bar(a){try{foo()}catch(b){alert("Exception caught (foo not defined)")}alert(a)}bar(10)
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue53.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue53.js
deleted file mode 100644 (file)
index cd42c05..0000000
+++ /dev/null
@@ -1 +0,0 @@
-x=(y,z)
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue54.1.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue54.1.js
deleted file mode 100644 (file)
index ef06794..0000000
+++ /dev/null
@@ -1 +0,0 @@
-foo+"",a.toString(16),b.toString.call(c)
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue68.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue68.js
deleted file mode 100644 (file)
index d7f63f7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-function f(){function b(){}a||b()}
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue69.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue69.js
deleted file mode 100644 (file)
index d25ecd6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[(a,b)]
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue9.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue9.js
deleted file mode 100644 (file)
index db8d48c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a={a:1,b:2}
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/mangle.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/mangle.js
deleted file mode 100644 (file)
index 6226e8a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-(function(){var a=function b(a,b,c){return b}})()
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/strict-equals.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/strict-equals.js
deleted file mode 100644 (file)
index 0b7375b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-typeof a=="string",b+""!=c+"",d<e==f<g
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/var.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/var.js
deleted file mode 100644 (file)
index 01091cf..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a=1,b=2
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/with.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/with.js
deleted file mode 100644 (file)
index 3d9d911..0000000
+++ /dev/null
@@ -1 +0,0 @@
-with({})
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array1.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array1.js
deleted file mode 100644 (file)
index ae0851d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-new Array();
-new Array(1);
-new Array(1, 2, 3);
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array2.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array2.js
deleted file mode 100644 (file)
index 74226df..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-(function(){
-        var Array = function(){};
-        return new Array(1, 2, 3, 4);
-})();
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array3.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array3.js
deleted file mode 100644 (file)
index 6cc9742..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-(function(){
-        return new Array(1, 2, 3, 4);
-        function Array() {};
-})();
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array4.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array4.js
deleted file mode 100644 (file)
index 7392861..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-(function(){
-        (function(){
-                return new Array(1, 2, 3);
-        })();
-        function Array(){};
-})();
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/assignment.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/assignment.js
deleted file mode 100644 (file)
index 4e00389..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-a=1;
-b=a;
-c=1;
-d=b;
-e=d;
-longname=2;
-if (longname+1) {
-    x=3;
-    if (x) var z = 7;
-}
-z=1,y=1,x=1
-
-g+=1;
-h=g;
-
-++i;
-j=i;
-
-i++;
-j=i+17;
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/concatstring.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/concatstring.js
deleted file mode 100644 (file)
index a4a0037..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-var a = a + "a" + "b" + 1 + c;
-var b = a + "c" + "ds" + 123 + c;
-var c = a + "c" + 123 + d + "ds" + c;
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/const.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/const.js
deleted file mode 100644 (file)
index f2c62e9..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-// test that the calculation is fold to 13\r
-var a = 1 + 2 * 6;\r
-\r
-// test that it isn't replaced with 0.3333 because that is more characters\r
-var b = 1/3;
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/empty-blocks.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/empty-blocks.js
deleted file mode 100644 (file)
index 2d679c1..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-var x = 5;
-function bar() { return --x; }
-function foo() { while (bar()); }
-function mak() { for(;;); }
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/forstatement.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/forstatement.js
deleted file mode 100644 (file)
index d2a14f9..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-a=func();
-b=z;
-for (a++; i < 10; i++) { alert(i); }
-
-var z=1;
-g=2;
-for (; i < 10; i++) { alert(i); }
-
-var a = 2;
-for (var i = 1; i < 10; i++) { alert(i); }
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/if.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/if.js
deleted file mode 100644 (file)
index a54e762..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-var a = 1;\r
-if (a == 1) {\r
-       a = 2;\r
-} else {\r
-       a = 17;\r
-}\r
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/ifreturn.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/ifreturn.js
deleted file mode 100644 (file)
index 1332c93..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-function a(b) {\r
-       if (b == 1) {\r
-               return 2;\r
-       } else {\r
-               return 17;\r
-       }\r
-\r
-       return 3;\r
-}
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/ifreturn2.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/ifreturn2.js
deleted file mode 100644 (file)
index 5d763ea..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-function x(a) {
-    if (typeof a === 'object')
-        return a;
-
-    if (a === 42)
-        return 0;
-
-    return a * 2;
-}
-
-function y(a) {
-    if (typeof a === 'object')
-        return a;
-
-    return null;
-};
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue10.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue10.js
deleted file mode 100644 (file)
index 20adcaa..0000000
+++ /dev/null
@@ -1 +0,0 @@
-function f() { var a; if (a = 'a') { return a; } else { return a; } }; f();
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue11.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue11.js
deleted file mode 100644 (file)
index f4dbf1f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-new (A, B)
-new (A || B)
-new (X ? A : B)
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue13.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue13.js
deleted file mode 100644 (file)
index 4328a20..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a = /^(?:(\w+):)?(?:\/\/(?:(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#])(?::(\d))?)?(..?$|(?:[^?#\/]\/))([^?#]*)(?:\?([^#]))?(?:#(.))?/;
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue14.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue14.js
deleted file mode 100644 (file)
index 70c26af..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'};
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue16.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue16.js
deleted file mode 100644 (file)
index 53b857b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var a = 0xC1BDCEEE;
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue17.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue17.js
deleted file mode 100644 (file)
index 2dfab55..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-var a = function(b) {
-    b();
-    a()
-}
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue20.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue20.js
deleted file mode 100644 (file)
index 5a9dde5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{a: 1}
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue21.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue21.js
deleted file mode 100644 (file)
index 30d1e1d..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-var a = 0;
-switch(a) {
-    case 0:
-        a++;
-        break;
-}
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue25.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue25.js
deleted file mode 100644 (file)
index 9ca921d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-label1 : {
-    label2 : {
-        break label2;
-        console.log(2);
-    }
-    console.log(1);
-}
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue27.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue27.js
deleted file mode 100644 (file)
index 89394db..0000000
+++ /dev/null
@@ -1 +0,0 @@
-(a ? b : c) ? d : e
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue28.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue28.js
deleted file mode 100644 (file)
index 7188e27..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-o = {'.5':.5}
-o = {'0.5':.5}
-o = {0.5:.5}
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue29.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue29.js
deleted file mode 100644 (file)
index f07cf4d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-result=(function(){ return 1;})()
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue30.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue30.js
deleted file mode 100644 (file)
index 4e634e2..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-var a = 1 << 3;
-var b = 8 >> 1;
-var c = 8 >>> 1;
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue34.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue34.js
deleted file mode 100644 (file)
index 022f7a3..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-var a = {};
-a["this"] = 1;
-a["that"] = 2;
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue4.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue4.js
deleted file mode 100644 (file)
index 0b76103..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-var a = 2e3;
-var b = 2e-3;
-var c = 2e-5;
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue48.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue48.js
deleted file mode 100644 (file)
index 031e85b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-var s, i; s = ''; i = 0;
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue50.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue50.js
deleted file mode 100644 (file)
index 060f9df..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-function bar(a) {
-        try {
-                foo();
-        } catch(e) {
-                alert("Exception caught (foo not defined)");
-        }
-        alert(a);               // 10 in FF, "[object Error]" in IE
-}
-bar(10);
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue53.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue53.js
deleted file mode 100644 (file)
index 4f8b32f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-x = (y, z)
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue54.1.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue54.1.js
deleted file mode 100644 (file)
index 967052e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-foo.toString();
-a.toString(16);
-b.toString.call(c);
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue68.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue68.js
deleted file mode 100644 (file)
index 14054d0..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-function f() {
-        if (a) return;
-        g();
-        function g(){}
-};
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue69.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue69.js
deleted file mode 100644 (file)
index d25ecd6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[(a,b)]
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue9.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue9.js
deleted file mode 100644 (file)
index 6158861..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-var a = {
-    a: 1,
-    b: 2, // <-- trailing comma
-};
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/mangle.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/mangle.js
deleted file mode 100644 (file)
index c271a26..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-(function() {
-    var x = function fun(a, fun, b) {
-        return fun;
-    };
-}());
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/strict-equals.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/strict-equals.js
deleted file mode 100644 (file)
index b631f4c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-typeof a === 'string'
-b + "" !== c + ""
-d < e === f < g
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/var.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/var.js
deleted file mode 100644 (file)
index 609a35d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-// var declarations after each other should be combined\r
-var a = 1;\r
-var b = 2;
\ No newline at end of file
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/with.js b/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/with.js
deleted file mode 100644 (file)
index de266ed..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-with({}) {
-};
diff --git a/node/node_modules/___uglify-js.npm/package/test/unit/scripts.js b/node/node_modules/___uglify-js.npm/package/test/unit/scripts.js
deleted file mode 100644 (file)
index 5d1f526..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-var fs = require('fs'),
-       uglify = require('uglify-js'),
-       jsp = uglify.parser,
-       nodeunit = require('nodeunit'),
-       path = require('path'),
-       pro = uglify.uglify;
-
-var Script = process.binding('evals').Script;
-
-var scriptsPath = __dirname;
-
-function compress(code) {
-       var ast = jsp.parse(code);
-       ast = pro.ast_mangle(ast);
-       ast = pro.ast_squeeze(ast, {no_warnings: true, extra: true});
-        ast = pro.ast_squeeze_more(ast);
-       return pro.gen_code(ast);
-};
-
-var testDir = path.join(scriptsPath, "compress", "test");
-var expectedDir = path.join(scriptsPath, "compress", "expected");
-
-function getTester(script) {
-       return function(test) {
-               var testPath = path.join(testDir, script);
-               var expectedPath = path.join(expectedDir, script);
-               var content = fs.readFileSync(testPath, 'utf-8');
-               var outputCompress = compress(content);
-
-               // Check if the noncompressdata is larger or same size as the compressed data
-               test.ok(content.length >= outputCompress.length);
-
-               // Check that a recompress gives the same result
-               var outputReCompress = compress(content);
-               test.equal(outputCompress, outputReCompress);
-
-               // Check if the compressed output is what is expected
-               var expected = fs.readFileSync(expectedPath, 'utf-8');
-               test.equal(outputCompress, expected.replace(/(\r?\n)+$/, ""));
-
-               test.done();
-       };
-};
-
-var tests = {};
-
-var scripts = fs.readdirSync(testDir);
-for (var i in scripts) {
-       var script = scripts[i];
-       if (/\.js$/.test(script)) {
-               tests[script] = getTester(script);
-       }
-}
-
-module.exports = nodeunit.testCase(tests);
diff --git a/node/node_modules/___uglify-js.npm/package/tmp/instrument.js b/node/node_modules/___uglify-js.npm/package/tmp/instrument.js
deleted file mode 100644 (file)
index c6a9d79..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-// sample on how to use the parser and walker API to instrument some code
-
-var jsp = require("uglify-js").parser;
-var pro = require("uglify-js").uglify;
-
-function instrument(code) {
-        var ast = jsp.parse(code, false, true); // true for the third arg specifies that we want
-                                                // to have start/end tokens embedded in the
-                                                // statements
-        var w = pro.ast_walker();
-
-        // we're gonna need this to push elements that we're currently looking at, to avoid
-        // endless recursion.
-        var analyzing = [];
-        function do_stat() {
-                var ret;
-                if (this[0].start && analyzing.indexOf(this) < 0) {
-                        // without the `analyzing' hack, w.walk(this) would re-enter here leading
-                        // to infinite recursion
-                        analyzing.push(this);
-                        ret = [ "splice", // XXX: "block" is safer
-                                [ [ "stat",
-                                    [ "call", [ "name", "trace" ],
-                                      [ [ "string", this[0].toString() ],
-                                        [ "num", this[0].start.line ],
-                                        [ "num", this[0].start.col ],
-                                        [ "num", this[0].end.line ],
-                                        [ "num", this[0].end.col ]]]],
-                                  w.walk(this) ]];
-                        analyzing.pop(this);
-                }
-                return ret;
-        };
-        var new_ast = w.with_walkers({
-                "stat"     : do_stat,
-                "label"    : do_stat,
-                "break"    : do_stat,
-                "continue" : do_stat,
-                "debugger" : do_stat,
-                "var"      : do_stat,
-                "const"    : do_stat,
-                "return"   : do_stat,
-                "throw"    : do_stat,
-                "try"      : do_stat,
-                "defun"    : do_stat,
-                "if"       : do_stat,
-                "while"    : do_stat,
-                "do"       : do_stat,
-                "for"      : do_stat,
-                "for-in"   : do_stat,
-                "switch"   : do_stat,
-                "with"     : do_stat
-        }, function(){
-                return w.walk(ast);
-        });
-        return pro.gen_code(new_ast, { beautify: true });
-}
-
-
-
-
-////// test code follows.
-
-var code = instrument(test.toString());
-console.log(code);
-
-function test() {
-        // simple stats
-        a = 5;
-        c += a + b;
-        "foo";
-
-        // var
-        var foo = 5;
-        const bar = 6, baz = 7;
-
-        // switch block.  note we can't track case lines the same way.
-        switch ("foo") {
-            case "foo":
-                return 1;
-            case "bar":
-                return 2;
-        }
-
-        // for/for in
-        for (var i = 0; i < 5; ++i) {
-                console.log("Hello " + i);
-        }
-        for (var i in [ 1, 2, 3]) {
-                console.log(i);
-        }
-
-        // note however that the following is broken.  I guess we
-        // should add the block brackets in this case...
-        for (var i = 0; i < 5; ++i)
-                console.log("foo");
-}
diff --git a/node/node_modules/___uglify-js.npm/package/tmp/instrument2.js b/node/node_modules/___uglify-js.npm/package/tmp/instrument2.js
deleted file mode 100644 (file)
index 6aee5f3..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-// sample on how to use the parser and walker API to instrument some code
-
-var jsp = require("uglify-js").parser;
-var pro = require("uglify-js").uglify;
-
-function instrument(code) {
-        var ast = jsp.parse(code, false, true); // true for the third arg specifies that we want
-                                                // to have start/end tokens embedded in the
-                                                // statements
-        var w = pro.ast_walker();
-
-        function trace (line, comment) {
-                var code = pro.gen_code(line, { beautify: true });
-                var data = line[0]
-
-                var args = []
-                if (!comment) comment = ""
-                if (typeof data === "object") {
-                        code = code.split(/\n/).shift()
-                        args = [ [ "string", data.toString() ],
-                                 [ "string", code ],
-                                 [ "num", data.start.line ],
-                                 [ "num", data.start.col ],
-                                 [ "num", data.end.line ],
-                                 [ "num", data.end.col ]]
-                } else {
-                        args = [ [ "string", data ],
-                                 [ "string", code ]]
-
-                }
-                return [ "call", [ "name", "trace" ], args ];
-        }
-
-        // we're gonna need this to push elements that we're currently looking at, to avoid
-        // endless recursion.
-        var analyzing = [];
-        function do_stat() {
-                var ret;
-                if (this[0].start && analyzing.indexOf(this) < 0) {
-                        // without the `analyzing' hack, w.walk(this) would re-enter here leading
-                        // to infinite recursion
-                        analyzing.push(this);
-                        ret = [ "splice",
-                                [ [ "stat", trace(this) ],
-                                  w.walk(this) ]];
-                        analyzing.pop(this);
-                }
-                return ret;
-        }
-
-        function do_cond(c, t, f) {
-                return [ this[0], w.walk(c),
-                         ["seq", trace(t), w.walk(t) ],
-                         ["seq", trace(f), w.walk(f) ]];
-        }
-
-        function do_binary(c, l, r) {
-                if (c !== "&&" && c !== "||") {
-                        return [this[0], c, w.walk(l), w.walk(r)];
-                }
-                return [ this[0], c,
-                         ["seq", trace(l), w.walk(l) ],
-                         ["seq", trace(r), w.walk(r) ]];
-        }
-
-        var new_ast = w.with_walkers({
-                "stat"        : do_stat,
-                "label"       : do_stat,
-                "break"       : do_stat,
-                "continue"    : do_stat,
-                "debugger"    : do_stat,
-                "var"         : do_stat,
-                "const"       : do_stat,
-                "return"      : do_stat,
-                "throw"       : do_stat,
-                "try"         : do_stat,
-                "defun"       : do_stat,
-                "if"          : do_stat,
-                "while"       : do_stat,
-                "do"          : do_stat,
-                "for"         : do_stat,
-                "for-in"      : do_stat,
-                "switch"      : do_stat,
-                "with"        : do_stat,
-                "conditional" : do_cond,
-                "binary"      : do_binary
-        }, function(){
-                return w.walk(ast);
-        });
-        return pro.gen_code(new_ast, { beautify: true });
-}
-
-
-////// test code follows.
-
-var code = instrument(test.toString());
-console.log(code);
-
-function test() {
-        // simple stats
-        a = 5;
-        c += a + b;
-        "foo";
-
-        // var
-        var foo = 5;
-        const bar = 6, baz = 7;
-
-        // switch block.  note we can't track case lines the same way.
-        switch ("foo") {
-            case "foo":
-                return 1;
-            case "bar":
-                return 2;
-        }
-
-        // for/for in
-        for (var i = 0; i < 5; ++i) {
-                console.log("Hello " + i);
-        }
-        for (var i in [ 1, 2, 3]) {
-                console.log(i);
-        }
-
-        for (var i = 0; i < 5; ++i)
-                console.log("foo");
-
-        for (var i = 0; i < 5; ++i) {
-                console.log("foo");
-        }
-
-        var k = plurp() ? 1 : 0;
-        var x = a ? doX(y) && goZoo("zoo")
-              : b ? blerg({ x: y })
-              : null;
-
-        var x = X || Y;
-}
diff --git a/node/node_modules/___uglify-js.npm/package/uglify-js.js b/node/node_modules/___uglify-js.npm/package/uglify-js.js
deleted file mode 100644 (file)
index 4305e23..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-//convienence function(src, [options]);
-function uglify(orig_code, options){
-  options || (options = {});
-  var jsp = uglify.parser;
-  var pro = uglify.uglify;
-
-  var ast = jsp.parse(orig_code, options.strict_semicolons); // parse code and get the initial AST
-  ast = pro.ast_mangle(ast, options.mangle_options); // get a new AST with mangled names
-  ast = pro.ast_squeeze(ast, options.squeeze_options); // get an AST with compression optimizations
-  var final_code = pro.gen_code(ast, options.gen_options); // compressed code here
-  return final_code;
-};
-
-uglify.parser = require("./lib/parse-js");
-uglify.uglify = require("./lib/process");
-
-module.exports = uglify
\ No newline at end of file
index 98b2116f307ffc5a6de5bf5aa4f33db01a7e7fe4..790a98b7313adef01005d9fbd990c9e991a58b24 100644 (file)
@@ -1,4 +1,62 @@
 
+0.15.4 / 2011-09-05 
+==================
+
+  * Fixed script template html. Closes #316
+  * Revert "Fixed script() tag with trailing ".". Closes #314"
+
+0.15.3 / 2011-08-30 
+==================
+
+  * Added Makefile example. Closes #312
+  * Fixed script() tag with trailing ".". Closes #314
+
+0.15.2 / 2011-08-26 
+==================
+
+  * Fixed new conditional boundaries. Closes #307
+
+0.15.1 / 2011-08-26 
+==================
+
+  * Fixed jade(1) support due to `res.render()` removal
+  * Removed --watch support (use a makefile + watch...)
+
+0.15.0 / 2011-08-26 
+==================
+
+  * Added `client` option to reference runtime helpers
+  * Added `Array.isArray()` for runtime.js as well
+  * Added `Object.keys()` for the client-side runtime
+  * Added first-class `if`, `unless`, `else` and `else if` support
+  * Added first-class `each` / `for` support
+  * Added `make benchmark` for continuous-bench
+  * Removed `inline` option, SS helpers are no longer inlined either
+  * Removed `Parser#debug()`
+  * Removed `jade.render()` and `jade.renderFile()`
+  * Fixed runtime.js `escape()` bug causing window.escape to be used
+  * Fixed a bunch of tests
+
+0.14.2 / 2011-08-16 
+==================
+
+  * Added `include` support for non-jade files
+  * Fixed code indentation when followed by newline(s). Closes #295 [reported by masylum]
+
+0.14.1 / 2011-08-14 
+==================
+
+  * Added `colons` option for everyone stuck with ":". Closes #231
+  * Optimization: consecutive lines are merged in compiled js
+
+0.14.0 / 2011-08-08 
+==================
+
+  * Added array iteration with index example. Closes #276
+  * Added _runtime.js_
+  * Added `compileDebug` option to enable lineno instrumentation
+  * Added `inline` option to disable inlining of helpers (for client-side)
+
 0.13.0 / 2011-07-13 
 ==================
 
index 714d3da056f8e2314c3d9f808d848958e7eb438e..ea4d5c6ac6a3daea9a3655c9b0ac03bac440f752 100644 (file)
@@ -3,17 +3,15 @@ TESTS = test/*.js
 SRC = $(shell find lib -name "*.js" -type f)
 UGLIFY_FLAGS = --no-mangle 
 
+all: jade.min.js runtime.min.js
+
 test:
        @./node_modules/.bin/expresso \
                -I node_modules \
                $(TESTS)
 
 benchmark:
-       @node benchmarks/jade.js \
-        && node benchmarks/jade-self.js \
-        && node benchmarks/haml.js \
-        && node benchmarks/haml2.js \
-        && node benchmarks/ejs.js
+       @node support/benchmark
 
 jade.js: $(SRC)
        @node support/compile.js $^
@@ -23,8 +21,18 @@ jade.min.js: jade.js
                && du jade.min.js \
                && du jade.js
 
+runtime.js: lib/runtime.js
+       @cat support/head.js $< support/foot.js > $@
+
+runtime.min.js: runtime.js
+       @uglifyjs $(UGLIFY_FLAGS) $< > $@ \
+         && du runtime.min.js \
+         && du runtime.js
+
 clean:
        rm -f jade.js
        rm -f jade.min.js
+       rm -f runtime.js
+       rm -f runtime.min.js
 
 .PHONY: test benchmark clean
index c70f81b97b8d0aa94e15cdf3dc74d5029e7316f5..fd5c42cee9cd6239e4fcdb14ff6893c6ae380467 100644 (file)
@@ -1,4 +1,3 @@
-
 # Jade - template engine
 
  Jade is a high performance template engine heavily influenced by [Haml](http://haml-lang.com)
@@ -21,7 +20,7 @@
   - combine dynamic and static tag classes
   - parse tree manipulation via _filters_
   - supports [Express JS](http://expressjs.com) out of the box
-  - transparent iteration over objects, arrays, and even non-enumerables via `each`
+  - transparent iteration over objects, arrays, and even non-enumerables via `each`
   - block comments
   - no tag prefix
   - AST filters
@@ -54,37 +53,60 @@ via npm:
  
     $ make jade.js
 
- Alternatively, if uglifyjs is installed via npm (`npm install uglify-js`) you may execute the following which will create both files.
+ Alternatively, if uglifyjs is installed via npm (`npm install uglify-js`) you may execute the following which will create both files. However each release builds these for you.
  
     $ make jade.min.js
 
+  By default Jade instruments templates with line number statements such as `__.lineno = 3` for debugging purposes. When used in a browser it's useful to minimize this boiler plate, you can do so by passing the option `{ compileDebug: false }`. The following template
+  
+    p Hello #{name}
+
+ Can then be as small as the following generated function:
+
+```js
+function anonymous(locals, attrs, escape, rethrow) {
+  var buf = [];
+  with (locals || {}) {
+    var interp;
+    buf.push('\n<p>Hello ' + escape((interp = name) == null ? '' : interp) + '\n</p>');
+  }
+  return buf.join("");
+}
+```
+
+  Through the use of Jade's `./runtime.js` you may utilize these pre-compiled templates on the client-side _without_ Jade itself, all you need is the associated utility functions (in runtime.js), which are then available as `jade.attrs`, `jade.escape` etc. To enable this you should pass `{ client: true }` to `jade.compile()` to tell Jade to reference the helper functions
+  via `jade.attrs`, `jade.escape` etc.
+
+```js
+function anonymous(locals, attrs, escape, rethrow) {
+  var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow;
+  var buf = [];
+  with (locals || {}) {
+    var interp;
+    buf.push('\n<p>Hello ' + escape((interp = name) == null ? '' : interp) + '\n</p>');
+  }
+  return buf.join("");
+}
+```
+
 ## Public API
 
 ```javascript
     var jade = require('jade');
 
-    // Render a string
-    jade.render('string of jade', { options: 'here' });
-
-    // Render a file
-    jade.renderFile('path/to/some.jade', { options: 'here' }, function(err, html){
-           // options are optional,
-           // the callback can be the second arg
-    });
-
     // Compile a function
     var fn = jade.compile('string of jade', options);
-    fn.call(scope, locals);
+    fn(locals);
 ```
 
 ### Options
 
- - `scope`     Evaluation scope (`this`)
  - `self`      Use a `self` namespace to hold the locals. _false by default_
  - `locals`    Local variable object
  - `filename`  Used in exceptions, and required when using includes
  - `debug`     Outputs tokens and function body generated
  - `compiler`  Compiler to replace jade's default
+ - `compileDebug`  When `false` no debug instrumentation is compiled
 
 ## Syntax
 
@@ -146,8 +168,7 @@ well cool, but how about large bodies of text:
 renders `<p>foo bar baz rawr.....</p>`
 
 interpolation? yup! both types of text can utilize interpolation,
-if we passed `{ locals: { name: 'tj', email: 'tj@vision-media.ca' }}` to `render()`
-we can do the following:
+if we passed `{ name: 'tj', email: 'tj@vision-media.ca' }` to the compiled function we can do the following:
 
     #user #{name} &lt;#{email}&gt;
 
@@ -216,6 +237,16 @@ outputs:
 
     <p>.</p>
 
+
+It should be noted that text blocks should be doubled escaped.  For example if you desire the following output.
+
+    </p>foo\bar</p>
+
+use:
+
+    p.
+      foo\\bar
+
 ### Comments
 
 Single line comments currently look the same as JavaScript comments,
@@ -305,13 +336,18 @@ Jade currently supports '(' and ')' as attribute delimiters.
 
     a(href='/login', title='View login page') Login
 
+When a value is `undefined` or `null` the attribute is _not_ added,
+so this is fine, it will not compile 'something="null"'.
+
+    div(something=null)
+
 Boolean attributes are also supported:
 
     input(type="checkbox", checked)
 
 Boolean attributes with code will only output the attribute when `true`:
 
-    input(type="checkbox", checked= someValue)
+    input(type="checkbox", checked=someValue)
     
 Multiple lines work too:
 
@@ -343,7 +379,8 @@ we could use regular javascript concatenation:
 
     a(href='/user/' + user.id)= user.name
 
-or we could use jade's interpolation:
+or we could use jade's interpolation, which I added because everyone
+using Ruby or CoffeeScript seems to think this is legal js..:
 
    a(href='/user/#{user.id}')= user.name
 
@@ -352,6 +389,45 @@ allowing you to pass an array such as `bodyClasses = ['user', 'authenticated']`
 
     body(class=bodyClasses)
 
+### HTML
+
+ Inline html is fine, we can use the pipe syntax to 
+ write arbitrary text, in this case some html:
+
+```
+html
+  body
+    | <h1>Title</h1>
+    | <p>foo bar baz</p>
+```
+
+ Or we can use the trailing `.` to indicate to Jade that we
+ only want text in this block, allowing us to omit the pipes:
+
+```
+html
+  body.
+    <h1>Title</h1>
+    <p>foo bar baz</p>
+```
+
+ Both of these examples yield the same result:
+
+```
+<html><body><h1>Title</h1>
+<p>foo bar baz</p>
+</body></html>
+```
+
+ The same rule applies for anywhere you can have text
+ in jade, raw html is fine:
+
+```
+html
+  body
+    h1 User <em>#{name}</em>
+```
+
 ### Doctypes
 
 To add a doctype simply use `!!!`, or `doctype` followed by an optional value:
@@ -471,15 +547,18 @@ you may use `!=`:
 
     p!= aVarContainingMoreHTML
 
-The on exception made in terms of allowing "vanilla" JavaScript, is
-the `- each` token. This takes the form of:
+## Iteration
 
-    - each VAL[, KEY] in OBJ
+ Along with vanilla JavaScript Jade also supports a subset of
+ constructs that allow you to create more designer-friendly templates,
+ one of these constructs is `each`, taking the form:
+
+    each VAL[, KEY] in OBJ
 
 An example iterating over an array:
 
     - var items = ["one", "two", "three"]
-    each item in items
+    each item in items
       li= item
 
 outputs:
@@ -488,28 +567,68 @@ outputs:
     <li>two</li>
     <li>three</li>
 
+iterating an array with index:
+
+    - var items = ["one", "two", "three"]
+    each item, i in items
+      li #{item}: #{i}
+
+outputs:
+
+    <li>one: 0</li>
+    <li>two: 1</li>
+    <li>three: 2</li>
+
 iterating an object's keys and values:
 
     - var obj = { foo: 'bar' }
-    each val, key in obj
+    each val, key in obj
       li #{key}: #{val}
 
 would output `<li>foo: bar</li>`
 
-You can also nest these!
+Internally Jade converts these statements to regular
+JavaScript loops such as `users.forEach(function(user){`,
+so lexical scope and nesting applies as it would with regular
+JavaScript:
 
-    each user in users
-      each role in user.roles
+    each user in users
+      each role in user.roles
         li= role
 
-When a property is undefined, Jade will output an empty string. For example:
+ You may also use `for` if you prefer:
+    for user in users
+      for role in user.roles
+        li= role
+
+## Conditionals
+
+ Jade conditionals are equivalent to those using the code (`-`) prefix,
+ however allow you to ditch parenthesis to become more designer friendly,
+ however keep in mind the expression given is _regular_ JavaScript:
 
-    textarea= user.signature
+    for user in users
+      if user.role == 'admin'
+        p #{user.name} is an admin
+      else
+        p= user.name
 
-when undefined would normally output "undefined" in your html, however recent
-versions of Jade will simply render:
+ is equivalent to the following using vanilla JavaScript literals:
 
-    <textarea></textarea>
+     for user in users
+       - if (user.role == 'admin')
+         p #{user.name} is an admin
+       - else
+         p= user.name
+
+  Jade also provides have `unless` which is equivalent to `if (!(expr))`:
+
+     for user in users
+       unless user.isAnonymous
+         p
+           | Click to view
+           a(href='/users/' + user.id)= user.name 
 
 ## Includes
 
@@ -534,9 +653,7 @@ and the following _layout.jade_:
 
 both includes _includes/head_ and _includes/foot_ are
 read relative to the `filename` option given to _layout.jade_,
-which should be an absolute path to this file, however Express
-and the `renderFile()` method do this for you. Include then parses
-these files, and injects the AST produced to render what you would expect:
+which should be an absolute path to this file, however Express does this for you. Include then parses these files, and injects the AST produced to render what you would expect:
 
 ```html
 <html>
@@ -599,31 +716,132 @@ these files, and injects the AST produced to render what you would expect:
 </div>
 ```
 
-## bin/jade
+## Generated Output
+
+ Suppose we have the following Jade:
+
+```
+- var title = 'yay'
+h1.title #{title}
+p Just an example
+```
+
+ When the `compileDebug` option is not explicitly `false`, Jade
+ will compile the function instrumented with `__.lineno = n;`, which
+ in the event of an exception is passed to `rethrow()` which constructs
+ a useful message relative to the initial Jade input.
+
+```js
+function anonymous(locals) {
+  var __ = { lineno: 1, input: "- var title = 'yay'\nh1.title #{title}\np Just an example", filename: "testing/test.js" };
+  var rethrow = jade.rethrow;
+  try {
+    var attrs = jade.attrs, escape = jade.escape;
+    var buf = [];
+    with (locals || {}) {
+      var interp;
+      __.lineno = 1;
+       var title = 'yay'
+      __.lineno = 2;
+      buf.push('<h1');
+      buf.push(attrs({ "class": ('title') }));
+      buf.push('>');
+      buf.push('' + escape((interp = title) == null ? '' : interp) + '');
+      buf.push('</h1>');
+      __.lineno = 3;
+      buf.push('<p>');
+      buf.push('Just an example');
+      buf.push('</p>');
+    }
+    return buf.join("");
+  } catch (err) {
+    rethrow(err, __.input, __.filename, __.lineno);
+  }
+}
+```
+
+When the `compileDebug` option _is_ explicitly `false`, this instrumentation
+is stripped, which is very helpful for light-weight client-side templates. Combining Jade's options with the `./runtime.js` file in this repo allows you
+to toString() compiled templates and avoid running the entire Jade library on
+the client, increasing performance, and decreasing the amount of JavaScript
+required.
+
+```js
+function anonymous(locals) {
+  var attrs = jade.attrs, escape = jade.escape;
+  var buf = [];
+  with (locals || {}) {
+    var interp;
+    var title = 'yay'
+    buf.push('<h1');
+    buf.push(attrs({ "class": ('title') }));
+    buf.push('>');
+    buf.push('' + escape((interp = title) == null ? '' : interp) + '');
+    buf.push('</h1>');
+    buf.push('<p>');
+    buf.push('Just an example');
+    buf.push('</p>');
+  }
+  return buf.join("");
+}
+```
 
-Output html to _stdout_:
+## Example Makefile
 
-    jade < my.jade > my.html
+  Below is an example Makefile used to compile _pages/*.jade_
+  into _pages/*.html_ files by simply executing `make`.
+```make
+JADE = $(shell find pages/*.jade)
+HTML = $(JADE:.jade=.html)
 
-Generate _examples/*.html_:
+all: $(HTML)
+       
+%.html: %.jade
+       jade < $< > $@
 
-    jade examples/*.jade
+clean:
+       rm -f $(HTML)
+
+.PHONY: clean
+```
 
-Pass options:
+this can be combined with the `watch(1)` command to produce
+a watcher-like behaviour:
+
+     $ watch make
+
+## jade(1)
+
+```
 
-    jade examples/layout.jade --options '{ locals: { title: "foo" }}'
+Usage: jade [options] [dir|file ...]
 
-Usage info:
+Options:
 
-    Usage: jade [options]
-                [path ...]
-                < in.jade > out.jade  
-    Options:
-      -o, --options <str>  JavaScript options object passed
-      -h, --help           Output help information
-      -w, --watch          Watch file(s) or folder(s) for changes and re-compile
-      -v, --version        Output jade version
-      --out <dir>          Output the compiled html to <dir>
+  -h, --help       output usage information
+  -v, --version    output the version number
+  -o, --obj <str>  javascript options object
+  -O, --out <dir>  output the compiled html to <dir>
+
+Examples:
+
+  # translate jade the templates dir
+  $ jade templates
+
+  # create {foo,bar}.html
+  $ jade {foo,bar}.jade
+
+  # jade over stdio
+  $ jade < my.jade > my.html
+
+  # jade over stdio
+  $ echo "h1 Jade!" | jade
+
+  # foo, bar dirs rendering to /tmp
+  $ jade foo bar --out /tmp 
+
+```
 
 ## License 
 
diff --git a/node/node_modules/jade/benchmarks/common.js b/node/node_modules/jade/benchmarks/common.js
deleted file mode 100644 (file)
index f7cb3a9..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var sys = require('sys');
-
-var currentLabel,
-    startTime;
-
-exports.times = 2000;
-
-exports.start = function(label){
-    currentLabel = label;
-    startTime = new Date;
-    sys.print('  - \x1b[33m' + currentLabel + '\x1b[0m: ');
-};
-
-exports.stop = function(){
-    var stopTime = new Date,
-        duration = stopTime - startTime;
-    sys.print(duration + ' ms\n');
-};
-
-exports.locals = {
-    one: 'one',
-    two: 'two',
-    three: 'three',
-    items: Array(200).join('test ').split(' ')
-};
-
-console.log('\nbenchmarking %d times\n', exports.times);
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/ejs.js b/node/node_modules/jade/benchmarks/ejs.js
deleted file mode 100644 (file)
index a872d47..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var bm = require('./common'),
-    ejs = require('./ejs/lib/ejs'),
-    fs = require('fs');
-
-var str = fs.readFileSync(__dirname + '/example.ejs', 'ascii');
-
-var n = bm.times;
-bm.start('ejs compilation');
-while (n--) {
-    ejs.render(str, { locals: bm.locals });
-}
-bm.stop();
-
-var n = bm.times;
-bm.start('ejs execution');
-while (n--) {
-    ejs.render(str, { locals: bm.locals, cache: true, filename: 'example.ejs' });
-}
-bm.stop();
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/ejs/.gitignore b/node/node_modules/jade/benchmarks/ejs/.gitignore
deleted file mode 100644 (file)
index 99a4d6e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# ignore any vim files:
-*.sw[a-z]
-vim/.netrwhist
diff --git a/node/node_modules/jade/benchmarks/ejs/.gitmodules b/node/node_modules/jade/benchmarks/ejs/.gitmodules
deleted file mode 100644 (file)
index 51ea138..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "support/expresso"]
-       path = support/expresso
-       url = http://github.com/visionmedia/expresso.git
diff --git a/node/node_modules/jade/benchmarks/ejs/History.md b/node/node_modules/jade/benchmarks/ejs/History.md
deleted file mode 100644 (file)
index d8307c4..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-
-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/node_modules/jade/benchmarks/ejs/Makefile b/node/node_modules/jade/benchmarks/ejs/Makefile
deleted file mode 100644 (file)
index f971a59..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-
-test:
-       @./support/expresso/bin/expresso -I lib test/*.test.js
-
-.PHONY: test
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/ejs/Readme.md b/node/node_modules/jade/benchmarks/ejs/Readme.md
deleted file mode 100644 (file)
index 85409ab..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-
-# 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
-
-## Example
-
-    <% if (user) { %>
-           <h2><%= user.name %></h2>
-    <% } %>
-
-## 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:
-
-    <h1>{{= title }}</h1>
-
-## 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:
-
-    <p><%=: users | map:'name' | join %></p>
-
-Output:
-
-    <p>Tj, Mape, Guillermo</p>
-
-Render call:
-
-    ejs.render(str, {
-        locals: {
-            users: [
-                { name: 'tj' },
-                { name: 'mape' },
-                { name: 'guillermo' }
-            ]
-        }
-    });
-
-Or perhaps capitalize the first user's name for display:
-
-    <p><%=: users | first | capitalize %></p>
-
-## 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'
-
-## License 
-
-(The MIT License)
-
-Copyright (c) 2009-2010 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
-
-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/node_modules/jade/benchmarks/ejs/benchmark.js b/node/node_modules/jade/benchmarks/ejs/benchmark.js
deleted file mode 100644 (file)
index 7b267e1..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-var ejs = require('./lib/ejs'),
-    str = '<% if (foo) { %><p><%= foo %></p><% } %>',
-    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/node_modules/jade/benchmarks/ejs/examples/list.ejs b/node/node_modules/jade/benchmarks/ejs/examples/list.ejs
deleted file mode 100644 (file)
index d571330..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<% if (names.length) { %>
-  <ul>
-    <% names.forEach(function(name){ %>
-      <li><%= name %></li>
-    <% }) %>
-  </ul>
-<% } %>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/ejs/examples/list.js b/node/node_modules/jade/benchmarks/ejs/examples/list.js
deleted file mode 100644 (file)
index 9cd7168..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-
-/**
- * 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/node_modules/jade/benchmarks/ejs/index.js b/node/node_modules/jade/benchmarks/ejs/index.js
deleted file mode 100644 (file)
index 20bf71a..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-
-module.exports = require('./lib/ejs');
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/ejs/lib/ejs.js b/node/node_modules/jade/benchmarks/ejs/lib/ejs.js
deleted file mode 100644 (file)
index 5c3784c..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-
-/*!
- * EJS
- * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
- * MIT Licensed
- */
-
-/**
- * Module dependencies.
- */
-
-var sys = require('sys')
-  , utils = require('./utils');
-
-/**
- * Library version.
- */
-
-exports.version = '0.3.0';
-
-/**
- * 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 + ')';
-  });
-};
-
-/**
- * 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('"
-  ];
-
-  for (var i = 0, len = str.length; i < len; ++i) {
-    if (str.slice(i, open.length + i) == open) {
-      i += open.length
-  
-      var prefix, postfix;
-      switch (str[i]) {
-        case '=':
-          prefix = "', escape(";
-          postfix = "), '";
-          ++i;
-          break;
-        case '-':
-          prefix = "', ";
-          postfix = ", '";
-          ++i;
-          break;
-        default:
-          prefix = "'); ";
-          postfix = "; buf.push('";
-      }
-
-      var start = i;
-      var end = str.indexOf(close, i);
-      var js = str.substring(i, end);
-      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");
-    } 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 || {};
-  if (options.debug) sys.puts(exports.parse(str));
-  var fn = new Function('locals, filters, escape', exports.parse(str, options));
-  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/node_modules/jade/benchmarks/ejs/lib/filters.js b/node/node_modules/jade/benchmarks/ejs/lib/filters.js
deleted file mode 100644 (file)
index d425c8d..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-
-/*!
- * EJS - Filters
- * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
- * 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/node_modules/jade/benchmarks/ejs/lib/utils.js b/node/node_modules/jade/benchmarks/ejs/lib/utils.js
deleted file mode 100644 (file)
index 8d569d6..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-
-/*!
- * EJS
- * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
- * 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, '&amp;')
-    .replace(/</g, '&lt;')
-    .replace(/>/g, '&gt;')
-    .replace(/"/g, '&quot;');
-};
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/ejs/package.json b/node/node_modules/jade/benchmarks/ejs/package.json
deleted file mode 100644 (file)
index 6b82fce..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "name": "ejs",
-  "description": "Embedded JavaScript templates",
-  "version": "0.3.1",
-  "author": "TJ Holowaychuk <tj@vision-media.ca>",
-  "keywords": ["template", "engine", "ejs"],
-  "main": "./lib/ejs.js"
-}
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/ejs/test/ejs.test.js b/node/node_modules/jade/benchmarks/ejs/test/ejs.test.js
deleted file mode 100644 (file)
index 1f8b614..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var ejs = require('ejs');
-
-module.exports = {
-    'test .version': function(assert){
-        assert.ok(/^\d+\.\d+\.\d+$/.test(ejs.version), 'Test .version format');
-    },
-    
-    'test html': function(assert){
-        assert.equal('<p>yay</p>', ejs.render('<p>yay</p>'));
-    },
-    
-    'test buffered code': function(assert){
-        var html = '<p>tj</p>',
-            str = '<p><%= name %></p>',
-            locals = { name: 'tj' };
-        assert.equal(html, ejs.render(str, { locals: locals }));
-    },
-    
-    'test unbuffered code': function(assert){
-        var html = '<p>tj</p>',
-            str = '<% if (name) { %><p><%= name %></p><% } %>',
-            locals = { name: 'tj' };
-        assert.equal(html, ejs.render(str, { locals: locals }));
-    },
-    
-    'test `scope` option': function(assert){
-        var html = '<p>tj</p>',
-            str = '<p><%= this %></p>';
-        assert.equal(html, ejs.render(str, { scope: 'tj' }));
-    },
-    
-    'test escaping': function(assert){
-        assert.equal('&lt;script&gt;', ejs.render('<%= "<script>" %>'));
-        assert.equal('<script>', ejs.render('<%- "<script>" %>'));
-    },
-    
-    'test newlines': function(assert){
-        var html = '\n<p>tj</p>\n<p>tj@sencha.com</p>',
-            str = '<% if (name) { %>\n<p><%= name %></p>\n<p><%= email %></p><% } %>',
-            locals = { name: 'tj', email: 'tj@sencha.com' };
-        assert.equal(html, ejs.render(str, { locals: locals }));
-    },
-    
-    'test single quotes': function(assert){
-        var html = '<p>WAHOO</p>',
-            str = "<p><%= up('wahoo') %></p>",
-            locals = { up: function(str){ return str.toUpperCase(); }};
-        assert.equal(html, ejs.render(str, { locals: locals }));
-    },
-
-    'test single quotes in the html': function(assert){
-        var html = '<p>WAHOO that\'s cool</p>',
-            str = '<p><%= up(\'wahoo\') %> that\'s cool</p>',
-            locals = { up: function(str){ return str.toUpperCase(); }};
-        assert.equal(html, ejs.render(str, { locals: locals }));
-    },
-
-    'test multiple single quotes': function(assert) {
-        var html = "<p>couldn't shouldn't can't</p>",
-            str = "<p>couldn't shouldn't can't</p>";
-        assert.equal(html, ejs.render(str));
-    },
-
-    'test single quotes inside tags': function(assert) {
-        var html = '<p>string</p>',
-            str = "<p><%= 'string' %></p>";
-        assert.equal(html, ejs.render(str));
-    },
-
-    'test back-slashes in the document': function(assert) {
-        var html = "<p>backslash: '\\'</p>",
-            str = "<p>backslash: '\\'</p>";
-        assert.equal(html, ejs.render(str));
-    },
-    
-    'test double quotes': function(assert){
-        var html = '<p>WAHOO</p>',
-            str = '<p><%= up("wahoo") %></p>',
-            locals = { up: function(str){ return str.toUpperCase(); }};
-        assert.equal(html, ejs.render(str, { locals: locals }));
-    },
-    
-    'test multiple double quotes': function(assert) {
-        var html = '<p>just a "test" wahoo</p>',
-            str = '<p>just a "test" wahoo</p>';
-        assert.equal(html, ejs.render(str));
-    },
-    
-    'test whitespace': function(assert){
-        var html = '<p>foo</p>',
-            str = '<p><%="foo"%></p>';
-        assert.equal(html, ejs.render(str));
-
-        var html = '<p>foo</p>',
-            str = '<p><%=bar%></p>';
-        assert.equal(html, ejs.render(str, { locals: { bar: 'foo' }}));
-    },
-    
-    'test custom tags': function(assert){
-        var html = '<p>foo</p>',
-            str = '<p>{{= "foo" }}</p>';
-
-        assert.equal(html, ejs.render(str, {
-            open: '{{',
-            close: '}}'
-        }));
-
-        var html = '<p>foo</p>',
-            str = '<p><?= "foo" ?></p>';
-
-        assert.equal(html, ejs.render(str, {
-            open: '<?',
-            close: '?>'
-        }));
-    },
-
-    'test custom tags over 2 chars': function(assert){
-        var html = '<p>foo</p>',
-            str = '<p>{{{{= "foo" }>>}</p>';
-
-        assert.equal(html, ejs.render(str, {
-            open: '{{{{',
-            close: '}>>}'
-        }));
-
-        var html = '<p>foo</p>',
-            str = '<p><??= "foo" ??></p>';
-
-        assert.equal(html, ejs.render(str, {
-            open: '<??',
-            close: '??>'
-        }));
-    },
-    
-    'test global custom tags': function(assert){
-        var html = '<p>foo</p>',
-            str = '<p>{{= "foo" }}</p>';
-        ejs.open = '{{';
-        ejs.close = '}}';
-        assert.equal(html, ejs.render(str));
-        delete ejs.open;
-        delete ejs.close;
-    },
-    
-    'test iteration': function(assert){
-        var html = '<p>foo</p>',
-            str = '<% for (var key in items) { %>'
-                + '<p><%= items[key] %></p>'
-                + '<% } %>';
-        assert.equal(html, ejs.render(str, {
-            locals: {
-                items: ['foo']
-            }
-        }));
-        
-        var html = '<p>foo</p>',
-            str = '<% items.forEach(function(item){ %>'
-                + '<p><%= item %></p>'
-                + '<% }) %>';
-        assert.equal(html, ejs.render(str, {
-            locals: {
-                items: ['foo']
-            }
-        }));
-    },
-    
-    'test filter support': function(assert){
-        var html = 'Zab',
-            str = '<%=: items | reverse | first | reverse | capitalize %>';
-        assert.equal(html, ejs.render(str, {
-            locals: {
-                items: ['foo', 'bar', 'baz']
-            }
-        }));
-    },
-    
-    'test filter argument support': function(assert){
-        var html = 'tj, guillermo',
-            str = '<%=: users | map:"name" | join:", " %>';
-        assert.equal(html, ejs.render(str, {
-            locals: {
-                users: [
-                    { name: 'tj' },
-                    { name: 'guillermo' }
-                ]
-            }
-        }));
-    },
-    
-    'test sort_by filter': function(assert){
-        var html = 'tj',
-            str = '<%=: users | sort_by:"name" | last | get:"name" %>';
-        assert.equal(html, ejs.render(str, {
-            locals: {
-                users: [
-                    { name: 'guillermo' },
-                    { name: 'tj' },
-                    { name: 'mape' }
-                ]
-            }
-        }));
-    },
-    
-    'test custom filters': function(assert){
-        var html = 'Welcome Tj Holowaychuk',
-            str = '<%=: users | first | greeting %>';
-
-        ejs.filters.greeting = function(user){
-            return 'Welcome ' + user.first + ' ' + user.last + '';
-        };
-
-        assert.equal(html, ejs.render(str, {
-            locals: {
-                users: [
-                    { first: 'Tj', last: 'Holowaychuk' }
-                ]
-            }
-        }));
-    }
-};
diff --git a/node/node_modules/jade/benchmarks/example-self.jade b/node/node_modules/jade/benchmarks/example-self.jade
deleted file mode 100644 (file)
index f157aa8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-ul
-  li!= self.one
-  li!= self.two
-  li!= self.three
-  - each item in self.items
-    li!= item
diff --git a/node/node_modules/jade/benchmarks/example.ejs b/node/node_modules/jade/benchmarks/example.ejs
deleted file mode 100644 (file)
index 626bbcd..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<ul>
-    <li><%- one %></li>
-    <li><%- two %></li>
-    <li><%- three %></li>
-    <% items.forEach(function(item){ %>
-      <li><%- item %></li>
-    <% }) %>
-</ul>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/example.haml b/node/node_modules/jade/benchmarks/example.haml
deleted file mode 100644 (file)
index 6cbe583..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-%ul
-  %li= one
-  %li= two
-  %li= three
-  :each item in items
-    %li= item
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/example.jade b/node/node_modules/jade/benchmarks/example.jade
deleted file mode 100644 (file)
index e561512..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-ul
-  li!= one
-  li!= two
-  li!= three
-  - each item in items
-    li!= item
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/example2.haml b/node/node_modules/jade/benchmarks/example2.haml
deleted file mode 100644 (file)
index 236e790..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-%ul
-  %li!= one
-  %li!= two
-  %li!= three
-  - each item in items
-    %li!= item
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/CHANGELOG.markdown b/node/node_modules/jade/benchmarks/haml-js/CHANGELOG.markdown
deleted file mode 100644 (file)
index 3247a67..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-# HAML-JS Changelog
-
-- **v0.2.5** - *2010-05-06* - NPM support
-
-  Fixed to work with Node Package Manager
-
-- **v0.2.4** - *2010-04-16* - Bug fixes, XML support
-
-  Allow for commas in calls to helpers in attributes.  Also make haml more XML friendly.
-
-- **v0.2.3** - *2010-04-10* - Bug fixes
-
-  Fixed an issue where "content" html attributes got munched. (This broke meta tags)
-
-- **v0.2.2** - *2010-04-05* - Bug fixes
-
-  Fixed two issues where the parser incorrectly parsed blank lines and extra spaces in attribute blocks.
-
-- **v0.2.1** - *2010-04-01* - Minor speed tweak
-
-  `Haml()` now caches the eval step so that there is no eval in executing a compiled template.  This should make things a bit faster.
-
-- **v0.2.0** - *2010-03-31* - Function based API, Safe whitespace, Code interpolation.
-
-  At the request of some users, I've removed the new insertion into the generated html.  This means that most html will be on one long line, but as an added advantage you won't have that extra whitespace next to your anchor labels messing up your visual display.
-  
-  Also I added string interpolation to every place I could fit it.  This means you can do crazy stuff like interpolate within strings in attributes, in the body on plain text sections, and of course in javascript and css plugin blocks.
-  
-  In order to tame the API, I deprecated the four old interfaces `compile`, `optimize`, `execute` and `render`.  The new API is that the Haml/exports object itself is now a function that takes in haml text and outputs a compiled, optimized, ready to execute function.
-
-- **0.1.2** - *2010-02-03* - Bug fixes, plugin aliases, CommonJS, and more...
-
-  This is a big release with many improvements.  First haml-js is now a CommonJS module and is in the Tusk repository.  Thanks to Tom Robinson for helping with that.  Some of the plugins got aliases for people who didn't like the original name.  For example, you can now do `:javascript` instead of `:script` and `:for` instead of `:each`.  There were many bug fixes now that the code is starting to be actually used by myself and others.
-
-- **0.1.1** - *2010-01-09* - Add :css and :script plugins
-
-  Added two quick plugins that make working with javascript and css much easier.
-
- - **0.1.0** - *2010-01-09* - Complete Rewrite
-
-   Rewrote the compiler to be recursive and compile to JavaScript code instead of JSON data structures.  This fixes all the outstanding bugs and simplifies the code.  Pending is restoring the `:script` and `:css` plugins.
-
- - **0.0.1** - *2009-12-16* - Initial release
-
-   Change how haml is packaged. It is a pure JS function with no node dependencies. There is an exports hook for commonjs usability. It's now the responsibility of the script user to acquire the haml text.
-
-
diff --git a/node/node_modules/jade/benchmarks/haml-js/LICENSE b/node/node_modules/jade/benchmarks/haml-js/LICENSE
deleted file mode 100644 (file)
index ad2a669..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Copyright (c) 2009 Tim Caswell
-
-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/node_modules/jade/benchmarks/haml-js/README.markdown b/node/node_modules/jade/benchmarks/haml-js/README.markdown
deleted file mode 100644 (file)
index acbbb3c..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-# haml-js - Server side templating language for JavaScript
-
-Ever wanted to use the excellent HAML syntax on a javascript project?  Me too, so I made one!.  This has most of the same functionality as the traditional [haml][].
-
-## About the language
-
-Here is the first example(with a little extra added) from the [haml][] site converted to haml-js:
-
-**haml-js**
-
-    !!! XML
-    !!! strict
-    %html{ xmlns: "http://www.w3.org/1999/xhtml" }
-      %head
-        %title Sample haml template
-      %body
-        .profile
-          .left.column
-            #date= print_date()
-            #address= current_user.address
-          .right.column
-            #email= current_user.email
-            #bio= current_user.bio
-
-**html**
-
-    <?xml version='1.0' encoding='utf-8' ?>
-    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-    <html xmlns="http://www.w3.org/1999/xhtml"><head><title>Sample haml template
-    </title></head><body><div class="profile"><div class="left column"><div id="date">January 1, 2009
-    </div><div id="address">Richardson, TX
-    </div></div><div class="right column"><div id="email">tim@creationix.com
-    </div><div id="bio">Experienced software professional...
-    </div></div></div></body></html>
-
-Note that this works almost the same as ruby's [haml][], but doesn't pretty print the html.  This would greatly slow down and complicate the code.  If you really want pretty printed html, then I suggest writing one using the xml parser library and process the resulting html..
-
-## API
-
-### Haml(haml) -> template(locals) -> html
-
-This is the new (as of 0.2.0) way to generate haml templates.  A haml template is a live function that takes in "this" context and a "locals" variable.  This compile step takes a few milliseconds to complete so it should be done at startup and the resulting function should be cached.  Then to use the template function you simply call it with the desired local variables and it will output html at blazing speeds (we're talking millions per second on my 13" MBP)
-
-Compile and store a template:
-
-    var main = Haml(main_haml);
-
-Then use it whenever you need a new version:
-
-    main({name: "Tim", age: 28});
-
-That's it. Haml templating made easy!
-
-If you want to store the generated javascript to a file to skip the compile step later on you can either decompile the template function or use the `compile` and `optimize` advanced functions directly.
-
-
-### Haml.compile(text) -> JavaScript compiled template
-
-Given a haml template as raw text, this compiles it to a javascript expression
-that can later be eval'ed to get the final HTML.
-
-The following input:
-
-    #home
-      = title
-      %ul.menu
-        %li Go Home
-        %li Go Back
-
-Produces the following JavaScript expression:
-
-    "<div id=\"home\">" + 
-    title +
-    "\n" + 
-    "<ul class=\"menu\">" + 
-    "<li>" + 
-    "Go Home\n" + 
-    "</li>" + 
-    "<li>" + 
-    "Go Back\n" + 
-    "</li>" + 
-    "</ul>" + 
-    "</div>"
-
-### Haml.optimize(js) -> optimized JavaScript expression
-
-Takes the output of compile and optimizes it to run faster with the tradeoff of longer compile time.  This is useful for framework developers wanting to use haml in their framework and want to cache the compiled templates for performance.
-
-With the previous input it outputs:
-
-    "<div id=\"home\">" + 
-    title +
-    "\n<ul class=\"menu\"><li>Go Home\n</li><li>Go Back\n</li></ul></div>"
-
-Notice how congruent static strings are merged into a single string literal when possible.
-
-### Haml.execute(js, context, locals) -> Executes a compiles template
-
-Context is the value of `this` in the template, and locals is a hash of local variables.
-
-### Haml.render(text, options) -> html text
-
-This is a convenience function that compiles and executes to html in one shot.  Most casual users will want to use this function exclusively.
-
-The `text` parameter is the haml source already read from a file.
-
-The three recognized `options` are:
-
- - **context**: This is the `this` context within the haml template.
- - **locals**: This is an object that's used in the `with` scope.  Basically it creates local variables and function accessible to the haml template.
- - **optimize**: This is a flag to tell the compiler to use the extra optimizations.
-See [test.js][] for an example usage of Haml.render
-
-## Code interpolation
-
-New in version 0.2.0 there is string interpolation throughout.  This means that the body of regular text areas can have embedded code.  This is true for attributes and the contents of plugins like javascript and markdown also.  If you notice an area that doesn't support interpolation and it should then send me a note and I'll add it.
-
-## Plugins
-
-There are plugins in the parser for things like inline script tags, css blocks, and support for if statements and for loops.
-
-### `:if` statements
-
-`if` statements evaluate a condition for truthiness (as opposed to a strict comparison to `true`) and includes the content inside the block if it's truthy.
-
-    :if todolist.length > 20
-      %p Oh my, you are a busy fellow!
-
-### `:each` loops
-
-`:each` loops allow you to loop over a collection including a block of content once for each item. You need to what variable to pull the data from and where to put the index and value.  The index variable is optional and defaults to `__key__`.
-
-Here is an example over a simple array.
-
-    %ul.todolist
-      :each item in todolist
-        %li= item.description
-
-You can loop over the keys and values of objects too (Note the inner `:each` loop)
-
-    :each item in data
-      :if item.age < 100
-        %dl
-          :each name, value in item
-            %dt&= name
-            %dd&= value
-
-### `:css` and `:javascript` helpers.
-
-It's easy to embed javascript and css blocks in an haml document.
-
-    %head
-      :javascript
-        function greet(message) {
-          alert("Message from MCP: " + message);
-        }
-      %title Script and Css test
-      :css
-        body {
-          color: pink;
-        }
-    %body{ onload: "greet(\"I'm Pink\")" } COLOR ME PINK
-
-This compiles to the following HTML:
-
-    <head>
-    <script type="text/javascript">
-    //<![CDATA[
-      function greet(message) {
-        alert("Message from MCP: " + message);
-      }
-    //]]>
-    </script>
-    <title>Script and Css test
-    </title>
-    <style type="text/css">
-      body {
-        color: pink;
-      }
-    </style>
-    </head><body onload="greet(&quot;I'm Pink&quot;)"> COLOR ME PINK
-    </body>
-
-## Get Involved
-
-If you want to use this project and something is missing then send me a message.  I'm very busy and have several open source projects I manage.  I'll contribute to this project as I have time, but if there is more interest for some particular aspect, I'll work on it a lot faster.  Also you're welcome to fork this project and send me patches/pull-requests.
-
-## About Performance
-
-The haml compiler isn't built for speed, it's built for maintainability.  The actual generated templates, however are blazing fast.  I benchmarked them with over 65 million renders per second on a small (20 line) template with some dynamic data on my laptop.  Compare this to the 629 compiles per second I got out of the compiler.  The idea is that you pre-compile your templates and reuse them on every request.  While 629 per second is nothing compared to 65 million, that still means that your server with over 600 different views can boot up in about a second.  I think that's fine for something that only happens every few weeks.
-
-## License
-
-Haml-js is [licensed][] under the [MIT license][].
-
-[MIT license]: http://creativecommons.org/licenses/MIT/
-[licensed]: http://github.com/creationix/haml-js/blob/master/LICENSE
-[jquery-haml]: http://github.com/creationix/jquery-haml
-[haml]: http://haml-lang.com/
-[test.js]: http://github.com/creationix/haml-js/blob/master/test/test.js
-
-
diff --git a/node/node_modules/jade/benchmarks/haml-js/lib/haml.js b/node/node_modules/jade/benchmarks/haml-js/lib/haml.js
deleted file mode 100755 (executable)
index b5ec4d3..0000000
+++ /dev/null
@@ -1,506 +0,0 @@
-var Haml;
-
-(function () {
-
-  var matchers, self_close_tags, embedder, forceXML;
-
-  function html_escape(text) {
-    return (text + "").
-      replace(/&/g, "&amp;").
-      replace(/</g, "&lt;").
-      replace(/>/g, "&gt;").
-      replace(/\"/g, "&quot;");
-  }
-
-  function render_attribs(attribs) {
-    var key, value, result = [];
-    for (key in attribs) {
-      if (key !== '_content' && attribs.hasOwnProperty(key)) {
-        switch (attribs[key]) {
-        case 'undefined':
-        case 'false':
-        case 'null':
-        case '""':
-          break;
-        default:
-          try {
-            value = JSON.parse("[" + attribs[key] +"]")[0];
-            if (value === true) {
-              value = key;
-            } else if (typeof value === 'string' && embedder.test(value)) {
-              value = '" +\n' + parse_interpol(html_escape(value)) + ' +\n"';
-            } else {
-              value = html_escape(value);
-            }
-            result.push(" " + key + '=\\"' + value + '\\"');
-          } catch (e) {
-            result.push(" " + key + '=\\"" + html_escape(' + attribs[key] + ') + "\\"');
-          }
-        }
-      }
-    }
-    return result.join("");
-  }
-
-  // Parse the attribute block using a state machine
-  function parse_attribs(line) {
-    var attributes = {},
-        l = line.length,
-        i, c,
-        count = 1,
-        quote = false,
-        skip = false,
-        open, close, joiner, seperator,
-        pair = {
-          start: 1,
-          middle: null,
-          end: null
-        };
-
-    if (!(l > 0 && (line.charAt(0) === '{' || line.charAt(0) === '('))) {
-      return {
-        _content: line[0] === ' ' ? line.substr(1, l) : line
-      };
-    }
-    open = line.charAt(0);
-    close = (open === '{') ? '}' : ')';
-    joiner = (open === '{') ? ':' : '=';
-    seperator = (open === '{') ? ',' : ' ';
-
-    function process_pair() {
-      if (typeof pair.start === 'number' &&
-          typeof pair.middle === 'number' &&
-          typeof pair.end === 'number') {
-        var key = line.substr(pair.start, pair.middle - pair.start).trim(),
-            value = line.substr(pair.middle + 1, pair.end - pair.middle - 1).trim();
-        attributes[key] = value;
-      }
-      pair = {
-        start: null,
-        middle: null,
-        end: null
-      };
-    }
-
-    for (i = 1; count > 0; i += 1) {
-
-      // If we reach the end of the line, then there is a problem
-      if (i > l) {
-        throw "Malformed attribute block";
-      }
-
-      c = line.charAt(i);
-      if (skip) {
-        skip = false;
-      } else {
-        if (quote) {
-          if (c === '\\') {
-            skip = true;
-          }
-          if (c === quote) {
-            quote = false;
-          }
-        } else {
-          if (c === '"' || c === "'") {
-            quote = c;
-          }
-
-          if (count === 1) {
-            if (c === joiner) {
-              pair.middle = i;
-            }
-            if (c === seperator || c === close) {
-              pair.end = i;
-              process_pair();
-              if (c === seperator) {
-                pair.start = i + 1;
-              }
-            }
-          }
-
-          if (c === open || c === "(") {
-            count += 1;
-          }
-          if (c === close || (count > 1 && c === ")")) {
-            count -= 1;
-          }
-        }
-      }
-    }
-    attributes._content = line.substr(i, line.length);
-    return attributes;
-  }
-
-  // Split interpolated strings into an array of literals and code fragments.
-  function parse_interpol(value) {
-    var items = [],
-        pos = 0,
-        next = 0,
-        match;
-    while (true) {
-      // Match up to embedded string
-      next = value.substr(pos).search(embedder);
-      if (next < 0) {
-        if (pos < value.length) {
-          items.push(JSON.stringify(value.substr(pos)));
-        }
-        break;
-      }
-      items.push(JSON.stringify(value.substr(pos, next)));
-      pos += next;
-
-      // Match embedded string
-      match = value.substr(pos).match(embedder);
-      next = match[0].length;
-      if (next < 0) { break; }
-      items.push(match[1] || match[2]);
-      pos += next;
-    }
-    return items.filter(function (part) { return part && part.length > 0}).join(" +\n");
-  }
-
-  // Used to find embedded code in interpolated strings.
-  embedder = /\#\{([^}]*)\}/;
-
-  self_close_tags = ["meta", "img", "link", "br", "hr", "input", "area", "base"];
-
-  // All matchers' regexps should capture leading whitespace in first capture
-  // and trailing content in last capture
-  matchers = [
-    // html tags
-    {
-      regexp: /^(\s*)((?:[.#%][a-z_\-][a-z0-9_:\-]*)+)(.*)$/i,
-      process: function () {
-        var tag, classes, ids, attribs, content;
-        tag = this.matches[2];
-        classes = tag.match(/\.([a-z_\-][a-z0-9_\-]*)/gi);
-        ids = tag.match(/\#([a-z_\-][a-z0-9_\-]*)/gi);
-        tag = tag.match(/\%([a-z_\-][a-z0-9_:\-]*)/gi);
-
-        // Default to <div> tag
-        tag = tag ? tag[0].substr(1, tag[0].length) : 'div';
-
-        attribs = this.matches[3];
-        if (attribs) {
-          attribs = parse_attribs(attribs);
-          if (attribs._content) {
-            this.contents.unshift(attribs._content.trim());
-            delete(attribs._content);
-          }
-        } else {
-          attribs = {};
-        }
-
-        if (classes) {
-          classes = classes.map(function (klass) {
-            return klass.substr(1, klass.length);
-          }).join(' ');
-          if (attribs['class']) {
-            try {
-              attribs['class'] = JSON.stringify(classes + " " + JSON.parse(attribs['class']));
-            } catch (e) {
-              attribs['class'] = JSON.stringify(classes + " ") + " + " + attribs['class'];
-            }
-          } else {
-            attribs['class'] = JSON.stringify(classes);
-          }
-        }
-        if (ids) {
-          ids = ids.map(function (id) {
-            return id.substr(1, id.length);
-          }).join(' ');
-          if (attribs.id) {
-            attribs.id = JSON.stringify(ids + " ") + attribs.id;
-          } else {
-            attribs.id = JSON.stringify(ids);
-          }
-        }
-
-        attribs = render_attribs(attribs);
-
-        content = this.render_contents();
-        if (content === '""') {
-          content = '';
-        }
-
-        if (forceXML ? content.length > 0 : self_close_tags.indexOf(tag) == -1) {
-          return '"<' + tag + attribs + '>"' +
-            (content.length > 0 ? ' + \n' + content : "") +
-            ' + \n"</' + tag + '>"';
-        } else {
-          return '"<' + tag + attribs + ' />"';
-        }
-      }
-    },
-
-    // each loops
-    {
-      regexp: /^(\s*)(?::for|:each)\s+(?:([a-z_][a-z_\-]*),\s*)?([a-z_][a-z_\-]*)\s+in\s+(.*)(\s*)$/i,
-      process: function () {
-        var ivar = this.matches[2] || '__key__', // index
-            vvar = this.matches[3],              // value
-            avar = this.matches[4],              // array
-            rvar = '__result__';                 // results
-
-        if (this.matches[5]) {
-          this.contents.unshift(this.matches[5]);
-        }
-        return '(function () { ' +
-          'var ' + rvar + ' = [], ' + ivar + ', ' + vvar + '; ' +
-          'for (' + ivar + ' in ' + avar + ') { ' +
-          'if (' + avar + '.hasOwnProperty(' + ivar + ')) { ' +
-          vvar + ' = ' + avar + '[' + ivar + ']; ' +
-          rvar + '.push(\n' + (this.render_contents() || "''") + '\n); ' +
-          '} } return ' + rvar + '.join(""); }).call(this)';
-      }
-    },
-
-    // if statements
-    {
-      regexp: /^(\s*):if\s+(.*)\s*$/i,
-      process: function () {
-        var condition = this.matches[2];
-        return '(function () { ' +
-          'if (' + condition + ') { ' +
-          'return (\n' + (this.render_contents() || '') + '\n);' +
-          '} else { return ""; } }).call(this)';
-      }
-    },
-
-    // declarations
-    {
-      regexp: /^()!!!(?:\s*(.*))\s*$/,
-      process: function () {
-        var line = '';
-        switch ((this.matches[2] || '').toLowerCase()) {
-        case '':
-          // XHTML 1.0 Transitional
-          line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
-          break;
-        case 'strict':
-        case '1.0':
-          // XHTML 1.0 Strict
-          line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
-          break;
-        case 'frameset':
-          // XHTML 1.0 Frameset
-          line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">';
-          break;
-        case '5':
-          // XHTML 5
-          line = '<!DOCTYPE html>';
-          break;
-        case '1.1':
-          // XHTML 1.1
-          line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';
-          break;
-        case 'basic':
-          // XHTML Basic 1.1
-          line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">';
-          break;
-        case 'mobile':
-          // XHTML Mobile 1.2
-          line = '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">';
-          break;
-        case 'xml':
-          // XML
-          line = "<?xml version='1.0' encoding='utf-8' ?>";
-          break;
-        case 'xml iso-8859-1':
-          // XML iso-8859-1
-          line = "<?xml version='1.0' encoding='iso-8859-1' ?>";
-          break;
-        }
-        return JSON.stringify(line + "\n");
-      }
-    },
-
-    // Embedded markdown. Needs to be added to exports externally.
-    {
-      regexp: /^(\s*):markdown\s*$/i,
-      process: function () {
-        return parse_interpol(exports.Markdown.encode(this.contents.join("\n")));
-      }
-    },
-
-    // script blocks
-    {
-      regexp: /^(\s*):(?:java)?script\s*$/,
-      process: function () {
-        return parse_interpol('\n<script type="text/javascript">\n' +
-          '//<![CDATA[\n' +
-          this.contents.join("\n") +
-          "\n//]]>\n</script>\n");
-      }
-    },
-
-    // css blocks
-    {
-      regexp: /^(\s*):css\s*$/,
-      process: function () {
-        return JSON.stringify('\n<style type="text/css">\n' +
-          this.contents.join("\n") +
-          "\n</style>\n");
-      }
-    },
-
-  ];
-
-  function compile(lines) {
-    var block = false,
-        output = [];
-
-    // If lines is a string, turn it into an array
-    if (typeof lines === 'string') {
-      lines = lines.trim().split("\n");
-    }
-
-    lines.forEach(function(line) {
-      var match, found = false;
-
-      // Collect all text as raw until outdent
-      if (block) {
-        match = block.check_indent(line);
-        if (match) {
-          block.contents.push(match[1] || "");
-          return;
-        } else {
-          output.push(block.process());
-          block = false;
-        }
-      }
-
-      matchers.forEach(function (matcher) {
-        if (!found) {
-          match = matcher.regexp(line);
-          if (match) {
-            block = {
-              contents: [],
-              matches: match,
-              check_indent: new RegExp("^(?:\\s*|" + match[1] + "  (.*))$"),
-              process: matcher.process,
-              render_contents: function () {
-                return compile(this. contents);
-              }
-            };
-            found = true;
-          }
-        }
-      });
-
-      // Match plain text
-      if (!found) {
-        output.push(function () {
-          // Escaped plain text
-          if (line[0] === '\\') {
-            return parse_interpol(line.substr(1, line.length));
-          }
-
-          // Plain variable data
-          if (line[0] === '=') {
-            line = line.substr(1, line.length).trim();
-            try {
-              return parse_interpol(JSON.parse(line));
-            } catch (e) {
-              return line;
-            }
-          }
-
-          // HTML escape variable data
-          if (line.substr(0, 2) === "&=") {
-            line = line.substr(2, line.length).trim();
-            try {
-              return JSON.stringify(html_escape(JSON.parse(line)));
-            } catch (e2) {
-              return 'html_escape(' + line + ')';
-            }
-          }
-
-          // Plain text
-          return parse_interpol(line);
-        }());
-      }
-
-    });
-    if (block) {
-      output.push(block.process());
-    }
-    return output.filter(function (part) { return part && part.length > 0}).join(" +\n");
-  };
-
-  function optimize(js) {
-    var new_js = [], buffer = [], part, end;
-
-    function flush() {
-      if (buffer.length > 0) {
-        new_js.push(JSON.stringify(buffer.join("")) + end);
-        buffer = [];
-      }
-    }
-    js.split("\n").forEach(function (line) {
-      part = line.match(/^(\".*\")(\s*\+\s*)?$/);
-      if (!part) {
-        flush();
-        new_js.push(line);
-        return;
-      }
-      end = part[2] || "";
-      part = part[1];
-      try {
-        buffer.push(JSON.parse(part));
-      } catch (e) {
-        flush();
-        new_js.push(line);
-      }
-    });
-    flush();
-    return new_js.join("\n");
-  };
-
-  function render(text, options) {
-    options = options || {};
-    text = text || "";
-    var js = compile(text);
-    if (options.optimize) {
-      js = Haml.optimize(js);
-    }
-    return execute(js, options.context || Haml, options.locals);
-  };
-
-  function execute(js, self, locals) {
-    return (function () {
-      with(locals || {}) {
-        try {
-          return eval("(" + js + ")");
-        } catch (e) {
-          return "\n<pre class='error'>" + html_escape(e.stack) + "</pre>\n";
-        }
-
-      }
-    }).call(self);
-  };
-
-  Haml = function Haml(haml, xml) {
-    forceXML = xml;
-    var js = optimize(compile(haml));
-    return new Function("locals",
-      html_escape + "\n" +
-      "with(locals || {}) {\n" +
-      "  try {\n" +
-      "    return (" + js + ");\n" +
-      "  } catch (e) {\n" +
-      "    return \"\\n<pre class='error'>\" + html_escape(e.stack) + \"</pre>\\n\";\n" +
-      "  }\n" +
-      "}");
-  }
-  Haml.compile = compile;
-  Haml.optimize = optimize;
-  Haml.render = render;
-  Haml.execute = execute;
-
-}());
-
-// Hook into module system
-if (typeof module !== 'undefined') {
-  module.exports = Haml;
-}
diff --git a/node/node_modules/jade/benchmarks/haml-js/package.json b/node/node_modules/jade/benchmarks/haml-js/package.json
deleted file mode 100644 (file)
index e08678b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "name": "haml",
-    "description": "Haml ported to server-side Javascript. This is a traditional server-side templating language.",
-    "keywords": ["haml", "template"],
-    "main" : "./lib/haml",
-    "author": "Tim Caswell <tim@creationix.com>",
-    "version": "0.2.5"
-}
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/alt_attribs.haml b/node/node_modules/jade/benchmarks/haml-js/test/alt_attribs.haml
deleted file mode 100644 (file)
index 9e66fd4..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-%tag(name="value" name2=true ns:tag=100)
-%input#space-end(type="hidden" value="3" )
-%input#space-start( type="hidden" value="3" )
-%input#space-middle(type="hidden"  value="3")
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/alt_attribs.html b/node/node_modules/jade/benchmarks/haml-js/test/alt_attribs.html
deleted file mode 100644 (file)
index ef8ce3c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<tag name="value" name2="name2" ns:tag="100"></tag><input type="hidden" value="3" id="space-end" /><input type="hidden" value="3" id="space-start" /><input type="hidden" value="3" id="space-middle" />
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/div_nesting.haml b/node/node_modules/jade/benchmarks/haml-js/test/div_nesting.haml
deleted file mode 100644 (file)
index ac22bdc..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-%div
-  Does not close properly
-  %div Nested same level as next div
-%div
-  Will be nested, but should be top level
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/div_nesting.html b/node/node_modules/jade/benchmarks/haml-js/test/div_nesting.html
deleted file mode 100644 (file)
index 67983ee..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<div>Does not close properly<div>Nested same level as next div</div></div><div>Will be nested, but should be top level</div>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/doctype.haml b/node/node_modules/jade/benchmarks/haml-js/test/doctype.haml
deleted file mode 100644 (file)
index b08273b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-!!!
-!!! strict
-!!! 1.1
-!!! 5
-!!! xml
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/doctype.html b/node/node_modules/jade/benchmarks/haml-js/test/doctype.html
deleted file mode 100644 (file)
index df8955f..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<!DOCTYPE html>
-<?xml version='1.0' encoding='utf-8' ?>
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/embedded_code.haml b/node/node_modules/jade/benchmarks/haml-js/test/embedded_code.haml
deleted file mode 100644 (file)
index 72591af..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-%head
-  :javascript
-    Page.chapter = #{JSON.stringify(chapter)};
-%body
-  %h1 Welcome #{name}
-  %div{class: "div_#{id}"}
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/embedded_code.html b/node/node_modules/jade/benchmarks/haml-js/test/embedded_code.html
deleted file mode 100644 (file)
index 8fa69ec..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<head>
-<script type="text/javascript">
-//<![CDATA[
-Page.chapter = {"name":"Ninja","page":42};
-//]]>
-</script>
-</head><body><h1>Welcome Tim</h1><div class="div_42"></div></body>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/embedded_code.js b/node/node_modules/jade/benchmarks/haml-js/test/embedded_code.js
deleted file mode 100644 (file)
index 5e04d9d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  locals: {
-    chapter: {name: "Ninja", page: 42},
-    name: "Tim",
-    id: 42
-  }
-}
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/foreach.haml b/node/node_modules/jade/benchmarks/haml-js/test/foreach.haml
deleted file mode 100644 (file)
index 9ab286f..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-:each color in colors
-  .preview{style: "color: " + color + ";"}&= name
-:each item in data
-  :if item.age < 100
-    %dl
-      :each name, value in item
-        %dt&= name
-        %dd&= value
-:each number in [1,2,3,4,5,6,7]
-  = number
-:for word in "Hello World".split(" ")
-  = word
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/foreach.html b/node/node_modules/jade/benchmarks/haml-js/test/foreach.html
deleted file mode 100644 (file)
index 2f81fd1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<div style="color: #f80;" class="preview">My Rainbow</div><div style="color: #08f;" class="preview">My Rainbow</div><div style="color: #4f4;" class="preview">My Rainbow</div><dl><dt>name</dt><dd>Tim Caswell</dd><dt>age</dt><dd>27</dd></dl>1234567HelloWorld
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/foreach.js b/node/node_modules/jade/benchmarks/haml-js/test/foreach.js
deleted file mode 100644 (file)
index 97de8e1..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  locals: {
-    colors: ["#f80", "#08f", "#4f4"],
-    name: "My Rainbow",
-    data: [
-      {name: "Tim Caswell", age: 27},
-      {name: "John Smith", age: 107},
-    ]
-  }
-}
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/meta.haml b/node/node_modules/jade/benchmarks/haml-js/test/meta.haml
deleted file mode 100644 (file)
index 59700e7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%meta(http-equiv="content-type" content="text/html; charset=UTF-8")
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/meta.html b/node/node_modules/jade/benchmarks/haml-js/test/meta.html
deleted file mode 100644 (file)
index fec8b93..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/nanline.haml b/node/node_modules/jade/benchmarks/haml-js/test/nanline.haml
deleted file mode 100644 (file)
index f57fe22..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-!!! 5
-%html
-    %head
-        %title atomix
-
-        %script(src='atomix_xlib.js')
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/nanline.html b/node/node_modules/jade/benchmarks/haml-js/test/nanline.html
deleted file mode 100644 (file)
index 78e1623..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<!DOCTYPE html>
-<html><head><title>atomix</title><script src="atomix_xlib.js"></script></head></html>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/nested_context.haml b/node/node_modules/jade/benchmarks/haml-js/test/nested_context.haml
deleted file mode 100644 (file)
index 907c484..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-%p= this.name
-#main
-  :each item in items
-    .item= this.name + ": " + item
-  :if items
-    #cool= this.name
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/nested_context.html b/node/node_modules/jade/benchmarks/haml-js/test/nested_context.html
deleted file mode 100644 (file)
index 0aa937e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<p>Frank</p><div id="main"><div class="item">Frank: 1</div><div class="item">Frank: 2</div><div class="item">Frank: 3</div><div id="cool">Frank</div></div>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/nested_context.js b/node/node_modules/jade/benchmarks/haml-js/test/nested_context.js
deleted file mode 100644 (file)
index f823655..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  context: {
-    name: "Frank"
-  },
-  locals: {
-    items: [1,2,3]
-  }
-}
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/no_self_close_div.haml b/node/node_modules/jade/benchmarks/haml-js/test/no_self_close_div.haml
deleted file mode 100644 (file)
index 05ccbee..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-%html
-  %body
-    %div#a
-    %div I do not self close.
-    :javascript
-      (function(){
-        document.getElementById('a').textContent='I self close';
-      })();
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/no_self_close_div.html b/node/node_modules/jade/benchmarks/haml-js/test/no_self_close_div.html
deleted file mode 100644 (file)
index 5067557..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<html><body><div id="a"></div><div>I do not self close.</div>
-<script type="text/javascript">
-//<![CDATA[
-(function(){
-  document.getElementById('a').textContent='I self close';
-})();
-//]]>
-</script>
-</body></html>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/non-string-attribs.haml b/node/node_modules/jade/benchmarks/haml-js/test/non-string-attribs.haml
deleted file mode 100644 (file)
index 4e70727..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#plain= "Plain Text"
-#escaped&= "<escaped>"
-%input{checked: true}
-%input{checked: false}
-%input{checked: null}
-%input{checked: undefined}
-%input{checked: 0}
-%input{checked: ""}
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/non-string-attribs.html b/node/node_modules/jade/benchmarks/haml-js/test/non-string-attribs.html
deleted file mode 100644 (file)
index b390396..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<div id="plain">Plain Text</div><div id="escaped">&lt;escaped&gt;</div><input checked="checked" /><input /><input /><input /><input checked="0" /><input />
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/script_css.haml b/node/node_modules/jade/benchmarks/haml-js/test/script_css.haml
deleted file mode 100644 (file)
index ed9a9d4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-%head
-  :javascript
-    function greet(message) {
-      alert("Message from MCP: " + message);
-    }
-  %title Script and Css test
-  :css
-    body {
-      color: pink;
-    }
-%body{onload: "greet(\"I'm Pink\")"} COLOR ME PINK
-
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/script_css.html b/node/node_modules/jade/benchmarks/haml-js/test/script_css.html
deleted file mode 100644 (file)
index f4bd4c4..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-<head>
-<script type="text/javascript">
-//<![CDATA[
-function greet(message) {
-  alert("Message from MCP: " + message);
-}
-//]]>
-</script>
-<title>Script and Css test</title>
-<style type="text/css">
-body {
-  color: pink;
-}
-</style>
-</head><body onload="greet(&quot;I'm Pink&quot;)">COLOR ME PINK</body>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/self_close.haml b/node/node_modules/jade/benchmarks/haml-js/test/self_close.haml
deleted file mode 100644 (file)
index a26cdcd..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-%html
-  %head
-    :if url !='/'
-      %script
-    %meta{name: "test", value:"Monkey"}
-  %body
-    %a{ href: url }
-      link
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/self_close.html b/node/node_modules/jade/benchmarks/haml-js/test/self_close.html
deleted file mode 100644 (file)
index 90b50a0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<html><head><script></script><meta name="test" value="Monkey" /></head><body><a href="http://nodejs.org/">link</a></body></html>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/self_close.js b/node/node_modules/jade/benchmarks/haml-js/test/self_close.js
deleted file mode 100644 (file)
index 5f6f85c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  locals: {
-    url: "http://nodejs.org/"
-  }
-}
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/standard.haml b/node/node_modules/jade/benchmarks/haml-js/test/standard.haml
deleted file mode 100644 (file)
index 955fe05..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-!!! XML
-!!! strict
-%html{ xmlns: "http://www.w3.org/1999/xhtml" }
-  %head
-    %title
-      Sample haml template
-  %body
-    .profile
-      .left.column
-        #date= print_date()
-        #address= current_user.address
-      .right.column
-        #email= current_user.email
-        #bio= current_user.bio
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/standard.html b/node/node_modules/jade/benchmarks/haml-js/test/standard.html
deleted file mode 100644 (file)
index bb24daa..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Sample haml template</title></head><body><div class="profile"><div class="left column"><div id="date">January 1, 2009</div><div id="address">Richardson, TX</div></div><div class="right column"><div id="email">tim@creationix.com</div><div id="bio">Experienced software professional...</div></div></div></body></html>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/standard.js b/node/node_modules/jade/benchmarks/haml-js/test/standard.js
deleted file mode 100644 (file)
index 23abf66..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  locals: {
-    print_date: function () {
-      return 'January 1, 2009';
-    },
-    current_user: {
-      address: "Richardson, TX",
-      email: "tim@creationix.com",
-      bio: "Experienced software professional..."
-    }
-  }
-}
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/test-commonjs.js b/node/node_modules/jade/benchmarks/haml-js/test/test-commonjs.js
deleted file mode 100644 (file)
index b20c2ac..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-var FILE = require("file");
-var ASSERT = require("assert");
-
-var Haml = require("../lib/haml");
-
-FILE.glob("test/*.haml").forEach(function(hamlFile) {
-    exports["test " + hamlFile] = function() {
-        var scopeFile = hamlFile.replace(/haml$/, "js");
-        var htmlFile = hamlFile.replace(/haml$/, "html");
-
-        var haml = FILE.read(hamlFile);
-        var expected = FILE.read(htmlFile);
-        var scope = FILE.exists(scopeFile) ? eval("("+FILE.read(scopeFile)+")") : {};
-
-        var js = Haml.compile(haml);
-        var js_opt = Haml.optimize(js);
-        var actual = Haml.execute(js_opt, scope.context, scope.locals);
-        ASSERT.equal(actual.trim(), expected.trim());
-    }
-});
-
-if (module == require.main)
-    require("os").exit(require("test").run(exports));
diff --git a/node/node_modules/jade/benchmarks/haml-js/test/test.js b/node/node_modules/jade/benchmarks/haml-js/test/test.js
deleted file mode 100644 (file)
index 9bbcadb..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-var fs = require('fs');
-var assert = require('assert');
-var sys = require('sys');
-
-var Haml = require("../lib/haml");
-
-fs.readdir('.', function (err, files) {
-  files.forEach(function (haml_file) {
-    var m = haml_file.match(/^(.*)\.haml/),
-        base;
-    if (!m) {
-      return;
-    }
-    base = m[1];
-
-    function load_haml(scope) {
-      fs.readFile(haml_file, "utf8", function (err, haml) {
-        fs.readFile(base + ".html", "utf8", function (err, expected) {
-          try {
-            var js = Haml.compile(haml);
-            var js_opt = Haml.optimize(js);
-            var actual = Haml(haml).call(scope.context, scope.locals);
-            assert.equal(actual, expected);
-            
-            sys.puts(haml_file + " Passed")
-          } catch (e) {
-            var message = e.name;
-            if (e.message) { message += ": " + e.message; }
-            sys.error(haml_file + " FAILED")
-            sys.error(message);
-            sys.error("\nJS:\n\n" + js);
-            sys.error("\nOptimized JS:\n\n" + js_opt);
-            sys.error("\nActual:\n\n" + actual);
-            sys.error("\nExpected:\n\n" + expected);
-            process.exit();
-          }
-        });
-      });
-    }
-
-    // Load scope
-    if (files.indexOf(base + ".js") >= 0) {
-      fs.readFile(base + ".js", "utf8", function (err, js) {
-        load_haml(eval("(" + js + ")"));
-      });
-    } else {
-      load_haml({});
-    }
-  });
-});
-
-
diff --git a/node/node_modules/jade/benchmarks/haml.js b/node/node_modules/jade/benchmarks/haml.js
deleted file mode 100644 (file)
index 7afbf36..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var bm = require('./common'),
-    haml = require('./haml-js/lib/haml'),
-    fs = require('fs');
-
-var str = fs.readFileSync(__dirname + '/example.haml', 'ascii');
-
-var n = bm.times;
-bm.start('haml-js compilation');
-while (n--) {
-    haml(str);
-}
-bm.stop();
-
-var n = bm.times;
-var fn = haml(str);
-bm.start('haml-js execution');
-while (n--) {
-    fn.call('whatever scope', bm.locals);
-}
-bm.stop();
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/.gitmodules b/node/node_modules/jade/benchmarks/haml/.gitmodules
deleted file mode 100644 (file)
index 83fc8f9..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "benchmarks/haml-js"]
-       path = benchmarks/haml-js
-       url = git://github.com/creationix/haml-js.git
diff --git a/node/node_modules/jade/benchmarks/haml/.ignore b/node/node_modules/jade/benchmarks/haml/.ignore
deleted file mode 100644 (file)
index 81736c9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-benchmarks
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/History.md b/node/node_modules/jade/benchmarks/haml/History.md
deleted file mode 100644 (file)
index 814f78c..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-
-0.4.5 / 2010-06-04
-==================
-
-  * Ignoring stray indent
-
-0.4.4 / 2010-05-27
-==================
-
-  * Fixed arbitrary whitespace support
-
-0.4.3 / 2010-05-25
-==================
-
-  * Fixed support for CRLF / CR line-endings, converted on input
-  * Exporting HamlError
-
-0.4.2 / 2010-05-25
-==================
-
-  * Added HamlError
-  * Buffer newline indentation. Closes #23
-  * Benchmarks with node-bench
-
-0.4.1 / 2010-05-17
-==================
-
-  * Fixed "- each" with non-enumerables, no longer throws exception
-  * Fixed array iteration
-
-0.4.0 / 2010-05-06
-==================
-
-  * Using Function constructor instead of eval()
-  * Performance enhanced by faster iteration implementation for "- each"
-
-0.3.1 / 2010-04-26
-==================
-
-  * Fixed support for tags with hypens (both namespace / tag name, ex: "fb:login-button")
-
-0.3.0 / 2010-04-16
-==================
-
-  * Added xml namespace support
-  * Added xml support
-
-0.2.0 / 2010-04-06
-==================
-
-  * Added conditional comment support [ciaranj]
-  * Fixed; Trimming input string before tokenization
-  * Fixed issue requiring quoting of "for" when used in attrs [aheckmann]
-  * Fixed; Exposing Haml compilation cache. Closes #12
-  * Fixed :javascript "type" attr, now "text/javascript" [aheckmann]
-
-0.1.0 / 2010-03-31
-==================
-
-  * Added "cache" option, making haml.js over 90 times faster than haml-js
-  * Improved textBlock whitespace replication
-  * Fixed empty tags followed by class / ids on new lines. Closes #6
-
-0.0.4 / 2010-03-29
-==================
-
-  * Added better error reporting
-
-0.0.3 / 2010-03-29
-==================
-
-  * Added "filename" option support to aid in error reporting
-  * Added exports.compile() to create intermediate javascript
-  * Added `make benchmark`
-  * Changed; caching function templates to increase performance
-  * Fixed; ids and classes allowing underscores. Closes #5
-  * Fixed outdent issue when \n is not followed by whitespace. Closes #8
-
-0.0.2 / 2010-03-26
-==================
-
-  * Added haml.js vs haml-js benchmarks
-  * Fixed; commenting :javascript CDATA
-
-0.0.1 / 2010-03-26
-==================
-
-  * Initial release
diff --git a/node/node_modules/jade/benchmarks/haml/Makefile b/node/node_modules/jade/benchmarks/haml/Makefile
deleted file mode 100644 (file)
index 5580ecf..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-
-test:
-       @node spec/node.js
-       
-benchmark:
-       @node-bench benchmarks/run.js
-       
-.PHONY: test benchmark
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/Readme.md b/node/node_modules/jade/benchmarks/haml/Readme.md
deleted file mode 100644 (file)
index c629679..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-
-# Haml.js
-
-  High performance JavaScript [Haml](http://haml-lang.com) implementation for [nodejs](http://nodejs.org)
-  
-  For a higher quality implementation you may want to look at my [Jade](http://jade-lang.com) template engine,
-  however the syntax is slightly different. Jade's engine may be back-ported to haml.js in the future.
-
-## Installation
-
-  Install the [Kiwi package manager for nodejs](http://github.com/visionmedia/kiwi)
-  and run:
-  
-      $ kiwi install haml
-
-      node> require('haml')
-
-Or npm:
-
-      $ npm install hamljs
-
-      node> require('hamljs')
-
-## About
-
-  Benchmarks rendering the same 21 line haml file located at _benchmarks/page.haml_,
-  shows that this library is nearly **65%** or **3 times** faster than haml-js.
-  
-      Winner: haml.js
-      Compared with next highest (haml-js), it's:
-      65.39% faster
-      2.89 times as fast
-      0 order(s) of magnitude faster
-
-  Haml.js attempts to comply with the original [Haml](http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html)
-  implementation as well as possible. There are no magic "plugins" like
-  found in other JavaScript haml implementations, for example the following
-  will work just fine:
-  
-    - if (items)
-      %ul
-        - for (var i = 0; i < items.length; ++i)
-          %li= items[i]
-  
-  Iteration is the one exception to these magical plugins,
-  since this is **ugly** in JavaScript, you may also:
-  
-    - if (items)
-      %ul
-        - each item in items
-          %li= item
-          
-## Usage
-
-    var haml = require('haml')
-    haml.render('a string of haml', { a: 'hash', of: 'options' })
-    
-## Options
-
-  * context
-    - when passed the value of "this" becomes the given "context" object
-  * locals
-    - when passed all members of this object become available to this template
-  * filename
-    - required when _cache_ is enabled
-  * cache
-    - compiled intermediate javascript is cached in memory keyed by _filename_
-    
-## Tags
-
-    %div text
-
-html:
-
-    <div>text</div>
-    
-## Classes
-
-    %div.article.first
-      article text here
-      and here
-      
-html:
-
-    <div class="article first">
-      article text here and here
-    </div>
-    
-## Div Class Shortcut
-
-    .comment hey
-    
-html:
-
-    <div class="comment">hey</div>
-    
-## Div Id Shortcut
-
-    #article-1 foo
-    
-html:
-
-    <div id="article-1">foo</div>
-    
-## Combining Ids and Classes
-
-You may chain id and classes in any order:
-
-    .article#first.summary content
-    
-html:
-
-    <div id="first" class="article summary">context</div>
-    
-## Attributes
-
-    %a{ href: 'http://google.com', title: 'Google It' } Google
-    
-html:
-
-    <a href="http://google.com" title="Google It">Google</a>
-
-Attribute keys such as "for" are automatically quoted
-by haml.js, so instead of:
-
-    %label{ 'for': 'something' }
-
-you should:
-
-    %label{ for: 'something' }
-
-which will render:
-
-    <label for="something"></label>
-    
-## Boolean Attributes
-
-    %input{ type: 'checkbox', checked: true }
-    
-html:
-
-    <input type="checkbox" checked="checked"/>
-    
-## Combining Attributes, Ids, and Classes
-    
-Wemay also contain id and classes before or after:
-
-    %a.button{ href: 'http://google.com', title: 'Google It' }.first Google
-    
-html:
-
-    <a href="http://google.com" title="Google It" class="button first">Google</a>
-    
-## Code
-
-Code starting with a hyphen will be executed but
-not buffered, where as code using the equals sign
-will be buffered:
-
-    - a = 1
-    - b = 2
-    = a + b
-    
-html:
-
-    3
-    
-HTML buffered with equals sign will **always** be escaped:
-
-    = "<br/>"
-    
-html:
-   
-    &lt;br/&gt;
-    
-To prevent escaping of HTML entities we can use _!=_:
-
-    != "<br/>"
-    
-html:
-
-    <br/>
-    
-## Iteration
-
-    %ul
-      - each item in items
-        %li= item
-        
-html:
-
-    <ul>
-      <li>one</li>
-      <li>two</li>
-      <li>three</li>
-    </ul>
-    
-If you require the key or index of the object
-or array during iteration simple append a comma
-following another id:
-
-    %ul
-      - each item, index in items
-        %li= item + '(' + index + ')'
-        
-html:
-
-    <ul>
-      <li>one(0)</li>
-      <li>two(1)</li>
-      <li>three(2)</li>
-    </ul>
-    
-## Doctypes
-
-Defaults to transitional:
-    
-    !!!
-    
-html:
-
-    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-    
-Optionally pass a supported doctype name:
-
-    !!! strict
-    
-html:
-
-    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
-currently supported doctypes, which can be
-extended simply by adding values to to _haml.doctypes_.
-
-    '5': '<!DOCTYPE html>',
-    'xml': '<?xml version="1.0" encoding="utf-8" ?>',
-    'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
-    'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
-    'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
-    '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
-    'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
-    'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
-
-
-## :cdata
-
-    %script
-      :cdata
-        foo
-        
-html:
-
-    <script><![CDATA[
-    foo
-    ]]></script>
-    
-## :javascript
-
-    %head
-      :javascript
-        if (foo)
-          if (bar)
-            alert('baz')
-      
-html:
-
-    <head>
-      <script type="javascript">
-      //<![CDATA[
-      if (foo)
-        if (bar)
-          alert('baz')
-      //]]>
-      </script>
-    </head>
-    
-## Extending Haml
-
-### Adding Filters
-
-    var haml = require('haml')
-    haml.filters.my_filter = function(str) {
-      return doSomethingWith(str)
-    }
-
-by registering the filter function _my_filter_ we can now
-utilize it within our Haml templates as shown below:
-    %p
-      :my_filter
-        some text
-        here yay
-        whoop awesome
-
-### Adding Doctypes
-
-    var haml = require('haml')
-    haml.doctypes.foo = '<!DOCTYPE ... >'
-    
-Will now allow you to:
-    !!! foo
-    
-## Running Benchmarks
-
-To run benchmarks against [haml-js](http://github.com/creationix/haml-js)
-simply execute:
-
-    $ git submodule update --init
-    $ node benchmarks/run.js
-    
-## More Information
-
-  * View _spec/fixtures_ for more examples
-  * Official [Haml](http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html) reference
-  * JavaScript [Sass](http://github.com/visionmedia/sass.js) implementation
-
-## License 
-
-(The MIT License)
-
-Copyright (c) 2010 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
-
-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/node_modules/jade/benchmarks/haml/benchmarks/page.haml b/node/node_modules/jade/benchmarks/haml/benchmarks/page.haml
deleted file mode 100644 (file)
index 98b40fb..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-!!!
-%html
-  %head
-    %title Welcome
-    %script{ src: 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js', type: 'javascript' }
-    -# javascript filter (and others)
-    -# support arbitrary whitespace
-    :javascript
-      $(function(){
-        alert('yay!')
-      })
-    %meta{ name: 'keywords', content: 'foo bar baz' }
-  %body
-    %h1 Title
-    %ul
-      %li one
-      %li two
-      %li
-        %ol
-          %li one
-          %li two
-      %li three
-      %li four
-      %ul
-        %li five
-        %li six
-        %li
-          %ol
-            %li seven
-            %li eight
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/benchmarks/run.js b/node/node_modules/jade/benchmarks/haml/benchmarks/run.js
deleted file mode 100644 (file)
index 190aec8..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-
-var fs = require('fs'),
-    haml = require('../lib/haml'),
-    hamlJS = require('./haml-js/lib/haml'),
-    page = fs.readFileSync('benchmarks/page.haml')
-
-var js = hamlJS.compile(page)
-
-exports.compare = {
-    'haml.js': function(){
-        haml.render(page)
-    },
-    'haml.js cached': function(){
-        haml.render(page, { cache: true, filename: 'page.haml' })
-    },
-    'haml-js': function(){
-        hamlJS.render(page)
-    },
-    'haml-js cached': function(){
-        hamlJS.execute(js)
-    },
-    'haml-js cached / optimized': function(){
-        hamlJS.execute(js)
-    }
-}
diff --git a/node/node_modules/jade/benchmarks/haml/examples/example.js b/node/node_modules/jade/benchmarks/haml/examples/example.js
deleted file mode 100644 (file)
index b3e7816..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-
-var sys = require('sys'),
-    fs = require('fs'),
-    haml = require('../lib/haml')
-    
-var options = {
-  filename: 'page.haml',
-  locals: {
-    title: 'Welcome',
-    body: 'wahoo',
-    usersOnline: 15
-  }
-}
-
-sys.puts(haml.render(fs.readFileSync('examples/page.haml'), options))
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/examples/page.haml b/node/node_modules/jade/benchmarks/haml/examples/page.haml
deleted file mode 100644 (file)
index ffb69ef..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-%html
-  %head
-    %title= title
-  
-    %script{ src: 'jquery.js' }
-    
-    %script{ src: 'jquery.ui.js' }
-    
-  %body
-    %h1 Welcome
-    
-    %ul#menu
-      %li.first one
-      %li two
-      %li.last three
-      %li
-        %ul
-          %li nested
-          
-    #content
-      = body
-    #usersOnline= usersOnline
diff --git a/node/node_modules/jade/benchmarks/haml/index.js b/node/node_modules/jade/benchmarks/haml/index.js
deleted file mode 120000 (symlink)
index 55a170f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-lib/haml.js
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/lib/haml.js b/node/node_modules/jade/benchmarks/haml/lib/haml.js
deleted file mode 100644 (file)
index 8da6ba3..0000000
+++ /dev/null
@@ -1,666 +0,0 @@
-
-// Haml - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
-
-/**
- * Module dependencies.
- */
-
-var sys = require('sys')
-
-/**
- * Version.
- */
-
-exports.version = '0.4.5'
-
-/**
- * Haml template cache.
- */
-
-exports.cache = {}
-
-/**
- * Default error context length.
- */
-
-exports.errorContextLength = 15
-
-/**
- * Self closing tags.
- */
-exports.selfClosing = [
-    'meta',
-    'img',
-    'link',
-    'br',
-    'hr',
-    'input',
-    'area',
-    'base'
-  ]
-
-/**
- * Default supported doctypes.
- */
-
-exports.doctypes = {
-  '5': '<!DOCTYPE html>',
-  'xml': '<?xml version="1.0" encoding="utf-8" ?>',
-  'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
-  'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
-  'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
-  '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
-  'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
-  'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
-}
-
-/**
- * Default filters.
- */
-exports.filters = {
-  
-  /**
-   * Return plain string.
-   */
-  
-  plain: function(str) {
-    return str
-  },
-  
-  /**
-   * Wrap with CDATA tags.
-   */
-  
-  cdata: function(str) {
-    return '<![CDATA[\n' + str + '\n]]>'
-  },
-  
-  /**
-   * Wrap with <script> and CDATA tags.
-   */
-  
-  javascript: function(str) {
-    return '<script type="text/javascript">\n//<![CDATA[\n' + str + '\n//]]></script>'
-  }
-}
-
-/**
- * Function templates.
- */
-exports.templates = {
-  
-  /**
-   * Execute __code__.
-   */
-  
-  code: (function(){
-    __code__;
-    return ""
-  }).toString(),
-  
-  /**
-   * Execute __code__ followed by buffering __block__.
-   */
-  
-  codeBlock: (function(){
-    var buf = [];
-    __code__
-    buf.push(__block__);
-    return buf.join("")
-  }).toString(),
-  
-  /**
-   * Iterate __vals__ as __val__ while buffering __block__.
-   */
-  
-  iterate: (function(){
-    var buf = [];
-    if (__vals__ instanceof Array) {
-      for (var i = 0, len = __vals__.length; i < len; ++i) {
-        var __key__ = i;
-        var __val__ = __vals__[i];
-        buf.push(__block__);
-      }
-    } else if (__vals__) {
-      var keys = Object.keys(__vals__);
-      for (var i = 0, len = keys.length; i < len; ++i) {
-        var __key__ = keys[i];
-        var __val__ = __vals__[__key__];
-        buf.push(__block__);
-      }
-    }
-    return buf.join("")
-  }).toString()
-}
-
-/**
- * HamlError.
- */
-
-var HamlError = exports.HamlError = function(msg) {
-    this.name = 'HamlError'
-    this.message = msg
-    Error.captureStackTrace(this, exports.render)
-}
-sys.inherits(HamlError, Error)
-
-/**
- * Lexing rules.
- */
-
-var rules = {
-  indent: /^\n( *)(?! *-#)/,
-  conditionalComment: /^\/(\[[^\n]+\])/,
-  comment: /^\n? *\/ */,
-  silentComment: /^\n? *-#([^\n]*)/,
-  doctype: /^!!! *([^\n]*)/,
-  escape: /^\\(.)/,
-  filter: /^:(\w+) */,
-  each: /^\- *each *(\w+)(?: *, *(\w+))? * in ([^\n]+)/,
-  code: /^\-([^\n]+)/,
-  outputCode: /^!=([^\n]+)/,
-  escapeCode: /^=([^\n]+)/,
-  attrs: /^\{(.*?)\}/,
-  tag: /^%([-a-zA-Z][-a-zA-Z0-9:]*)/,
-  class: /^\.([\w\-]+)/,
-  id: /^\#([\w\-]+)/,
-  text: /^([^\n]+)/
-}
-
-/**
- * Return error context _str_.
- *
- * @param  {string} str
- * @return {string}
- * @api private
- */
-
-function context(str) {
-  return String(str)
-    .substr(0, exports.errorContextLength)
-    .replace(/\n/g, '\\n')
-}
-
-/**
- * Tokenize _str_.
- *
- * @param  {string} str
- * @return {array}
- * @api private
- */
-
-function tokenize(str) {
-  var captures,
-      token,
-      tokens = [],
-      line = 1,
-      lastIndents = 0,
-      str = String(str).trim().replace(/\r\n|\r/g, '\n')
-  function error(msg){ throw new HamlError('(Haml):' + line + ' ' + msg) }
-  while (str.length) {
-    for (var type in rules)
-      if (captures = rules[type].exec(str)) {
-        token = {
-          type: type,
-          line: line,
-          match: captures[0],
-          val: captures.length > 2
-            ? captures.slice(1)
-            : captures[1]
-        }
-        str = str.substr(captures[0].length)
-        if (type === 'newline' ||
-            type === 'indent') ++line
-        if (type !== 'indent') break
-        var indents = token.val.length / 2
-        if (indents % 1)
-          error('invalid indentation; got ' + token.val.length + ' spaces, should be multiple of 2')
-        else if (indents - 1 > lastIndents)
-          error('invalid indentation; got ' + indents + ', when previous was ' + lastIndents)
-        else if (lastIndents > indents)
-          while (lastIndents-- > indents)
-            tokens.push({ type: 'outdent', line: line })
-        else if (lastIndents !== indents)
-          tokens.push({ type: 'indent', line: line })
-        else
-          tokens.push({ type: 'newline', line: line })
-        lastIndents = indents
-      }
-    if (token) {
-      if (token.type !== 'silentComment')
-        tokens.push(token)
-      token = null
-    } else 
-      error('near "' + context(str) + '"')
-  }
-  return tokens.concat({ type: 'eof' })
-}
-
-/**
- * Render template _name_ with the given placeholder _vals_.
- *
- * @param  {string} name
- * @param  {object} vals
- * @return {string}
- * @api private
- */
-
-function template(name, vals) {
-  var buf = '(' + exports.templates[name] + ').call(this)'
-  for (var key in vals)
-    buf = buf.replace(new RegExp(key, 'g'), vals[key])
-  return buf
-}
-
-// --- Parser
-
-/**
- * Initialize parser with _str_ and _options_.
- */
-
-function Parser(str, options) {
-  options = options || {}
-  this.tokens = tokenize(str)
-  this.xml = options.xml
-}
-
-Parser.prototype = {
-  
-  /**
-   * Lookahead a single token.
-   *
-   * @return {object}
-   * @api private
-   */
-  
-  get peek() {
-    return this.tokens[0]
-  },
-  
-  /**
-   * Advance a single token.
-   *
-   * @return {object}
-   * @api private
-   */
-  
-  get advance() {
-    return this.current = this.tokens.shift()
-  },
-  
-  /**
-   *    outdent
-   *  | eof
-   */
-  
-  get outdent() {
-    switch (this.peek.type) {
-      case 'eof':
-        return
-      case 'outdent':
-        return this.advance
-      default:
-        throw new HamlError('expected outdent, got ' + this.peek.type)
-    }
-  },
-  
-  /**
-   * text
-   */
-  
-  get text() {
-    return '"' + this.advance.val.trim() + '"'
-  },
-  
-  /**
-   * indent expr outdent
-   */
-  
-  get block() {
-    var buf = []
-    this.advance
-    while (this.peek.type !== 'outdent' &&
-           this.peek.type !== 'eof')
-      buf.push(this.expr)
-    this.outdent
-    return buf.join(' + ')
-  },
-  
-  /**
-   * indent expr
-   */
-  
-  get textBlock() {
-    var token,
-        indents = 1,
-        buf = []
-    this.advance
-    while (this.peek.type !== 'eof' && indents)
-      switch((token = this.advance).type) {
-        case 'newline':
-          buf.push('"\\n' + Array(indents).join('  ') + '"')
-          break
-        case 'indent':
-          ++indents
-          buf.push('"\\n' + Array(indents).join('  ') + '"')
-          break
-        case 'outdent':
-          --indents
-          if (indents === 1) buf.push('"\\n"')
-          break
-        default:
-          buf.push('"' + token.match.replace(/"/g, '\\\"') + '"')
-      }
-    return buf.join(' + ')
-  },
-  
-  /**
-   *  ( attrs | class | id )*
-   */
-  
-  get attrs() {
-    var attrs = ['attrs', 'class', 'id'],
-        classes = [],
-        buf = []
-    while (attrs.indexOf(this.peek.type) !== -1)
-      switch (this.peek.type) {
-        case 'id':
-          buf.push('id: "' + this.advance.val + '"')
-          break
-        case 'class':
-          classes.push(this.advance.val)
-          break
-        case 'attrs':
-          buf.push(this.advance.val.replace(/(for) *:/gi, '"$1":'))
-      }
-    if (classes.length)
-      buf.push('"class": "' + classes.join(' ') + '"')
-    return buf.length 
-      ? ' " + attrs({' + buf.join() + '}) + "'
-      : ''
-  },
-  
-  /**
-   *   tag
-   * | tag text
-   * | tag conditionalComment
-   * | tag comment
-   * | tag outputCode
-   * | tag escapeCode
-   * | tag block
-   */
-  
-  get tag() {
-    var tag = this.advance.val,
-        selfClosing = !this.xml && exports.selfClosing.indexOf(tag) !== -1,
-        buf = ['"\\n<' + tag + this.attrs + (selfClosing ? '/>"' : '>"')]
-    switch (this.peek.type) {
-      case 'text':
-        buf.push(this.text)
-        break
-      case 'conditionalComment':
-        buf.push(this.conditionalComment)
-        break;
-      case 'comment':
-        buf.push(this.comment)
-        break
-      case 'outputCode':
-        buf.push(this.outputCode)
-        break
-      case 'escapeCode':
-        buf.push(this.escapeCode)
-        break
-      case 'indent':
-        buf.push(this.block)
-    }
-    if (!selfClosing) buf.push('"</' + tag + '>"')
-    return buf.join(' + ')
-  },
-  
-  /**
-   * outputCode
-   */
-  
-  get outputCode() {
-    return this.advance.val
-  },
-  
-  /**
-   * escapeCode
-   */
-  
-  get escapeCode() {
-    return 'escape(' + this.advance.val + ')'
-  },
-  
-  /**
-   * doctype
-   */
-  
-  get doctype() {
-    var doctype = this.advance.val.trim().toLowerCase() || 'default'
-    if (doctype in exports.doctypes)
-      return '"' + exports.doctypes[doctype].replace(/"/g, '\\"') + '"'
-    else
-      throw new HamlError("doctype `" + doctype + "' does not exist")
-  },
-  
-  /**
-   * conditional comment expr
-   */
-
-  get conditionalComment() {
-    var condition= this.advance.val
-    var buf = this.peek.type === 'indent'
-      ? this.block
-      : this.expr
-    return '"<!--' + condition + '>" + (' + buf + ') + "<![endif]-->"'
-  },
-
-  /**
-   * comment expr
-   */
-  
-  get comment() {
-    this.advance
-    var buf = this.peek.type === 'indent'
-      ? this.block
-      : this.expr
-    return '"<!-- " + (' + buf + ') + " -->"'
-  },
-  
-  /**
-   *   code
-   * | code block 
-   */
-  
-  get code() {
-    var code = this.advance.val
-    if (this.peek.type === 'indent')
-      return template('codeBlock', { __code__: code, __block__: this.block })
-    return template('code', { __code__: code })
-  },
-  
-  /**
-   * filter textBlock
-   */
-  
-  get filter() {
-    var filter = this.advance.val
-    if (!(filter in exports.filters))
-      throw new HamlError("filter `" + filter + "' does not exist")
-    if (this.peek.type !== 'indent')
-      throw new HamlError("filter `" + filter + "' expects a text block")
-    return 'exports.filters.' + filter + '(' + this.textBlock + ')'
-  },
-  
-  /**
-   * each block
-   */
-  
-  get iterate() {
-    var each = this.advance
-    if (this.peek.type !== 'indent')
-      throw new HamlError("'- each' expects a block, but got " + this.peek.type)
-    return template('iterate', {
-      __key__: each.val[1],
-      __vals__: each.val[2],
-      __val__: each.val[0],
-      __block__: this.block
-    })
-  },
-  
-  /**
-   *   eof
-   * | tag
-   * | text*
-   * | each
-   * | code
-   * | escape
-   * | doctype
-   * | filter
-   * | comment
-   * | conditionalComment
-   * | escapeCode
-   * | outputCode
-   */
-  
-  get expr() {
-    switch (this.peek.type) {
-      case 'id': 
-      case 'class':
-        this.tokens.unshift({ type: 'tag', val: 'div' })
-        return this.tag
-      case 'tag':
-        return this.tag
-      case 'text':
-        var buf = []
-        while (this.peek.type === 'text') {
-          buf.push(this.advance.val.trim())
-          if (this.peek.type === 'newline')
-            this.advance
-        }
-        return '"' + buf.join(' ') + '"'
-      case 'each':
-        return this.iterate
-      case 'code':
-        return this.code
-      case 'escape':
-        return '"' + this.advance.val + '"'
-      case 'doctype':
-        return this.doctype
-      case 'filter':
-        return this.filter
-      case 'conditionalComment':
-        return this.conditionalComment
-      case 'comment':
-        return this.comment
-      case 'escapeCode':
-        return this.escapeCode
-      case 'outputCode':
-        return this.outputCode
-      case 'newline':
-      case 'indent':
-      case 'outdent':
-        this.advance
-        return this.expr
-      default:
-        throw new HamlError('unexpected ' + this.peek.type)
-    }
-  },
-  
-  /**
-   * expr*
-   */
-  
-  get js() {
-    var buf = []
-    while (this.peek.type !== 'eof')
-      buf.push(this.expr)
-    return buf.join(' + ')
-  }
-}
-
-/**
- * Escape html entities in _str_.
- *
- * @param  {string} str
- * @return {string}
- * @api private
- */
-
-function escape(str) {
-  return String(str)
-    .replace(/&/g, '&amp;')
-    .replace(/>/g, '&gt;')
-    .replace(/</g, '&lt;')
-    .replace(/"/g, '&quot;')
-}
-
-/**
- * Render _attrs_ to html escaped attributes.
- *
- * @param  {object} attrs
- * @return {string}
- * @api public
- */
-
-function attrs(attrs) {
-  var buf = []
-  for (var key in attrs)
-    if (typeof attrs[key] === 'boolean') {
-      if (attrs[key] === true)
-        buf.push(key + '="' + key + '"')
-    } else if (attrs[key])
-      buf.push(key + '="' + escape(attrs[key]) + '"')
-  return buf.join(' ')
-}
-
-/**
- * Render a _str_ of haml.
- *
- * Options:
- *
- *   - locals   Local variables available to the template
- *   - context  Context in which the template is evaluated (becoming "this")
- *   - filename Filename used to aid in error reporting
- *   - cache    Cache compiled javascript, requires "filename"
- *   - xml      Force xml support (no self-closing tags)
- *
- * @param  {string} str
- * @param  {object} options
- * @return {string}
- * @api public
- */
-
-exports.render = function(str, options) {
-  var parser,
-      options = options || {}
-  if (options.cache && !options.filename)
-    throw new Error('filename option must be passed when cache is enabled')
-  return (function(){
-    try {
-      var fn
-      if (options.cache && exports.cache[options.filename])
-        fn = exports.cache[options.filename]
-      else {
-        parser = new Parser(str, options)
-        fn = Function('locals, attrs, escape, exports', 'with (locals || {}){ return ' + parser.js + '}')
-      }
-      return (options.cache
-          ? exports.cache[options.filename] = fn
-          : fn).call(options.context, options.locals, attrs, escape, exports)
-    } catch (err) {
-      if (parser && err instanceof HamlError)
-        err.message = '(Haml):' + parser.peek.line + ' ' + err.message
-      else if (!(err instanceof HamlError))
-        err.message = '(Haml): ' + err.message
-      if (options.filename)
-        err.message = err.message.replace('Haml', options.filename) 
-      throw err
-    }
-  }).call(options.context)
-}
diff --git a/node/node_modules/jade/benchmarks/haml/package.json b/node/node_modules/jade/benchmarks/haml/package.json
deleted file mode 100644 (file)
index f0170e7..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "name": "hamljs",
-  "description": "Faster, harder, better HAML template engine",
-  "keywords": ["haml", "template", "engine", "view", "nodejs"],
-  "author": "TJ Holowaychuk <tj@vision-media.ca>",
-  "version": "0.4.5",
-  "directories": {
-    "lib": "."
-  }
-}
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/seed.yml b/node/node_modules/jade/benchmarks/haml/seed.yml
deleted file mode 100644 (file)
index 9fdfe3b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
----
-  name: Haml
-  description: Faster, harder, better HAML template engine
-  tags: haml html template engine
-  version: 0.4.5
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/class.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/class.haml
deleted file mode 100644 (file)
index f11f685..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.users
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/class.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/class.html
deleted file mode 100644 (file)
index 4dc2d12..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<div class="users"></div>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/classes.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/classes.haml
deleted file mode 100644 (file)
index dc250ce..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.foo.bar.baz_is-awesome
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/classes.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/classes.html
deleted file mode 100644 (file)
index 94bf993..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<div class="foo bar baz_is-awesome"></div>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.haml
deleted file mode 100644 (file)
index 9dbc82e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-%ul
-  - each item in items
-    %li= item
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.html
deleted file mode 100644 (file)
index bfdb0cd..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<ul>
-<li>one</li>
-<li>two</li>
-<li>three</li></ul>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.index.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.index.haml
deleted file mode 100644 (file)
index bfaf81f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-%ul
-  - each item, index in items
-    %li= item + '(' + index + ')'
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.index.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.index.html
deleted file mode 100644 (file)
index b449d4b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<ul>
-<li>one(0)</li>
-<li>two(1)</li>
-<li>three(2)</li></ul>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.non-enumerable.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.non-enumerable.haml
deleted file mode 100644 (file)
index bfaf81f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-%ul
-  - each item, index in items
-    %li= item + '(' + index + ')'
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.non-enumerable.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.each.non-enumerable.html
deleted file mode 100644 (file)
index e2d1b04..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<ul></ul>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.escape.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.escape.haml
deleted file mode 100644 (file)
index aacec56..0000000
+++ /dev/null
@@ -1 +0,0 @@
-= "<br" + "/>"
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.escape.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.escape.html
deleted file mode 100644 (file)
index a18ba70..0000000
+++ /dev/null
@@ -1 +0,0 @@
-&lt;br/&gt;
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.haml
deleted file mode 100644 (file)
index 4236fe0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-!= "foo" + "bar"
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.html
deleted file mode 100644 (file)
index f6ea049..0000000
+++ /dev/null
@@ -1 +0,0 @@
-foobar
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.if.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.if.haml
deleted file mode 100644 (file)
index 6731782..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-- name = "tj"
-- if (name === 'tj')
-  %p You are logged in
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.if.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.if.html
deleted file mode 100644 (file)
index 07c3d71..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<p>You are logged in</p>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.nested.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.nested.haml
deleted file mode 100644 (file)
index a86a44f..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-- if (true)
-  - if (false)
-    %p nope
-  - if (true)
-    %p yay
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.nested.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/code.nested.html
deleted file mode 100644 (file)
index 26c4fe1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<p>yay</p>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.conditional.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.conditional.haml
deleted file mode 100644 (file)
index 213e9a9..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/[if IE]
-  %a{ 'href' : 'http://www.mozilla.com/en-US/firefox/' }
-    %h1 Get Firefox
-/[if IE]
-  %a{ 'href' : 'http://www.mozilla.com/en-US/firefox/' }
-    /[if IE 6]
-      %h1 Get Firefox (IE6 user)
-    /[if IE 7]
-      %h1 Get Firefox (IE7 user)
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.conditional.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.conditional.html
deleted file mode 100644 (file)
index f0020fa..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<!--[if IE]>
-<a href="http://www.mozilla.com/en-US/firefox/">
-<h1>Get Firefox</h1></a><![endif]--><!--[if IE]>
-<a href="http://www.mozilla.com/en-US/firefox/"><!--[if IE 6]>
-<h1>Get Firefox (IE6 user)</h1><![endif]--><!--[if IE 7]>
-<h1>Get Firefox (IE7 user)</h1><![endif]--></a><![endif]-->
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.haml
deleted file mode 100644 (file)
index 39041ea..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-/
-  %ul
-    %li nope
-    %li nope
-    %li nope
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.html
deleted file mode 100644 (file)
index cfbdcb7..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<!-- 
-<ul>
-<li>nope</li>
-<li>nope</li>
-<li>nope</li></ul> -->
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.haml
deleted file mode 100644 (file)
index 92d8988..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
--# nothing
-%p yay
-  -# whatever you want
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.html
deleted file mode 100644 (file)
index 26c4fe1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<p>yay</p>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.tag.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.tag.haml
deleted file mode 100644 (file)
index 880db37..0000000
+++ /dev/null
@@ -1 +0,0 @@
-  / %p foo
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.tag.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.tag.html
deleted file mode 100644 (file)
index 1fde28f..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<!-- 
-<p>foo</p> -->
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.complex.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.complex.haml
deleted file mode 100644 (file)
index 187cb4f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-%ul
-  %li one
-  / first item
-  %li two
-  / second item
-  %ul
-    %li three
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.complex.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.complex.html
deleted file mode 100644 (file)
index 301aaf7..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<ul>
-<li>one</li><!-- first item -->
-<li>two</li><!-- second item -->
-<ul>
-<li>three</li></ul></ul>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.haml
deleted file mode 100644 (file)
index 4dfe18d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%p
-  / foo bar baz
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.html
deleted file mode 100644 (file)
index 0d5b7c9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<p><!-- foo bar baz --></p>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/context.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/context.haml
deleted file mode 100644 (file)
index a22be1c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%p= this
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/context.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/context.html
deleted file mode 100644 (file)
index 26c4fe1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<p>yay</p>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/cr.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/cr.haml
deleted file mode 100644 (file)
index a492ae1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#foo\r  .bar
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/cr.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/cr.html
deleted file mode 100644 (file)
index 65e61f7..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<div id="foo">
-<div class="bar"></div>
-</div>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/crlf.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/crlf.haml
deleted file mode 100644 (file)
index 7263f27..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#foo\r
-  .bar
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/crlf.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/crlf.html
deleted file mode 100644 (file)
index 65e61f7..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<div id="foo">
-<div class="bar"></div>
-</div>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.haml
deleted file mode 100644 (file)
index 08faabd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-!!!
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.html
deleted file mode 100644 (file)
index f38b71c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.case.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.case.haml
deleted file mode 100644 (file)
index 57e66ca..0000000
+++ /dev/null
@@ -1 +0,0 @@
-!!!    xml
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.case.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.case.html
deleted file mode 100644 (file)
index 3297f54..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.haml
deleted file mode 100644 (file)
index 3f0fe33..0000000
+++ /dev/null
@@ -1 +0,0 @@
-!!! XML
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.html
deleted file mode 100644 (file)
index 3297f54..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/error.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/error.haml
deleted file mode 100644 (file)
index c5b0877..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-%html
-  %body
-      %p
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/escape.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/escape.haml
deleted file mode 100644 (file)
index d226974..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%p
-  \.foo
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/escape.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/escape.html
deleted file mode 100644 (file)
index a919d0c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<p>.foo</p>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/feed.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/feed.haml
deleted file mode 100644 (file)
index bc4b080..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-!!! xml
-%rss{ version: '2.0' }
-  %channel
-    %title ExpressJS
-    %link http://expressjs.com
-    %description Is super cool
-    %language en-us
-    %item
-      %title Creating Routes
-      %description Some stuff
-      %link http://expressjs.com/routes
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/feed.xml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/feed.xml
deleted file mode 100644 (file)
index 6e0633d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<rss version="2.0">
-<channel>
-<title>ExpressJS</title>
-<link>http://expressjs.com</link>
-<description>Is super cool</description>
-<language>en-us</language>
-<item>
-<title>Creating Routes</title>
-<description>Some stuff</description>
-<link>http://expressjs.com/routes</link></item></channel></rss>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.haml
deleted file mode 100644 (file)
index ede8c5b..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-%script
-  :cdata
-    foo
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.html
deleted file mode 100644 (file)
index 8cefa09..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<script><![CDATA[
-foo
-]]></script>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.whitespace.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.whitespace.haml
deleted file mode 100644 (file)
index 30db588..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-%script
-  :cdata
-    $(function(){
-      if (foo)
-        if (bar)
-          alert('yay')
-    })
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.whitespace.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.whitespace.html
deleted file mode 100644 (file)
index c09bdd9..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<script><![CDATA[
-$(function(){
-  if (foo)
-    if (bar)
-      alert('yay')
-})
-]]></script>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.javascript.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.javascript.haml
deleted file mode 100644 (file)
index 6a4fb39..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-%head
-  :javascript
-    if (foo)
-      if (bar)
-        alert("baz")
-    foo()
-    bar()
-  %title Yay
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.javascript.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.javascript.html
deleted file mode 100644 (file)
index 62eefe2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<head><script type="text/javascript">
-//<![CDATA[
-if (foo)
-  if (bar)
-    alert("baz")
-foo()
-bar()
-//]]></script>
-<title>Yay</title></head>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.plain.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.plain.haml
deleted file mode 100644 (file)
index 3d70c5d..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-%body
-  :plain
-    .foo
-    bar
-    = baz
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.plain.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/filter.plain.html
deleted file mode 100644 (file)
index d2b9084..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<body>.foo
-bar
-= baz</body>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/html.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/html.haml
deleted file mode 100644 (file)
index a516e3c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%div
-  <p>literal</p>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/html.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/html.html
deleted file mode 100644 (file)
index cf23b5b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<div><p>literal</p></div>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/id.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/id.haml
deleted file mode 100644 (file)
index f2c7c82..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#users
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/id.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/id.html
deleted file mode 100644 (file)
index c0171e2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<div id="users"></div>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/issue.#10.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/issue.#10.haml
deleted file mode 100644 (file)
index d6a16e3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%label{ for: "forsomething"}
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/issue.#10.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/issue.#10.html
deleted file mode 100644 (file)
index c3e1e61..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<label for="forsomething"></label>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/issue.#8.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/issue.#8.haml
deleted file mode 100644 (file)
index 6611716..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-%ul
-  - each item in items
-    %li= item
-%p= "Total: " + items.length
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/issue.#8.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/issue.#8.html
deleted file mode 100644 (file)
index b0d3442..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<ul>
-<li>foo</li>
-<li>bar</li>
-<li>baz</li></ul>
-<p>Total: 3</p>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/literals.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/literals.haml
deleted file mode 100644 (file)
index 8ddd574..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%p= user
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/literals.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/literals.html
deleted file mode 100644 (file)
index ab8d4e5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<p>tj</p>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/namespace.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/namespace.haml
deleted file mode 100644 (file)
index 45fbdb6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%h:table{ 'xmlns:h': 'http://www.w3.org/1999/xhtml' }
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/namespace.tag.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/namespace.tag.haml
deleted file mode 100644 (file)
index ab6f9b2..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-%body
-  %fb:test.a
-  %fb:bar
-  %fb:foo{ title: 'home' }
-  %fb:login-button
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/namespace.tag.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/namespace.tag.html
deleted file mode 100644 (file)
index a5db0c0..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<body>
-<fb:test class="a"></fb:test>
-<fb:bar></fb:bar>
-<fb:foo title="home"></fb:foo>
-<fb:login-button></fb:login-button></body>
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/namespace.xml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/namespace.xml
deleted file mode 100644 (file)
index 8d1888a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<h:table xmlns:h="http://www.w3.org/1999/xhtml"></h:table>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/nesting.complex.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/nesting.complex.haml
deleted file mode 100644 (file)
index b3bc8cc..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-%html
-  %head
-    %title Page Title
-  %body
-    %h1 Title
-    %p some stuff
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/nesting.complex.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/nesting.complex.html
deleted file mode 100644 (file)
index b6eb8b5..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<html>
-<head>
-<title>Page Title</title></head>
-<body>
-<h1>Title</h1>
-<p>some stuff</p></body></html>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/nesting.simple.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/nesting.simple.haml
deleted file mode 100644 (file)
index 7a91ed3..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-%ul
-  %li one
-  %li two
-  %li
-    %ul
-      %li three
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/nesting.simple.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/nesting.simple.html
deleted file mode 100644 (file)
index 50544e2..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<ul>
-<li>one</li>
-<li>two</li>
-<li>
-<ul>
-<li>three</li></ul></li></ul>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/newlines.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/newlines.haml
deleted file mode 100644 (file)
index b087e44..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-%ul
-  %li one
-  %li two
-  %li three
-  %li
-    %ul
-      %li four
-
-%p foo
-%p
-  bar
-  baz
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/newlines.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/newlines.html
deleted file mode 100644 (file)
index 5beb1f9..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<ul>
-<li>one</li>
-<li>two</li>
-<li>three</li>
-<li>
-<ul>
-<li>four</li></ul></li></ul>
-<p>foo</p>
-<p>bar baz</p>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.bools.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.bools.haml
deleted file mode 100644 (file)
index 7e0dc4f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%input{ type: 'checkbox', checked: true }
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.bools.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.bools.html
deleted file mode 100644 (file)
index 84416da..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<input type="checkbox" checked="checked"/>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.escape.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.escape.haml
deleted file mode 100644 (file)
index b9f40e1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%option{ value: '<script></script>' }
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.escape.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.escape.html
deleted file mode 100644 (file)
index a958f38..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<option value="&lt;script&gt;&lt;/script&gt;"></option>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.haml
deleted file mode 100644 (file)
index 84d2729..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%a{ href: '/', title: 'home' }
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.html
deleted file mode 100644 (file)
index 2f8ca31..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<a href="/" title="home"></a>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.class.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.class.haml
deleted file mode 100644 (file)
index 66dbc04..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%h1.title
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.class.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.class.html
deleted file mode 100644 (file)
index 101bb29..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<h1 class="title"></h1>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.classes.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.classes.haml
deleted file mode 100644 (file)
index 61a79a6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%body.front-page.editing-user
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.classes.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.classes.html
deleted file mode 100644 (file)
index 173556e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<body class="front-page editing-user"></body>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.haml
deleted file mode 100644 (file)
index 679e61c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%div= "yay"
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.html
deleted file mode 100644 (file)
index b3d55fc..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<div>yay</div>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.no-escape.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.no-escape.haml
deleted file mode 100644 (file)
index f092e67..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%div!= "<br/>"
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.no-escape.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.no-escape.html
deleted file mode 100644 (file)
index 2c2ec7a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<div><br/></div>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.complex.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.complex.haml
deleted file mode 100644 (file)
index 307f672..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%a#delete-user.first.button{ href: '/', title: 'Click to delete' }= "Delete " + "tj"
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.complex.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.complex.html
deleted file mode 100644 (file)
index 4ddee81..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<a id="delete-user" href="/" title="Click to delete" class="first button">Delete tj</a>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.empty.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.empty.haml
deleted file mode 100644 (file)
index fdfb6cb..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-%body
-  %div.a
-  %div.b
-  .c
-  .d
-  #e
-  #f
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.empty.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.empty.html
deleted file mode 100644 (file)
index ddc05d3..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<body>
-<div class="a"></div>
-<div class="b"></div>
-<div class="c"></div>
-<div class="d"></div>
-<div id="e"></div>
-<div id="f"></div></body>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.escape.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.escape.haml
deleted file mode 100644 (file)
index d33a301..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%div= "<br/>"
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.escape.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.escape.html
deleted file mode 100644 (file)
index 5b703e7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<div>&lt;br/&gt;</div>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.self-close.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.self-close.haml
deleted file mode 100644 (file)
index 63096c9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%br
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.self-close.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.self-close.html
deleted file mode 100644 (file)
index 4bbea23..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<br/>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.simple.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.simple.haml
deleted file mode 100644 (file)
index 20d531e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%div
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.simple.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.simple.html
deleted file mode 100644 (file)
index 281c686..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<div></div>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.complex.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.complex.haml
deleted file mode 100644 (file)
index cc55e16..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-%p
-  Visit
-  %a{ href: 'http://vision-media.ca' } Vision Media
-  because im amazing,
-  yes...
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.complex.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.complex.html
deleted file mode 100644 (file)
index 07c2b6b..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<p>Visit
-<a href="http://vision-media.ca">Vision Media</a>because im amazing, yes...</p>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.haml
deleted file mode 100644 (file)
index 20c5bcf..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-%p
-  some text
-  and more text
-  and even more text!
-  OMG
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.html
deleted file mode 100644 (file)
index e02ce19..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<p>some text and more text and even more text! OMG</p>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.haml
deleted file mode 100644 (file)
index 8718f9a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-%div some text
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.html
deleted file mode 100644 (file)
index e64083b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<div>some text</div>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/trailing-indent.haml b/node/node_modules/jade/benchmarks/haml/spec/fixtures/trailing-indent.haml
deleted file mode 100644 (file)
index 1e118cd..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-%a
-  %b
-  
-        
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/fixtures/trailing-indent.html b/node/node_modules/jade/benchmarks/haml/spec/fixtures/trailing-indent.html
deleted file mode 100644 (file)
index 094e68b..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<a>
-<b></b></a>
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/images/bg.png b/node/node_modules/jade/benchmarks/haml/spec/lib/images/bg.png
deleted file mode 100644 (file)
index 947804f..0000000
Binary files a/node/node_modules/jade/benchmarks/haml/spec/lib/images/bg.png and /dev/null differ
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/images/hr.png b/node/node_modules/jade/benchmarks/haml/spec/lib/images/hr.png
deleted file mode 100644 (file)
index 4a94d12..0000000
Binary files a/node/node_modules/jade/benchmarks/haml/spec/lib/images/hr.png and /dev/null differ
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/images/loading.gif b/node/node_modules/jade/benchmarks/haml/spec/lib/images/loading.gif
deleted file mode 100644 (file)
index c69e937..0000000
Binary files a/node/node_modules/jade/benchmarks/haml/spec/lib/images/loading.gif and /dev/null differ
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/images/sprites.bg.png b/node/node_modules/jade/benchmarks/haml/spec/lib/images/sprites.bg.png
deleted file mode 100644 (file)
index dc8790f..0000000
Binary files a/node/node_modules/jade/benchmarks/haml/spec/lib/images/sprites.bg.png and /dev/null differ
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/images/sprites.png b/node/node_modules/jade/benchmarks/haml/spec/lib/images/sprites.png
deleted file mode 100644 (file)
index 010b98e..0000000
Binary files a/node/node_modules/jade/benchmarks/haml/spec/lib/images/sprites.png and /dev/null differ
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/images/vr.png b/node/node_modules/jade/benchmarks/haml/spec/lib/images/vr.png
deleted file mode 100644 (file)
index b2e7617..0000000
Binary files a/node/node_modules/jade/benchmarks/haml/spec/lib/images/vr.png and /dev/null differ
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.css b/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.css
deleted file mode 100644 (file)
index 629d41c..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-body.jspec {
-  margin: 45px 0;
-  font: 12px "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
-  background: #efefef url(images/bg.png) top left repeat-x;
-  text-align: center;
-}
-#jspec {
-  margin: 0 auto;
-  padding-top: 30px;
-  width: 1008px;
-  background: url(images/vr.png) top left repeat-y;
-  text-align: left;
-}
-#jspec-top {
-  position: relative;
-  margin: 0 auto;
-  width: 1008px;
-  height: 40px;
-  background: url(images/sprites.bg.png) top left no-repeat;
-}
-#jspec-bottom {
-  margin: 0 auto;
-  width: 1008px;
-  height: 15px;
-  background: url(images/sprites.bg.png) bottom left no-repeat;
-}
-#jspec .loading {
-  margin-top: -45px;
-  width: 1008px;
-  height: 80px;
-  background: url(images/loading.gif) 50% 50% no-repeat;
-}
-#jspec-title {
-  position: absolute;
-  top: 15px;
-  left: 20px;
-  width: 160px;
-  font-size: 22px;
-  font-weight: normal;
-  background: url(images/sprites.png) 0 -126px no-repeat;
-  text-align: center;
-}
-#jspec-title em {
-  font-size: 10px;
-  font-style: normal;
-  color: #BCC8D1;
-}
-#jspec-report * {
-       margin: 0;
-       padding: 0;
-       background: none;
-       border: none;
-}
-#jspec-report {
-  padding: 15px 40px;
-       font: 11px "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
-       color: #7B8D9B;
-}
-#jspec-report.has-failures {
-  padding-bottom: 30px;
-}
-#jspec-report .hidden {
-  display: none;
-}
-#jspec-report .heading {
-  margin-bottom: 15px;
-}
-#jspec-report .heading span {
-  padding-right: 10px;
-}
-#jspec-report .heading .passes em {
-  color: #0ea0eb;
-}
-#jspec-report .heading .failures em {
-  color: #FA1616;
-}
-#jspec-report table {
-  font-size: 11px;
-  border-collapse: collapse;
-}
-#jspec-report td {
-  padding: 8px;
-  text-indent: 30px;
-  color: #7B8D9B;
-}
-#jspec-report tr.body {
-  display: none;
-}
-#jspec-report tr.body pre {
-  margin: 0;
-  padding: 0 0 5px 25px;
-}
-#jspec-report tr.even:hover + tr.body, 
-#jspec-report tr.odd:hover + tr.body {
-  display: block;
-}
-#jspec-report tr td:first-child em {
-       display: block;
-       clear: both;
-  font-style: normal;
-  font-weight: normal;
-  color: #7B8D9B;
-}
-#jspec-report tr.even:hover, 
-#jspec-report tr.odd:hover {
-  text-shadow: 1px 1px 1px #fff;
-  background: #F2F5F7;
-}
-#jspec-report td + td {
-  padding-right: 0;
-  width: 15px;
-}
-#jspec-report td.pass {
-  background: url(images/sprites.png) 3px -7px no-repeat;
-}
-#jspec-report td.fail {
-  background: url(images/sprites.png) 3px -158px no-repeat;
-  font-weight: bold;
-  color: #FC0D0D;
-}
-#jspec-report td.requires-implementation {
-  background: url(images/sprites.png) 3px -333px no-repeat;
-}
-#jspec-report tr.description td {
-  margin-top: 25px;
-  padding-top: 25px;
-  font-size: 12px;
-  font-weight: bold;
-  text-indent: 0;
-  color: #1a1a1a;
-}
-#jspec-report tr.description:first-child td {
-  border-top: none;  
-}
-#jspec-report .assertion {
-  display: block;
-  float: left;
-  margin: 0 0 0 1px;
-  padding: 0;
-  width: 1px;
-  height: 5px;
-  background: #7B8D9B;
-}
-#jspec-report .assertion.failed {
-  background: red;
-}
-.jspec-sandbox {
-  display: none;
-}
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.growl.js b/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.growl.js
deleted file mode 100644 (file)
index a150257..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-
-// JSpec - Growl - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
-
-;(function(){
-  
-  Growl = {
-    
-    // --- Version
-    
-    version: '1.0.0',
-    
-    /**
-     * Execute the given _cmd_, returning an array of lines from stdout.
-     *
-     * Examples:
-     *
-     *   Growl.exec('growlnotify', '-m', msg)
-     *
-     * @param  {string ...} cmd
-     * @return {array}
-     * @api public
-     */
-
-    exec: function(cmd) {
-      var lines = [], line
-      with (JavaImporter(java.lang, java.io)) {
-        var proccess = Runtime.getRuntime().exec(Array.prototype.slice.call(arguments))
-        var stream = new DataInputStream(proccess.getInputStream())
-        while (line = stream.readLine())
-          lines.push(line + '')
-        stream.close()    
-      }
-      return lines
-    },
-    
-    /**
-     * Return the extension of the given _path_ or null.
-     *
-     * @param  {string} path
-     * @return {string}
-     * @api private
-     */
-    
-    extname: function(path) {
-      return path.lastIndexOf('.') != -1 ? 
-        path.slice(path.lastIndexOf('.') + 1, path.length) :
-          null
-    },
-
-    /**
-     * Version of the 'growlnotify' binary.
-     *
-     * @return {string}
-     * @api private
-     */
-
-    binVersion: function() {
-      try { return this.exec('growlnotify', '-v')[0].split(' ')[1] } catch (e) {}
-    },
-
-    /**
-     * Send growl notification _msg_ with _options_.
-     *
-     * Options:
-     *
-     *  - title   Notification title
-     *  - sticky  Make the notification stick (defaults to false)
-     *  - name    Application name (defaults to growlnotify)
-     *  - image
-     *    - path to an icon sets --iconpath
-     *    - path to an image sets --image
-     *    - capitalized word sets --appIcon
-     *    - filename uses extname as --icon
-     *    - otherwise treated as --icon
-     *
-     * Examples:
-     *
-     *   Growl.notify('New email')
-     *   Growl.notify('5 new emails', { title: 'Thunderbird' })
-     *
-     * @param {string} msg
-     * @param {options} hash
-     * @api public
-     */
-
-    notify: function(msg, options) {
-      options = options || {}
-      var args = ['growlnotify', '-m', msg]
-      if (!this.binVersion()) throw new Error('growlnotify executable is required')
-      if (image = options.image) {
-        var flag, ext = this.extname(image)
-        flag = flag || ext == 'icns' && 'iconpath'
-        flag = flag || /^[A-Z]/.test(image) && 'appIcon'
-        flag = flag || /^png|gif|jpe?g$/.test(ext) && 'image'
-        flag = flag || ext && (image = ext) && 'icon'
-        flag = flag || 'icon'
-        args.push('--' + flag, image)
-      }
-      if (options.sticky) args.push('--sticky')
-      if (options.name) args.push('--name', options.name)
-      if (options.title) args.push(options.title)
-      this.exec.apply(this, args)
-    }
-  }
-  
-  JSpec.include({
-    name: 'Growl',
-    reporting: function(options){
-      var stats = JSpec.stats
-      if (stats.failures) Growl.notify('failed ' + stats.failures + ' assertions', { title: 'JSpec'})
-      else Growl.notify('passed ' + stats.passes + ' assertions', { title: 'JSpec' })
-    }
-  })
-  
-})()
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.jquery.js b/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.jquery.js
deleted file mode 100644 (file)
index 46422ec..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-
-// JSpec - jQuery - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
-
-JSpec
-.requires('jQuery', 'when using jspec.jquery.js')
-.include({
-  name: 'jQuery',
-  
-  // --- Initialize
-  
-  init : function() {
-    jQuery.ajaxSetup({ async: false })
-  },
-  
-  // --- Utilities
-  
-  utilities : {
-    element:  jQuery,
-    elements: jQuery,
-    sandbox : function() {
-      return jQuery('<div class="sandbox"></div>')
-    }
-  },
-  
-  // --- Matchers
-  
-  matchers : {    
-    have_tag      : "jQuery(expected, actual).length === 1",
-    have_one      : "alias have_tag",
-    have_tags     : "jQuery(expected, actual).length > 1",
-    have_many     : "alias have_tags",
-    have_any      : "alias have_tags",
-    have_child    : "jQuery(actual).children(expected).length === 1",
-    have_children : "jQuery(actual).children(expected).length > 1",
-    have_text     : "jQuery(actual).text() === expected",
-    have_value    : "jQuery(actual).val() === expected",
-    be_enabled    : "!jQuery(actual).attr('disabled')",
-    have_class    : "jQuery(actual).hasClass(expected)",
-    be_animated   : "jQuery(actual).queue().length > 0",        
-        
-    be_visible : function(actual) {
-      return jQuery(actual).css('display') != 'none' &&
-             jQuery(actual).css('visibility') != 'hidden' &&
-             jQuery(actual).attr('type') != 'hidden'
-    },
-    
-    be_hidden : function(actual) {
-      return !JSpec.does(actual, 'be_visible')
-    },
-    
-    have_classes : function(actual) {
-      return !JSpec.any(JSpec.toArray(arguments, 1), function(arg){
-        return !JSpec.does(actual, 'have_class', arg)
-      })
-    },
-
-    have_attr : function(actual, attr, value) {
-      return value ? jQuery(actual).attr(attr) == value:
-                     jQuery(actual).attr(attr)
-    },
-    
-    have_event_handlers : function(actual, expected) {
-      return jQuery(actual).data('events') ?
-        jQuery(actual).data('events').hasOwnProperty(expected) :
-          false
-    },
-    
-    'be disabled selected checked' : function(attr) {
-      return 'jQuery(actual).attr("' + attr + '")'
-    },
-    
-    'have type id title alt href src sel rev name target' : function(attr) {
-      return function(actual, value) {
-        return JSpec.does(actual, 'have_attr', attr, value)
-      }
-    }
-  }
-})
-
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.js b/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.js
deleted file mode 100644 (file)
index 131c745..0000000
+++ /dev/null
@@ -1,1893 +0,0 @@
-
-// JSpec - Core - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
-
-;(function(){
-
-  JSpec = {
-    version   : '4.3.2',
-    assert    : true,
-    cache     : {},
-    suites    : [],
-    modules   : [],
-    allSuites : [],
-               sharedBehaviors: [],
-    matchers  : {},
-    stubbed   : [],
-    options   : {},
-    request   : 'XMLHttpRequest' in this ? XMLHttpRequest : null,
-    stats     : { specs: 0, assertions: 0, failures: 0, passes: 0, specsFinished: 0, suitesFinished: 0 },
-
-    /**
-     * Default context in which bodies are evaluated.
-     *
-     * Replace context simply by setting JSpec.context
-     * to your own like below:
-     *
-     * JSpec.context = { foo : 'bar' }
-     *
-     * Contexts can be changed within any body, this can be useful
-     * in order to provide specific helper methods to specific suites.
-     *
-     * To reset (usually in after hook) simply set to null like below:
-     *
-     * JSpec.context = null
-     *
-     */
-
-     defaultContext : {
-      
-      /**
-       * Return an object used for proxy assertions. 
-       * This object is used to indicate that an object
-       * should be an instance of _object_, not the constructor
-       * itself.
-       *
-       * @param  {function} constructor
-       * @return {hash}
-       * @api public
-       */
-      
-      an_instance_of : function(constructor) {
-        return { an_instance_of : constructor }
-      },
-      
-      /**
-       * Load fixture at _path_.
-       *
-       * Fixtures are resolved as:
-       *
-       *  - <path>
-       *  - <path>.html
-       *
-       * @param  {string} path
-       * @return {string}
-       * @api public
-       */
-      
-      fixture : function(path) {
-        if (JSpec.cache[path]) return JSpec.cache[path]
-        return JSpec.cache[path] = 
-          JSpec.tryLoading(JSpec.options.fixturePath + '/' + path) ||
-          JSpec.tryLoading(JSpec.options.fixturePath + '/' + path + '.html')
-      },
-      
-      /**
-       * Load json fixture at _path_.
-       *
-       * JSON fixtures are resolved as:
-       *
-       *  - <path>
-       *  - <path>.json
-       *
-       * @param  {string} path
-       * @return {object}
-       * @api public
-       */
-      
-      json_fixture: function(path) {
-        if (!JSpec.cache['json:' + path])
-          JSpec.cache['json:' + path] =
-            JSpec.tryLoading(JSpec.options.fixturePath + '/' + path) ||
-            JSpec.tryLoading(JSpec.options.fixturePath + '/' + path + '.json')
-        try {
-          return eval('(' + JSpec.cache['json:' + path] + ')')
-        } catch (e) {
-          throw 'json_fixture("' + path + '"): ' + e
-        }
-      }
-    },
-
-    // --- Objects
-    
-    reporters : {
-      
-      /**
-       * Report to server.
-       * 
-       * Options:
-       *  - uri           specific uri to report to.
-       *  - verbose       weither or not to output messages
-       *  - failuresOnly  output failure messages only
-       *
-       * @api public
-       */
-      
-      Server : function(results, options) {
-        var uri = options.uri || 'http://' + window.location.host + '/results'
-        JSpec.post(uri, {
-          stats: JSpec.stats,
-          options: options,
-          results: map(results.allSuites, function(suite) {
-            if (suite.isExecutable())
-              return {
-                description: suite.description,
-                specs: map(suite.specs, function(spec) {
-                  return {
-                    description: spec.description,
-                    message: !spec.passed() ? spec.failure().message : null,
-                    status: spec.requiresImplementation() ? 'pending' :
-                              spec.passed() ? 'pass' :
-                                'fail',
-                    assertions: map(spec.assertions, function(assertion){
-                      return {
-                        passed: assertion.passed  
-                      }
-                    })
-                  }
-                })
-              }
-          })
-        })
-                       if ('close' in main) main.close()
-      },
-
-      /**
-       * Default reporter, outputting to the DOM.
-       *
-       * Options:
-       *   - reportToId    id of element to output reports to, defaults to 'jspec'
-       *   - failuresOnly  displays only suites with failing specs
-       *
-       * @api public
-       */
-
-      DOM : function(results, options) {
-        var id = option('reportToId') || 'jspec',
-            report = document.getElementById(id),
-            failuresOnly = option('failuresOnly'),
-            classes = results.stats.failures ? 'has-failures' : ''
-        if (!report) throw 'JSpec requires the element #' + id + ' to output its reports'
-        
-        function bodyContents(body) {
-          return JSpec.
-            escape(JSpec.contentsOf(body)).
-            replace(/^ */gm, function(a){ return (new Array(Math.round(a.length / 3))).join(' ') }).
-            replace(/\r\n|\r|\n/gm, '<br/>')
-        }
-        
-        report.innerHTML = '<div id="jspec-report" class="' + classes + '"><div class="heading"> \
-        <span class="passes">Passes: <em>' + results.stats.passes + '</em></span>                \
-        <span class="failures">Failures: <em>' + results.stats.failures + '</em></span>          \
-        <span class="passes">Duration: <em>' + results.duration + '</em> ms</span>          \
-        </div><table class="suites">' + map(results.allSuites, function(suite) {
-          var displaySuite = failuresOnly ? suite.ran && !suite.passed() : suite.ran
-          if (displaySuite && suite.isExecutable())
-            return '<tr class="description"><td colspan="2">' + escape(suite.description) + '</td></tr>' +
-              map(suite.specs, function(i, spec) {
-                return '<tr class="' + (i % 2 ? 'odd' : 'even') + '">' +
-                  (spec.requiresImplementation() ?
-                    '<td class="requires-implementation" colspan="2">' + escape(spec.description) + '</td>' :
-                      (spec.passed() && !failuresOnly) ?
-                        '<td class="pass">' + escape(spec.description)+ '</td><td>' + spec.assertionsGraph() + '</td>' :
-                          !spec.passed() ?
-                            '<td class="fail">' + escape(spec.description) + 
-                                                                                                       map(spec.failures(), function(a){ return '<em>' + escape(a.message) + '</em>' }).join('') +
-                                                                                                               '</td><td>' + spec.assertionsGraph() + '</td>' :
-                              '') +
-                  '<tr class="body"><td colspan="2"><pre>' + bodyContents(spec.body) + '</pre></td></tr>'
-              }).join('') + '</tr>'
-        }).join('') + '</table></div>'
-      },
-      
-      /**
-       * Terminal reporter.
-       *
-       * @api public
-       */
-       
-       Terminal : function(results, options) {
-         var failuresOnly = option('failuresOnly')
-         print(color("\n Passes: ", 'bold') + color(results.stats.passes, 'green') + 
-               color(" Failures: ", 'bold') + color(results.stats.failures, 'red') +
-               color(" Duration: ", 'bold') + color(results.duration, 'green') + " ms \n")
-              
-         function indent(string) {
-           return string.replace(/^(.)/gm, '  $1')
-         }
-         
-         each(results.allSuites, function(suite) {
-           var displaySuite = failuresOnly ? suite.ran && !suite.passed() : suite.ran
-            if (displaySuite && suite.isExecutable()) {
-              print(color(' ' + suite.description, 'bold'))
-              each(suite.specs, function(spec){
-                var assertionsGraph = inject(spec.assertions, '', function(graph, assertion){
-                  return graph + color('.', assertion.passed ? 'green' : 'red')
-                })
-                if (spec.requiresImplementation())
-                  print(color('  ' + spec.description, 'blue') + assertionsGraph)
-                else if (spec.passed() && !failuresOnly)
-                  print(color('  ' + spec.description, 'green') + assertionsGraph)
-                else if (!spec.passed())
-                  print(color('  ' + spec.description, 'red') + assertionsGraph + 
-                        "\n" + indent(map(spec.failures(), function(a){ return a.message }).join("\n")) + "\n")
-              })
-              print("")
-            }
-         })
-         
-         quit(results.stats.failures)
-       }
-    },
-    
-    Assertion : function(matcher, actual, expected, negate) {
-      extend(this, {
-        message: '',
-        passed: false,
-        actual: actual,
-        negate: negate,
-        matcher: matcher,
-        expected: expected,
-        
-        // Report assertion results
-        
-        report : function() {
-          if (JSpec.assert) 
-            this.passed ? JSpec.stats.passes++ : JSpec.stats.failures++
-          return this
-        },
-        
-        // Run the assertion
-        
-        run : function() {
-          // TODO: remove unshifting 
-          expected.unshift(actual)
-          this.result = matcher.match.apply(this, expected)
-          this.passed = negate ? !this.result : this.result
-          if (!this.passed) this.message = matcher.message.call(this, actual, expected, negate, matcher.name)
-          return this
-        }
-      })
-    },
-    
-    ProxyAssertion : function(object, method, times, negate) {
-      var self = this,
-          old = object[method]
-      
-      // Proxy
-      
-      object[method] = function(){
-        var args = toArray(arguments),
-            result = old.apply(object, args)
-        self.calls.push({ args : args, result : result })
-        return result
-      }
-      
-      // Times
-      
-      this.times = {
-        once  : 1,
-        twice : 2
-      }[times] || times || 1
-      
-      extend(this, {
-        calls: [],
-        message: '',
-        defer: true,
-        passed: false,
-        negate: negate,
-        object: object,
-        method: method,
-        
-        // Proxy return value
-        
-        and_return : function(result) {
-          this.expectedResult = result
-          return this
-        },
-        
-        // Proxy arguments passed
-        
-        with_args : function() {
-          this.expectedArgs = toArray(arguments)
-          return this
-        },
-        
-        // Check if any calls have failing results
-        
-        anyResultsFail : function() {
-          return any(this.calls, function(call){
-            return self.expectedResult.an_instance_of ?
-                     call.result.constructor != self.expectedResult.an_instance_of:
-                       !equal(self.expectedResult, call.result)
-          })
-        },
-        
-        // Check if any calls have passing results
-        
-        anyResultsPass : function() {
-          return any(this.calls, function(call){
-            return self.expectedResult.an_instance_of ?
-                     call.result.constructor == self.expectedResult.an_instance_of:
-                       equal(self.expectedResult, call.result)
-          })
-        },
-        
-        // Return the passing result
-        
-        passingResult : function() {
-          return this.anyResultsPass().result
-        },
-
-        // Return the failing result
-        
-        failingResult : function() {
-          return this.anyResultsFail().result
-        },
-        
-        // Check if any arguments fail
-        
-        anyArgsFail : function() {
-          return any(this.calls, function(call){
-            return any(self.expectedArgs, function(i, arg){
-              if (arg == null) return call.args[i] == null
-              return arg.an_instance_of ?
-                       call.args[i].constructor != arg.an_instance_of:
-                         !equal(arg, call.args[i])
-                       
-            })
-          })
-        },
-        
-        // Check if any arguments pass
-        
-        anyArgsPass : function() {
-          return any(this.calls, function(call){
-            return any(self.expectedArgs, function(i, arg){
-              return arg.an_instance_of ?
-                       call.args[i].constructor == arg.an_instance_of:
-                         equal(arg, call.args[i])
-                       
-            })
-          })
-        },
-        
-        // Return the passing args
-        
-        passingArgs : function() {
-          return this.anyArgsPass().args
-        },
-                
-        // Return the failing args
-        
-        failingArgs : function() {
-          return this.anyArgsFail().args
-        },
-        
-        // Report assertion results
-        
-        report : function() {
-          if (JSpec.assert) 
-            this.passed ? ++JSpec.stats.passes : ++JSpec.stats.failures
-          return this
-        },
-        
-        // Run the assertion
-                
-        run : function() {
-          var methodString = 'expected ' + object.toString() + '.' + method + '()' + (negate ? ' not' : '' )
-          
-          function times(n) {
-            return n > 2 ?  n + ' times' : { 1: 'once', 2: 'twice' }[n]
-          }
-          
-          if (this.expectedResult != null && (negate ? this.anyResultsPass() : this.anyResultsFail()))
-            this.message = methodString + ' to return ' + puts(this.expectedResult) + 
-              ' but ' + (negate ? 'it did' : 'got ' + puts(this.failingResult())) 
-
-          if (this.expectedArgs && (negate ? !this.expectedResult && this.anyArgsPass() : this.anyArgsFail()))
-            this.message = methodString + ' to be called with ' + puts.apply(this, this.expectedArgs) +
-             ' but was' + (negate ? '' : ' called with ' + puts.apply(this, this.failingArgs()))
-
-          if (negate ? !this.expectedResult && !this.expectedArgs && this.calls.length >= this.times : this.calls.length != this.times)
-            this.message = methodString + ' to be called ' + times(this.times) + 
-            ', but ' +  (this.calls.length == 0 ? ' was not called' : ' was called ' + times(this.calls.length))
-                
-          if (!this.message.length) 
-            this.passed = true
-          
-          return this
-        }
-      })
-    },
-      
-    /**
-     * Specification Suite block object.
-     *
-     * @param {string} description
-     * @param {function} body
-     * @api private
-     */
-
-    Suite : function(description, body, isShared) {
-      var self = this
-      extend(this, {
-        body: body,
-        description: description,
-        suites: [],
-                               sharedBehaviors: [],
-        specs: [],
-        ran: false,
-                               shared: isShared, 
-                               hooks: {        'before' : [], 'after' : [], 
-                                                                       'before_each' : [], 'after_each' : [],
-                                                                       'before_nested' : [], 'after_nested' : []},
-        
-                               // Add a spec to the suite
-
-        addSpec : function(description, body) {
-          var spec = new JSpec.Spec(description, body)
-          this.specs.push(spec)
-          JSpec.stats.specs++ // TODO: abstract
-          spec.suite = this
-        },
-
-        // Add a before hook to the suite
-
-        addBefore : function(options, body) {
-                                       body.options = options || {}
-          this.befores.push(body)
-        },
-
-        // Add an after hook to the suite
-
-        addAfter : function(options, body) {
-                                       body.options = options || {}
-          this.afters.unshift(body)
-        },
-
-        // Add a hook to the suite
-        addHook : function(hook, body) {
-          this.hooks[hook].push(body)
-        },
-
-        // Add a nested suite
-
-        addSuite : function(description, body, isShared) {
-          var suite = new JSpec.Suite(description, body, isShared)
-          JSpec.allSuites.push(suite)
-          suite.name = suite.description
-          suite.description = this.description + ' ' + suite.description
-          this.suites.push(suite)
-          suite.suite = this
-        },
-
-                               // Invoke a hook in context to this suite
-
-        hook : function(hook) {
-                                       if (hook != 'before' && hook != 'after')        
-               if (this.suite) this.suite.hook(hook)
-
-          each(this.hooks[hook], function(body) {
-            JSpec.evalBody(body, "Error in hook '" + hook + "', suite '" + self.description + "': ")
-          })
-        },
-                               
-        // Check if nested suites are present
-
-        hasSuites : function() {
-          return this.suites.length  
-        },
-
-        // Check if this suite has specs
-
-        hasSpecs : function() {
-          return this.specs.length
-        },
-
-        // Check if the entire suite passed
-
-        passed : function() {
-          return !any(this.specs, function(spec){
-            return !spec.passed() 
-          })
-        },
-
-                               isShared : function(){
-                                       return this.shared
-                               },
-
-                               isExecutable : function() {
-                                       return !this.isShared() && this.hasSpecs()
-                               }
-      })
-    },
-    
-    /**
-     * Specification block object.
-     *
-     * @param {string} description
-     * @param {function} body
-     * @api private
-     */
-
-    Spec : function(description, body) {
-      extend(this, {
-        body: body,
-        description: description,
-        assertions: [],
-        
-        // Add passing assertion
-        
-        pass : function(message) {
-          this.assertions.push({ passed: true, message: message })
-          if (JSpec.assert) ++JSpec.stats.passes
-        },
-        
-        // Add failing assertion
-        
-        fail : function(message) {
-          this.assertions.push({ passed: false, message: message })
-          if (JSpec.assert) ++JSpec.stats.failures
-        },
-                
-        // Run deferred assertions
-        
-        runDeferredAssertions : function() {
-          each(this.assertions, function(assertion){
-            if (assertion.defer) assertion.run().report(), hook('afterAssertion', assertion)
-          })
-        },
-        
-        // Find first failing assertion
-
-        failure : function() {
-          return find(this.assertions, function(assertion){
-            return !assertion.passed
-          })
-        },
-
-        // Find all failing assertions
-
-        failures : function() {
-          return select(this.assertions, function(assertion){
-            return !assertion.passed
-          })
-        },
-
-        // Weither or not the spec passed
-
-        passed : function() {
-          return !this.failure()
-        },
-
-        // Weither or not the spec requires implementation (no assertions)
-
-        requiresImplementation : function() {
-          return this.assertions.length == 0
-        },
-
-        // Sprite based assertions graph
-
-        assertionsGraph : function() {
-          return map(this.assertions, function(assertion){
-            return '<span class="assertion ' + (assertion.passed ? 'passed' : 'failed') + '"></span>'
-          }).join('')
-        }
-      })
-    },
-    
-    Module : function(methods) {
-      extend(this, methods)
-    },
-    
-    JSON : {
-      
-      /**
-       * Generic sequences.
-       */
-      
-      meta : {
-        '\b' : '\\b',
-        '\t' : '\\t',
-        '\n' : '\\n',
-        '\f' : '\\f',
-        '\r' : '\\r',
-        '"'  : '\\"',
-        '\\' : '\\\\'
-      },
-      
-      /**
-       * Escapable sequences.
-       */
-      
-      escapable : /[\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
-      
-      /**
-       * JSON encode _object_.
-       *
-       * @param  {mixed} object
-       * @return {string}
-       * @api private
-       */
-       
-      encode : function(object) {
-        var self = this
-        if (object == undefined || object == null) return 'null'
-        if (object === true) return 'true'
-        if (object === false) return 'false'
-        switch (typeof object) {
-          case 'number': return object
-          case 'string': return this.escapable.test(object) ?
-            '"' + object.replace(this.escapable, function (a) {
-              return typeof self.meta[a] === 'string' ? self.meta[a] :
-                '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4)
-            }) + '"' :
-            '"' + object + '"'
-          case 'object':  
-            if (object.constructor == Array)
-              return '[' + map(object, function(val){
-                return self.encode(val)
-              }).join(', ') + ']'
-            else if (object)
-              return '{' + map(object, function(key, val){
-                return self.encode(key) + ':' + self.encode(val)
-              }).join(', ') + '}'
-        }
-        return 'null'
-      }
-    },
-    
-    // --- DSLs
-    
-    DSLs : {
-      snake : {
-        expect : function(actual){
-          return JSpec.expect(actual)
-        },
-
-        describe : function(description, body) {
-          return JSpec.currentSuite.addSuite(description, body, false)
-        },
-
-        it : function(description, body) {
-          return JSpec.currentSuite.addSpec(description, body)
-        },
-
-        before : function(body) {
-          return JSpec.currentSuite.addHook('before', body)
-        },
-        after : function(body) {
-          return JSpec.currentSuite.addHook('after', body)
-        },
-        before_each : function(body) {
-          return JSpec.currentSuite.addHook('before_each', body)
-        },
-        after_each : function(body) {
-          return JSpec.currentSuite.addHook('after_each', body)
-        },
-
-                               before_nested : function(body) {
-                                       return JSpec.currentSuite.addHook('before_nested', body)
-                               },
-                               
-                               after_nested : function(body){
-                                       return JSpec.currentSuite.addhook('after_nested', body)
-                               },
-        
-                               shared_behaviors_for : function(description, body){
-                                 return JSpec.currentSuite.addSuite(description, body, true)
-                               },
-
-        should_behave_like : function(description) {
-          return JSpec.shareBehaviorsOf(description)
-        }
-      }
-    },
-
-    // --- Methods
-    
-    /**
-     * Check if _value_ is 'stop'. For use as a
-     * utility callback function.
-     *
-     * @param  {mixed} value
-     * @return {bool}
-     * @api public
-     */
-    
-    haveStopped : function(value) {
-      return value === 'stop'
-    },
-    
-    /**
-     * Include _object_ which may be a hash or Module instance.
-     *
-     * @param  {hash, Module} object
-     * @return {JSpec}
-     * @api public
-     */
-    
-    include : function(object) {
-      var module = object.constructor == JSpec.Module ? object : new JSpec.Module(object)
-      this.modules.push(module)
-      if ('init' in module) module.init()
-      if ('utilities' in module) extend(this.defaultContext, module.utilities)
-      if ('matchers' in module) this.addMatchers(module.matchers)
-      if ('reporters' in module) extend(this.reporters, module.reporters)
-      if ('DSLs' in module)
-        each(module.DSLs, function(name, methods){
-          JSpec.DSLs[name] = JSpec.DSLs[name] || {}
-          extend(JSpec.DSLs[name], methods)
-        })
-      return this
-    },
-    
-    /**
-     * Add a module hook _name_, which is immediately
-     * called per module with the _args_ given. An array of
-     * hook return values is returned.
-     *
-     * @param  {name} string
-     * @param  {...} args
-     * @return {array}
-     * @api private
-     */
-    
-    hook : function(name, args) {
-      args = toArray(arguments, 1)
-      return inject(JSpec.modules, [], function(results, module){
-        if (typeof module[name] == 'function')
-          results.push(JSpec.evalHook(module, name, args))
-      })
-    },
-    
-    /**
-     * Eval _module_ hook _name_ with _args_. Evaluates in context
-     * to the module itself, JSpec, and JSpec.context.
-     *
-     * @param  {Module} module
-     * @param  {string} name
-     * @param  {array} args
-     * @return {mixed}
-     * @api private
-     */
-    
-    evalHook : function(module, name, args) {
-      hook('evaluatingHookBody', module, name)
-      return module[name].apply(module, args)
-    },
-    
-    /**
-     * Same as hook() however accepts only one _arg_ which is
-     * considered immutable. This function passes the arg
-     * to the first module, then passes the return value of the last
-     * module called, to the following module. 
-     *
-     * @param  {string} name
-     * @param  {mixed} arg
-     * @return {mixed}
-     * @api private
-     */
-    
-    hookImmutable : function(name, arg) {
-      return inject(JSpec.modules, arg, function(result, module){
-        if (typeof module[name] == 'function')
-          return JSpec.evalHook(module, name, [result])
-      })
-    },
-    
-    /**
-     * Find a shared example suite by its description or name.
-     * First searches parent tree of suites for shared behavior
-     * before falling back to global scoped nested behaviors.
-     *
-     * @param  {string} description
-     * @return {Suite}
-     * @api private
-     */
-    
-    findSharedBehavior : function(description) {
-      var behavior
-      return (behavior = JSpec.findLocalSharedBehavior(description))
-        ? behavior
-        : JSpec.findGlobalSharedBehavior(description)
-    },
-
-    /**
-     * Find a shared example suite within the current suite's
-     * parent tree by its description or name.
-     *
-     * @param  {string} description
-     * @return {Suite}
-     * @api private
-     */
-     
-               findLocalSharedBehavior : function(description) {
-                       var behavior,
-                           currentSuite = JSpec.currentSuite.suite
-                       while (currentSuite)
-                               if (behavior = find(currentSuite.suites, JSpec.suiteDescriptionPredicate(description)))
-                                 return behavior
-                               else
-                                 currentSuite = currentSuite.suite
-               },
-               
-    /**
-     * Find a shared example suite within the global
-     * scope by its description or name.
-     *
-     * @param  {string} description
-     * @return {Suite}
-     * @api private
-     */
-     
-               findGlobalSharedBehavior : function(description) {
-          return find(JSpec.suites, JSpec.suiteDescriptionPredicate(description))
-               },
-    
-    /**
-     * Build a predicate that will match a suite based on name or description
-     *
-     * @param  {string} description
-     * @return {function}
-     * @api private
-     */
-     
-               suiteDescriptionPredicate : function(description) {
-                       return function(suite){
-                         return suite.name === description ||
-                                suite.description === description
-                       }
-               },
-
-    /**
-     * Share behaviors (specs) of the given suite with
-     * the current suite.
-     *
-     * @param  {string} description
-     * @api public
-     */
-    
-    shareBehaviorsOf : function(description) {
-      var suite = JSpec.findSharedBehavior(description)
-      if (suite)
-        JSpec.evalBody(suite.body)
-      else
-        throw new Error("failed to find shared behaviors named `" + description + "'")
-    },
-    
-    
-    /**
-     * Convert arguments to an array.
-     *
-     * @param  {object} arguments
-     * @param  {int} offset
-     * @return {array}
-     * @api public
-     */
-    
-    toArray : function(arguments, offset) {
-      return Array.prototype.slice.call(arguments, offset || 0)
-    },
-    
-    /**
-     * Return ANSI-escaped colored string.
-     *
-     * @param  {string} string
-     * @param  {string} color
-     * @return {string}
-     * @api public
-     */
-    
-    color : function(string, color) {
-      if (option('disableColors')) {
-        return string
-      } else {
-        return "\u001B[" + {
-         bold    : 1,
-         black   : 30,
-         red     : 31,
-         green   : 32,
-         yellow  : 33,
-         blue    : 34,
-         magenta : 35,
-         cyan    : 36,
-         white   : 37
-        }[color] + 'm' + string + "\u001B[0m"
-      }
-    },
-    
-    /**
-     * Default matcher message callback.
-     *
-     * @api private
-     */
-    
-    defaultMatcherMessage : function(actual, expected, negate, name) {
-      return 'expected ' + puts(actual) + ' to ' + 
-               (negate ? 'not ' : '') + 
-                  name.replace(/_/g, ' ') +
-                    ' ' + (expected.length > 1 ?
-                      puts.apply(this, expected.slice(1)) :
-                        '')
-    },
-    
-    /**
-     * Normalize a matcher message.
-     *
-     * When no messge callback is present the defaultMatcherMessage
-     * will be assigned, will suffice for most matchers.
-     *
-     * @param  {hash} matcher
-     * @return {hash}
-     * @api public
-     */
-    
-    normalizeMatcherMessage : function(matcher) {
-      if (typeof matcher.message != 'function') 
-        matcher.message = this.defaultMatcherMessage
-      return matcher
-    },
-    
-    /**
-     * Normalize a matcher body
-     * 
-     * This process allows the following conversions until
-     * the matcher is in its final normalized hash state.
-     *
-     * - '==' becomes 'actual == expected'
-     * - 'actual == expected' becomes 'return actual == expected'
-     * - function(actual, expected) { return actual == expected } becomes 
-     *   { match : function(actual, expected) { return actual == expected }}
-     *
-     * @param  {mixed} body
-     * @return {hash}
-     * @api public
-     */
-    
-    normalizeMatcherBody : function(body) {
-      var captures
-      switch (body.constructor) {
-        case String:
-          if (captures = body.match(/^alias (\w+)/)) return JSpec.matchers[last(captures)]
-          if (body.length < 4) body = 'actual ' + body + ' expected'
-          return { match: function(actual, expected) { return eval(body) }}  
-          
-        case Function:
-          return { match: body }
-          
-        default:
-          return body
-      }
-    },
-    
-    /**
-     * Get option value. This method first checks if
-     * the option key has been set via the query string,
-     * otherwise returning the options hash value.
-     *
-     * @param  {string} key
-     * @return {mixed}
-     * @api public
-     */
-     
-     option : function(key) {
-       return (value = query(key)) !== null ? value :
-                JSpec.options[key] || null
-     },
-     
-     /**
-      * Check if object _a_, is equal to object _b_.
-      *
-      * @param  {object} a
-      * @param  {object} b
-      * @return {bool}
-      * @api private
-      */
-     
-     equal: function(a, b) {
-       if (typeof a != typeof b) return
-       if (a === b) return true
-       if (a instanceof RegExp)
-         return a.toString() === b.toString()
-       if (a instanceof Date)
-         return Number(a) === Number(b)
-       if (typeof a != 'object') return
-       if (a.length !== undefined)
-         if (a.length !== b.length) return
-         else
-           for (var i = 0, len = a.length; i < len; ++i)
-             if (!equal(a[i], b[i]))
-               return
-       for (var key in a)
-         if (!equal(a[key], b[key]))
-           return
-       return true
-     },
-
-    /**
-     * Return last element of an array.
-     *
-     * @param  {array} array
-     * @return {object}
-     * @api public
-     */
-
-    last : function(array) {
-      return array[array.length - 1]
-    },
-
-    /**
-     * Convert object(s) to a print-friend string.
-     *
-     * @param  {...} object
-     * @return {string}
-     * @api public
-     */
-
-    puts : function(object) {
-      if (arguments.length > 1)
-        return map(toArray(arguments), function(arg){
-          return puts(arg)
-        }).join(', ')
-      if (object === undefined) return 'undefined'
-      if (object === null) return 'null'
-      if (object === true) return 'true'
-      if (object === false) return 'false'
-      if (object.an_instance_of) return 'an instance of ' + object.an_instance_of.name
-      if (object.jquery && object.selector.length > 0) return 'selector ' + puts(object.selector)
-      if (object.jquery) return object.get(0).outerHTML
-      if (object.nodeName) return object.outerHTML
-      switch (object.constructor) {
-        case Function: return object.name || object 
-        case String: 
-          return '"' + object
-            .replace(/"/g,  '\\"')
-            .replace(/\n/g, '\\n')
-            .replace(/\t/g, '\\t')
-            + '"'
-        case Array: 
-          return inject(object, '[', function(b, v){
-            return b + ', ' + puts(v)
-          }).replace('[,', '[') + ' ]'
-        case Object:
-          object.__hit__ = true
-          return inject(object, '{', function(b, k, v) {
-            if (k == '__hit__') return b
-            return b + ', ' + k + ': ' + (v && v.__hit__ ? '<circular reference>' : puts(v))
-          }).replace('{,', '{') + ' }'
-        default: 
-          return object.toString()
-      }
-    },
-
-    /**
-     * Parse an XML String and return a 'document'.
-     *
-     * @param {string} text
-     * @return {document}
-     * @api public
-     */
-
-    parseXML : function(text) {
-      var xmlDoc
-      if (window.DOMParser)
-        xmlDoc = (new DOMParser()).parseFromString(text, "text/xml")
-      else {
-        xmlDoc = new ActiveXObject("Microsoft.XMLDOM")
-        xmlDoc.async = "false"
-        xmlDoc.loadXML(text)
-      }
-      return xmlDoc
-    },
-
-    /**
-     * Escape HTML.
-     *
-     * @param  {string} html
-     * @return {string}
-     * @api public
-     */
-
-     escape : function(html) {
-       return html.toString()
-         .replace(/&/gmi, '&amp;')
-         .replace(/"/gmi, '&quot;')
-         .replace(/>/gmi, '&gt;')
-         .replace(/</gmi, '&lt;')
-     },
-     
-     /**
-      * Perform an assertion without reporting.
-      *
-      * This method is primarily used for internal
-      * matchers in order retain DRYness. May be invoked 
-      * like below:
-      *
-      *   does('foo', 'eql', 'foo')
-      *   does([1,2], 'include', 1, 2)
-      *
-      * External hooks are not run for internal assertions
-      * performed by does().
-      *
-      * @param  {mixed} actual
-      * @param  {string} matcher
-      * @param  {...} expected
-      * @return {mixed}
-      * @api private
-      */
-     
-     does : function(actual, matcher, expected) {
-       var assertion = new JSpec.Assertion(JSpec.matchers[matcher], actual, toArray(arguments, 2))
-       return assertion.run().result
-     },
-
-    /**
-     * Perform an assertion.
-     *
-     *   expect(true).to('be', true)
-     *   expect('foo').not_to('include', 'bar')
-     *   expect([1, [2]]).to('include', 1, [2])
-     *
-     * @param  {mixed} actual
-     * @return {hash}
-     * @api public
-     */
-
-    expect : function(actual) {
-      function assert(matcher, args, negate) {
-        var expected = toArray(args, 1)
-        matcher.negate = negate  
-        var assertion = new JSpec.Assertion(matcher, actual, expected, negate)
-        hook('beforeAssertion', assertion)
-        if (matcher.defer) assertion.run()
-        else JSpec.currentSpec.assertions.push(assertion.run().report()), hook('afterAssertion', assertion)
-        return assertion.result
-      }
-      
-      function to(matcher) {
-        return assert(matcher, arguments, false)
-      }
-      
-      function not_to(matcher) {
-        return assert(matcher, arguments, true)
-      }
-      
-      return {
-        to : to,
-        should : to,
-        not_to: not_to,
-        should_not : not_to
-      }
-    },
-
-    /**
-     * Strim whitespace or chars.
-     *
-     * @param  {string} string
-     * @param  {string} chars
-     * @return {string}
-     * @api public
-     */
-
-     strip : function(string, chars) {
-       return string.
-         replace(new RegExp('['  + (chars || '\\s') + ']*$'), '').
-         replace(new RegExp('^[' + (chars || '\\s') + ']*'),  '')
-     },
-     
-     /**
-      * Call an iterator callback with arguments a, or b
-      * depending on the arity of the callback.
-      *
-      * @param  {function} callback
-      * @param  {mixed} a
-      * @param  {mixed} b
-      * @return {mixed}
-      * @api private
-      */
-     
-     callIterator : function(callback, a, b) {
-       return callback.length == 1 ? callback(b) : callback(a, b)
-     },
-     
-     /**
-      * Extend an object with another.
-      *
-      * @param  {object} object
-      * @param  {object} other
-      * @api public
-      */
-     
-     extend : function(object, other) {
-       each(other, function(property, value){
-         object[property] = value
-       })
-     },
-     
-     /**
-      * Iterate an object, invoking the given callback.
-      *
-      * @param  {hash, array} object
-      * @param  {function} callback
-      * @return {JSpec}
-      * @api public
-      */
-
-     each : function(object, callback) {
-       if (object.constructor == Array)
-         for (var i = 0, len = object.length; i < len; ++i)
-           callIterator(callback, i, object[i])
-       else
-         for (var key in object) 
-           if (object.hasOwnProperty(key))
-             callIterator(callback, key, object[key])
-     },
-
-     /**
-      * Iterate with memo.
-      *
-      * @param  {hash, array} object
-      * @param  {object} memo
-      * @param  {function} callback
-      * @return {object}
-      * @api public
-      */
-
-     inject : function(object, memo, callback) {
-       each(object, function(key, value){
-         memo = (callback.length == 2 ?
-                   callback(memo, value):
-                     callback(memo, key, value)) ||
-                       memo
-       })
-       return memo
-     },
-     
-     /**
-      * Destub _object_'s _method_. When no _method_ is passed
-      * all stubbed methods are destubbed. When no arguments
-      * are passed every object found in JSpec.stubbed will be
-      * destubbed.
-      *
-      * @param  {mixed} object
-      * @param  {string} method
-      * @api public
-      */
-     
-     destub : function(object, method) {
-       var captures
-       if (method) {
-         if (object['__prototype__' + method])
-           delete object[method]
-         else
-           object[method] = object['__original__' + method]
-         delete object['__prototype__' + method]
-         delete object['__original____' + method]
-       }
-       else if (object) {
-         for (var key in object)
-           if (captures = key.match(/^(?:__prototype__|__original__)(.*)/))
-             destub(object, captures[1])
-       }
-       else
-         while (JSpec.stubbed.length)
-            destub(JSpec.stubbed.shift())
-     },
-     
-     /**
-      * Stub _object_'s _method_. 
-      *
-      * stub(foo, 'toString').and_return('bar')
-      *
-      * @param  {mixed} object
-      * @param  {string} method
-      * @return {hash}
-      * @api public
-      */
-     
-     stub : function(object, method) {
-       hook('stubbing', object, method)
-       JSpec.stubbed.push(object)
-       var type = object.hasOwnProperty(method) ? '__original__' : '__prototype__'
-       object[type + method] = object[method]
-       object[method] = function(){}
-       return {
-         and_return : function(value) {
-           if (typeof value == 'function') object[method] = value
-           else object[method] = function(){ return value }
-         }
-      }
-     },
-     
-    /**
-     * Map callback return values.
-     *
-     * @param  {hash, array} object
-     * @param  {function} callback
-     * @return {array}
-     * @api public
-     */
-
-    map : function(object, callback) {
-      return inject(object, [], function(memo, key, value){
-        memo.push(callIterator(callback, key, value))
-      })
-    },
-    
-    /**
-     * Returns the first matching expression or null.
-     *
-     * @param  {hash, array} object
-     * @param  {function} callback
-     * @return {mixed}
-     * @api public
-     */
-         
-    any : function(object, callback) {
-      return inject(object, null, function(state, key, value){
-        if (state == undefined)
-          return callIterator(callback, key, value) ? value : state
-      })
-    },
-    
-    /**
-     * Returns an array of values collected when the callback
-     * given evaluates to true.
-     *
-     * @param  {hash, array} object
-     * @return {function} callback
-     * @return {array}
-     * @api public
-     */
-    
-    select : function(object, callback) {
-      return inject(object, [], function(selected, key, value){
-        if (callIterator(callback, key, value))
-          selected.push(value)
-      })
-    },
-
-    /**
-     * Define matchers.
-     *
-     * @param  {hash} matchers
-     * @api public
-     */
-
-    addMatchers : function(matchers) {
-      each(matchers, function(name, body){
-        JSpec.addMatcher(name, body)  
-      })
-    },
-    
-    /**
-     * Define a matcher.
-     *
-     * @param  {string} name
-     * @param  {hash, function, string} body
-     * @api public
-     */
-    
-    addMatcher : function(name, body) {
-      hook('addingMatcher', name, body)
-      if (name.indexOf(' ') != -1) {
-        var matchers = name.split(/\s+/)
-        var prefix = matchers.shift()
-        each(matchers, function(name) {
-          JSpec.addMatcher(prefix + '_' + name, body(name))
-        })
-      }
-      this.matchers[name] = this.normalizeMatcherMessage(this.normalizeMatcherBody(body))
-      this.matchers[name].name = name
-    },
-    
-    /**
-     * Add a root suite to JSpec.
-     *
-     * @param  {string} description
-     * @param  {body} function
-     * @api public
-     */
-    
-    describe : function(description, body) {
-      var suite = new JSpec.Suite(description, body, false)
-      hook('addingSuite', suite)
-      this.allSuites.push(suite)
-      this.suites.push(suite)
-    },
-    
-    /**
-     * Add a shared example suite to JSpec.
-     *
-     * @param  {string} description
-     * @param  {body} function
-     * @api public
-     */
-    
-    shared_behaviors_for : function(description, body) {
-      var suite = new JSpec.Suite(description, body, true)
-      hook('addingSuite', suite)
-      this.allSuites.push(suite)
-      this.suites.push(suite)
-    },
-
-    /**
-     * Return the contents of a function body.
-     *
-     * @param  {function} body
-     * @return {string}
-     * @api public
-     */
-    
-    contentsOf : function(body) {
-      return body.toString().match(/^[^\{]*{((.*\n*)*)}/m)[1]
-    },
-
-    /**
-     * Evaluate a JSpec capture body.
-     *
-     * @param  {function} body
-     * @param  {string} errorMessage (optional)
-     * @return {Type}
-     * @api private
-     */
-
-    evalBody : function(body, errorMessage) {
-      var dsl = this.DSL || this.DSLs.snake
-      var matchers = this.matchers
-      var context = this.context || this.defaultContext
-      var contents = this.contentsOf(body)
-                       hook('evaluatingBody', dsl, matchers, context, contents)
-      with (dsl){ with (context) { with (matchers) { eval(contents) }}}
-    },
-
-    /**
-     * Pre-process a string of JSpec.
-     *
-     * @param  {string} input
-     * @return {string}
-     * @api private
-     */
-
-    preprocess : function(input) {
-      if (typeof input != 'string') return
-      input = hookImmutable('preprocessing', input)
-      return input.
-        replace(/\t/g, '  ').
-        replace(/\r\n|\n|\r/g, '\n').
-        split('__END__')[0].
-        replace(/([\w\.]+)\.(stub|destub)\((.*?)\)$/gm, '$2($1, $3)').
-        replace(/describe\s+(.*?)$/gm, 'describe($1, function(){').
-        replace(/shared_behaviors_for\s+(.*?)$/gm, 'shared_behaviors_for($1, function(){').
-        replace(/^\s+it\s+(.*?)$/gm, ' it($1, function(){').
-                               replace(/^ *(before_nested|after_nested|before_each|after_each|before|after)(?= |\n|$)/gm, 'JSpec.currentSuite.addHook("$1", function(){').
-        replace(/^\s*end(?=\s|$)/gm, '});').
-        replace(/-\{/g, 'function(){').
-        replace(/(\d+)\.\.(\d+)/g, function(_, a, b){ return range(a, b) }).
-        replace(/\.should([_\.]not)?[_\.](\w+)(?: |;|$)(.*)$/gm, '.should$1_$2($3)').
-        replace(/([\/\s]*)(.+?)\.(should(?:[_\.]not)?)[_\.](\w+)\((.*)\)\s*;?$/gm, '$1 expect($2).$3($4, $5)').
-        replace(/, \)/g, ')').
-        replace(/should\.not/g, 'should_not')
-    },
-
-    /**
-     * Create a range string which can be evaluated to a native array.
-     *
-     * @param  {int} start
-     * @param  {int} end
-     * @return {string}
-     * @api public
-     */
-
-    range : function(start, end) {
-      var current = parseInt(start), end = parseInt(end), values = [current]
-      if (end > current) while (++current <= end) values.push(current)
-      else               while (--current >= end) values.push(current)
-      return '[' + values + ']'
-    },
-
-    /**
-     * Report on the results. 
-     *
-     * @api public
-     */
-
-    report : function() {
-      this.duration = Number(new Date) - this.start
-      hook('reporting', JSpec.options)
-      new (JSpec.options.reporter || JSpec.reporters.DOM)(JSpec, JSpec.options)
-    },
-
-    /**
-     * Run the spec suites. Options are merged
-     * with JSpec options when present.
-     *
-     * @param  {hash} options
-     * @return {JSpec}
-     * @api public
-     */
-
-    run : function(options) {
-      if (any(hook('running'), haveStopped)) return this
-      if (options) extend(this.options, options)
-      this.start = Number(new Date)
-      each(this.suites, function(suite) { JSpec.runSuite(suite) })
-      return this
-    },
-    
-    /**
-     * Run a suite.
-     *
-     * @param  {Suite} suite
-     * @api public
-     */
-
-    runSuite : function(suite) {
-                       if (!suite.isShared())
-                       {
-             this.currentSuite = suite
-             this.evalBody(suite.body)
-             suite.ran = true
-             hook('beforeSuite', suite), suite.hook('before'), suite.hook('before_nested')
-             each(suite.specs, function(spec) {
-               hook('beforeSpec', spec)
-               suite.hook('before_each')
-               JSpec.runSpec(spec)
-               hook('afterSpec', spec)
-               suite.hook('after_each')
-             })
-             if (suite.hasSuites()) {
-               each(suite.suites, function(suite) {
-                 JSpec.runSuite(suite)
-               })
-             }
-             hook('afterSuite', suite), suite.hook('after_nested'), suite.hook('after')
-             this.stats.suitesFinished++
-                       }       
-               },
-         
-    /**
-     * Report a failure for the current spec.
-     *
-     * @param  {string} message
-     * @api public
-     */
-     
-     fail : function(message) {
-       JSpec.currentSpec.fail(message)
-     },
-     
-     /**
-      * Report a passing assertion for the current spec.
-      *
-      * @param  {string} message
-      * @api public
-      */
-      
-     pass : function(message) {
-       JSpec.currentSpec.pass(message)
-     },
-
-    /**
-     * Run a spec.
-     *
-     * @param  {Spec} spec
-     * @api public
-     */
-
-    runSpec : function(spec) {
-      this.currentSpec = spec
-      try { this.evalBody(spec.body) }
-      catch (e) { fail(e) }
-      spec.runDeferredAssertions()
-      destub()
-      this.stats.specsFinished++
-      this.stats.assertions += spec.assertions.length
-    },
-
-    /**
-     * Require a dependency, with optional message.
-     *
-     * @param  {string} dependency
-     * @param  {string} message (optional)
-     * @return {JSpec}
-     * @api public
-     */
-
-    requires : function(dependency, message) {
-      hook('requiring', dependency, message)
-      try { eval(dependency) }
-      catch (e) { throw 'JSpec depends on ' + dependency + ' ' + message }
-      return this
-    },
-
-    /**
-     * Query against the current query strings keys
-     * or the queryString specified.
-     *
-     * @param  {string} key
-     * @param  {string} queryString
-     * @return {string, null}
-     * @api private
-     */
-
-    query : function(key, queryString) {
-      var queryString = (queryString || (main.location ? main.location.search : null) || '').substring(1)
-      return inject(queryString.split('&'), null, function(value, pair){
-        parts = pair.split('=')
-        return parts[0] == key ? parts[1].replace(/%20|\+/gmi, ' ') : value
-      })
-    },
-
-    /**
-     * Ad-hoc POST request for JSpec server usage.
-     *
-     * @param  {string} uri
-     * @param  {string} data
-     * @api private
-     */
-    
-    post : function(uri, data) {
-      if (any(hook('posting', uri, data), haveStopped)) return
-      var request = this.xhr()
-      request.open('POST', uri, false)
-      request.setRequestHeader('Content-Type', 'application/json')
-      request.send(JSpec.JSON.encode(data))
-    },
-
-    /**
-     * Instantiate an XMLHttpRequest.
-     *
-     * Here we utilize IE's lame ActiveXObjects first which
-     * allow IE access serve files via the file: protocol, otherwise
-     * we then default to XMLHttpRequest.
-     *
-     * @return {XMLHttpRequest, ActiveXObject}
-     * @api private
-     */
-    
-    xhr : function() {
-      return this.ieXhr() || new JSpec.request
-    },
-    
-    /**
-     * Return Microsoft piece of crap ActiveXObject.
-     *
-     * @return {ActiveXObject}
-     * @api public
-     */
-    
-    ieXhr : function() {
-      function object(str) {
-        try { return new ActiveXObject(str) } catch(e) {}
-      }
-      return object('Msxml2.XMLHTTP.6.0') ||
-        object('Msxml2.XMLHTTP.3.0') ||
-        object('Msxml2.XMLHTTP') ||
-        object('Microsoft.XMLHTTP')
-    },
-    
-    /**
-     * Check for HTTP request support.
-     *
-     * @return {bool}
-     * @api private
-     */
-    
-    hasXhr : function() {
-      return JSpec.request || 'ActiveXObject' in main
-    },
-    
-    /**
-     * Try loading _file_ returning the contents
-     * string or null. Chain to locate / read a file.
-     *
-     * @param  {string} file
-     * @return {string}
-     * @api public
-     */
-    
-    tryLoading : function(file) {
-      try { return JSpec.load(file) } catch (e) {}
-    },
-
-    /**
-     * Load a _file_'s contents.
-     *
-     * @param  {string} file
-     * @param  {function} callback
-     * @return {string}
-     * @api public
-     */
-
-    load : function(file, callback) {
-      if (any(hook('loading', file), haveStopped)) return
-      if ('readFile' in main)
-        return readFile(file)
-      else if (this.hasXhr()) {
-        var request = this.xhr()
-        request.open('GET', file, false)
-        request.send(null)
-        if (request.readyState == 4 && 
-           (request.status == 0 || 
-            request.status.toString().charAt(0) == 2)) 
-          return request.responseText
-      }
-      else
-        throw new Error("failed to load `" + file + "'")
-    },
-
-    /**
-     * Load, pre-process, and evaluate a file.
-     *
-     * @param {string} file
-     * @param {JSpec}
-     * @api public
-     */
-
-    exec : function(file) {
-      if (any(hook('executing', file), haveStopped)) return this
-      eval('with (JSpec){' + this.preprocess(this.load(file)) + '}')
-      return this
-    }
-  }
-  
-  // --- Node.js support
-  
-  if (typeof GLOBAL === 'object' && typeof exports === 'object') {
-    var fs = require('fs')
-    quit = process.exit
-    print = require('sys').puts
-    readFile = function(file){
-      return fs.readFileSync(file).toString('utf8')
-    }
-  }
-  
-  // --- Utility functions
-
-  var main = this,
-      find = JSpec.any,
-      utils = 'haveStopped stub hookImmutable hook destub map any last pass fail range each option inject select \
-               error escape extend puts query strip color does addMatchers callIterator toArray equal'.split(/\s+/)
-  while (utils.length) eval('var ' + utils[0] + ' = JSpec.' + utils.shift())
-  if (!main.setTimeout) main.setTimeout = function(callback){ callback() }
-
-  // --- Matchers
-
-  addMatchers({
-    equal              : "===",
-    eql                : "equal(actual, expected)",
-    be                 : "alias equal",
-    be_greater_than    : ">",
-    be_less_than       : "<",
-    be_at_least        : ">=",
-    be_at_most         : "<=",
-    be_a               : "actual.constructor == expected",
-    be_an              : "alias be_a",
-    be_an_instance_of  : "actual instanceof expected",
-    be_null            : "actual == null",
-    be_true            : "actual == true",
-    be_false           : "actual == false",
-    be_undefined       : "typeof actual == 'undefined'",
-    be_type            : "typeof actual == expected",
-    match              : "typeof actual == 'string' ? actual.match(expected) : false",
-    respond_to         : "typeof actual[expected] == 'function'",
-    have_length        : "actual.length == expected",
-    be_within          : "actual >= expected[0] && actual <= last(expected)",
-    have_length_within : "actual.length >= expected[0] && actual.length <= last(expected)",
-    
-    receive : { defer : true, match : function(actual, method, times) {
-      var proxy = new JSpec.ProxyAssertion(actual, method, times, this.negate)
-      JSpec.currentSpec.assertions.push(proxy)
-      return proxy
-    }},
-    
-    be_empty : function(actual) {
-      if (actual.constructor == Object && actual.length == undefined)
-        for (var key in actual)
-          return false;
-      return !actual.length
-    },
-
-    include : function(actual) {
-      for (var state = true, i = 1; i < arguments.length; i++) {
-        var arg = arguments[i]
-        switch (actual.constructor) {
-          case String: 
-          case Number:
-          case RegExp:
-          case Function:
-            state = actual.toString().indexOf(arg) !== -1
-            break
-         
-          case Object:
-            state = arg in actual
-            break
-          
-          case Array: 
-            state = any(actual, function(value){ return equal(value, arg) })
-            break
-        }
-        if (!state) return false
-      }
-      return true
-    },
-
-    throw_error : { match : function(actual, expected, message) {
-      try { actual() }
-      catch (e) {
-        this.e = e
-        var assert = function(arg) {
-          switch (arg.constructor) {
-            case RegExp   : return arg.test(e.message || e.toString())
-            case String   : return arg == (e.message || e.toString())
-            case Function : return e instanceof arg || e.name == arg.name
-          }
-        }
-        return message ? assert(expected) && assert(message) :
-                 expected ? assert(expected) :
-                   true
-      }
-    }, message : function(actual, expected, negate) {
-      // TODO: refactor when actual is not in expected [0]
-      var message_for = function(i) {
-        if (expected[i] == undefined) return 'exception'
-        switch (expected[i].constructor) {
-          case RegExp   : return 'exception matching ' + puts(expected[i])
-          case String   : return 'exception of ' + puts(expected[i])
-          case Function : return expected[i].name || 'Error'
-        }
-      }
-      var exception = message_for(1) + (expected[2] ? ' and ' + message_for(2) : '')
-      return 'expected ' + exception + (negate ? ' not ' : '' ) +
-               ' to be thrown, but ' + (this.e ? 'got ' + puts(this.e) : 'nothing was')
-    }},
-    
-    have : function(actual, length, property) {
-      return actual[property] == null ? false : actual[property].length == length
-    },
-    
-    have_at_least : function(actual, length, property) {
-      return actual[property] == null ? (length === 0) : actual[property].length >= length
-    },
-    
-    have_at_most :function(actual, length, property) {
-      return actual[property] == null || actual[property].length <= length
-    },
-    
-    have_within : function(actual, range, property) {
-      var length = actual[property] == undefined ? 0 : actual[property].length
-      return length >= range.shift() && length <= range.pop()
-    },
-    
-    have_prop : function(actual, property, value) {
-      var actualVal = actual[property], actualType = typeof actualVal
-      return (actualType == 'function' || actualType == 'undefined') ? false :
-        typeof value === 'undefined' ||
-        does(actual[property],'eql',value)
-    },
-    
-    have_property : function(actual, property, value) {
-      var actualVal = actual[property], actualType = typeof actualVal
-      return (actualType == 'function' || actualType == 'undefined') ? false :
-        typeof value === 'undefined' ||
-        value === actualVal
-    }
-  })
-  
-})()
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.nodejs.js b/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.nodejs.js
deleted file mode 100644 (file)
index 6765273..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-
-// JSpec - node - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
-
-JSpec
-.include({
-  name: 'node',
-  
-  // --- Matchers
-  
-  matchers : {
-    have_enumerable_property: 'actual.propertyIsEnumerable(expected)',
-    have_writable_property: 'Object.getOwnPropertyDescriptor(actual, expected).writable === true',
-    have_configurable_property: 'Object.getOwnPropertyDescriptor(actual, expected).configurable === true',
-    have_keys: 'does(Object.keys(actual), "eql", expected)',
-    have_prototype: 'Object.getPrototypeOf(actual) === expected'
-  }
-})
-
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.shell.js b/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.shell.js
deleted file mode 100644 (file)
index cb19c69..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-
-// JSpec - Shell - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
-
-;(function(){
-  
-  var _quit = quit
-  
-  Shell = {
-    
-    // --- Global
-    
-    main: this,
-    
-    // --- Commands
-    
-    commands: {
-      quit: ['Terminate the shell', function(){ _quit() }],
-      exit: ['Terminate the shell', function(){ _quit() }],
-      p: ['Inspect an object', function(o){ return o.toSource() }]
-    },
-    
-    /**
-     * Start the interactive shell.
-     *
-     * @api public
-     */
-    
-    start : function() {
-      for (var name in this.commands)
-        if (this.commands.hasOwnProperty(name))
-          this.commands[name][1].length ?
-            this.main[name] = this.commands[name][1] :
-              this.main.__defineGetter__(name, this.commands[name][1])
-    }
-  }
-  
-  Shell.start()
-  
-})()
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.timers.js b/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.timers.js
deleted file mode 100644 (file)
index c88d10b..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-
-// JSpec - Mock Timers - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
-
-;(function(){
-  
-  /**
-   * Version.
-   */
-   
-  mockTimersVersion = '1.0.2'
-  
-  /**
-   * Localized timer stack.
-   */
-  
-  var timers = []
-  
-  /**
-   * Set mock timeout with _callback_ and timeout of _ms_.
-   *
-   * @param  {function} callback
-   * @param  {int} ms
-   * @return {int}
-   * @api public
-   */
-  
-  setTimeout = function(callback, ms) {
-    var id
-       return id = setInterval(function(){
-         callback()
-         clearInterval(id)
-       }, ms)
-  }
-  
-  /**
-   * Set mock interval with _callback_ and interval of _ms_.
-   *
-   * @param  {function} callback
-   * @param  {int} ms
-   * @return {int}
-   * @api public
-   */
-
-  setInterval = function(callback, ms) {
-    callback.step = ms, callback.current = callback.last = 0
-    return timers[timers.length] = callback, timers.length
-  }
-  
-  /**
-   * Destroy timer with _id_.
-   *
-   * @param  {int} id
-   * @return {bool}
-   * @api public
-   */
-
-  clearInterval = clearTimeout = function(id) {
-    return delete timers[--id]
-  }
-  
-  /**
-   * Reset timers.
-   *
-   * @return {array}
-   * @api public
-   */
-  
-  resetTimers = function() {
-    return timers = []
-  }
-  
-  /**
-   * Increment each timers internal clock by _ms_.
-   *
-   * @param  {int} ms
-   * @api public
-   */
-  
-  tick = function(ms) {
-    for (var i = 0, len = timers.length; i < len; ++i)
-      if (timers[i] && (timers[i].current += ms))
-        if (timers[i].current - timers[i].last >= timers[i].step) {
-          var times = Math.floor((timers[i].current - timers[i].last) / timers[i].step)
-          var remainder = (timers[i].current - timers[i].last) % timers[i].step
-          timers[i].last = timers[i].current - remainder
-          while (times-- && timers[i]) timers[i]()
-        }
-  }
-  
-})()
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.xhr.js b/node/node_modules/jade/benchmarks/haml/spec/lib/jspec.xhr.js
deleted file mode 100644 (file)
index 3b96310..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-
-// JSpec - XHR - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
-
-(function(){
-
-  var lastRequest
-
-  // --- Original XMLHttpRequest
-
-  var OriginalXMLHttpRequest = 'XMLHttpRequest' in this ?
-                                 XMLHttpRequest :
-                                   function(){}
-  var OriginalActiveXObject = 'ActiveXObject' in this ?
-                                 ActiveXObject :
-                                   undefined
-
-  // --- MockXMLHttpRequest
-
-  var MockXMLHttpRequest = function() {
-    this.requestHeaders = {}
-  }
-
-  MockXMLHttpRequest.prototype = {
-    status: 0,
-    async: true,
-    readyState: 0,
-         responseXML: null,
-    responseText: '',
-    abort: function(){},
-    onreadystatechange: function(){},
-
-   /**
-    * Return response headers hash.
-    */
-
-    getAllResponseHeaders : function(){
-      return JSpec.inject(this.responseHeaders, '', function(buf, key, val){
-        return buf + key + ': ' + val + '\r\n'
-      })
-    },
-
-    /**
-     * Return case-insensitive value for header _name_.
-     */
-
-    getResponseHeader : function(name) {
-      return this.responseHeaders[name.toLowerCase()]
-    },
-
-    /**
-     * Set case-insensitive _value_ for header _name_.
-     */
-
-    setRequestHeader : function(name, value) {
-      this.requestHeaders[name.toLowerCase()] = value
-    },
-
-    /**
-     * Open mock request.
-     */
-
-    open : function(method, url, async, user, password) {
-      this.user = user
-      this.password = password
-      this.url = url
-      this.readyState = 1
-      this.method = method.toUpperCase()
-      if (async != undefined) this.async = async
-      if (this.async) this.onreadystatechange()
-    },
-
-    /**
-     * Send request _data_.
-     */
-
-    send : function(data) {
-      var self = this
-      this.data = data
-      this.readyState = 4
-      if (this.method == 'HEAD') this.responseText = null
-      this.responseHeaders['content-length'] = (this.responseText || '').length
-      if(this.async) this.onreadystatechange()
-           this.populateResponseXML()
-      lastRequest = function(){
-        return self
-      }
-    },
-
-       /**
-        * Parse request body and populate responseXML if response-type is xml
-        * Based on the standard specification : http://www.w3.org/TR/XMLHttpRequest/
-        */
-       populateResponseXML: function() {
-               var type = this.getResponseHeader("content-type")
-               if (!type || !this.responseText || !type.match(/(text\/xml|application\/xml|\+xml$)/g))
-                       return
-               this.responseXML = JSpec.parseXML(this.responseText)
-         }
-  }
-
-  // --- Response status codes
-
-  JSpec.statusCodes = {
-    100: 'Continue',
-    101: 'Switching Protocols',
-    200: 'OK',
-    201: 'Created',
-    202: 'Accepted',
-    203: 'Non-Authoritative Information',
-    204: 'No Content',
-    205: 'Reset Content',
-    206: 'Partial Content',
-    300: 'Multiple Choice',
-    301: 'Moved Permanently',
-    302: 'Found',
-    303: 'See Other',
-    304: 'Not Modified',
-    305: 'Use Proxy',
-    307: 'Temporary Redirect',
-    400: 'Bad Request',
-    401: 'Unauthorized',
-    402: 'Payment Required',
-    403: 'Forbidden',
-    404: 'Not Found',
-    405: 'Method Not Allowed',
-    406: 'Not Acceptable',
-    407: 'Proxy Authentication Required',
-    408: 'Request Timeout',
-    409: 'Conflict',
-    410: 'Gone',
-    411: 'Length Required',
-    412: 'Precondition Failed',
-    413: 'Request Entity Too Large',
-    414: 'Request-URI Too Long',
-    415: 'Unsupported Media Type',
-    416: 'Requested Range Not Satisfiable',
-    417: 'Expectation Failed',
-    422: 'Unprocessable Entity',
-    500: 'Internal Server Error',
-    501: 'Not Implemented',
-    502: 'Bad Gateway',
-    503: 'Service Unavailable',
-    504: 'Gateway Timeout',
-    505: 'HTTP Version Not Supported'
-  }
-
-  /**
-   * Mock XMLHttpRequest requests.
-   *
-   *   mockRequest().and_return('some data', 'text/plain', 200, { 'X-SomeHeader' : 'somevalue' })
-   *
-   * @return {hash}
-   * @api public
-   */
-
-  function mockRequest() {
-    return { and_return : function(body, type, status, headers) {
-      XMLHttpRequest = MockXMLHttpRequest
-      ActiveXObject = false
-      status = status || 200
-      headers = headers || {}
-      headers['content-type'] = type
-      JSpec.extend(XMLHttpRequest.prototype, {
-        responseText: body,
-        responseHeaders: headers,
-        status: status,
-        statusText: JSpec.statusCodes[status]
-      })
-    }}
-  }
-
-  /**
-   * Unmock XMLHttpRequest requests.
-   *
-   * @api public
-   */
-
-  function unmockRequest() {
-    XMLHttpRequest = OriginalXMLHttpRequest
-    ActiveXObject = OriginalActiveXObject
-  }
-
-  JSpec.include({
-    name: 'Mock XHR',
-
-    // --- Utilities
-
-    utilities : {
-      mockRequest: mockRequest,
-      unmockRequest: unmockRequest
-    },
-
-    // --- Hooks
-
-    afterSpec : function() {
-      unmockRequest()
-    },
-
-    // --- DSLs
-
-    DSLs : {
-      snake : {
-        mock_request: mockRequest,
-        unmock_request: unmockRequest,
-        last_request: function(){ return lastRequest() }
-      }
-    }
-
-  })
-})()
diff --git a/node/node_modules/jade/benchmarks/haml/spec/node.js b/node/node_modules/jade/benchmarks/haml/spec/node.js
deleted file mode 100644 (file)
index c96429c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-
-require.paths.unshift('spec', './spec/lib', 'lib')
-require('jspec')
-require('unit/spec.helper')
-haml = require('haml')
-
-JSpec
-  .exec('spec/unit/spec.js')
-  .run({ reporter: JSpec.reporters.Terminal, fixturePath: 'spec/fixtures', failuresOnly: true })
-  .report()
diff --git a/node/node_modules/jade/benchmarks/haml/spec/unit/spec.helper.js b/node/node_modules/jade/benchmarks/haml/spec/unit/spec.helper.js
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/node/node_modules/jade/benchmarks/haml/spec/unit/spec.js b/node/node_modules/jade/benchmarks/haml/spec/unit/spec.js
deleted file mode 100644 (file)
index 4e1e69d..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-
-describe 'haml'
-  describe '.version'
-    it 'should be a triplet'
-      haml.version.should.match(/^\d+\.\d+\.\d+$/)
-    end
-  end
-  
-  describe '.render()'
-    before
-      assertAs = function(name, type, options) {
-        var str = fixture(name + '.haml')
-        try {
-          var html = haml.render(str, options).trim(),
-              expected = fixture(name + '.' + type).trim()
-          if (html === expected)
-            pass()
-          else
-            fail('got:\n' + html + '\n\nexpected:\n' + expected)
-        } catch (err) {
-          if (err instanceof haml.HamlError) {
-            throw err
-          } else {
-            fail('\n:' + err.stack + '\n')
-          }
-        }
-      }
-      assert = function(name, options) {
-        assertAs(name, 'html', options, 'CRLF', '\r\n')
-      }
-      assertXML = function(name, options) {
-        assertAs(name, 'xml', options, 'CRLF', '\r\n')
-      }
-    end
-    
-    it 'should allow passing of a context object'
-      assert('context', { context: 'yay' })
-    end
-    
-    it 'should allow passing of literals'
-      assert('literals', { locals: { user: 'tj' }})
-    end
-    
-    it 'should not fail on trailing indents'
-      assert('trailing-indent')
-    end
-    
-    it 'should add xml support via the "xml" option'
-      assertXML('feed', { xml: true })
-    end
-    
-    it 'should support xml namespaces'
-      assertXML('namespace')
-    end
-    
-    it 'should utilize "filename" option when an error is thrown'
-      try { assert('error', { filename: 'error.haml' }) }
-      catch (err) {
-        err.message.should.eql '(error.haml):3 invalid indentation; got 3, when previous was 1'
-      }
-    end
-    
-    it 'should default filename to "Haml" when an error is thrown'
-      try { assert('error') }
-      catch (err) {
-        err.message.should.eql '(Haml):3 invalid indentation; got 3, when previous was 1'
-      }
-    end
-    
-    it 'should bitch when "cache" is true without a filename given'
-      // -{ assert('tag.simple', { cache: true }) }.should.throw_error
-    end
-    
-    it 'should pre-compiled and cache when "cache" is true'
-      assert('tag.simple', { cache: true, filename: 'tag.simple.haml' })
-      assert('tag.simple', { cache: true, filename: 'tag.simple.haml' })
-    end
-    
-    it 'should support blank lines'
-      assert('newlines')
-    end
-    
-    describe '.class'
-      it 'should output a div with the given class'
-        assert('class')
-      end
-      
-      it 'should work with several classes'
-        assert('classes')
-      end
-    end
-    
-    describe '#id'
-      it 'should output a div with the given id'
-        assert('id')
-      end
-    end
-    
-    describe '%tag'
-      it 'should work with no text or block'
-        assert('tag.simple')
-      end
-      
-      it 'should work with text'
-        assert('tag.text')
-      end
-      
-      it 'should work with block text'
-        assert('tag.text.block')
-      end
-      
-      it 'should work with blocks of text and tags'
-        assert('tag.text.block.complex')
-      end
-      
-      it 'should work with many classes / ids / attrs'
-        assert('tag.complex')
-      end
-      
-      it 'should allow empty tags'
-        assert('tag.empty')
-      end
-    end
-    
-    describe '%tag.class'
-      it 'should output tag with a class'
-        assert('tag.class')
-      end
-      
-      it 'should work with several classes'
-        assert('tag.classes')
-      end
-      
-      it 'should support self-closing tags'
-        assert('tag.self-close')
-      end
-    end
-    
-    describe '%tag!='
-      it 'should output the evaluated code'
-        assert('tag.code')
-      end
-      
-      it 'should not escape output'
-        assert('tag.code.no-escape')
-      end
-    end
-    
-    describe '%tag='
-      it 'should escape the evaluated code'
-        assert('tag.escape')
-      end
-    end
-    
-    describe '%namespace:tag'
-      it 'should output a tag with a namespace prefix'
-        assert('namespace.tag')
-      end
-    end
-    
-    describe '{...}'
-      it 'should be mapped as html attributes'
-        assert('tag.attrs')
-      end
-      
-      it 'should escape values'
-        assert('tag.attrs.escape')
-      end
-      
-      it 'should allow booleans'
-        assert('tag.attrs.bools')
-      end
-    end
-    
-    describe '!!!'
-      it 'should default the doctype to 1.0 transitional'
-        assert('doctype')
-      end
-    end
-    
-    describe '!!! NAME'
-      it 'should output a specific doctype'
-        assert('doctype.xml')
-      end
-      
-      it 'should be case-insensitive'
-        assert('doctype.xml.case')
-      end
-    end
-    
-    describe 'nesting'
-      it 'should work when nested downwards'
-        assert('nesting.simple')
-      end
-      
-      it 'should work when blocks outdent'
-        assert('nesting.complex')
-      end
-    end
-    
-    describe '- code'
-      it 'should work with if statements'
-        assert('code.if')
-      end
-      
-      it 'should work when nested'
-        assert('code.nested')
-      end
-    end
-    
-    describe '- each'
-      it 'should iterate'
-        assert('code.each', { locals: { items: ['one', 'two', 'three'] }})
-        assert('code.each.non-enumerable', { locals: { items: null }})
-      end
-      
-      it 'should iterate objects'
-        assert('code.each', { locals: { items: { 0: 'one', 1: 'two', 2: 'three' }}})
-        assert('code.each.index', { locals: { items: { 0: 'one', 1: 'two', 2: 'three' }}})
-      end
-      
-      it 'should iterate with index'
-        assert('code.each.index', { locals: { items: ['one', 'two', 'three'] }})
-      end
-    end
-    
-    describe '= code'
-      it 'should output evaluation'
-        assert('code')
-      end
-    end
-    
-    describe '&= code'
-      it 'should output evaluation while escaping html entities'
-        assert('code.escape')
-      end
-    end
-    
-    describe '<literal></html>'
-      it 'should remain intact'
-        assert('html')
-      end
-    end
-    
-    describe '\\char'
-      it 'should escape the character'
-        assert('escape')
-      end
-    end
-    
-    describe '-#'
-      it 'should become a silent comment'
-        assert('comment')
-      end
-    end
-    
-    describe '/'
-      it 'should comment out tags'
-        assert('comment.tag')
-      end
-      
-      it 'should comment out blocks'
-        assert('comment.block')
-      end
-      
-      it 'should comment out text'
-        assert('comment.text')
-      end
-      
-      it 'should work in blocks'
-        assert('comment.text.complex')
-      end
-    end
-    
-    describe '/[]'
-      it 'should insert conditional comment blocks'
-        assert('comment.block.conditional')
-      end
-    end
-
-    describe ':filter'
-      describe 'plain'
-        it 'should ignore haml specific characters'
-          assert('filter.plain')
-        end
-      end
-    
-      describe 'cdata'
-        it 'should wrap with CDATA tags'
-          assert('filter.cdata')
-        end
-        
-        it 'should retain whitespace'
-          assert('filter.cdata.whitespace')
-        end
-      end
-      
-      describe 'javascript'
-        it 'should wrap with <script> and CDATA tags'
-          assert('filter.javascript')
-        end
-      end
-    end
-    
-    describe 'bug fixes'
-      it '#8 code block'
-        assert('issue.#8', { locals: { items: ['foo', 'bar', 'baz'] }})
-      end
-      
-      it '#10 Attributes should not need quotes'
-        assert('issue.#10')
-      end
-    end
-    
-  end
-end
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/haml2.js b/node/node_modules/jade/benchmarks/haml2.js
deleted file mode 100644 (file)
index b1ad299..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var bm = require('./common'),
-    haml = require('./haml/lib/haml'),
-    fs = require('fs');
-
-var str = fs.readFileSync(__dirname + '/example2.haml', 'ascii');
-
-var n = bm.times;
-bm.start('haml compilation');
-while (n--) {
-    haml.render(str, {
-        locals: bm.locals
-    });
-}
-bm.stop();
-
-var n = bm.times;
-bm.start('haml execution');
-while (n--) {
-    haml.render(str, {
-        locals: bm.locals,
-        cache: true,
-        filename: 'example2.haml'
-    });
-}
-bm.stop();
\ No newline at end of file
diff --git a/node/node_modules/jade/benchmarks/jade-self.js b/node/node_modules/jade/benchmarks/jade-self.js
deleted file mode 100644 (file)
index f3329c9..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var bm = require('./common'),
-    jade = require('../lib/jade'),
-    fs = require('fs');
-
-var str = fs.readFileSync(__dirname + '/example-self.jade', 'ascii');
-var fn = jade.compile(str, { self: true });
-var n = bm.times;
-
-bm.start('jade self compilation');
-while (n--) {
-  jade.render(str, {
-    filename: 'example-self.jade'
-  , self: true
-  , locals: bm.locals
-  });
-}
-bm.stop();
-
-var n = bm.times;
-
-bm.start('jade self execution');
-while (n--) {
-  jade.render(str, {
-    filename: 'example-self.jade'
-  , self: true
-  , cache: true
-  , locals: bm.locals
-  });
-}
-bm.stop();
-
-var n = bm.times;
-
-bm.start('jade compile()');
-while (n--) {
-  fn(bm.locals);
-}
-bm.stop();
diff --git a/node/node_modules/jade/benchmarks/jade.js b/node/node_modules/jade/benchmarks/jade.js
deleted file mode 100644 (file)
index d691e7e..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var bm = require('./common'),
-    jade = require('../lib/jade'),
-    fs = require('fs');
-
-var str = fs.readFileSync(__dirname + '/example.jade', 'ascii');
-var fn = jade.compile(str);
-var n = bm.times;
-
-bm.start('jade compilation');
-while (n--) {
-    jade.render(str, {
-        filename: 'example.jade',
-        locals: bm.locals
-    });
-}
-bm.stop();
-
-var n = bm.times;
-
-bm.start('jade execution');
-while (n--) {
-    jade.render(str, {
-        filename: 'example.jade',
-        cache: true,
-        locals: bm.locals
-    });
-}
-bm.stop();
-
-var n = bm.times;
-
-bm.start('jade compile()');
-while (n--) {
-    fn(bm.locals);
-}
-bm.stop();
\ No newline at end of file
index 2abb700907623f67769bd23c8bccb04daa6dff2f..2c39e06c09fe91bc0429c2ed670e896abdb6e193 100755 (executable)
  */
 
 var fs = require('fs')
+  , program = require('commander')
   , path = require('path')
-  , resolve = path.resolve
   , basename = path.basename
   , dirname = path.dirname
-  , jade;
-
-try {
-  jade = require('../lib/jade');
-} catch (err) {
-  jade = require('jade');
-}
-
-/**
- * Arguments.
- */
-
-var args = process.argv.slice(2);
+  , resolve = path.resolve
+  , join = path.join
+  , mkdirp = require('mkdirp')
+  , jade = require('../');
 
-/**
- * Options javascript.
- */
+// jade options
 
 var options = {};
 
-/**
- * Destination dir.
- */
-
-var dest;
-
-/**
- * Watcher hash.
- */
-
-var watchers;
+// options
+
+program
+  .version(jade.version)
+  .usage('[options] [dir|file ...]')
+  .option('-o, --obj <str>', 'javascript options object')
+  .option('-O, --out <dir>', 'output the compiled html to <dir>')
+
+program.on('--help', function(){
+  console.log('  Examples:');
+  console.log('');
+  console.log('    # translate jade the templates dir');
+  console.log('    $ jade templates');
+  console.log('');
+  console.log('    # create {foo,bar}.html');
+  console.log('    $ jade {foo,bar}.jade');
+  console.log('');
+  console.log('    # jade over stdio');
+  console.log('    $ jade < my.jade > my.html');
+  console.log('');
+  console.log('    # jade over stdio');
+  console.log('    $ echo "h1 Jade!" | jade');
+  console.log('');
+  console.log('    # foo, bar dirs rendering to /tmp');
+  console.log('    $ jade foo bar --out /tmp ');
+  console.log('');
+});
+
+program.parse(process.argv);
+
+// options given, parse them
+
+if (program.obj) options = eval('(' + program.obj + ')');
+
+// left-over args are file paths
+
+var files = program.args;
+
+// compile files
+
+if (files.length) {
+  console.log();
+  files.forEach(renderFile);
+  process.on('exit', console.log);
+// stdio
+} else {
+  stdin();
+}
 
 /**
- * Usage information.
+ * Compile from stdin.
  */
 
-var usage = ''
-  + '\n'
-  + '  Usage: jade [options]\n'
-  + '              [path ...]\n'
-  + '              < in.jade > out.jade'
-  + '  \n'
-  + '  Options:\n'
-  + '    -o, --options <str>  JavaScript options object passed\n'
-  + '    -h, --help           Output help information\n'
-  + '    -w, --watch          Watch file(s) or folder(s) for changes and re-compile\n'
-  + '    -v, --version        Output jade version\n'
-  + '    --out <dir>          Output the compiled html to <dir>\n';
-  + '\n';
-
-// Parse arguments
-
-var arg
-  , files = [];
-while (args.length) {
-  arg = args.shift();
-  switch (arg) {
-    case '-h':
-    case '--help':
-      console.log(usage);
-      process.exit(1);
-    case '-v':
-    case '--version':
-      console.log(jade.version);
-      process.exit(1);
-    case '-o':
-    case '--options':
-      var str = args.shift();
-      if (str) {
-        options = eval('(' + str + ')');
-      } else {
-        console.error('-o, --options requires a string.');
-        process.exit(1);
-      }
-      break;
-    case '-w':
-    case '--watch':
-      watchers = {};
-      break;
-    case '--out':
-      dest = args.shift();
-      break;
-    default:
-      files.push(arg);
-  }
-}
-
-// Watching and no files passed - watch cwd
-if (watchers && !files.length) {
-  fs.readdirSync(process.cwd()).forEach(processFile);
-// Process passed files
-} else if (files.length) {
-  files.forEach(processFile);
-// Stdio
-} else {
+function stdin() {
   var buf = '';
   process.stdin.setEncoding('utf8');
-  process.stdin.on('data', function(chunk){
-    buf += chunk;
-  }).on('end', function(){
-    console.log(jade.render(buf, options));
+  process.stdin.on('data', function(chunk){ buf += chunk; });
+  process.stdin.on('end', function(){
+    var fn = jade.compile(buf, options);
+    process.stdout.write(fn(options));
   }).resume();
 }
 
 /**
  * Process the given path, compiling the jade files found.
- * Always walk the subdirectories.;
+ * Always walk the subdirectories.
  */
 
-function processFile(path) {
+function renderFile(path) {
+  var re = /\.jade$/;
   fs.lstat(path, function(err, stat) {
     if (err) throw err;
     // Found jade file
-    if (stat.isFile() && path.match(/\.jade$/)) {
-      renderJade(path);
+    if (stat.isFile() && re.test(path)) {
+      fs.readFile(path, 'utf8', function(err, str){
+        if (err) throw err;
+        var fn = jade.compile(str, options);
+        path = path.replace(re, '.html');
+        if (program.out) path = join(program.out, basename(path));
+        var dir = resolve(dirname(path));
+        mkdirp(dir, 0755, function(err){
+          if (err) throw err;
+          fs.writeFile(path, fn(options), function(err){
+            if (err) throw err;
+            console.log('  \033[90mrendered \033[36m%s\033[0m', path);
+          });
+        });
+      });
     // Found directory
     } else if (stat.isDirectory()) {
       fs.readdir(path, function(err, files) {
         if (err) throw err;
         files.map(function(filename) {
           return path + '/' + filename;
-        }).forEach(processFile);
+        }).forEach(renderFile);
       });
     }
   });
 }
-
-/**
- * Render jade
- */
-
-function renderJade(jadefile) {
-  jade.renderFile(jadefile, options, function(err, html) {
-    if (err) throw err;
-    writeFile(jadefile, html);
-  });
-}
-
-/**
- * mkdir -p implementation.
- */
-
-function mkdirs(path, fn) {
-  var segs = dirname(path).split('/')
-    , dir = '';
-
-  (function next() {
-    var seg = segs.shift();
-    if (seg) {
-      dir += seg + '/';
-      fs.mkdir(dir, 0755, function(err){
-        if (!err) return next();
-        if ('EEXIST' == err.code) return next();
-      });
-    } else {
-      fn();
-    }
-  })();
-}
-
-/**
- * Write the html output to a file.
- */
-
-function writeFile(src, html) {
-  var path = src.replace('.jade', '.html');
-  if (dest) path = dest + '/' + path;
-  mkdirs(path, function(err){
-    if (err) throw err;
-    fs.writeFile(path, html, function(err) {
-      if (err) throw err;
-      console.log('  \033[90mcompiled\033[0m %s', path);
-      watch(src, renderJade);
-    });
-  });
-}
-
-/**
- * Watch the given `file` and invoke `fn` when modified.
- */
-
-function watch(file, fn) {
-  // not watching
-  if (!watchers) return;
-
-  // already watched
-  if (watchers[file]) return;
-
-  // watch the file itself
-  watchers[file] = true;
-  console.log('  \033[90mwatching\033[0m %s', file);
-  fs.watchFile(file, { interval: 50 }, function(curr, prev){
-    if (curr.mtime > prev.mtime) fn(file);
-  });
-}
index f9b5a6725d552d868d53c8d71f424d63793cc8a7..439f0fcc115fcde76bb2c89506d82f987f6811f2 100644 (file)
@@ -1,4 +1,4 @@
 head
   title My Site
-  script(src='/javascripts/jquery.js')
-  script(src='/javascripts/app.js')
\ No newline at end of file
+  include scripts
+  include style.css
\ No newline at end of file
diff --git a/node/node_modules/jade/examples/includes/scripts.jade b/node/node_modules/jade/examples/includes/scripts.jade
new file mode 100644 (file)
index 0000000..2f478fc
--- /dev/null
@@ -0,0 +1,2 @@
+script(src='/javascripts/jquery.js')
+script(src='/javascripts/app.js')
diff --git a/node/node_modules/jade/examples/includes/style.css b/node/node_modules/jade/examples/includes/style.css
new file mode 100644 (file)
index 0000000..950708e
--- /dev/null
@@ -0,0 +1,5 @@
+<style>
+  body {
+    padding: 50px;
+  }
+</style>
\ No newline at end of file
index 7f60996f04abcd7ccb70eb1316c0805b9a95d81d..667ce9920552786c65eeb8aee9da294bb2422a44 100644 (file)
@@ -97,13 +97,12 @@ var nodes = require('./nodes')
 var Compiler = module.exports = function Compiler(node, options) {
   this.options = options = options || {};
   this.node = node;
-
   this.hasCompiledDoctype = false;
   this.hasCompiledTag = false;
+  this.pp = options.pretty || false;
+  this.debug = false !== options.compileDebug;
+  this.indents = 0;
   if (options.doctype) this.setDoctype(options.doctype);
-
-  this.pp = options.prettyprint || false;
-  this.indentDepth = 0;
 };
 
 /**
@@ -120,6 +119,7 @@ Compiler.prototype = {
   
   compile: function(){
     this.buf = ['var interp;'];
+    this.lastBufferedIdx = -1
     this.visit(this.node);
     return this.buf.join('\n');
   },
@@ -151,7 +151,15 @@ Compiler.prototype = {
   
   buffer: function(str, esc){
     if (esc) str = utils.escape(str);
-    this.buf.push("buf.push('" + str + "');");
+    
+    if (this.lastBufferedIdx == this.buf.length) {
+      this.lastBuffered += str;
+      this.buf[this.lastBufferedIdx - 1] = "buf.push('" + this.lastBuffered + "');"
+    } else {
+      this.buf.push("buf.push('" + str + "');");
+      this.lastBuffered = str;
+      this.lastBufferedIdx = this.buf.length;
+    }    
   },
   
   /**
@@ -162,7 +170,7 @@ Compiler.prototype = {
    */
   
   line: function(node){
-    if (node.instrumentLineNumber === false) return;
+    if (false === node.instrumentLineNumber) return;
     this.buf.push('__.lineno = ' + node.line + ';');
   },
   
@@ -174,7 +182,7 @@ Compiler.prototype = {
    */
   
   visit: function(node){
-    this.line(node);
+    if (this.debug) this.line(node);
     return this.visitNode(node);
   },
   
@@ -190,7 +198,19 @@ Compiler.prototype = {
       || node.constructor.toString().match(/function ([^(\s]+)()/)[1];
     return this['visit' + name](node);
   },
-  
+
+  /**
+   * Visit literal `node`.
+   *
+   * @param {Literal} node
+   * @api public
+   */
+
+  visitLiteral: function(node){
+    var str = node.str.replace(/\n/g, '\\\\n');
+    this.buffer(str);
+  },
+
   /**
    * Visit all nodes in `block`.
    *
@@ -199,7 +219,7 @@ Compiler.prototype = {
    */
 
   visitBlock: function(block){
-    var len = len = block.nodes.length;
+    var len = block.nodes.length;
     for (var i = 0; i < len; ++i) {
       this.visit(block.nodes[i]);
     }
@@ -222,7 +242,28 @@ Compiler.prototype = {
     if (this.doctype) this.buffer(this.doctype);
     this.hasCompiledDoctype = true;
   },
-  
+
+  /**
+   * Visit `mixin`, generating a function that
+   * may be called within the template.
+   *
+   * @param {Mixin} mixin
+   * @api public
+   */
+
+  visitMixin: function(mixin){
+    var name = mixin.name.replace(/-/g, '_') + '_mixin'
+      , args = mixin.args || '';
+
+    if (mixin.block) {
+      this.buf.push('var ' + name + ' = function(' + args + '){');
+      this.visit(mixin.block);
+      this.buf.push('}');
+    } else {
+      this.buf.push(name + '(' + args + ');');
+    }
+  },
+
   /**
    * Visit `tag` buffering tag markup, generating
    * attributes, visiting the `tag`'s code and block.
@@ -232,7 +273,7 @@ Compiler.prototype = {
    */
   
   visitTag: function(tag){
-    this.indentDepth++;
+    this.indents++;
     var name = tag.name;
 
     if (!this.hasCompiledTag) {
@@ -242,8 +283,10 @@ Compiler.prototype = {
       this.hasCompiledTag = true;
     }
 
-    if(this.pp && inlineTags.indexOf(name) == -1) 
-      this.buffer('\\n' + new Array(this.indentDepth).join('  '));
+    // pretty print
+    if (this.pp && inlineTags.indexOf(name) == -1) {
+      this.buffer('\\n' + Array(this.indents).join('  '));
+    }
 
     if (~selfClosing.indexOf(name) && !this.xml) {
       this.buffer('<' + name);
@@ -264,10 +307,15 @@ Compiler.prototype = {
       if (tag.text) this.buffer(utils.text(tag.text.nodes[0].trimLeft()));
       this.escape = 'pre' == tag.name;
       this.visit(tag.block);
-      if (this.pp && inlineTags.indexOf(name) == -1 && tag.textOnly == 0) this.buffer('\\n' + new Array(this.indentDepth).join('  '));
+
+      // pretty print
+      if (this.pp && !~inlineTags.indexOf(name) && !tag.textOnly) {
+        this.buffer('\\n' + Array(this.indents).join('  '));
+      }
+
       this.buffer('</' + name + '>');
     }
-    this.indentDepth--;
+    this.indents--;
   },
   
   /**
@@ -319,7 +367,7 @@ Compiler.prototype = {
   
   visitComment: function(comment){
     if (!comment.buffer) return;
-    if (this.pp) this.buffer('\\n' + new Array(this.indentDepth + 1).join('  '));
+    if (this.pp) this.buffer('\\n' + Array(this.indents + 1).join('  '));
     this.buffer('<!--' + utils.escape(comment.val) + '-->');
   },
   
@@ -331,6 +379,7 @@ Compiler.prototype = {
    */
   
   visitBlockComment: function(comment){
+    if (!comment.buffer) return;
     if (0 == comment.val.indexOf('if')) {
       this.buffer('<!--[' + comment.val + ']>');
       this.visit(comment.block);
@@ -583,25 +632,25 @@ require.register("inline-tags.js", function(module, exports, require){
  */
 
 module.exports = [
-  'a', 
-  'abbr', 
-  'acronym', 
-  'b',   
-  'br', 
-  'code',  
-  'em', 
-  'font', 
-  'i', 
-  'img', 
-  'ins', 
-  'kbd', 
-  'map', 
-  'samp', 
-  'small', 
-  'span', 
-  'strong', 
-  'sub', 
-  'sup'
+    'a'
+  , 'abbr'
+  , 'acronym'
+  , 'b'
+  , 'br'
+  , 'code'
+  , 'em'
+  , 'font'
+  , 'i'
+  , 'img'
+  , 'ins'
+  , 'kbd'
+  , 'map'
+  , 'samp'
+  , 'small'
+  , 'span'
+  , 'strong'
+  , 'sub'
+  'sup'
 ];
 }); // module: inline-tags.js
 
@@ -619,12 +668,13 @@ require.register("jade.js", function(module, exports, require){
 
 var Parser = require('./parser')
   , Compiler = require('./compiler')
+  , runtime = require('./runtime')
 
 /**
  * Library version.
  */
 
-exports.version = '0.12.1';
+exports.version = '0.15.4';
 
 /**
  * Intermediate JavaScript cache.
@@ -675,86 +725,10 @@ exports.Parser = Parser;
 exports.nodes = require('./nodes');
 
 /**
- * Render the given attributes object.
- *
- * @param {Object} obj
- * @return {String}
- * @api private
+ * Jade runtime helpers.
  */
 
-function attrs(obj){
-  var buf = []
-    , terse = obj.terse;
-  delete obj.terse;
-  var keys = Object.keys(obj)
-    , len = keys.length;
-  if (len) {
-    buf.push('');
-    for (var i = 0; i < len; ++i) {
-      var key = keys[i]
-        , val = obj[key];
-      if (typeof val === 'boolean' || val === '' || val == null) {
-        if (val) {
-          terse
-            ? buf.push(key)
-            : buf.push(key + '="' + key + '"');
-        }
-      } else {
-        buf.push(key + '="' + escape(val) + '"');
-      }
-    }
-  }
-  return buf.join(' ');
-}
-
-/**
- * Escape the given string of `html`.
- *
- * @param {String} html
- * @return {String}
- * @api private
- */
-
-function escape(html){
-  return String(html)
-    .replace(/&(?!\w+;)/g, '&amp;')
-    .replace(/</g, '&lt;')
-    .replace(/>/g, '&gt;')
-    .replace(/"/g, '&quot;');
-}
-
-/**
- * Re-throw the given `err` in context to the
- * `str` of jade, `filename`, and `lineno`.
- *
- * @param {Error} err
- * @param {String} str
- * @param {String} filename
- * @param {String} lineno
- * @api private
- */
-
-function rethrow(err, str, filename, lineno){
-  var context = 3
-    , lines = str.split('\n')
-    , start = Math.max(lineno - context, 0)
-    , end = Math.min(lines.length, lineno + context); 
-
-  // 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 || 'Jade') + ':' + lineno 
-    + '\n' + context + '\n\n' + err.message;
-  throw err;
-}
+exports.runtime = runtime;
 
 /**
  * Parse the given `str` of jade and return a function body.
@@ -767,10 +741,10 @@ function rethrow(err, str, filename, lineno){
 
 function parse(str, options){
   var filename = options.filename;
+  
   try {
     // Parse
-    var parser = new Parser(str, filename);
-    if (options.debug) parser.debug();
+    var parser = new Parser(str, filename, options);
 
     // Compile
     var compiler = new (options.compiler || Compiler)(parser.parse(), options)
@@ -783,25 +757,30 @@ function parse(str, options){
 
     try {
       return ''
-        + attrs.toString() + '\n\n'
-        + escape.toString()  + '\n\n'
         + 'var buf = [];\n'
         + (options.self
-          ? 'var self = locals || {}, __ = __ || locals.__;\n' + js
-          : 'with (locals || {}) {' + js + '}')
+          ? 'var self = locals || {};\n' + js
+          : 'with (locals || {}) {\n' + js + '\n}\n')
         + 'return buf.join("");';
+      
     } catch (err) {
       process.compile(js, filename || 'Jade');
       return;
     }
   } catch (err) {
-    rethrow(err, str, filename, parser.lexer.lineno);
+    runtime.rethrow(err, str, filename, parser.lexer.lineno);
   }
 }
 
 /**
  * Compile a `Function` representation of the given jade `str`.
  *
+ * Options:
+ * 
+ *   - `compileDebug` when `false` debugging code is stripped from the compiled template
+ *   - `client` when `true` the helper functions `escape()` etc will reference `jade.escape()`
+ *      for use with the Jade client-side runtime.js
+ *
  * @param {String} str
  * @param {Options} options
  * @return {Function}
@@ -811,113 +790,36 @@ function parse(str, options){
 exports.compile = function(str, options){
   var options = options || {}
     , input = JSON.stringify(str)
+    , client = options.client
     , filename = options.filename
       ? JSON.stringify(options.filename)
-      : 'undefined';
-
-  // Reduce closure madness by injecting some locals
-  var fn = [
-      'var __ = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };'
-    , rethrow.toString()
-    , 'try {'
-    , parse(String(str), options || {})
-    , '} catch (err) {'
-    , '  rethrow(err, __.input, __.filename, __.lineno);'
-    , '}'
-  ].join('\n');
-
-  return new Function('locals', fn);
-};
-
-/**
- * Render the given `str` of jade.
- *
- * Options:
- *
- *   - `scope`     Evaluation scope (`this`)
- *   - `locals`    Local variable object
- *   - `filename`  Used in exceptions, and required by `cache`
- *   - `cache`     Cache intermediate JavaScript in memory keyed by `filename`
- *   - `compiler`  Compiler to replade jade's default
- *   - `doctype`   Specify the default doctype
- *
- * @param {String|Buffer} str
- * @param {Object} options
- * @return {String}
- * @api public
- */
-
-exports.render = function(str, options){
-  var fn
-    , options = options || {}
-    , filename = options.filename;
-
-  // Accept Buffers
-  str = String(str);
-
-  // Cache support
-  if (options.cache) {
-    if (filename) {
-      if (cache[filename]) {
-        fn = cache[filename];
-      } else {
-        fn = cache[filename] = new Function('locals', parse(str, options));
-      }
-    } else {
-      throw new Error('filename is required when using the cache option');
-    }
+      : 'undefined'
+    , fn;
+
+  if (options.compileDebug !== false) {
+    fn = [
+        'var __ = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };'
+      , 'try {'
+      , parse(String(str), options || {})
+      , '} catch (err) {'
+      , '  rethrow(err, __.input, __.filename, __.lineno);'
+      , '}'
+    ].join('\n');
   } else {
-    fn = new Function('locals', parse(str, options));
+    fn = parse(String(str), options || {});
   }
 
-  // Render the template
-  try {
-    var locals = options.locals || {}
-      , meta = { lineno: 1 };
-    locals.__ = meta;
-    return fn.call(options.scope, locals); 
-  } catch (err) {
-    rethrow(err, str, filename, meta.lineno);
+  if (client) {
+    fn = 'var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow;\n' + fn;
   }
-};
-
-/**
- * Render jade template at the given `path`.
- *
- * @param {String} path
- * @param {Object} options
- * @param {Function} fn
- * @api public
- */
 
-exports.renderFile = function(path, options, fn){
-  var ret;
+  fn = new Function('locals, attrs, escape, rethrow', fn);
 
-  if (typeof options === 'function') {
-    fn = options;
-    options = {};
-  }
-  options.filename = path;
+  if (client) return fn;
 
-  // Primed cache
-  if (options.cache && cache[path]) {
-    try {
-      ret = exports.render('', options);
-    } catch (err) {
-      return fn(err);
-    }
-    fn(null, ret);
-  } else {
-    fs.readFile(path, 'utf8', function(err, str){
-      if (err) return fn(err);
-      try {
-        ret = exports.render(str, options);
-      } catch (err) {
-        return fn(err);
-      }
-      fn(null, ret);
-    });
-  }
+  return function(locals){
+    return fn(locals, runtime.attrs, runtime.escape, runtime.rethrow);
+  };
 };
 
 }); // module: jade.js
@@ -933,12 +835,19 @@ require.register("lexer.js", function(module, exports, require){
 /**
  * Initialize `Lexer` with the given `str`.
  *
+ * Options:
+ *
+ *   - `colons` allow colons for attr delimiters
+ *
  * @param {String} str
+ * @param {Object} options
  * @api private
  */
 
-var Lexer = module.exports = function Lexer(str) {
+var Lexer = module.exports = function Lexer(str, options) {
+  options = options || {};
   this.input = str.replace(/\r\n|\r/g, '\n');
+  this.colons = options.colons;
   this.deferredTokens = [];
   this.lastIndents = 0;
   this.lineno = 1;
@@ -1083,26 +992,13 @@ Lexer.prototype = {
     }
   },
 
-  /**
-   * Block comment
-   */
-
-   blockComment: function() {
-     var captures;
-     if (captures = /^\/([^\n]+)/.exec(this.input)) {
-       this.consume(captures[0].length);
-       var tok = this.tok('block-comment', captures[1]);
-       return tok;
-     }
-   },
-  
   /**
    * Comment.
    */
   
   comment: function() {
     var captures;
-    if (captures = /^ *\/\/(-)?([^\n]+)/.exec(this.input)) {
+    if (captures = /^ *\/\/(-)?([^\n]*)/.exec(this.input)) {
       this.consume(captures[0].length);
       var tok = this.tok('comment', captures[2]);
       tok.buffer = '-' != captures[1];
@@ -1146,7 +1042,7 @@ Lexer.prototype = {
   doctype: function() {
     return this.scan(/^(?:!!!|doctype) *(\w+)?/, 'doctype');
   },
-  
+
   /**
    * Id.
    */
@@ -1171,13 +1067,57 @@ Lexer.prototype = {
     return this.scan(/^(?:\| ?)?([^\n]+)/, 'text');
   },
 
+  /**
+   * Include.
+   */
+  
+  include: function() {
+    return this.scan(/^include +([^\n]+)/, 'include');
+  },
+
+  /**
+   * Mixin.
+   */
+
+  mixin: function(){
+    var captures;
+    if (captures = /^mixin +([-\w]+)(?:\(([^\)]+)\))?/.exec(this.input)) {
+      this.consume(captures[0].length);
+      var tok = this.tok('mixin', captures[1]);
+      tok.args = captures[2];
+      return tok;
+    }
+  },
+
+  /**
+   * Conditional.
+   */
+  
+  conditional: function() {
+    var captures;
+    if (captures = /^(if|unless|else if|else)\b([^\n]*)/.exec(this.input)) {
+      this.consume(captures[0].length);
+      var type = captures[1]
+        , js = captures[2];
+
+      switch (type) {
+        case 'if': js = 'if (' + js + ')'; break;
+        case 'unless': js = 'if (!(' + js + '))'; break;
+        case 'else if': js = 'else if (' + js + ')'; break;
+        case 'else': js = 'else'; break;
+      }
+
+      return this.tok('code', js);
+    }
+  },
+
   /**
    * Each.
    */
   
   each: function() {
     var captures;
-    if (captures = /^- *each *(\w+)(?: *, *(\w+))? * in *([^\n]+)/.exec(this.input)) {
+    if (captures = /^(?:- *)?(?:each|for) +(\w+)(?: *, *(\w+))? * in *([^\n]+)/.exec(this.input)) {
       this.consume(captures[0].length);
       var tok = this.tok('each', captures[1]);
       tok.key = captures[2] || 'index';
@@ -1213,6 +1153,7 @@ Lexer.prototype = {
         , str = this.input.substr(1, index-1)
         , tok = this.tok('attrs')
         , len = str.length
+        , colons = this.colons
         , states = ['key']
         , key = ''
         , val = ''
@@ -1233,6 +1174,9 @@ Lexer.prototype = {
       tok.attrs = {};
 
       function parse(c) {
+        var real = c;
+        // TODO: remove when people fix ":"
+        if (colons && ':' == c) c = '=';
         switch (c) {
           case ',':
           case '\n':
@@ -1257,14 +1201,14 @@ Lexer.prototype = {
           case '=':
             switch (state()) {
               case 'key char':
-                key += c;
+                key += real;
                 break;
               case 'val':
               case 'expr':
               case 'array':
               case 'string':
               case 'object':
-                val += c;
+                val += real;
                 break;
               default:
                 states.push('val');
@@ -1446,16 +1390,18 @@ Lexer.prototype = {
       || this.eos()
       || this.pipelessText()
       || this.doctype()
+      || this.include()
+      || this.mixin()
+      || this.conditional()
+      || this.each()
       || this.tag()
       || this.filter()
-      || this.each()
       || this.code()
       || this.id()
       || this.className()
       || this.attrs()
       || this.indent()
       || this.comment()
-      || this.blockComment()
       || this.colon()
       || this.text();
   }
@@ -1482,12 +1428,14 @@ var Node = require('./node');
  *
  * @param {String} val
  * @param {Block} block
+ * @param {Boolean} buffer
  * @api public
  */
 
-var BlockComment = module.exports = function BlockComment(val, block) {
+var BlockComment = module.exports = function BlockComment(val, block, buffer) {
   this.block = block;
   this.val = val;
+  this.buffer = buffer;
 };
 
 /**
@@ -1764,13 +1712,90 @@ exports.Code = require('./code');
 exports.Each = require('./each');
 exports.Text = require('./text');
 exports.Block = require('./block');
+exports.Mixin = require('./mixin');
 exports.Filter = require('./filter');
 exports.Comment = require('./comment');
+exports.Literal = require('./literal');
 exports.BlockComment = require('./block-comment');
 exports.Doctype = require('./doctype');
 
 }); // module: nodes/index.js
 
+require.register("nodes/literal.js", function(module, exports, require){
+
+/*!
+ * Jade - nodes - Literal
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var Node = require('./node');
+
+/**
+ * Initialize a `Literal` node with the given `str.
+ *
+ * @param {String} str
+ * @api public
+ */
+
+var Literal = module.exports = function Literal(str) {
+  this.str = str;
+};
+
+/**
+ * Inherit from `Node`.
+ */
+
+Literal.prototype = new Node;
+Literal.prototype.constructor = Literal;
+
+
+}); // module: nodes/literal.js
+
+require.register("nodes/mixin.js", function(module, exports, require){
+
+/*!
+ * Jade - nodes - Mixin
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var Node = require('./node');
+
+/**
+ * Initialize a new `Mixin` with `name` and `block`.
+ *
+ * @param {String} name
+ * @param {String} args
+ * @param {Block} block
+ * @api public
+ */
+
+var Mixin = module.exports = function Mixin(name, args, block){
+  this.name = name;
+  this.args = args;
+  this.block = block;
+};
+
+/**
+ * Inherit from `Node`.
+ */
+
+Mixin.prototype = new Node;
+Mixin.prototype.constructor = Mixin;
+
+
+
+}); // module: nodes/mixin.js
+
 require.register("nodes/node.js", function(module, exports, require){
 
 /*!
@@ -1942,12 +1967,13 @@ var Lexer = require('./lexer')
  *
  * @param {String} str
  * @param {String} filename
+ * @param {Object} options
  * @api public
  */
 
-var Parser = exports = module.exports = function Parser(str, filename){
+var Parser = exports = module.exports = function Parser(str, filename, options){
   this.input = str;
-  this.lexer = new Lexer(str);
+  this.lexer = new Lexer(str, options);
   this.filename = filename;
 };
 
@@ -1963,20 +1989,6 @@ var textOnly = exports.textOnly = ['code', 'script', 'textarea', 'style', 'title
 
 Parser.prototype = {
   
-  /**
-   * Output parse tree to stdout. 
-   *
-   * @api public
-   */
-  
-  debug: function(){
-    var lexer = new Lexer(this.input)
-      , tree = require('sys').inspect(this.parse(), false, 12, true);
-    console.log('\n\x1b[1mParse Tree\x1b[0m:\n');
-    console.log(tree);
-    this.lexer = lexer;
-  },
-  
   /**
    * Return the next token object.
    *
@@ -1987,6 +1999,17 @@ Parser.prototype = {
   advance: function(){
     return this.lexer.advance();
   },
+
+  /**
+   * Skip `n` tokens.
+   *
+   * @param {Number} n
+   * @api private
+   */
+
+  skip: function(n){
+    while (n--) this.advance();
+  },
   
   /**
    * Single token lookahead.
@@ -2073,6 +2096,8 @@ Parser.prototype = {
   /**
    *   tag
    * | doctype
+   * | mixin
+   * | include
    * | filter
    * | comment
    * | text
@@ -2086,14 +2111,16 @@ Parser.prototype = {
     switch (this.peek().type) {
       case 'tag':
         return this.parseTag();
+      case 'mixin':
+        return this.parseMixin();
+      case 'include':
+        return this.parseInclude();
       case 'doctype':
         return this.parseDoctype();
       case 'filter':
         return this.parseFilter();
       case 'comment':
         return this.parseComment();
-      case 'block-comment':
-        return this.parseBlockComment();
       case 'text':
         return this.parseText();
       case 'each':
@@ -2128,25 +2155,18 @@ Parser.prototype = {
   
   parseCode: function(){
     var tok = this.expect('code')
-      , node = new nodes.Code(tok.val, tok.buffer, tok.escape);
+      , node = new nodes.Code(tok.val, tok.buffer, tok.escape)
+      , block
+      , i = 1;
     node.line = this.line();
-    if ('indent' == this.peek().type) {
+    while (this.lookahead(i) && 'newline' == this.lookahead(i).type) ++i;
+    block = 'indent' == this.lookahead(i).type;
+    if (block) {
+      this.skip(i-1);
       node.block = this.parseBlock();
     }
     return node;
   },
-
-  /**
-   * block comment
-   */
-  
-  parseBlockComment: function(){
-    var tok = this.expect('block-comment')
-      , node = new nodes.BlockComment(tok.val, this.parseBlock());
-    node.line = this.line();
-    return node;
-  },
-
   
   /**
    * comment
@@ -2154,7 +2174,14 @@ Parser.prototype = {
   
   parseComment: function(){
     var tok = this.expect('comment')
-      , node = new nodes.Comment(tok.val, tok.buffer);
+      , node;
+
+    if ('indent' == this.peek().type) {
+      node = new nodes.BlockComment(tok.val, this.parseBlock(), tok.buffer);
+    } else {
+      node = new nodes.Comment(tok.val, tok.buffer);
+    }
+
     node.line = this.line();
     return node;
   },
@@ -2215,7 +2242,53 @@ Parser.prototype = {
     node.line = this.line();
     return node;
   },
-  
+
+  /**
+   * include
+   */
+
+  parseInclude: function(){
+    var path = require('path')
+      , fs = require('fs')
+      , dirname = path.dirname
+      , basename = path.basename
+      , join = path.join;
+
+    if (!this.filename)
+      throw new Error('the "filename" option is required to use includes');
+
+    var path = name = this.expect('include').val.trim()
+      , dir = dirname(this.filename);
+
+    // non-jade
+    if (~basename(path).indexOf('.')) {
+      var path = join(dir, path)
+        , str = fs.readFileSync(path, 'utf8');
+      return new nodes.Literal(str);
+    }
+
+    var path = join(dir, path + '.jade')
+      , str = fs.readFileSync(path, 'utf8')
+      , parser = new Parser(str, path)
+      , ast = parser.parse();
+
+    return ast;
+  },
+
+  /**
+   * mixin block
+   */
+
+  parseMixin: function(){
+    var tok = this.expect('mixin')
+      , name = tok.val
+      , args = tok.args;
+    var block = 'indent' == this.peek().type
+      ? this.parseBlock()
+      : null;
+    return new nodes.Mixin(name, args, block);
+  },
+
   /**
    * indent (text | newline)* outdent
    */
@@ -2243,7 +2316,8 @@ Parser.prototype = {
           text.push(indent + this.advance().val);
       }
     }
-    this._spaces = null;
+
+    if (spaces == this._spaces) this._spaces = null;
     this.expect('outdent');
     return text;
   },
@@ -2282,7 +2356,8 @@ Parser.prototype = {
     }
 
     var name = this.advance().val
-      , tag = new nodes.Tag(name);
+      , tag = new nodes.Tag(name)
+      , dot;
 
     tag.line = this.line();
 
@@ -2311,7 +2386,7 @@ Parser.prototype = {
 
     // check immediate '.'
     if ('.' == this.peek().val) {
-      tag.textOnly = true;
+      dot = tag.textOnly = true;
       this.advance();
     }
 
@@ -2338,7 +2413,7 @@ Parser.prototype = {
     // script special-case
     if ('script' == tag.name) {
       var type = tag.getAttribute('type');
-      if (type && 'text/javascript' != type.replace(/^['"]|['"]$/g, '')) {
+      if (!dot && type && 'text/javascript' != type.replace(/^['"]|['"]$/g, '')) {
         tag.textOnly = false;
       }
     }
@@ -2364,8 +2439,129 @@ Parser.prototype = {
     return tag;
   }
 };
+
 }); // module: parser.js
 
+require.register("runtime.js", function(module, exports, require){
+
+/*!
+ * Jade - runtime
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Lame Array.isArray() polyfill for now.
+ */
+
+if (!Array.isArray) {
+  Array.isArray = function(arr){
+    return '[object Array]' == toString.call(arr);
+  };
+}
+
+/**
+ * Lame Object.keys() polyfill for now.
+ */
+
+if (!Object.keys) {
+  Object.keys = function(obj){
+    var arr = [];
+    for (var key in obj) {
+      if (obj.hasOwnProperty(key)) {
+        arr.push(obj);
+      }
+    }
+    return arr;
+  } 
+}
+
+/**
+ * Render the given attributes object.
+ *
+ * @param {Object} obj
+ * @return {String}
+ * @api private
+ */
+
+exports.attrs = function attrs(obj){
+  var buf = []
+    , terse = obj.terse;
+  delete obj.terse;
+  var keys = Object.keys(obj)
+    , len = keys.length;
+  if (len) {
+    buf.push('');
+    for (var i = 0; i < len; ++i) {
+      var key = keys[i]
+        , val = obj[key];
+      if ('boolean' == typeof val || null == val) {
+        if (val) {
+          terse
+            ? buf.push(key)
+            : buf.push(key + '="' + key + '"');
+        }
+      } else if ('class' == key && Array.isArray(val)) {
+        buf.push(key + '="' + exports.escape(val.join(' ')) + '"');
+      } else {
+        buf.push(key + '="' + exports.escape(val) + '"');
+      }
+    }
+  }
+  return buf.join(' ');
+};
+
+/**
+ * Escape the given string of `html`.
+ *
+ * @param {String} html
+ * @return {String}
+ * @api private
+ */
+
+exports.escape = function escape(html){
+  return String(html)
+    .replace(/&(?!\w+;)/g, '&amp;')
+    .replace(/</g, '&lt;')
+    .replace(/>/g, '&gt;')
+    .replace(/"/g, '&quot;');
+};
+
+/**
+ * Re-throw the given `err` in context to the
+ * `str` of jade, `filename`, and `lineno`.
+ *
+ * @param {Error} err
+ * @param {String} str
+ * @param {String} filename
+ * @param {String} lineno
+ * @api private
+ */
+
+exports.rethrow = function rethrow(err, str, filename, lineno){
+  var context = 3
+    , lines = str.split('\n')
+    , start = Math.max(lineno - context, 0)
+    , end = Math.min(lines.length, lineno + context); 
+
+  // 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 || 'Jade') + ':' + lineno 
+    + '\n' + context + '\n\n' + err.message;
+  throw err;
+};
+
+}); // module: runtime.js
+
 require.register("self-closing.js", function(module, exports, require){
 
 /*!
index 14c31ab355334d53a5644a2125ad0ee2c075686d..ffe17731c24301e7b3f4b964b5f8bd6898fb8e3a 100644 (file)
@@ -1,2 +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]&&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];".."==seg?path.pop():"."!=seg&&path.push(seg)}return require(path.join("/"))}},require.register("compiler.js",function(module,exports,require){var nodes=require("./nodes"),filters=require("./filters"),doctypes=require("./doctypes"),selfClosing=require("./self-closing"),utils=require("./utils");Object.keys||(Object.keys=function(obj){var arr=[];for(var key in obj)obj.hasOwnProperty(key)&&arr.push(obj);return arr}),String.prototype.trimLeft||(String.prototype.trimLeft=function(){return this.replace(/^\s+/,"")});var Compiler=module.exports=function Compiler(node,options){this.options=options=options||{},this.node=node,this.hasCompiledDoctype=!1,this.hasCompiledTag=!1,options.doctype&&this.setDoctype(options.doctype)};Compiler.prototype={compile:function(){this.buf=["var interp;"],this.visit(this.node);return this.buf.join("\n")},setDoctype:function(name){var doctype=doctypes[(name||"default").toLowerCase()];if(!doctype)throw new Error('unknown doctype "'+name+'"');this.doctype=doctype,this.terse="5"==name||"html"==name,this.xml=0==this.doctype.indexOf("<?xml")},buffer:function(str,esc){esc&&(str=utils.escape(str)),this.buf.push("buf.push('"+str+"');")},line:function(node){node.instrumentLineNumber!==!1&&this.buf.push("__.lineno = "+node.line+";")},visit:function(node){this.line(node);return this.visitNode(node)},visitNode:function(node){var name=node.constructor.name||node.constructor.toString().match(/function ([^(\s]+)()/)[1];return this["visit"+name](node)},visitBlock:function(block){var len=len=block.nodes.length;for(var i=0;i<len;++i)this.visit(block.nodes[i])},visitDoctype:function(doctype){doctype&&(doctype.val||!this.doctype)&&this.setDoctype(doctype.val||"default"),this.doctype&&this.buffer(this.doctype),this.hasCompiledDoctype=!0},visitTag:function(tag){var name=tag.name;this.hasCompiledTag||(!this.hasCompiledDoctype&&"html"==name&&this.visitDoctype(),this.hasCompiledTag=!0),~selfClosing.indexOf(name)&&!this.xml?(this.buffer("<"+name),this.visitAttributes(tag.attrs),this.terse?this.buffer(">"):this.buffer("/>")):(tag.attrs.length?(this.buffer("<"+name),tag.attrs.length&&this.visitAttributes(tag.attrs),this.buffer(">")):this.buffer("<"+name+">"),tag.code&&this.visitCode(tag.code),tag.text&&this.buffer(utils.text(tag.text.nodes[0].trimLeft())),this.escape="pre"==tag.name,this.visit(tag.block),this.buffer("</"+name+">"))},visitFilter:function(filter){var fn=filters[filter.name];if(!fn)throw filter.isASTFilter?new Error('unknown ast filter "'+filter.name+':"'):new Error('unknown filter ":'+filter.name+'"');if(filter.isASTFilter)this.buf.push(fn(filter.block,this,filter.attrs));else{var text=filter.block.nodes.join("");this.buffer(utils.text(fn(text,filter.attrs)))}},visitText:function(text){text=utils.text(text.nodes.join("")),this.escape&&(text=escape(text)),this.buffer(text),this.buffer("\\n")},visitComment:function(comment){!comment.buffer||this.buffer("<!--"+utils.escape(comment.val)+"-->")},visitBlockComment:function(comment){0==comment.val.indexOf("if")?(this.buffer("<!--["+comment.val+"]>"),this.visit(comment.block),this.buffer("<![endif]-->")):(this.buffer("<!--"+comment.val),this.visit(comment.block),this.buffer("-->"))},visitCode:function(code){if(code.buffer){var val=code.val.trimLeft();this.buf.push("var __val__ = "+val),val='null == __val__ ? "" : __val__',code.escape&&(val="escape("+val+")"),this.buf.push("buf.push("+val+");")}else this.buf.push(code.val);code.block&&(code.buffer||this.buf.push("{"),this.visit(code.block),code.buffer||this.buf.push("}"))},visitEach:function(each){this.buf.push("// iterate "+each.obj+"\n"+"(function(){\n"+"  if ('number' == typeof "+each.obj+".length) {\n"+"    for (var "+each.key+" = 0, $$l = "+each.obj+".length; "+each.key+" < $$l; "+each.key+"++) {\n"+"      var "+each.val+" = "+each.obj+"["+each.key+"];\n"),this.visit(each.block),this.buf.push("    }\n  } else {\n    for (var "+each.key+" in "+each.obj+") {\n"+"      if ("+each.obj+".hasOwnProperty("+each.key+")){"+"      var "+each.val+" = "+each.obj+"["+each.key+"];\n"),this.visit(each.block),this.buf.push("      }\n"),this.buf.push("   }\n  }\n}).call(this);\n")},visitAttributes:function(attrs){var buf=[],classes=[];this.terse&&buf.push("terse: true"),attrs.forEach(function(attr){if(attr.name=="class")classes.push("("+attr.val+")");else{var pair="'"+attr.name+"':("+attr.val+")";buf.push(pair)}}),classes.length&&(classes=classes.join(" + ' ' + "),buf.push("class: "+classes)),buf=buf.join(", ").replace("class:",'"class":'),this.buf.push("buf.push(attrs({ "+buf+" }));")}};function escape(html){return String(html).replace(/&(?!\w+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}}),require.register("doctypes.js",function(module,exports,require){module.exports={5:"<!DOCTYPE html>",html:"<!DOCTYPE html>",xml:'<?xml version="1.0" encoding="utf-8" ?>',"default":'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',transitional:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',strict:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',frameset:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',1.1:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',basic:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',mobile:'<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'}}),require.register("filters.js",function(module,exports,require){module.exports={cdata:function(str){return"<![CDATA[\\n"+str+"\\n]]>"},sass:function(str){str=str.replace(/\\n/g,"\n");var sass=require("sass").render(str).replace(/\n/g,"\\n");return"<style>"+sass+"</style>"},stylus:function(str,options){var ret;str=str.replace(/\\n/g,"\n");var stylus=require("stylus");stylus(str,options).render(function(err,css){if(err)throw err;ret=css.replace(/\n/g,"\\n")});return"<style>"+ret+"</style>"},less:function(str){var ret;str=str.replace(/\\n/g,"\n"),require("less").render(str,function(err,css){if(err)throw err;ret="<style>"+css.replace(/\n/g,"\\n")+"</style>"});return ret},markdown:function(str){var md;try{md=require("markdown")}catch(err){try{md=require("discount")}catch(err){try{md=require("markdown-js")}catch(err){throw new Error("Cannot find markdown library, install markdown or discount")}}}str=str.replace(/\\n/g,"\n");return md.parse(str).replace(/\n/g,"\\n").replace(/'/g,"&#39;")},coffeescript:function(str){str=str.replace(/\\n/g,"\n");var js=require("coffee-script").compile(str).replace(/\n/g,"\\n");return'<script type="text/javascript">\\n'+js+"</script>"}}}),require.register("jade.js",function(module,exports,require){var Parser=require("./parser"),Compiler=require("./compiler");exports.version="0.12.1";var cache=exports.cache={};exports.selfClosing=require("./self-closing"),exports.doctypes=require("./doctypes"),exports.filters=require("./filters"),exports.utils=require("./utils"),exports.Compiler=Compiler,exports.Parser=Parser,exports.nodes=require("./nodes");function attrs(obj){var buf=[],terse=obj.terse;delete obj.terse;var keys=Object.keys(obj),len=keys.length;if(len){buf.push("");for(var i=0;i<len;++i){var key=keys[i],val=obj[key];typeof val=="boolean"||val===""||val==null?val&&(terse?buf.push(key):buf.push(key+'="'+key+'"')):buf.push(key+'="'+escape(val)+'"')}}return buf.join(" ")}function escape(html){return String(html).replace(/&(?!\w+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function rethrow(err,str,filename,lineno){var context=3,lines=str.split("\n"),start=Math.max(lineno-context,0),end=Math.min(lines.length,lineno+context),context=lines.slice(start,end).map(function(line,i){var curr=i+start+1;return(curr==lineno?"  > ":"    ")+curr+"| "+line}).join("\n");err.path=filename,err.message=(filename||"Jade")+":"+lineno+"\n"+context+"\n\n"+err.message;throw err}function parse(str,options){var filename=options.filename;try{var parser=new Parser(str,filename);options.debug&&parser.debug();var compiler=new(options.compiler||Compiler)(parser.parse(),options),js=compiler.compile();options.debug&&console.log("\n\e[1mCompiled Function\e[0m:\n\n%s",js.replace(/^/gm,"  "));try{return""+attrs.toString()+"\n\n"+escape.toString()+"\n\n"+"var buf = [];\n"+(options.self?"var self = locals || {}, __ = __ || locals.__;\n"+js:"with (locals || {}) {"+js+"}")+'return buf.join("");'}catch(err){process.compile(js,filename||"Jade");return}}catch(err){rethrow(err,str,filename,parser.lexer.lineno)}}exports.compile=function(str,options){var options=options||{},input=JSON.stringify(str),filename=options.filename?JSON.stringify(options.filename):"undefined",fn=["var __ = { lineno: 1, input: "+input+", filename: "+filename+" };",rethrow.toString(),"try {",parse(String(str),options||{}),"} catch (err) {","  rethrow(err, __.input, __.filename, __.lineno);","}"].join("\n");return new Function("locals",fn)},exports.render=function(str,options){var fn,options=options||{},filename=options.filename;str=String(str);if(options.cache)if(filename)cache[filename]?fn=cache[filename]:fn=cache[filename]=new Function("locals",parse(str,options));else throw new Error("filename is required when using the cache option");else fn=new Function("locals",parse(str,options));try{var locals=options.locals||{},meta={lineno:1};locals.__=meta;return fn.call(options.scope,locals)}catch(err){rethrow(err,str,filename,meta.lineno)}},exports.renderFile=function(path,options,fn){var ret;typeof options=="function"&&(fn=options,options={}),options.filename=path;if(options.cache&&cache[path]){try{ret=exports.render("",options)}catch(err){return fn(err)}fn(null,ret)}else fs.readFile(path,"utf8",function(err,str){if(err)return fn(err);try{ret=exports.render(str,options)}catch(err){return fn(err)}fn(null,ret)})}}),require.register("lexer.js",function(module,exports,require){var Lexer=module.exports=function Lexer(str){this.input=str.replace(/\r\n|\r/g,"\n"),this.deferredTokens=[],this.lastIndents=0,this.lineno=1,this.stash=[],this.indentStack=[],this.indentRe=null,this.pipeless=!1};Lexer.prototype={tok:function(type,val){return{type:type,line:this.lineno,val:val}},consume:function(len){this.input=this.input.substr(len)},scan:function(regexp,type){var captures;if(captures=regexp.exec(this.input)){this.consume(captures[0].length);return this.tok(type,captures[1])}},defer:function(tok){this.deferredTokens.push(tok)},lookahead:function(n){var fetch=n-this.stash.length;while(fetch-->0)this.stash.push(this.next());return this.stash[--n]},indexOfDelimiters:function(start,end){var str=this.input,nstart=0,nend=0,pos=0;for(var i=0,len=str.length;i<len;++i)if(start==str[i])++nstart;else if(end==str[i]&&++nend==nstart){pos=i;break}return pos},stashed:function(){return this.stash.length&&this.stash.shift()},deferred:function(){return this.deferredTokens.length&&this.deferredTokens.shift()},eos:function(){if(!this.input.length){if(this.indentStack.length){this.indentStack.shift();return this.tok("outdent")}return this.tok("eos")}},blockComment:function(){var captures;if(captures=/^\/([^\n]+)/.exec(this.input)){this.consume(captures[0].length);var tok=this.tok("block-comment",captures[1]);return tok}},comment:function(){var captures;if(captures=/^ *\/\/(-)?([^\n]+)/.exec(this.input)){this.consume(captures[0].length);var tok=this.tok("comment",captures[2]);tok.buffer="-"!=captures[1];return tok}},tag:function(){var captures;if(captures=/^(\w[-:\w]*)/.exec(this.input)){this.consume(captures[0].length);var tok,name=captures[1];if(":"==name[name.length-1]){name=name.slice(0,-1),tok=this.tok("tag",name),this.deferredTokens.push(this.tok(":"));while(" "==this.input[0])this.input=this.input.substr(1)}else tok=this.tok("tag",name);return tok}},filter:function(){return this.scan(/^:(\w+)/,"filter")},doctype:function(){return this.scan(/^(?:!!!|doctype) *(\w+)?/,"doctype")},id:function(){return this.scan(/^#([\w-]+)/,"id")},className:function(){return this.scan(/^\.([\w-]+)/,"class")},text:function(){return this.scan(/^(?:\| ?)?([^\n]+)/,"text")},each:function(){var captures;if(captures=/^- *each *(\w+)(?: *, *(\w+))? * in *([^\n]+)/.exec(this.input)){this.consume(captures[0].length);var tok=this.tok("each",captures[1]);tok.key=captures[2]||"index",tok.code=captures[3];return tok}},code:function(){var captures;if(captures=/^(!?=|-)([^\n]+)/.exec(this.input)){this.consume(captures[0].length);var flags=captures[1];captures[1]=captures[2];var tok=this.tok("code",captures[1]);tok.escape=flags[0]==="=",tok.buffer=flags[0]==="="||flags[1]==="=";return tok}},attrs:function(){if("("==this.input[0]){var index=this.indexOfDelimiters("(",")"),str=this.input.substr(1,index-1),tok=this.tok("attrs"),len=str.length,states=["key"],key="",val="",quote,c;function state(){return states[states.length-1]}function interpolate(attr){return attr.replace(/#\{([^}]+)\}/g,function(_,expr){return quote+" + ("+expr+") + "+quote})}this.consume(index+1),tok.attrs={};function parse(c){switch(c){case",":case"\n":switch(state()){case"expr":case"array":case"string":case"object":val+=c;break;default:states.push("key"),val=val.trim(),key=key.trim();if(""==key)return;tok.attrs[key.replace(/^['"]|['"]$/g,"")]=""==val?!0:interpolate(val),key=val=""}break;case"=":switch(state()){case"key char":key+=c;break;case"val":case"expr":case"array":case"string":case"object":val+=c;break;default:states.push("val")}break;case"(":"val"==state()&&states.push("expr"),val+=c;break;case")":"expr"==state()&&states.pop(),val+=c;break;case"{":"val"==state()&&states.push("object"),val+=c;break;case"}":"object"==state()&&states.pop(),val+=c;break;case"[":"val"==state()&&states.push("array"),val+=c;break;case"]":"array"==state()&&states.pop(),val+=c;break;case'"':case"'":switch(state()){case"key":states.push("key char");break;case"key char":states.pop();break;case"string":c==quote&&states.pop(),val+=c;break;default:states.push("string"),val+=c,quote=c}break;case"":break;default:switch(state()){case"key":case"key char":key+=c;break;default:val+=c}}}for(var i=0;i<len;++i)parse(str[i]);parse(",");return tok}},indent:function(){var captures,re;this.indentRe?captures=this.indentRe.exec(this.input):(re=/^\n(\t*) */,captures=re.exec(this.input),captures&&!captures[1].length&&(re=/^\n( *)/,captures=re.exec(this.input)),captures&&captures[1].length&&(this.indentRe=re));if(captures){var tok,indents=captures[1].length;++this.lineno,this.consume(indents+1);if(" "==this.input[0]||"\t"==this.input[0])throw new Error("Invalid indentation, you can use tabs or spaces but not both");if("\n"==this.input[0])return this.tok("newline");if(this.indentStack.length&&indents<this.indentStack[0]){while(this.indentStack.length&&this.indentStack[0]>indents)this.stash.push(this.tok("outdent")),this.indentStack.shift();tok=this.stash.pop()}else indents&&indents!=this.indentStack[0]?(this.indentStack.unshift(indents),tok=this.tok("indent",indents)):tok=this.tok("newline");return tok}},pipelessText:function(){if(this.pipeless){if("\n"==this.input[0])return;var i=this.input.indexOf("\n");-1==i&&(i=this.input.length);var str=this.input.substr(0,i);this.consume(str.length);return this.tok("text",str)}},colon:function(){return this.scan(/^: */,":")},advance:function(){return this.stashed()||this.next()},next:function(){return this.deferred()||this.eos()||this.pipelessText()||this.doctype()||this.tag()||this.filter()||this.each()||this.code()||this.id()||this.className()||this.attrs()||this.indent()||this.comment()||this.blockComment()||this.colon()||this.text()}}}),require.register("nodes/block-comment.js",function(module,exports,require){var Node=require("./node"),BlockComment=module.exports=function BlockComment(val,block){this.block=block,this.val=val};BlockComment.prototype=new Node,BlockComment.prototype.constructor=BlockComment}),require.register("nodes/block.js",function(module,exports,require){var Node=require("./node"),Block=module.exports=function Block(node){this.nodes=[],node&&this.push(node)};Block.prototype=new Node,Block.prototype.constructor=Block,Block.prototype.push=function(node){return this.nodes.push(node)},Block.prototype.unshift=function(node){return this.nodes.unshift(node)}}),require.register("nodes/code.js",function(module,exports,require){var Node=require("./node"),Code=module.exports=function Code(val,buffer,escape){this.val=val,this.buffer=buffer,this.escape=escape,/^ *else/.test(val)&&(this.instrumentLineNumber=!1)};Code.prototype=new Node,Code.prototype.constructor=Code}),require.register("nodes/comment.js",function(module,exports,require){var Node=require("./node"),Comment=module.exports=function Comment(val,buffer){this.val=val,this.buffer=buffer};Comment.prototype=new Node,Comment.prototype.constructor=Comment}),require.register("nodes/doctype.js",function(module,exports,require){var Node=require("./node"),Doctype=module.exports=function Doctype(val){this.val=val};Doctype.prototype=new Node,Doctype.prototype.constructor=Doctype}),require.register("nodes/each.js",function(module,exports,require){var Node=require("./node"),Each=module.exports=function Each(obj,val,key,block){this.obj=obj,this.val=val,this.key=key,this.block=block};Each.prototype=new Node,Each.prototype.constructor=Each}),require.register("nodes/filter.js",function(module,exports,require){var Node=require("./node"),Block=require("./block"),Filter=module.exports=function Filter(name,block,attrs){this.name=name,this.block=block,this.attrs=attrs,this.isASTFilter=block instanceof Block};Filter.prototype=new Node,Filter.prototype.constructor=Filter}),require.register("nodes/index.js",function(module,exports,require){exports.Node=require("./node"),exports.Tag=require("./tag"),exports.Code=require("./code"),exports.Each=require("./each"),exports.Text=require("./text"),exports.Block=require("./block"),exports.Filter=require("./filter"),exports.Comment=require("./comment"),exports.BlockComment=require("./block-comment"),exports.Doctype=require("./doctype")}),require.register("nodes/node.js",function(module,exports,require){var Node=module.exports=function(){}}),require.register("nodes/tag.js",function(module,exports,require){var Node=require("./node"),Block=require("./block"),Tag=module.exports=function Tag(name,block){this.name=name,this.attrs=[],this.block=block||new Block};Tag.prototype=new Node,Tag.prototype.constructor=Tag,Tag.prototype.setAttribute=function(name,val){this.attrs.push({name:name,val:val});return this},Tag.prototype.removeAttribute=function(name){for(var i=0,len=this.attrs.length;i<len;++i)this.attrs[i]&&this.attrs[i].name==name&&delete this.attrs[i]},Tag.prototype.getAttribute=function(name){for(var i=0,len=this.attrs.length;i<len;++i)if(this.attrs[i]&&this.attrs[i].name==name)return this.attrs[i].val}}),require.register("nodes/text.js",function(module,exports,require){var Node=require("./node"),Text=module.exports=function Text(line){this.nodes=[],"string"==typeof line&&this.push(line)};Text.prototype=new Node,Text.prototype.constructor=Text,Text.prototype.push=function(node){return this.nodes.push(node)}}),require.register("parser.js",function(module,exports,require){var Lexer=require("./lexer"),nodes=require("./nodes"),Parser=exports=module.exports=function Parser(str,filename){this.input=str,this.lexer=new Lexer(str),this.filename=filename},textOnly=exports.textOnly=["code","script","textarea","style"];Parser.prototype={debug:function(){var lexer=new Lexer(this.input),tree=require("sys").inspect(this.parse(),!1,12,!0);console.log("\n\e[1mParse Tree\e[0m:\n"),console.log(tree),this.lexer=lexer},advance:function(){return this.lexer.advance()},peek:function(){return this.lookahead(1)},line:function(){return this.lexer.lineno},lookahead:function(n){return this.lexer.lookahead(n)},parse:function(){var block=new nodes.Block;block.line=this.line();while("eos"!=this.peek().type)"newline"==this.peek().type?this.advance():block.push(this.parseExpr());return block},expect:function(type){if(this.peek().type===type)return this.advance();throw new Error('expected "'+type+'", but got "'+this.peek().type+'"')},accept:function(type){if(this.peek().type===type)return this.advance()},parseExpr:function(){switch(this.peek().type){case"tag":return this.parseTag();case"doctype":return this.parseDoctype();case"filter":return this.parseFilter();case"comment":return this.parseComment();case"block-comment":return this.parseBlockComment();case"text":return this.parseText();case"each":return this.parseEach();case"code":return this.parseCode();case"id":case"class":var tok=this.advance();this.lexer.defer(this.lexer.tok("tag","div")),this.lexer.defer(tok);return this.parseExpr();default:throw new Error('unexpected token "'+this.peek().type+'"')}},parseText:function(){var tok=this.expect("text"),node=new nodes.Text(tok.val);node.line=this.line();return node},parseCode:function(){var tok=this.expect("code"),node=new nodes.Code(tok.val,tok.buffer,tok.escape);node.line=this.line(),"indent"==this.peek().type&&(node.block=this.parseBlock());return node},parseBlockComment:function(){var tok=this.expect("block-comment"),node=new nodes.BlockComment(tok.val,this.parseBlock());node.line=this.line();return node},parseComment:function(){var tok=this.expect("comment"),node=new nodes.Comment(tok.val,tok.buffer);node.line=this.line();return node},parseDoctype:function(){var tok=this.expect("doctype"),node=new nodes.Doctype(tok.val);node.line=this.line();return node},parseFilter:function(){var block,tok=this.expect("filter"),attrs=this.accept("attrs");this.lexer.pipeless=!0,block=this.parseTextBlock(),this.lexer.pipeless=!1;var node=new nodes.Filter(tok.val,block,attrs&&attrs.attrs);node.line=this.line();return node},parseASTFilter:function(){var block,tok=this.expect("tag"),attrs=this.accept("attrs");this.expect(":"),block=this.parseBlock();var node=new nodes.Filter(tok.val,block,attrs&&attrs.attrs);node.line=this.line();return node},parseEach:function(){var tok=this.expect("each"),node=new nodes.Each(tok.code,tok.val,tok.key,this.parseBlock());node.line=this.line();return node},parseTextBlock:function(){var text=new nodes.Text;text.line=this.line();var spaces=this.expect("indent").val;null==this._spaces&&(this._spaces=spaces);var indent=Array(spaces-this._spaces+1).join(" ");while("outdent"!=this.peek().type)switch(this.peek().type){case"newline":text.push("\\n"),this.advance();break;case"indent":text.push("\\n"),this.parseTextBlock().nodes.forEach(function(node){text.push(node)}),text.push("\\n");break;default:text.push(indent+this.advance().val)}this._spaces=null,this.expect("outdent");return text},parseBlock:function(){var block=new nodes.Block;block.line=this.line(),this.expect("indent");while("outdent"!=this.peek().type)"newline"==this.peek().type?this.advance():block.push(this.parseExpr());this.expect("outdent");return block},parseTag:function(){var i=2;"attrs"==this.lookahead(i).type&&++i;if(":"==this.lookahead(i).type&&"indent"==this.lookahead(++i).type)return this.parseASTFilter();var name=this.advance().val,tag=new nodes.Tag(name);tag.line=this.line();out:for(;;)switch(this.peek().type){case"id":case"class":var tok=this.advance();tag.setAttribute(tok.type,"'"+tok.val+"'");continue;case"attrs":var obj=this.advance().attrs,names=Object.keys(obj);for(var i=0,len=names.length;i<len;++i){var name=names[i],val=obj[name];tag.setAttribute(name,val)}continue;default:break out}"."==this.peek().val&&(tag.textOnly=!0,this.advance());switch(this.peek().type){case"text":tag.text=this.parseText();break;case"code":tag.code=this.parseCode();break;case":":this.advance(),tag.block=new nodes.Block,tag.block.push(this.parseTag())}while("newline"==this.peek().type)this.advance();tag.textOnly=tag.textOnly||~textOnly.indexOf(tag.name);if("script"==tag.name){var type=tag.getAttribute("type");type&&"text/javascript"!=type.replace(/^['"]|['"]$/g,"")&&(tag.textOnly=!1)}if("indent"==this.peek().type)if(tag.textOnly)this.lexer.pipeless=!0,tag.block=this.parseTextBlock(),this.lexer.pipeless=!1;else{var block=this.parseBlock();if(tag.block)for(var i=0,len=block.nodes.length;i<len;++i)tag.block.push(block.nodes[i]);else tag.block=block}return tag}}}),require.register("self-closing.js",function(module,exports,require){module.exports=["meta","img","link","input","area","base","col","br","hr"]}),require.register("utils.js",function(module,exports,require){var interpolate=exports.interpolate=function(str){return str.replace(/(\\)?([#!]){(.*?)}/g,function(str,escape,flag,code){return escape?str:"' + "+("!"==flag?"":"escape")+"((interp = "+code.replace(/\\'/g,"'")+") == null ? '' : interp) + '"})},escape=exports.escape=function(str){return str.replace(/'/g,"\\'")};exports.text=function(str){return interpolate(escape(str))}})
\ No newline at end of file
+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]&&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];".."==seg?path.pop():"."!=seg&&path.push(seg)}return require(path.join("/"))}},require.register("compiler.js",function(module,exports,require){var nodes=require("./nodes"),filters=require("./filters"),doctypes=require("./doctypes"),selfClosing=require("./self-closing"),inlineTags=require("./inline-tags"),utils=require("./utils");Object.keys||(Object.keys=function(obj){var arr=[];for(var key in obj)obj.hasOwnProperty(key)&&arr.push(obj);return arr}),String.prototype.trimLeft||(String.prototype.trimLeft=function(){return this.replace(/^\s+/,"")});var Compiler=module.exports=function Compiler(node,options){this.options=options=options||{},this.node=node,this.hasCompiledDoctype=!1,this.hasCompiledTag=!1,this.pp=options.pretty||!1,this.debug=!1!==options.compileDebug,this.indents=0,options.doctype&&this.setDoctype(options.doctype)};Compiler.prototype={compile:function(){this.buf=["var interp;"],this.lastBufferedIdx=-1,this.visit(this.node);return this.buf.join("\n")},setDoctype:function(name){var doctype=doctypes[(name||"default").toLowerCase()];if(!doctype)throw new Error('unknown doctype "'+name+'"');this.doctype=doctype,this.terse="5"==name||"html"==name,this.xml=0==this.doctype.indexOf("<?xml")},buffer:function(str,esc){esc&&(str=utils.escape(str)),this.lastBufferedIdx==this.buf.length?(this.lastBuffered+=str,this.buf[this.lastBufferedIdx-1]="buf.push('"+this.lastBuffered+"');"):(this.buf.push("buf.push('"+str+"');"),this.lastBuffered=str,this.lastBufferedIdx=this.buf.length)},line:function(node){!1!==node.instrumentLineNumber&&this.buf.push("__.lineno = "+node.line+";")},visit:function(node){this.debug&&this.line(node);return this.visitNode(node)},visitNode:function(node){var name=node.constructor.name||node.constructor.toString().match(/function ([^(\s]+)()/)[1];return this["visit"+name](node)},visitLiteral:function(node){var str=node.str.replace(/\n/g,"\\\\n");this.buffer(str)},visitBlock:function(block){var len=block.nodes.length;for(var i=0;i<len;++i)this.visit(block.nodes[i])},visitDoctype:function(doctype){doctype&&(doctype.val||!this.doctype)&&this.setDoctype(doctype.val||"default"),this.doctype&&this.buffer(this.doctype),this.hasCompiledDoctype=!0},visitMixin:function(mixin){var name=mixin.name.replace(/-/g,"_")+"_mixin",args=mixin.args||"";mixin.block?(this.buf.push("var "+name+" = function("+args+"){"),this.visit(mixin.block),this.buf.push("}")):this.buf.push(name+"("+args+");")},visitTag:function(tag){this.indents++;var name=tag.name;this.hasCompiledTag||(!this.hasCompiledDoctype&&"html"==name&&this.visitDoctype(),this.hasCompiledTag=!0),this.pp&&inlineTags.indexOf(name)==-1&&this.buffer("\\n"+Array(this.indents).join("  ")),~selfClosing.indexOf(name)&&!this.xml?(this.buffer("<"+name),this.visitAttributes(tag.attrs),this.terse?this.buffer(">"):this.buffer("/>")):(tag.attrs.length?(this.buffer("<"+name),tag.attrs.length&&this.visitAttributes(tag.attrs),this.buffer(">")):this.buffer("<"+name+">"),tag.code&&this.visitCode(tag.code),tag.text&&this.buffer(utils.text(tag.text.nodes[0].trimLeft())),this.escape="pre"==tag.name,this.visit(tag.block),this.pp&&!~inlineTags.indexOf(name)&&!tag.textOnly&&this.buffer("\\n"+Array(this.indents).join("  ")),this.buffer("</"+name+">")),this.indents--},visitFilter:function(filter){var fn=filters[filter.name];if(!fn)throw filter.isASTFilter?new Error('unknown ast filter "'+filter.name+':"'):new Error('unknown filter ":'+filter.name+'"');if(filter.isASTFilter)this.buf.push(fn(filter.block,this,filter.attrs));else{var text=filter.block.nodes.join("");this.buffer(utils.text(fn(text,filter.attrs)))}},visitText:function(text){text=utils.text(text.nodes.join("")),this.escape&&(text=escape(text)),this.buffer(text),this.buffer("\\n")},visitComment:function(comment){!comment.buffer||(this.pp&&this.buffer("\\n"+Array(this.indents+1).join("  ")),this.buffer("<!--"+utils.escape(comment.val)+"-->"))},visitBlockComment:function(comment){!comment.buffer||(0==comment.val.indexOf("if")?(this.buffer("<!--["+comment.val+"]>"),this.visit(comment.block),this.buffer("<![endif]-->")):(this.buffer("<!--"+comment.val),this.visit(comment.block),this.buffer("-->")))},visitCode:function(code){if(code.buffer){var val=code.val.trimLeft();this.buf.push("var __val__ = "+val),val='null == __val__ ? "" : __val__',code.escape&&(val="escape("+val+")"),this.buf.push("buf.push("+val+");")}else this.buf.push(code.val);code.block&&(code.buffer||this.buf.push("{"),this.visit(code.block),code.buffer||this.buf.push("}"))},visitEach:function(each){this.buf.push("// iterate "+each.obj+"\n"+"(function(){\n"+"  if ('number' == typeof "+each.obj+".length) {\n"+"    for (var "+each.key+" = 0, $$l = "+each.obj+".length; "+each.key+" < $$l; "+each.key+"++) {\n"+"      var "+each.val+" = "+each.obj+"["+each.key+"];\n"),this.visit(each.block),this.buf.push("    }\n  } else {\n    for (var "+each.key+" in "+each.obj+") {\n"+"      if ("+each.obj+".hasOwnProperty("+each.key+")){"+"      var "+each.val+" = "+each.obj+"["+each.key+"];\n"),this.visit(each.block),this.buf.push("      }\n"),this.buf.push("   }\n  }\n}).call(this);\n")},visitAttributes:function(attrs){var buf=[],classes=[];this.terse&&buf.push("terse: true"),attrs.forEach(function(attr){if(attr.name=="class")classes.push("("+attr.val+")");else{var pair="'"+attr.name+"':("+attr.val+")";buf.push(pair)}}),classes.length&&(classes=classes.join(" + ' ' + "),buf.push("class: "+classes)),buf=buf.join(", ").replace("class:",'"class":'),this.buf.push("buf.push(attrs({ "+buf+" }));")}};function escape(html){return String(html).replace(/&(?!\w+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}}),require.register("doctypes.js",function(module,exports,require){module.exports={5:"<!DOCTYPE html>",html:"<!DOCTYPE html>",xml:'<?xml version="1.0" encoding="utf-8" ?>',"default":'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',transitional:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',strict:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',frameset:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',1.1:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',basic:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',mobile:'<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'}}),require.register("filters.js",function(module,exports,require){module.exports={cdata:function(str){return"<![CDATA[\\n"+str+"\\n]]>"},sass:function(str){str=str.replace(/\\n/g,"\n");var sass=require("sass").render(str).replace(/\n/g,"\\n");return"<style>"+sass+"</style>"},stylus:function(str,options){var ret;str=str.replace(/\\n/g,"\n");var stylus=require("stylus");stylus(str,options).render(function(err,css){if(err)throw err;ret=css.replace(/\n/g,"\\n")});return"<style>"+ret+"</style>"},less:function(str){var ret;str=str.replace(/\\n/g,"\n"),require("less").render(str,function(err,css){if(err)throw err;ret="<style>"+css.replace(/\n/g,"\\n")+"</style>"});return ret},markdown:function(str){var md;try{md=require("markdown")}catch(err){try{md=require("discount")}catch(err){try{md=require("markdown-js")}catch(err){throw new Error("Cannot find markdown library, install markdown or discount")}}}str=str.replace(/\\n/g,"\n");return md.parse(str).replace(/\n/g,"\\n").replace(/'/g,"&#39;")},coffeescript:function(str){str=str.replace(/\\n/g,"\n");var js=require("coffee-script").compile(str).replace(/\n/g,"\\n");return'<script type="text/javascript">\\n'+js+"</script>"}}}),require.register("inline-tags.js",function(module,exports,require){module.exports=["a","abbr","acronym","b","br","code","em","font","i","img","ins","kbd","map","samp","small","span","strong","sub","sup"]}),require.register("jade.js",function(module,exports,require){var Parser=require("./parser"),Compiler=require("./compiler"),runtime=require("./runtime");exports.version="0.15.4";var cache=exports.cache={};exports.selfClosing=require("./self-closing"),exports.doctypes=require("./doctypes"),exports.filters=require("./filters"),exports.utils=require("./utils"),exports.Compiler=Compiler,exports.Parser=Parser,exports.nodes=require("./nodes"),exports.runtime=runtime;function parse(str,options){var filename=options.filename;try{var parser=new Parser(str,filename,options),compiler=new(options.compiler||Compiler)(parser.parse(),options),js=compiler.compile();options.debug&&console.log("\n\e[1mCompiled Function\e[0m:\n\n%s",js.replace(/^/gm,"  "));try{return"var buf = [];\n"+(options.self?"var self = locals || {};\n"+js:"with (locals || {}) {\n"+js+"\n}\n")+'return buf.join("");'}catch(err){process.compile(js,filename||"Jade");return}}catch(err){runtime.rethrow(err,str,filename,parser.lexer.lineno)}}exports.compile=function(str,options){var options=options||{},input=JSON.stringify(str),client=options.client,filename=options.filename?JSON.stringify(options.filename):"undefined",fn;options.compileDebug!==!1?fn=["var __ = { lineno: 1, input: "+input+", filename: "+filename+" };","try {",parse(String(str),options||{}),"} catch (err) {","  rethrow(err, __.input, __.filename, __.lineno);","}"].join("\n"):fn=parse(String(str),options||{}),client&&(fn="var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow;\n"+fn),fn=new Function("locals, attrs, escape, rethrow",fn);if(client)return fn;return function(locals){return fn(locals,runtime.attrs,runtime.escape,runtime.rethrow)}}}),require.register("lexer.js",function(module,exports,require){var Lexer=module.exports=function Lexer(str,options){options=options||{},this.input=str.replace(/\r\n|\r/g,"\n"),this.colons=options.colons,this.deferredTokens=[],this.lastIndents=0,this.lineno=1,this.stash=[],this.indentStack=[],this.indentRe=null,this.pipeless=!1};Lexer.prototype={tok:function(type,val){return{type:type,line:this.lineno,val:val}},consume:function(len){this.input=this.input.substr(len)},scan:function(regexp,type){var captures;if(captures=regexp.exec(this.input)){this.consume(captures[0].length);return this.tok(type,captures[1])}},defer:function(tok){this.deferredTokens.push(tok)},lookahead:function(n){var fetch=n-this.stash.length;while(fetch-->0)this.stash.push(this.next());return this.stash[--n]},indexOfDelimiters:function(start,end){var str=this.input,nstart=0,nend=0,pos=0;for(var i=0,len=str.length;i<len;++i)if(start==str[i])++nstart;else if(end==str[i]&&++nend==nstart){pos=i;break}return pos},stashed:function(){return this.stash.length&&this.stash.shift()},deferred:function(){return this.deferredTokens.length&&this.deferredTokens.shift()},eos:function(){if(!this.input.length){if(this.indentStack.length){this.indentStack.shift();return this.tok("outdent")}return this.tok("eos")}},comment:function(){var captures;if(captures=/^ *\/\/(-)?([^\n]*)/.exec(this.input)){this.consume(captures[0].length);var tok=this.tok("comment",captures[2]);tok.buffer="-"!=captures[1];return tok}},tag:function(){var captures;if(captures=/^(\w[-:\w]*)/.exec(this.input)){this.consume(captures[0].length);var tok,name=captures[1];if(":"==name[name.length-1]){name=name.slice(0,-1),tok=this.tok("tag",name),this.deferredTokens.push(this.tok(":"));while(" "==this.input[0])this.input=this.input.substr(1)}else tok=this.tok("tag",name);return tok}},filter:function(){return this.scan(/^:(\w+)/,"filter")},doctype:function(){return this.scan(/^(?:!!!|doctype) *(\w+)?/,"doctype")},id:function(){return this.scan(/^#([\w-]+)/,"id")},className:function(){return this.scan(/^\.([\w-]+)/,"class")},text:function(){return this.scan(/^(?:\| ?)?([^\n]+)/,"text")},include:function(){return this.scan(/^include +([^\n]+)/,"include")},mixin:function(){var captures;if(captures=/^mixin +([-\w]+)(?:\(([^\)]+)\))?/.exec(this.input)){this.consume(captures[0].length);var tok=this.tok("mixin",captures[1]);tok.args=captures[2];return tok}},conditional:function(){var captures;if(captures=/^(if|unless|else if|else)\b([^\n]*)/.exec(this.input)){this.consume(captures[0].length);var type=captures[1],js=captures[2];switch(type){case"if":js="if ("+js+")";break;case"unless":js="if (!("+js+"))";break;case"else if":js="else if ("+js+")";break;case"else":js="else"}return this.tok("code",js)}},each:function(){var captures;if(captures=/^(?:- *)?(?:each|for) +(\w+)(?: *, *(\w+))? * in *([^\n]+)/.exec(this.input)){this.consume(captures[0].length);var tok=this.tok("each",captures[1]);tok.key=captures[2]||"index",tok.code=captures[3];return tok}},code:function(){var captures;if(captures=/^(!?=|-)([^\n]+)/.exec(this.input)){this.consume(captures[0].length);var flags=captures[1];captures[1]=captures[2];var tok=this.tok("code",captures[1]);tok.escape=flags[0]==="=",tok.buffer=flags[0]==="="||flags[1]==="=";return tok}},attrs:function(){if("("==this.input[0]){var index=this.indexOfDelimiters("(",")"),str=this.input.substr(1,index-1),tok=this.tok("attrs"),len=str.length,colons=this.colons,states=["key"],key="",val="",quote,c;function state(){return states[states.length-1]}function interpolate(attr){return attr.replace(/#\{([^}]+)\}/g,function(_,expr){return quote+" + ("+expr+") + "+quote})}this.consume(index+1),tok.attrs={};function parse(c){var real=c;colons&&":"==c&&(c="=");switch(c){case",":case"\n":switch(state()){case"expr":case"array":case"string":case"object":val+=c;break;default:states.push("key"),val=val.trim(),key=key.trim();if(""==key)return;tok.attrs[key.replace(/^['"]|['"]$/g,"")]=""==val?!0:interpolate(val),key=val=""}break;case"=":switch(state()){case"key char":key+=real;break;case"val":case"expr":case"array":case"string":case"object":val+=real;break;default:states.push("val")}break;case"(":"val"==state()&&states.push("expr"),val+=c;break;case")":"expr"==state()&&states.pop(),val+=c;break;case"{":"val"==state()&&states.push("object"),val+=c;break;case"}":"object"==state()&&states.pop(),val+=c;break;case"[":"val"==state()&&states.push("array"),val+=c;break;case"]":"array"==state()&&states.pop(),val+=c;break;case'"':case"'":switch(state()){case"key":states.push("key char");break;case"key char":states.pop();break;case"string":c==quote&&states.pop(),val+=c;break;default:states.push("string"),val+=c,quote=c}break;case"":break;default:switch(state()){case"key":case"key char":key+=c;break;default:val+=c}}}for(var i=0;i<len;++i)parse(str[i]);parse(",");return tok}},indent:function(){var captures,re;this.indentRe?captures=this.indentRe.exec(this.input):(re=/^\n(\t*) */,captures=re.exec(this.input),captures&&!captures[1].length&&(re=/^\n( *)/,captures=re.exec(this.input)),captures&&captures[1].length&&(this.indentRe=re));if(captures){var tok,indents=captures[1].length;++this.lineno,this.consume(indents+1);if(" "==this.input[0]||"\t"==this.input[0])throw new Error("Invalid indentation, you can use tabs or spaces but not both");if("\n"==this.input[0])return this.tok("newline");if(this.indentStack.length&&indents<this.indentStack[0]){while(this.indentStack.length&&this.indentStack[0]>indents)this.stash.push(this.tok("outdent")),this.indentStack.shift();tok=this.stash.pop()}else indents&&indents!=this.indentStack[0]?(this.indentStack.unshift(indents),tok=this.tok("indent",indents)):tok=this.tok("newline");return tok}},pipelessText:function(){if(this.pipeless){if("\n"==this.input[0])return;var i=this.input.indexOf("\n");-1==i&&(i=this.input.length);var str=this.input.substr(0,i);this.consume(str.length);return this.tok("text",str)}},colon:function(){return this.scan(/^: */,":")},advance:function(){return this.stashed()||this.next()},next:function(){return this.deferred()||this.eos()||this.pipelessText()||this.doctype()||this.include()||this.mixin()||this.conditional()||this.each()||this.tag()||this.filter()||this.code()||this.id()||this.className()||this.attrs()||this.indent()||this.comment()||this.colon()||this.text()}}}),require.register("nodes/block-comment.js",function(module,exports,require){var Node=require("./node"),BlockComment=module.exports=function BlockComment(val,block,buffer){this.block=block,this.val=val,this.buffer=buffer};BlockComment.prototype=new Node,BlockComment.prototype.constructor=BlockComment}),require.register("nodes/block.js",function(module,exports,require){var Node=require("./node"),Block=module.exports=function Block(node){this.nodes=[],node&&this.push(node)};Block.prototype=new Node,Block.prototype.constructor=Block,Block.prototype.push=function(node){return this.nodes.push(node)},Block.prototype.unshift=function(node){return this.nodes.unshift(node)}}),require.register("nodes/code.js",function(module,exports,require){var Node=require("./node"),Code=module.exports=function Code(val,buffer,escape){this.val=val,this.buffer=buffer,this.escape=escape,/^ *else/.test(val)&&(this.instrumentLineNumber=!1)};Code.prototype=new Node,Code.prototype.constructor=Code}),require.register("nodes/comment.js",function(module,exports,require){var Node=require("./node"),Comment=module.exports=function Comment(val,buffer){this.val=val,this.buffer=buffer};Comment.prototype=new Node,Comment.prototype.constructor=Comment}),require.register("nodes/doctype.js",function(module,exports,require){var Node=require("./node"),Doctype=module.exports=function Doctype(val){this.val=val};Doctype.prototype=new Node,Doctype.prototype.constructor=Doctype}),require.register("nodes/each.js",function(module,exports,require){var Node=require("./node"),Each=module.exports=function Each(obj,val,key,block){this.obj=obj,this.val=val,this.key=key,this.block=block};Each.prototype=new Node,Each.prototype.constructor=Each}),require.register("nodes/filter.js",function(module,exports,require){var Node=require("./node"),Block=require("./block"),Filter=module.exports=function Filter(name,block,attrs){this.name=name,this.block=block,this.attrs=attrs,this.isASTFilter=block instanceof Block};Filter.prototype=new Node,Filter.prototype.constructor=Filter}),require.register("nodes/index.js",function(module,exports,require){exports.Node=require("./node"),exports.Tag=require("./tag"),exports.Code=require("./code"),exports.Each=require("./each"),exports.Text=require("./text"),exports.Block=require("./block"),exports.Mixin=require("./mixin"),exports.Filter=require("./filter"),exports.Comment=require("./comment"),exports.Literal=require("./literal"),exports.BlockComment=require("./block-comment"),exports.Doctype=require("./doctype")}),require.register("nodes/literal.js",function(module,exports,require){var Node=require("./node"),Literal=module.exports=function Literal(str){this.str=str};Literal.prototype=new Node,Literal.prototype.constructor=Literal}),require.register("nodes/mixin.js",function(module,exports,require){var Node=require("./node"),Mixin=module.exports=function Mixin(name,args,block){this.name=name,this.args=args,this.block=block};Mixin.prototype=new Node,Mixin.prototype.constructor=Mixin}),require.register("nodes/node.js",function(module,exports,require){var Node=module.exports=function(){}}),require.register("nodes/tag.js",function(module,exports,require){var Node=require("./node"),Block=require("./block"),Tag=module.exports=function Tag(name,block){this.name=name,this.attrs=[],this.block=block||new Block};Tag.prototype=new Node,Tag.prototype.constructor=Tag,Tag.prototype.setAttribute=function(name,val){this.attrs.push({name:name,val:val});return this},Tag.prototype.removeAttribute=function(name){for(var i=0,len=this.attrs.length;i<len;++i)this.attrs[i]&&this.attrs[i].name==name&&delete this.attrs[i]},Tag.prototype.getAttribute=function(name){for(var i=0,len=this.attrs.length;i<len;++i)if(this.attrs[i]&&this.attrs[i].name==name)return this.attrs[i].val}}),require.register("nodes/text.js",function(module,exports,require){var Node=require("./node"),Text=module.exports=function Text(line){this.nodes=[],"string"==typeof line&&this.push(line)};Text.prototype=new Node,Text.prototype.constructor=Text,Text.prototype.push=function(node){return this.nodes.push(node)}}),require.register("parser.js",function(module,exports,require){var Lexer=require("./lexer"),nodes=require("./nodes"),Parser=exports=module.exports=function Parser(str,filename,options){this.input=str,this.lexer=new Lexer(str,options),this.filename=filename},textOnly=exports.textOnly=["code","script","textarea","style","title"];Parser.prototype={advance:function(){return this.lexer.advance()},skip:function(n){while(n--)this.advance()},peek:function(){return this.lookahead(1)},line:function(){return this.lexer.lineno},lookahead:function(n){return this.lexer.lookahead(n)},parse:function(){var block=new nodes.Block;block.line=this.line();while("eos"!=this.peek().type)"newline"==this.peek().type?this.advance():block.push(this.parseExpr());return block},expect:function(type){if(this.peek().type===type)return this.advance();throw new Error('expected "'+type+'", but got "'+this.peek().type+'"')},accept:function(type){if(this.peek().type===type)return this.advance()},parseExpr:function(){switch(this.peek().type){case"tag":return this.parseTag();case"mixin":return this.parseMixin();case"include":return this.parseInclude();case"doctype":return this.parseDoctype();case"filter":return this.parseFilter();case"comment":return this.parseComment();case"text":return this.parseText();case"each":return this.parseEach();case"code":return this.parseCode();case"id":case"class":var tok=this.advance();this.lexer.defer(this.lexer.tok("tag","div")),this.lexer.defer(tok);return this.parseExpr();default:throw new Error('unexpected token "'+this.peek().type+'"')}},parseText:function(){var tok=this.expect("text"),node=new nodes.Text(tok.val);node.line=this.line();return node},parseCode:function(){var tok=this.expect("code"),node=new nodes.Code(tok.val,tok.buffer,tok.escape),block,i=1;node.line=this.line();while(this.lookahead(i)&&"newline"==this.lookahead(i).type)++i;block="indent"==this.lookahead(i).type,block&&(this.skip(i-1),node.block=this.parseBlock());return node},parseComment:function(){var tok=this.expect("comment"),node;"indent"==this.peek().type?node=new nodes.BlockComment(tok.val,this.parseBlock(),tok.buffer):node=new nodes.Comment(tok.val,tok.buffer),node.line=this.line();return node},parseDoctype:function(){var tok=this.expect("doctype"),node=new nodes.Doctype(tok.val);node.line=this.line();return node},parseFilter:function(){var block,tok=this.expect("filter"),attrs=this.accept("attrs");this.lexer.pipeless=!0,block=this.parseTextBlock(),this.lexer.pipeless=!1;var node=new nodes.Filter(tok.val,block,attrs&&attrs.attrs);node.line=this.line();return node},parseASTFilter:function(){var block,tok=this.expect("tag"),attrs=this.accept("attrs");this.expect(":"),block=this.parseBlock();var node=new nodes.Filter(tok.val,block,attrs&&attrs.attrs);node.line=this.line();return node},parseEach:function(){var tok=this.expect("each"),node=new nodes.Each(tok.code,tok.val,tok.key,this.parseBlock());node.line=this.line();return node},parseInclude:function(){var path=require("path"),fs=require("fs"),dirname=path.dirname,basename=path.basename,join=path.join;if(!this.filename)throw new Error('the "filename" option is required to use includes');var path=name=this.expect("include").val.trim(),dir=dirname(this.filename);if(~basename(path).indexOf(".")){var path=join(dir,path),str=fs.readFileSync(path,"utf8");return new nodes.Literal(str)}var path=join(dir,path+".jade"),str=fs.readFileSync(path,"utf8"),parser=new Parser(str,path),ast=parser.parse();return ast},parseMixin:function(){var tok=this.expect("mixin"),name=tok.val,args=tok.args,block="indent"==this.peek().type?this.parseBlock():null;return new nodes.Mixin(name,args,block)},parseTextBlock:function(){var text=new nodes.Text;text.line=this.line();var spaces=this.expect("indent").val;null==this._spaces&&(this._spaces=spaces);var indent=Array(spaces-this._spaces+1).join(" ");while("outdent"!=this.peek().type)switch(this.peek().type){case"newline":text.push("\\n"),this.advance();break;case"indent":text.push("\\n"),this.parseTextBlock().nodes.forEach(function(node){text.push(node)}),text.push("\\n");break;default:text.push(indent+this.advance().val)}spaces==this._spaces&&(this._spaces=null),this.expect("outdent");return text},parseBlock:function(){var block=new nodes.Block;block.line=this.line(),this.expect("indent");while("outdent"!=this.peek().type)"newline"==this.peek().type?this.advance():block.push(this.parseExpr());this.expect("outdent");return block},parseTag:function(){var i=2;"attrs"==this.lookahead(i).type&&++i;if(":"==this.lookahead(i).type&&"indent"==this.lookahead(++i).type)return this.parseASTFilter();var name=this.advance().val,tag=new nodes.Tag(name),dot;tag.line=this.line();out:for(;;)switch(this.peek().type){case"id":case"class":var tok=this.advance();tag.setAttribute(tok.type,"'"+tok.val+"'");continue;case"attrs":var obj=this.advance().attrs,names=Object.keys(obj);for(var i=0,len=names.length;i<len;++i){var name=names[i],val=obj[name];tag.setAttribute(name,val)}continue;default:break out}"."==this.peek().val&&(dot=tag.textOnly=!0,this.advance());switch(this.peek().type){case"text":tag.text=this.parseText();break;case"code":tag.code=this.parseCode();break;case":":this.advance(),tag.block=new nodes.Block,tag.block.push(this.parseTag())}while("newline"==this.peek().type)this.advance();tag.textOnly=tag.textOnly||~textOnly.indexOf(tag.name);if("script"==tag.name){var type=tag.getAttribute("type");!dot&&type&&"text/javascript"!=type.replace(/^['"]|['"]$/g,"")&&(tag.textOnly=!1)}if("indent"==this.peek().type)if(tag.textOnly)this.lexer.pipeless=!0,tag.block=this.parseTextBlock(),this.lexer.pipeless=!1;else{var block=this.parseBlock();if(tag.block)for(var i=0,len=block.nodes.length;i<len;++i)tag.block.push(block.nodes[i]);else tag.block=block}return tag}}}),require.register("runtime.js",function(module,exports,require){Array.isArray||(Array.isArray=function(arr){return"[object Array]"==toString.call(arr)}),Object.keys||(Object.keys=function(obj){var arr=[];for(var key in obj)obj.hasOwnProperty(key)&&arr.push(obj);return arr}),exports.attrs=function(obj){var buf=[],terse=obj.terse;delete obj.terse;var keys=Object.keys(obj),len=keys.length;if(len){buf.push("");for(var i=0;i<len;++i){var key=keys[i],val=obj[key];"boolean"==typeof val||null==val?val&&(terse?buf.push(key):buf.push(key+'="'+key+'"')):"class"==key&&Array.isArray(val)?buf.push(key+'="'+exports.escape(val.join(" "))+'"'):buf.push(key+'="'+exports.escape(val)+'"')}}return buf.join(" ")},exports.escape=function(html){return String(html).replace(/&(?!\w+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")},exports.rethrow=function(err,str,filename,lineno){var context=3,lines=str.split("\n"),start=Math.max(lineno-context,0),end=Math.min(lines.length,lineno+context),context=lines.slice(start,end).map(function(line,i){var curr=i+start+1;return(curr==lineno?"  > ":"    ")+curr+"| "+line}).join("\n");err.path=filename,err.message=(filename||"Jade")+":"+lineno+"\n"+context+"\n\n"+err.message;throw err}}),require.register("self-closing.js",function(module,exports,require){module.exports=["meta","img","link","input","area","base","col","br","hr"]}),require.register("utils.js",function(module,exports,require){var interpolate=exports.interpolate=function(str){return str.replace(/(\\)?([#!]){(.*?)}/g,function(str,escape,flag,code){return escape?str:"' + "+("!"==flag?"":"escape")+"((interp = "+code.replace(/\\'/g,"'")+") == null ? '' : interp) + '"})},escape=exports.escape=function(str){return str.replace(/'/g,"\\'")};exports.text=function(str){return interpolate(escape(str))}})
\ No newline at end of file
index 15f0dd876341629bb86ab1fa8c2b7cf6d7f42641..342e1f4b590b6e176f5c3d277cc1b9c8ac595550 100644 (file)
@@ -53,6 +53,7 @@ var Compiler = module.exports = function Compiler(node, options) {
   this.hasCompiledDoctype = false;
   this.hasCompiledTag = false;
   this.pp = options.pretty || false;
+  this.debug = false !== options.compileDebug;
   this.indents = 0;
   if (options.doctype) this.setDoctype(options.doctype);
 };
@@ -70,7 +71,8 @@ Compiler.prototype = {
    */
   
   compile: function(){
-    this.buf = [];
+    this.buf = ['var interp;'];
+    this.lastBufferedIdx = -1
     this.visit(this.node);
     return this.buf.join('\n');
   },
@@ -102,7 +104,15 @@ Compiler.prototype = {
   
   buffer: function(str, esc){
     if (esc) str = utils.escape(str);
-    this.buf.push("buf.push('" + str + "');");
+    
+    if (this.lastBufferedIdx == this.buf.length) {
+      this.lastBuffered += str;
+      this.buf[this.lastBufferedIdx - 1] = "buf.push('" + this.lastBuffered + "');"
+    } else {
+      this.buf.push("buf.push('" + str + "');");
+      this.lastBuffered = str;
+      this.lastBufferedIdx = this.buf.length;
+    }    
   },
   
   /**
@@ -113,7 +123,7 @@ Compiler.prototype = {
    */
   
   line: function(node){
-    if (node.instrumentLineNumber === false) return;
+    if (false === node.instrumentLineNumber) return;
     this.buf.push('__.lineno = ' + node.line + ';');
   },
   
@@ -125,7 +135,7 @@ Compiler.prototype = {
    */
   
   visit: function(node){
-    this.line(node);
+    if (this.debug) this.line(node);
     return this.visitNode(node);
   },
   
@@ -141,7 +151,19 @@ Compiler.prototype = {
       || node.constructor.toString().match(/function ([^(\s]+)()/)[1];
     return this['visit' + name](node);
   },
-  
+
+  /**
+   * Visit literal `node`.
+   *
+   * @param {Literal} node
+   * @api public
+   */
+
+  visitLiteral: function(node){
+    var str = node.str.replace(/\n/g, '\\\\n');
+    this.buffer(str);
+  },
+
   /**
    * Visit all nodes in `block`.
    *
@@ -150,7 +172,7 @@ Compiler.prototype = {
    */
 
   visitBlock: function(block){
-    var len = len = block.nodes.length;
+    var len = block.nodes.length;
     for (var i = 0; i < len; ++i) {
       this.visit(block.nodes[i]);
     }
index 25fafef02b0f960b5684e73e31db655f0cce1c06..b21025538e510311d366d59924bda10515f37de2 100644 (file)
@@ -11,6 +11,7 @@
 
 var Parser = require('./parser')
   , Compiler = require('./compiler')
+  , runtime = require('./runtime')
 // if node
   , fs = require('fs');
 // end
@@ -19,7 +20,7 @@ var Parser = require('./parser')
  * Library version.
  */
 
-exports.version = '0.13.0';
+exports.version = '0.15.4';
 
 /**
  * Intermediate JavaScript cache.
@@ -70,88 +71,10 @@ exports.Parser = Parser;
 exports.nodes = require('./nodes');
 
 /**
- * Render the given attributes object.
- *
- * @param {Object} obj
- * @return {String}
- * @api private
- */
-
-function attrs(obj){
-  var buf = []
-    , terse = obj.terse;
-  delete obj.terse;
-  var keys = Object.keys(obj)
-    , len = keys.length;
-  if (len) {
-    buf.push('');
-    for (var i = 0; i < len; ++i) {
-      var key = keys[i]
-        , val = obj[key];
-      if ('boolean' == typeof val || null == val) {
-        if (val) {
-          terse
-            ? buf.push(key)
-            : buf.push(key + '="' + key + '"');
-        }
-      } else if ('class' == key && Array.isArray(val)) {
-        buf.push(key + '="' + escape(val.join(' ')) + '"');
-      } else {
-        buf.push(key + '="' + escape(val) + '"');
-      }
-    }
-  }
-  return buf.join(' ');
-}
-
-/**
- * Escape the given string of `html`.
- *
- * @param {String} html
- * @return {String}
- * @api private
+ * Jade runtime helpers.
  */
 
-function escape(html){
-  return String(html)
-    .replace(/&(?!\w+;)/g, '&amp;')
-    .replace(/</g, '&lt;')
-    .replace(/>/g, '&gt;')
-    .replace(/"/g, '&quot;');
-}
-
-/**
- * Re-throw the given `err` in context to the
- * `str` of jade, `filename`, and `lineno`.
- *
- * @param {Error} err
- * @param {String} str
- * @param {String} filename
- * @param {String} lineno
- * @api private
- */
-
-function rethrow(err, str, filename, lineno){
-  var context = 3
-    , lines = str.split('\n')
-    , start = Math.max(lineno - context, 0)
-    , end = Math.min(lines.length, lineno + context); 
-
-  // 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 || 'Jade') + ':' + lineno 
-    + '\n' + context + '\n\n' + err.message;
-  throw err;
-}
+exports.runtime = runtime;
 
 /**
  * Parse the given `str` of jade and return a function body.
@@ -164,10 +87,10 @@ function rethrow(err, str, filename, lineno){
 
 function parse(str, options){
   var filename = options.filename;
+  
   try {
     // Parse
-    var parser = new Parser(str, filename);
-    if (options.debug) parser.debug();
+    var parser = new Parser(str, filename, options);
 
     // Compile
     var compiler = new (options.compiler || Compiler)(parser.parse(), options)
@@ -180,25 +103,30 @@ function parse(str, options){
 
     try {
       return ''
-        + attrs.toString() + '\n\n'
-        + escape.toString()  + '\n\n'
         + 'var buf = [];\n'
         + (options.self
-          ? 'var self = locals || {}, __ = __ || locals.__;\n' + js
-          : 'with (locals || {}) {' + js + '}')
+          ? 'var self = locals || {};\n' + js
+          : 'with (locals || {}) {\n' + js + '\n}\n')
         + 'return buf.join("");';
+      
     } catch (err) {
       process.compile(js, filename || 'Jade');
       return;
     }
   } catch (err) {
-    rethrow(err, str, filename, parser.lexer.lineno);
+    runtime.rethrow(err, str, filename, parser.lexer.lineno);
   }
 }
 
 /**
  * Compile a `Function` representation of the given jade `str`.
  *
+ * Options:
+ * 
+ *   - `compileDebug` when `false` debugging code is stripped from the compiled template
+ *   - `client` when `true` the helper functions `escape()` etc will reference `jade.escape()`
+ *      for use with the Jade client-side runtime.js
+ *
  * @param {String} str
  * @param {Options} options
  * @return {Function}
@@ -208,111 +136,34 @@ function parse(str, options){
 exports.compile = function(str, options){
   var options = options || {}
     , input = JSON.stringify(str)
+    , client = options.client
     , filename = options.filename
       ? JSON.stringify(options.filename)
-      : 'undefined';
-
-  // Reduce closure madness by injecting some locals
-  var fn = [
-      'var __ = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };'
-    , rethrow.toString()
-    , 'try {'
-    , parse(String(str), options || {})
-    , '} catch (err) {'
-    , '  rethrow(err, __.input, __.filename, __.lineno);'
-    , '}'
-  ].join('\n');
-
-  return new Function('locals', fn);
-};
-
-/**
- * Render the given `str` of jade.
- *
- * Options:
- *
- *   - `scope`     Evaluation scope (`this`)
- *   - `locals`    Local variable object
- *   - `filename`  Used in exceptions, and required by `cache`
- *   - `cache`     Cache intermediate JavaScript in memory keyed by `filename`
- *   - `compiler`  Compiler to replade jade's default
- *   - `doctype`   Specify the default doctype
- *
- * @param {String|Buffer} str
- * @param {Object} options
- * @return {String}
- * @api public
- */
-
-exports.render = function(str, options){
-  var fn
-    , options = options || {}
-    , filename = options.filename;
-
-  // Accept Buffers
-  str = String(str);
-
-  // Cache support
-  if (options.cache) {
-    if (filename) {
-      if (cache[filename]) {
-        fn = cache[filename];
-      } else {
-        fn = cache[filename] = new Function('locals', parse(str, options));
-      }
-    } else {
-      throw new Error('filename is required when using the cache option');
-    }
+      : 'undefined'
+    , fn;
+
+  if (options.compileDebug !== false) {
+    fn = [
+        'var __ = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };'
+      , 'try {'
+      , parse(String(str), options || {})
+      , '} catch (err) {'
+      , '  rethrow(err, __.input, __.filename, __.lineno);'
+      , '}'
+    ].join('\n');
   } else {
-    fn = new Function('locals', parse(str, options));
+    fn = parse(String(str), options || {});
   }
 
-  // Render the template
-  try {
-    var locals = options.locals || {}
-      , meta = { lineno: 1 };
-    locals.__ = meta;
-    return fn.call(options.scope, locals); 
-  } catch (err) {
-    rethrow(err, str, filename, meta.lineno);
+  if (client) {
+    fn = 'var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow;\n' + fn;
   }
-};
 
-/**
- * Render jade template at the given `path`.
- *
- * @param {String} path
- * @param {Object} options
- * @param {Function} fn
- * @api public
- */
+  fn = new Function('locals, attrs, escape, rethrow', fn);
 
-exports.renderFile = function(path, options, fn){
-  var ret;
+  if (client) return fn;
 
-  if (typeof options === 'function') {
-    fn = options;
-    options = {};
-  }
-  options.filename = path;
-
-  // Primed cache
-  if (options.cache && cache[path]) {
-    try {
-      ret = exports.render('', options);
-    } catch (err) {
-      return fn(err);
-    }
-    fn(null, ret);
-  } else {
-    fs.readFile(path, 'utf8', function(err, str){
-      if (err) return fn(err);
-      try {
-        ret = exports.render(str, options);
-      } catch (err) {
-        return fn(err);
-      }
-      fn(null, ret);
-    });
-  }
+  return function(locals){
+    return fn(locals, runtime.attrs, runtime.escape, runtime.rethrow);
+  };
 };
index 641eae5d61a7cc52b0c548b927a7525780acf8c9..fb4d7c3750298e3a3c40eb8168fd6b262e228777 100644 (file)
@@ -8,12 +8,19 @@
 /**
  * Initialize `Lexer` with the given `str`.
  *
+ * Options:
+ *
+ *   - `colons` allow colons for attr delimiters
+ *
  * @param {String} str
+ * @param {Object} options
  * @api private
  */
 
-var Lexer = module.exports = function Lexer(str) {
+var Lexer = module.exports = function Lexer(str, options) {
+  options = options || {};
   this.input = str.replace(/\r\n|\r/g, '\n');
+  this.colons = options.colons;
   this.deferredTokens = [];
   this.lastIndents = 0;
   this.lineno = 1;
@@ -255,13 +262,35 @@ Lexer.prototype = {
     }
   },
 
+  /**
+   * Conditional.
+   */
+  
+  conditional: function() {
+    var captures;
+    if (captures = /^(if|unless|else if|else)\b([^\n]*)/.exec(this.input)) {
+      this.consume(captures[0].length);
+      var type = captures[1]
+        , js = captures[2];
+
+      switch (type) {
+        case 'if': js = 'if (' + js + ')'; break;
+        case 'unless': js = 'if (!(' + js + '))'; break;
+        case 'else if': js = 'else if (' + js + ')'; break;
+        case 'else': js = 'else'; break;
+      }
+
+      return this.tok('code', js);
+    }
+  },
+
   /**
    * Each.
    */
   
   each: function() {
     var captures;
-    if (captures = /^- *each *(\w+)(?: *, *(\w+))? * in *([^\n]+)/.exec(this.input)) {
+    if (captures = /^(?:- *)?(?:each|for) +(\w+)(?: *, *(\w+))? * in *([^\n]+)/.exec(this.input)) {
       this.consume(captures[0].length);
       var tok = this.tok('each', captures[1]);
       tok.key = captures[2] || 'index';
@@ -297,6 +326,7 @@ Lexer.prototype = {
         , str = this.input.substr(1, index-1)
         , tok = this.tok('attrs')
         , len = str.length
+        , colons = this.colons
         , states = ['key']
         , key = ''
         , val = ''
@@ -317,6 +347,9 @@ Lexer.prototype = {
       tok.attrs = {};
 
       function parse(c) {
+        var real = c;
+        // TODO: remove when people fix ":"
+        if (colons && ':' == c) c = '=';
         switch (c) {
           case ',':
           case '\n':
@@ -341,14 +374,14 @@ Lexer.prototype = {
           case '=':
             switch (state()) {
               case 'key char':
-                key += c;
+                key += real;
                 break;
               case 'val':
               case 'expr':
               case 'array':
               case 'string':
               case 'object':
-                val += c;
+                val += real;
                 break;
               default:
                 states.push('val');
@@ -532,9 +565,10 @@ Lexer.prototype = {
       || this.doctype()
       || this.include()
       || this.mixin()
+      || this.conditional()
+      || this.each()
       || this.tag()
       || this.filter()
-      || this.each()
       || this.code()
       || this.id()
       || this.className()
index 4ac5816686a45ddf039dcc5b4615cbb4dc236756..869d01abffa83d58d73091f254cb363b0a94da32 100644 (file)
@@ -14,5 +14,6 @@ exports.Block = require('./block');
 exports.Mixin = require('./mixin');
 exports.Filter = require('./filter');
 exports.Comment = require('./comment');
+exports.Literal = require('./literal');
 exports.BlockComment = require('./block-comment');
 exports.Doctype = require('./doctype');
diff --git a/node/node_modules/jade/lib/nodes/literal.js b/node/node_modules/jade/lib/nodes/literal.js
new file mode 100644 (file)
index 0000000..a8a02a2
--- /dev/null
@@ -0,0 +1,29 @@
+
+/*!
+ * Jade - nodes - Literal
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var Node = require('./node');
+
+/**
+ * Initialize a `Literal` node with the given `str.
+ *
+ * @param {String} str
+ * @api public
+ */
+
+var Literal = module.exports = function Literal(str) {
+  this.str = str;
+};
+
+/**
+ * Inherit from `Node`.
+ */
+
+Literal.prototype.__proto__ = Node.prototype;
index 9edb5e37b2c3a3f3830278f7d3c5d9f21aa1a834..25f1601a37184fbb8ca5ae8b2c6ecf591fa367be 100644 (file)
  */
 
 var Lexer = require('./lexer')
-  , nodes = require('./nodes')
-  , path = require('path')
-  , dirname = path.dirname
-  , join = path.join
-  , fs = require('fs');
+  , nodes = require('./nodes');
 
 /**
  * Initialize `Parser` with the given input `str` and `filename`.
  *
  * @param {String} str
  * @param {String} filename
+ * @param {Object} options
  * @api public
  */
 
-var Parser = exports = module.exports = function Parser(str, filename){
+var Parser = exports = module.exports = function Parser(str, filename, options){
   this.input = str;
-  this.lexer = new Lexer(str);
+  this.lexer = new Lexer(str, options);
   this.filename = filename;
 };
 
@@ -42,20 +39,6 @@ var textOnly = exports.textOnly = ['code', 'script', 'textarea', 'style', 'title
 
 Parser.prototype = {
   
-  /**
-   * Output parse tree to stdout. 
-   *
-   * @api public
-   */
-  
-  debug: function(){
-    var lexer = new Lexer(this.input)
-      , tree = require('sys').inspect(this.parse(), false, 12, true);
-    console.log('\n\x1b[1mParse Tree\x1b[0m:\n');
-    console.log(tree);
-    this.lexer = lexer;
-  },
-  
   /**
    * Return the next token object.
    *
@@ -66,6 +49,17 @@ Parser.prototype = {
   advance: function(){
     return this.lexer.advance();
   },
+
+  /**
+   * Skip `n` tokens.
+   *
+   * @param {Number} n
+   * @api private
+   */
+
+  skip: function(n){
+    while (n--) this.advance();
+  },
   
   /**
    * Single token lookahead.
@@ -211,9 +205,14 @@ Parser.prototype = {
   
   parseCode: function(){
     var tok = this.expect('code')
-      , node = new nodes.Code(tok.val, tok.buffer, tok.escape);
+      , node = new nodes.Code(tok.val, tok.buffer, tok.escape)
+      , block
+      , i = 1;
     node.line = this.line();
-    if ('indent' == this.peek().type) {
+    while (this.lookahead(i) && 'newline' == this.lookahead(i).type) ++i;
+    block = 'indent' == this.lookahead(i).type;
+    if (block) {
+      this.skip(i-1);
       node.block = this.parseBlock();
     }
     return node;
@@ -299,14 +298,27 @@ Parser.prototype = {
    */
 
   parseInclude: function(){
+    var path = require('path')
+      , fs = require('fs')
+      , dirname = path.dirname
+      , basename = path.basename
+      , join = path.join;
+
     if (!this.filename)
       throw new Error('the "filename" option is required to use includes');
 
     var path = name = this.expect('include').val.trim()
-      , dir = dirname(this.filename)
-      , path = join(dir, path + '.jade');
+      , dir = dirname(this.filename);
+
+    // non-jade
+    if (~basename(path).indexOf('.')) {
+      var path = join(dir, path)
+        , str = fs.readFileSync(path, 'utf8');
+      return new nodes.Literal(str);
+    }
 
-    var str = fs.readFileSync(path, 'utf8')
+    var path = join(dir, path + '.jade')
+      , str = fs.readFileSync(path, 'utf8')
       , parser = new Parser(str, path)
       , ast = parser.parse();
 
@@ -394,7 +406,8 @@ Parser.prototype = {
     }
 
     var name = this.advance().val
-      , tag = new nodes.Tag(name);
+      , tag = new nodes.Tag(name)
+      , dot;
 
     tag.line = this.line();
 
@@ -423,7 +436,7 @@ Parser.prototype = {
 
     // check immediate '.'
     if ('.' == this.peek().val) {
-      tag.textOnly = true;
+      dot = tag.textOnly = true;
       this.advance();
     }
 
@@ -450,7 +463,7 @@ Parser.prototype = {
     // script special-case
     if ('script' == tag.name) {
       var type = tag.getAttribute('type');
-      if (type && 'text/javascript' != type.replace(/^['"]|['"]$/g, '')) {
+      if (!dot && type && 'text/javascript' != type.replace(/^['"]|['"]$/g, '')) {
         tag.textOnly = false;
       }
     }
diff --git a/node/node_modules/jade/lib/runtime.js b/node/node_modules/jade/lib/runtime.js
new file mode 100644 (file)
index 0000000..b826252
--- /dev/null
@@ -0,0 +1,116 @@
+
+/*!
+ * Jade - runtime
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Lame Array.isArray() polyfill for now.
+ */
+
+if (!Array.isArray) {
+  Array.isArray = function(arr){
+    return '[object Array]' == toString.call(arr);
+  };
+}
+
+/**
+ * Lame Object.keys() polyfill for now.
+ */
+
+if (!Object.keys) {
+  Object.keys = function(obj){
+    var arr = [];
+    for (var key in obj) {
+      if (obj.hasOwnProperty(key)) {
+        arr.push(obj);
+      }
+    }
+    return arr;
+  } 
+}
+
+/**
+ * Render the given attributes object.
+ *
+ * @param {Object} obj
+ * @return {String}
+ * @api private
+ */
+
+exports.attrs = function attrs(obj){
+  var buf = []
+    , terse = obj.terse;
+  delete obj.terse;
+  var keys = Object.keys(obj)
+    , len = keys.length;
+  if (len) {
+    buf.push('');
+    for (var i = 0; i < len; ++i) {
+      var key = keys[i]
+        , val = obj[key];
+      if ('boolean' == typeof val || null == val) {
+        if (val) {
+          terse
+            ? buf.push(key)
+            : buf.push(key + '="' + key + '"');
+        }
+      } else if ('class' == key && Array.isArray(val)) {
+        buf.push(key + '="' + exports.escape(val.join(' ')) + '"');
+      } else {
+        buf.push(key + '="' + exports.escape(val) + '"');
+      }
+    }
+  }
+  return buf.join(' ');
+};
+
+/**
+ * Escape the given string of `html`.
+ *
+ * @param {String} html
+ * @return {String}
+ * @api private
+ */
+
+exports.escape = function escape(html){
+  return String(html)
+    .replace(/&(?!\w+;)/g, '&amp;')
+    .replace(/</g, '&lt;')
+    .replace(/>/g, '&gt;')
+    .replace(/"/g, '&quot;');
+};
+
+/**
+ * Re-throw the given `err` in context to the
+ * `str` of jade, `filename`, and `lineno`.
+ *
+ * @param {Error} err
+ * @param {String} str
+ * @param {String} filename
+ * @param {String} lineno
+ * @api private
+ */
+
+exports.rethrow = function rethrow(err, str, filename, lineno){
+  var context = 3
+    , lines = str.split('\n')
+    , start = Math.max(lineno - context, 0)
+    , end = Math.min(lines.length, lineno + context); 
+
+  // 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 || 'Jade') + ':' + lineno 
+    + '\n' + context + '\n\n' + err.message;
+  throw err;
+};
index cbfe6611a31d4633f17a314644fbbd05dc903d9f..2dedf7b23698f3ad7ce54287f1b48e3d12baebf7 100644 (file)
@@ -1,18 +1,23 @@
 {
   "name": "jade",
   "description": "Jade template engine",
-  "version": "0.13.0",
+  "version": "0.15.4",
   "author": "TJ Holowaychuk <tj@vision-media.ca>",
   "repository": "git://github.com/visionmedia/jade",
   "main": "./index.js",
   "bin": { "jade": "./bin/jade" },
+  "dependencies": {
+    "commander": "0.1.0",
+    "mkdirp": "0.0.6"
+  },
   "devDependencies": {
     "expresso": "0.6.4",
     "coffee-script": ">= 0.0.1",
     "sass": ">= 0.0.1",
     "less": ">= 0.0.1",
     "markdown": ">= 0.0.1",
-    "stylus": ">= 0.0.1"
+    "stylus": ">= 0.0.1",
+    "uubench": "0.0.1"
   },
   "scripts" : { "prepublish" : "npm prune" },
   "engines": { "node": ">= 0.1.98" }
diff --git a/node/node_modules/jade/runtime.js b/node/node_modules/jade/runtime.js
new file mode 100644 (file)
index 0000000..b7f5fba
--- /dev/null
@@ -0,0 +1,121 @@
+
+var jade = (function(exports){
+/*!
+ * Jade - runtime
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Lame Array.isArray() polyfill for now.
+ */
+
+if (!Array.isArray) {
+  Array.isArray = function(arr){
+    return '[object Array]' == toString.call(arr);
+  };
+}
+
+/**
+ * Lame Object.keys() polyfill for now.
+ */
+
+if (!Object.keys) {
+  Object.keys = function(obj){
+    var arr = [];
+    for (var key in obj) {
+      if (obj.hasOwnProperty(key)) {
+        arr.push(obj);
+      }
+    }
+    return arr;
+  } 
+}
+
+/**
+ * Render the given attributes object.
+ *
+ * @param {Object} obj
+ * @return {String}
+ * @api private
+ */
+
+exports.attrs = function attrs(obj){
+  var buf = []
+    , terse = obj.terse;
+  delete obj.terse;
+  var keys = Object.keys(obj)
+    , len = keys.length;
+  if (len) {
+    buf.push('');
+    for (var i = 0; i < len; ++i) {
+      var key = keys[i]
+        , val = obj[key];
+      if ('boolean' == typeof val || null == val) {
+        if (val) {
+          terse
+            ? buf.push(key)
+            : buf.push(key + '="' + key + '"');
+        }
+      } else if ('class' == key && Array.isArray(val)) {
+        buf.push(key + '="' + exports.escape(val.join(' ')) + '"');
+      } else {
+        buf.push(key + '="' + exports.escape(val) + '"');
+      }
+    }
+  }
+  return buf.join(' ');
+};
+
+/**
+ * Escape the given string of `html`.
+ *
+ * @param {String} html
+ * @return {String}
+ * @api private
+ */
+
+exports.escape = function escape(html){
+  return String(html)
+    .replace(/&(?!\w+;)/g, '&amp;')
+    .replace(/</g, '&lt;')
+    .replace(/>/g, '&gt;')
+    .replace(/"/g, '&quot;');
+};
+
+/**
+ * Re-throw the given `err` in context to the
+ * `str` of jade, `filename`, and `lineno`.
+ *
+ * @param {Error} err
+ * @param {String} str
+ * @param {String} filename
+ * @param {String} lineno
+ * @api private
+ */
+
+exports.rethrow = function rethrow(err, str, filename, lineno){
+  var context = 3
+    , lines = str.split('\n')
+    , start = Math.max(lineno - context, 0)
+    , end = Math.min(lines.length, lineno + context); 
+
+  // 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 || 'Jade') + ':' + lineno 
+    + '\n' + context + '\n\n' + err.message;
+  throw err;
+};
+
+  return exports;
+
+})({});
\ No newline at end of file
diff --git a/node/node_modules/jade/runtime.min.js b/node/node_modules/jade/runtime.min.js
new file mode 100644 (file)
index 0000000..6e1efc9
--- /dev/null
@@ -0,0 +1 @@
+var jade=function(exports){Array.isArray||(Array.isArray=function(arr){return"[object Array]"==toString.call(arr)}),Object.keys||(Object.keys=function(obj){var arr=[];for(var key in obj)obj.hasOwnProperty(key)&&arr.push(obj);return arr}),exports.attrs=function(obj){var buf=[],terse=obj.terse;delete obj.terse;var keys=Object.keys(obj),len=keys.length;if(len){buf.push("");for(var i=0;i<len;++i){var key=keys[i],val=obj[key];"boolean"==typeof val||null==val?val&&(terse?buf.push(key):buf.push(key+'="'+key+'"')):"class"==key&&Array.isArray(val)?buf.push(key+'="'+exports.escape(val.join(" "))+'"'):buf.push(key+'="'+exports.escape(val)+'"')}}return buf.join(" ")},exports.escape=function(html){return String(html).replace(/&(?!\w+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")},exports.rethrow=function(err,str,filename,lineno){var context=3,lines=str.split("\n"),start=Math.max(lineno-context,0),end=Math.min(lines.length,lineno+context),context=lines.slice(start,end).map(function(line,i){var curr=i+start+1;return(curr==lineno?"  > ":"    ")+curr+"| "+line}).join("\n");err.path=filename,err.message=(filename||"Jade")+":"+lineno+"\n"+context+"\n\n"+err.message;throw err};return exports}({})
\ No newline at end of file
diff --git a/node/node_modules/jade/support/benchmark.js b/node/node_modules/jade/support/benchmark.js
new file mode 100644 (file)
index 0000000..85c2f3f
--- /dev/null
@@ -0,0 +1,62 @@
+
+/**
+ * Module dependencies.
+ */
+
+var uubench = require('uubench')
+  , jade = require('../');
+
+
+var suite = new uubench.Suite({
+  min: 200,
+  result: function(name, stats){
+    var persec = 1000 / stats.elapsed
+      , ops = stats.iterations * persec;
+    console.log('%s: %d', name, ops | 0);
+  }
+});
+
+var str = 'html\n  body\n    h1 Title'
+  , fn = jade.compile(str);
+
+suite.bench('tiny', function(next){
+  fn();
+  next();
+});
+
+str = '\
+html\n\
+  body\n\
+    h1 Title\n\
+    ul#menu\n\
+      li: a(href="#") Home\n\
+      li: a(href="#") About Us\n\
+      li: a(href="#") Store\n\
+      li: a(href="#") FAQ\n\
+      li: a(href="#") Contact\n\
+';
+
+var fn2 = jade.compile(str);
+
+suite.bench('small', function(next){
+  fn2();
+  next();
+});
+
+str = '\
+html\n\
+  body\n\
+    h1 #{title}\n\
+    ul#menu\n\
+      - each link in links\r\n\
+        li: a(href="#")= link\r\n\
+';
+
+var fn3 = jade.compile(str);
+
+suite.bench('small locals', function(next){
+  fn3({ title: 'Title', links: ['Home', 'About Us', 'Store', 'FAQ', 'Contact'] });
+  next();
+});
+
+suite.run();
\ No newline at end of file
diff --git a/node/node_modules/jade/support/foot.js b/node/node_modules/jade/support/foot.js
new file mode 100644 (file)
index 0000000..92f4251
--- /dev/null
@@ -0,0 +1,4 @@
+
+  return exports;
+
+})({});
\ No newline at end of file
diff --git a/node/node_modules/jade/support/head.js b/node/node_modules/jade/support/head.js
new file mode 100644 (file)
index 0000000..83775aa
--- /dev/null
@@ -0,0 +1,2 @@
+
+var jade = (function(exports){
\ No newline at end of file
index 8f157f5ae1abad23a90181ea108f80fedf1fe69f..1d8ffac1d904de35db8fc74c332222be4bf6fb26 100644 (file)
@@ -3,10 +3,16 @@
  * Module dependencies.
  */
 
-var jade = require('../'),
-    Compiler = jade.Compiler,
-    render = jade.render,
-    nodes = jade.nodes;
+var jade = require('../')
+  , Compiler = jade.Compiler
+  , nodes = jade.nodes;
+
+// Shortcut
+
+var render = function(str, options){
+  var fn = jade.compile(str, options);
+  return fn(options);
+};
 
 jade.filters.conditionals = function(block, compiler){
     return new Visitor(block).compile();
@@ -19,21 +25,13 @@ function Visitor(node) {
 Visitor.prototype.__proto__ = Compiler.prototype;
 
 Visitor.prototype.visit = function(node){
-    if (node.name != 'else') this.line(node);
+    if (node.name != 'or') this.line(node);
     this.visitNode(node);
 };
 
 Visitor.prototype.visitTag = function(node){
   switch (node.name) {
-    case 'if':
-      // First text -> line
-      var condition = node.text[0]
-        , block = node.block;
-      node = new nodes.Code('if (' + condition + ')');
-      node.block = block;
-      this.visit(node);
-      break;
-    case 'else':
+    case 'or':
       var block = node.block;
       node = new nodes.Code('else');
       node.block = block;
@@ -46,108 +44,108 @@ Visitor.prototype.visitTag = function(node){
 };
 
 module.exports = {
-    'test :cdata filter': function(assert){
-      assert.equal('<![CDATA[\nfoo\n]]>', render(':cdata\n  foo'));
-      assert.equal('<![CDATA[\nfoo\nbar\n]]>', render(':cdata\n  foo\n  bar'));
-      assert.equal('<![CDATA[\nfoo\nbar\n]]><p>something else</p>', render(':cdata\n  foo\n  bar\np something else'));
-    },
-    
-    'test :markdown filter': function(assert){
-        assert.equal(
-            '<h1>foo</h1>\n\n<ul><li>bar</li><li>baz</li></ul>',
-            render(':markdown\n  #foo\n  - bar\n  - baz\n'))
-    },
-    
-    'test :stylus filter': function(assert){
-        assert.equal(
-            '<style>body {\n  color: #c00;\n}\n</style>',
-            render(':stylus\n  body\n    color #c00'));
-    },
-
-    'test :stylus filter with options': function(assert){
-        assert.equal(
-            '<style>body{color:#c00}\n</style>',
-            render(':stylus(compress=true)\n  body\n    color #c00'));
-    },
-
-    'test :less filter': function(assert){
-        assert.equal(
-            '<style>.class {\n  width: 20px;\n}\n</style>',
-            render(':less\n  .class { width: 10px * 2 }\n'));
-    },
-
-    'test :coffeescript filter': function(assert){
-        var coffee, js;
-        coffee = [
-            ':coffeescript',
-            '  square = (x) ->',
-            '    x * x'
-        ].join('\n');
-        js = [
-            '<script type="text/javascript">',
-            '(function() {',
-            '  var square;',
-            '  square = function(x) {',
-            '    return x * x;',
-            '  };',
-            '}).call(this);',
-            '</script>'
-        ].join('\n');
-
-        assert.equal(js, render(coffee));
-
-        coffee = [
-            ':coffeescript',
-            '  $ ->',
-            '    $("#flash").fadeIn ->',
-            '      console.log("first line")',
-            '      console.log("second line")'
-        ].join('\n');
-        js = [
-            '<script type="text/javascript">',
-            '(function() {',
-            '  $(function() {',
-            '    return $("#flash").fadeIn(function() {',
-            '      console.log("first line");',
-            '      return console.log("second line");',
-            '    });',
-            '  });',
-            '}).call(this);',
-            '</script>'
-        ].join('\n');
-
-        assert.equal(js, render(coffee));
-    },
-    
-    'test parse tree': function(assert){
-        var str = [
-            'conditionals:',
-            '  if false',
-            '    | oh noes',
-            '  else',
-            '    if null == false',
-            '      p doh',
-            '    else',
-            '      p amazing!'
-        ].join('\n');
-    
-        var html = [
-            '<p>amazing!</p>'
-        ].join('');
-    
-        assert.equal(html, render(str));
-    },
-    
-    'test filter attrs': function(assert){
-        jade.filters.testing = function(str, attrs){
-          return str + ' ' + attrs.stuff;
-        };
-
-        var str = [
-            ':testing(stuff)',
-            '  foo bar',
-        ].join('\n');
-
-        assert.equal('foo bar true', render(str));
-     
+  'test :cdata filter': function(assert){
+    assert.equal('<![CDATA[\nfoo\n]]>', render(':cdata\n  foo'));
+    assert.equal('<![CDATA[\nfoo\nbar\n]]>', render(':cdata\n  foo\n  bar'));
+    assert.equal('<![CDATA[\nfoo\nbar\n]]><p>something else</p>', render(':cdata\n  foo\n  bar\np something else'));
+  },
+  
+  'test :markdown filter': function(assert){
+      assert.equal(
+          '<h1>foo</h1>\n\n<ul><li>bar</li><li>baz</li></ul>',
+          render(':markdown\n  #foo\n  - bar\n  - baz\n'))
+  },
+  
+  'test :stylus filter': function(assert){
+      assert.equal(
+          '<style>body {\n  color: #c00;\n}\n</style>',
+          render(':stylus\n  body\n    color #c00'));
+  },
+  
+  'test :stylus filter with options': function(assert){
+      assert.equal(
+          '<style>body{color:#c00}\n</style>',
+          render(':stylus(compress=true)\n  body\n    color #c00'));
+  },
+  
+  'test :less filter': function(assert){
+      assert.equal(
+          '<style>.class {\n  width: 20px;\n}\n</style>',
+          render(':less\n  .class { width: 10px * 2 }\n'));
+  },
+  
+  'test :coffeescript filter': function(assert){
+      var coffee, js;
+      coffee = [
+          ':coffeescript',
+          '  square = (x) ->',
+          '    x * x'
+      ].join('\n');
+      js = [
+          '<script type="text/javascript">',
+          '(function() {',
+          '  var square;',
+          '  square = function(x) {',
+          '    return x * x;',
+          '  };',
+          '}).call(this);',
+          '</script>'
+      ].join('\n');
+  
+      assert.equal(js, render(coffee));
+  
+      coffee = [
+          ':coffeescript',
+          '  $ ->',
+          '    $("#flash").fadeIn ->',
+          '      console.log("first line")',
+          '      console.log("second line")'
+      ].join('\n');
+      js = [
+          '<script type="text/javascript">',
+          '(function() {',
+          '  $(function() {',
+          '    return $("#flash").fadeIn(function() {',
+          '      console.log("first line");',
+          '      return console.log("second line");',
+          '    });',
+          '  });',
+          '}).call(this);',
+          '</script>'
+      ].join('\n');
+  
+      assert.equal(js, render(coffee));
+  },
+  
+  'test parse tree': function(assert){
+      var str = [
+          'conditionals:',
+          '  if false',
+          '    | oh noes',
+          '  or',
+          '    if null == false',
+          '      p doh',
+          '    or',
+          '      p amazing!'
+      ].join('\n');
+  
+      var html = [
+          '<p>amazing!</p>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+  },
+  
+  'test filter attrs': function(assert){
+     jade.filters.testing = function(str, attrs){
+       return str + ' ' + attrs.stuff;
+     };
+  
+     var str = [
+         ':testing(stuff)',
+         '  foo bar',
+     ].join('\n');
+  
+     assert.equal('foo bar true', render(str));
+  } 
 };
\ No newline at end of file
index bfb375e597aabe2f023817976eca355ba8446777..89f1ce3306d91bb15828c6c66288b399aa301abc 100644 (file)
  * Module dependencies.
  */
 
-var jade = require('../')
-  , ENOENT;
-
-// COMPAT:
-
-try {
-  ENOENT = require('constants').ENOENT;
-} catch (err) {
-  ENOENT = process.ENOENT;
-}
+var jade = require('../');
 
 // Shortcut
 
-var render = jade.render;
+var render = function(str, options){
+  var fn = jade.compile(str, options);
+  return fn(options);
+};
 
 module.exports = {
-    'test .version': function(assert){
-        assert.ok(/^\d+\.\d+\.\d+$/.test(jade.version), "Invalid version format");
-    },
-    
-    'test exports': function(assert){
-        assert.equal('object', typeof jade.selfClosing, 'exports.selfClosing missing');
-        assert.equal('object', typeof jade.doctypes, 'exports.doctypes missing');
-        assert.equal('object', typeof jade.filters, 'exports.filters missing');
-        assert.equal('object', typeof jade.utils, 'exports.utils missing');
-        assert.equal('function', typeof jade.Compiler, 'exports.Compiler missing');
-    },
-    
-    'test doctypes': function(assert){
-        assert.equal('<?xml version="1.0" encoding="utf-8" ?>', render('!!! xml'));
-        assert.equal('<!DOCTYPE html>', render('doctype html'));
-        assert.equal('<!DOCTYPE html>', render('doctype HTML'));
-        assert.equal('<!DOCTYPE html>', render('!!! 5'));
-        assert.equal('<!DOCTYPE html>', render('!!!', { doctype:'html' }));
-        assert.equal('<!DOCTYPE html>', render('!!! html', { doctype:'xml' }));
-        assert.equal('<html></html>', render('html'));
-        assert.equal('<!DOCTYPE html><html></html>', render('html', { doctype:'html' }));
-    },
-    
-    'test Buffers': function(assert){
-        assert.equal('<p>foo</p>', render(new Buffer('p foo')));
-    },
-    
-    'test line endings': function(assert){
-        var str = [
-            'p',
-            'div',
-            'img'
-        ].join('\r\n');
-
-        var html = [
-            '<p></p>',
-            '<div></div>',
-            '<img/>'
-        ].join('');
-
-        assert.equal(html, render(str));
-        
-        var str = [
-            'p',
-            'div',
-            'img'
-        ].join('\r');
-
-        var html = [
-            '<p></p>',
-            '<div></div>',
-            '<img/>'
-        ].join('');
-
-        assert.equal(html, render(str));
-        
-        var str = [
-            'p',
-            'div',
-            'img'
-        ].join('\r\n');
-
-        var html = [
-            '<p></p>',
-            '<div></div>',
-            '<img>'
-        ].join('');
-
-        assert.equal(html, render(str, { doctype:'html' }));
-    },
-    
-    'test single quotes': function(assert){
-        assert.equal("<p>'foo'</p>", render("p 'foo'"));
-        assert.equal("<p>'foo'\n</p>", render("p\n  | 'foo'"));
-        assert.equal('<a href="/foo"></a>', render("- var path = 'foo';\na(href='/' + path)"));
-    },
-
-    'test block-expansion': function(assert){
-        assert.equal("<li><a>foo</a></li><li><a>bar</a></li><li><a>baz</a></li>", render("li: a foo\nli: a bar\nli: a baz"));
-        assert.equal("<li class=\"first\"><a>foo</a></li><li><a>bar</a></li><li><a>baz</a></li>", render("li.first: a foo\nli: a bar\nli: a baz"));
-    },
-    
-    'test tags': function(assert){
-        var str = [
-            'p',
-            'div',
-            'img'
-        ].join('\n');
-
-        var html = [
-            '<p></p>',
-            '<div></div>',
-            '<img/>'
-        ].join('');
-
-        assert.equal(html, render(str), 'Test basic tags');
-        assert.equal('<fb:foo-bar></fb:foo-bar>', render('fb:foo-bar'), 'Test hyphens');
-        assert.equal('<div class="something"></div>', render('div.something'), 'Test classes');
-        assert.equal('<div id="something"></div>', render('div#something'), 'Test ids');
-        assert.equal('<div class="something"></div>', render('.something'), 'Test stand-alone classes');
-        assert.equal('<div id="something"></div>', render('#something'), 'Test stand-alone ids');
-        assert.equal('<div id="foo" class="bar"></div>', render('#foo.bar'));
-        assert.equal('<div id="foo" class="bar"></div>', render('.bar#foo'));
-        assert.equal('<div id="foo" class="bar"></div>', render('div#foo(class="bar")'));
-        assert.equal('<div id="foo" class="bar"></div>', render('div(class="bar")#foo'));
-        assert.equal('<div id="bar" class="foo"></div>', render('div(id="bar").foo'));
-        assert.equal('<div class="foo bar baz"></div>', render('div.foo.bar.baz'));
-        assert.equal('<div class="foo bar baz"></div>', render('div(class="foo").bar.baz'));
-        assert.equal('<div class="foo bar baz"></div>', render('div.foo(class="bar").baz'));
-        assert.equal('<div class="foo bar baz"></div>', render('div.foo.bar(class="baz")'));
-        assert.equal('<div class="a-b2"></div>', render('div.a-b2'));
-        assert.equal('<div class="a_b2"></div>', render('div.a_b2'));
-        assert.equal('<fb:user></fb:user>', render('fb:user'));
-        assert.equal('<fb:user:role></fb:user:role>', render('fb:user:role'));
-        assert.equal('<colgroup><col class="test"/></colgroup>', render('colgroup\n  col.test'));
-    },
-    
-    'test nested tags': function(assert){
-        var str = [
-            'ul',
-            '  li a',
-            '  li b',
-            '  li',
-            '    ul',
-            '      li c',
-            '      li d',
-            '  li e',
-        ].join('\n');
-
-        var html = [
-            '<ul>',
-            '<li>a</li>',
-            '<li>b</li>',
-            '<li><ul><li>c</li><li>d</li></ul></li>',
-            '<li>e</li>',
-            '</ul>'
-        ].join('');
-
-        assert.equal(html, render(str));
-        
-        var str = [
-            'a(href="#")',
-            '  | foo ',
-            '  | bar ',
-            '  | baz'
-        ].join('\n');
-        
-        assert.equal('<a href="#">foo \nbar \nbaz\n</a>', render(str));
-        
-        var str = [
-            'ul',
-            '  li one',
-            '  ul',
-            '    | two',
-            '    li three'
-        ].join('\n');
-        
-        var html = [
-            '<ul>',
-            '<li>one</li>',
-            '<ul>two\n',
-            '<li>three</li>',
-            '</ul>',
-            '</ul>'
-        ].join('');
-        
-        assert.equal(html, render(str));
-    },
-    
-    'test variable length newlines': function(assert){
-        var str = [
-            'ul',
-            '  li a',
-            '  ',
-            '  li b',
-            ' ',
-            '         ',
-            '  li',
-            '    ul',
-            '      li c',
-            '',
-            '      li d',
-            '  li e',
-        ].join('\n');
-
-        var html = [
-            '<ul>',
-            '<li>a</li>',
-            '<li>b</li>',
-            '<li><ul><li>c</li><li>d</li></ul></li>',
-            '<li>e</li>',
-            '</ul>'
-        ].join('');
-
-        assert.equal(html, render(str));
-    },
-    
-    'test tab conversion': function(assert){
-        var str = [
-            'ul',
-            '\tli a',
-            '\t',
-            '\tli b',
-            '\t\t',
-            '\t\t\t\t\t\t',
-            '\tli',
-            '\t\tul',
-            '\t\t\tli c',
-            '',
-            '\t\t\tli d',
-            '\tli e',
-        ].join('\n');
-
-        var html = [
-            '<ul>',
-            '<li>a</li>',
-            '<li>b</li>',
-            '<li><ul><li>c</li><li>d</li></ul></li>',
-            '<li>e</li>',
-            '</ul>'
-        ].join('');
-
-        assert.equal(html, render(str));
-    },
-    
-    'test newlines': function(assert){
-        var str = [
-            'ul',
-            '  li a',
-            '  ',
-            '    ',
-            '',
-            ' ',
-            '  li b',
-            '  li',
-            '    ',
-            '        ',
-            ' ',
-            '    ul',
-            '      ',
-            '      li c',
-            '      li d',
-            '  li e',
-        ].join('\n');
-
-        var html = [
-            '<ul>',
-            '<li>a</li>',
-            '<li>b</li>',
-            '<li><ul><li>c</li><li>d</li></ul></li>',
-            '<li>e</li>',
-            '</ul>'
-        ].join('');
-
-        assert.equal(html, render(str));
-        
-        var str = [
-            'html',
-            ' ',
-            '  head',
-            '    != "test"',
-            '  ',
-            '  ',
-            '  ',
-            '  body'
-        ].join('\n');
-
-        var html = [
-            '<html>',
-            '<head>',
-            'test',
-            '</head>',
-            '<body></body>',
-            '</html>'
-        ].join('');
-
-        assert.equal(html, render(str));
-        assert.equal('<foo></foo>something<bar></bar>', render('foo\n= "something"\nbar'));
-        assert.equal('<foo></foo>something<bar></bar>else', render('foo\n= "something"\nbar\n= "else"'));
-    },
-    
-    'test cache': function(assert){
-        var err;
-        try {
-            render('foo', { cache: true });
-        } catch (e) {
-            err = e;
-        }
-        assert.equal('filename is required when using the cache option', err.message);
-        
-        assert.equal('<p></p>', render('p', { cache: true, filename: 'foo.jade' }));
-        assert.equal('<p></p>', render('p', { cache: true, filename: 'foo.jade' }));
-        assert.ok(typeof jade.cache['foo.jade'] === 'function', 'Test cache');
-    },
-    
-    'test text': function(assert){
-        assert.equal('foo\nbar\nbaz\n', render('| foo\n| bar\n| baz'));
-        assert.equal('foo \nbar \nbaz\n', render('| foo \n| bar \n| baz'));
-        assert.equal('(hey)\n', render('| (hey)'));
-        assert.equal('some random text\n', render('| some random text'));
-        assert.equal('  foo\n', render('|   foo'));
-        assert.equal('  foo  \n', render('|   foo  '));
-        assert.equal('  foo  \n bar    \n', render('|   foo  \n|  bar    '));
-    },
-    
-    'test pipe-less text': function(assert){
-      assert.equal('<pre><code>foo\n\nbar\n</code></pre>', render('pre\n  code\n    foo\n\n    bar'));
-      assert.equal('<p>foo\n\nbar\n</p>', render('p.\n  foo\n\n  bar'));
-      assert.equal('<p>foo\n\n\n\nbar\n</p>', render('p.\n  foo\n\n\n\n  bar'));
-      assert.equal('<p>foo\n  bar\nfoo\n</p>', render('p.\n  foo\n    bar\n  foo'));
-      assert.equal('<script>s.parentNode.insertBefore(g,s)\n</script>', render('script\n  s.parentNode.insertBefore(g,s)\n'));
-      assert.equal('<script>s.parentNode.insertBefore(g,s)\n</script>', render('script\n  s.parentNode.insertBefore(g,s)'));
-    },
-    
-    'test tag text': function(assert){
-        assert.equal('<p>some random text</p>', render('p some random text'));
-        assert.equal('<p>click\n<a>Google</a>.\n</p>', render('p\n  | click\n  a Google\n  | .'));
-        assert.equal('<p>(parens)</p>', render('p (parens)'));
-        assert.equal('<p foo="bar">(parens)</p>', render('p(foo="bar") (parens)'));
-        assert.equal('<option value="">-- (optional) foo --</option>', render('option(value="") -- (optional) foo --'));
-    },
-    
-    'test tag text block': function(assert){
-        assert.equal('<p>foo \nbar \nbaz\n</p>', render('p\n  | foo \n  | bar \n  | baz'));
-        assert.equal('<label>Password:\n<input/></label>', render('label\n  | Password:\n  input'));
-        assert.equal('<label>Password:<input/></label>', render('label Password:\n  input'));
-    },
-    
-    'test tag text interpolation': function(assert){
-        assert.equal('yo, jade is cool\n', render('| yo, #{name} is cool\n', { locals: { name: 'jade' }}));
-        assert.equal('<p>yo, jade is cool</p>', render('p yo, #{name} is cool', { locals: { name: 'jade' }}));
-        assert.equal('yo, jade is cool\n', render('| yo, #{name || "jade"} is cool', { locals: { name: null }}));
-        assert.equal('yo, \'jade\' is cool\n', render('| yo, #{name || "\'jade\'"} is cool', { locals: { name: null }}));
-        assert.equal('foo &lt;script&gt; bar\n', render('| foo #{code} bar', { locals: { code: '<script>' }}));
-        assert.equal('foo <script> bar\n', render('| foo !{code} bar', { locals: { code: '<script>' }}));
-    },
-
-    'test flexible indentation': function(assert){
-        assert.equal('<html><body><h1>Wahoo</h1><p>test</p></body></html>', render('html\n  body\n   h1 Wahoo\n   p test'));
-    },
-    
-    'test interpolation values': function(assert){
-        assert.equal('<p>Users: 15</p>', render('p Users: #{15}'));
-        assert.equal('<p>Users: </p>', render('p Users: #{null}'));
-        assert.equal('<p>Users: </p>', render('p Users: #{undefined}'));
-        assert.equal('<p>Users: none</p>', render('p Users: #{undefined || "none"}'));
-        assert.equal('<p>Users: 0</p>', render('p Users: #{0}'));
-        assert.equal('<p>Users: false</p>', render('p Users: #{false}'));
-    },
-    
-    'test html 5 mode': function(assert){
-        assert.equal('<!DOCTYPE html><input type="checkbox" checked>', render('!!! 5\ninput(type="checkbox", checked)'));
-        assert.equal('<!DOCTYPE html><input type="checkbox" checked>', render('!!! 5\ninput(type="checkbox", checked=true)'));
-        assert.equal('<!DOCTYPE html><input type="checkbox">', render('!!! 5\ninput(type="checkbox", checked= false)'));
-    },
-    
-    'test multi-line attrs': function(assert){
-        assert.equal('<a foo="bar" bar="baz" checked="checked">foo</a>', render('a(foo="bar"\n  bar="baz"\n  checked) foo'));
-        assert.equal('<a foo="bar" bar="baz" checked="checked">foo</a>', render('a(foo="bar"\nbar="baz"\nchecked) foo'));
-        assert.equal('<a foo="bar" bar="baz" checked="checked">foo</a>', render('a(foo="bar"\n,bar="baz"\n,checked) foo'));
-        assert.equal('<a foo="bar" bar="baz" checked="checked">foo</a>', render('a(foo="bar",\nbar="baz",\nchecked) foo'));
-    },
-    
-    'test attrs': function(assert){
-        assert.equal('<img src="&lt;script&gt;"/>', render('img(src="<script>")'), 'Test attr escaping');
-        
-        assert.equal('<a data-attr="bar"></a>', render('a(data-attr="bar")'));
-        assert.equal('<a data-attr="bar" data-attr-2="baz"></a>', render('a(data-attr="bar", data-attr-2="baz")'));
-        
-        assert.equal('<a title="foo,bar"></a>', render('a(title= "foo,bar")'));
-        assert.equal('<a title="foo,bar" href="#"></a>', render('a(title= "foo,bar", href="#")'));
-        
-        assert.equal('<p class="foo"></p>', render("p(class='foo')"), 'Test single quoted attrs');
-        assert.equal('<input type="checkbox" checked="checked"/>', render('input( type="checkbox", checked )'));
-        assert.equal('<input type="checkbox" checked="checked"/>', render('input( type="checkbox", checked = true )'));
-        assert.equal('<input type="checkbox"/>', render('input(type="checkbox", checked= false)'));
-        assert.equal('<input type="checkbox"/>', render('input(type="checkbox", checked= null)'));
-        assert.equal('<input type="checkbox"/>', render('input(type="checkbox", checked= undefined)'));
-        
-        assert.equal('<img src="/foo.png"/>', render('img(src="/foo.png")'), 'Test attr =');
-        assert.equal('<img src="/foo.png"/>', render('img(src  =  "/foo.png")'), 'Test attr = whitespace');
-        assert.equal('<img src="/foo.png"/>', render('img(src="/foo.png")'), 'Test attr :');
-        assert.equal('<img src="/foo.png"/>', render('img(src  =  "/foo.png")'), 'Test attr : whitespace');
-        
-        assert.equal('<img src="/foo.png" alt="just some foo"/>', render('img(src="/foo.png", alt="just some foo")'));
-        assert.equal('<img src="/foo.png" alt="just some foo"/>', render('img(src = "/foo.png", alt = "just some foo")'));
-        
-        assert.equal('<p class="foo,bar,baz"></p>', render('p(class="foo,bar,baz")'));
-        assert.equal('<a href="http://google.com" title="Some : weird = title"></a>', render('a(href= "http://google.com", title= "Some : weird = title")'));
-        assert.equal('<label for="name"></label>', render('label(for="name")'));
-        assert.equal('<meta name="viewport" content="width=device-width"/>', render("meta(name= 'viewport', content='width=device-width')"), 'Test attrs that contain attr separators');
-        assert.equal('<div style="color= white"></div>', render("div(style='color= white')"));
-        assert.equal('<div style="color: white"></div>', render("div(style='color: white')"));
-        assert.equal('<p class="foo"></p>', render("p('class'='foo')"), 'Test keys with single quotes');
-        assert.equal('<p class="foo"></p>', render("p(\"class\"= 'foo')"), 'Test keys with double quotes');
-
-        assert.equal('<p data-lang="en"></p>', render('p(data-lang = "en")'));
-        assert.equal('<p data-dynamic="true"></p>', render('p("data-dynamic"= "true")'));
-        assert.equal('<p data-dynamic="true" class="name"></p>', render('p("class"= "name", "data-dynamic"= "true")'));
-        assert.equal('<p data-dynamic="true"></p>', render('p(\'data-dynamic\'= "true")'));
-        assert.equal('<p data-dynamic="true" class="name"></p>', render('p(\'class\'= "name", \'data-dynamic\'= "true")'));
-        assert.equal('<p data-dynamic="true" yay="yay" class="name"></p>', render('p(\'class\'= "name", \'data-dynamic\'= "true", yay)'));
-
-        assert.equal('<input checked="checked" type="checkbox"/>', render('input(checked, type="checkbox")'));
-
-        assert.equal('<a data-foo="{ foo: \'bar\', bar= \'baz\' }"></a>', render('a(data-foo  = "{ foo: \'bar\', bar= \'baz\' }")'));
-
-        assert.equal('<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>', render('meta(http-equiv="X-UA-Compatible", content="IE=edge,chrome=1")'));
-
-        assert.equal('<div style="background: url(/images/test.png)">Foo</div>', render("div(style= 'background: url(/images/test.png)') Foo"));
-        assert.equal('<div style="background = url(/images/test.png)">Foo</div>', render("div(style= 'background = url(/images/test.png)') Foo"));
-        assert.equal('<div style="foo">Foo</div>', render("div(style= ['foo', 'bar'][0]) Foo"));
-        assert.equal('<div style="bar">Foo</div>', render("div(style= { foo: 'bar', baz: 'raz' }['foo']) Foo"));
-        assert.equal('<a href="def">Foo</a>', render("a(href='abcdefg'.substr(3,3)) Foo"));
-        assert.equal('<a href="def">Foo</a>', render("a(href={test: 'abcdefg'}.test.substr(3,3)) Foo"));
-        assert.equal('<a href="def">Foo</a>', render("a(href={test: 'abcdefg'}.test.substr(3,[0,3][1])) Foo"));
-        
-        assert.equal('<rss xmlns:atom="atom"></rss>', render("rss(xmlns:atom=\"atom\")"));
-        assert.equal('<rss xmlns:atom="atom"></rss>', render("rss('xmlns:atom'=\"atom\")"));
-        assert.equal('<rss xmlns:atom="atom"></rss>', render("rss(\"xmlns:atom\"='atom')"));
-        assert.equal('<rss xmlns:atom="atom" foo="bar"></rss>', render("rss('xmlns:atom'=\"atom\", 'foo'= 'bar')"));
-        assert.equal('<a data-obj="{ foo: \'bar\' }"></a>', render("a(data-obj= \"{ foo: 'bar' }\")"));
-        
-        assert.equal('<meta content="what\'s up? \'weee\'"/>', render('meta(content="what\'s up? \'weee\'")'));
-    },
-
-    'test class attr array': function(assert){
-        assert.equal('<body class="foo bar baz"></body>', render('body(class=["foo", "bar", "baz"])'));
-    },
-
-    'test attr interpolation': function(assert){
-        // Test single quote interpolation
-        assert.equal('<a href="/user/12">tj</a>'
-          , render("a(href='/user/#{id}') #{name}", { locals: { name: 'tj', id: 12 }}));
-
-        assert.equal('<a href="/user/12-tj">tj</a>'
-          , render("a(href='/user/#{id}-#{name}') #{name}", { locals: { name: 'tj', id: 12 }}));
-
-        assert.equal('<a href="/user/&lt;script&gt;">tj</a>'
-          , render("a(href='/user/#{id}') #{name}", { locals: { name: 'tj', id: '<script>' }}));
-
-        // Test double quote interpolation
-        assert.equal('<a href="/user/13">ds</a>'
-          , render('a(href="/user/#{id}") #{name}', { locals: { name: 'ds', id: 13 }}));
-
-        assert.equal('<a href="/user/13-ds">ds</a>'
-          , render('a(href="/user/#{id}-#{name}") #{name}', { locals: { name: 'ds', id: 13 }}));
-
-        assert.equal('<a href="/user/&lt;script&gt;">ds</a>'
-          , render('a(href="/user/#{id}") #{name}', { locals: { name: 'ds', id: '<script>' }}));
-    },
-    
-    'test attr parens': function(assert){
-        assert.equal('<p foo="bar">baz</p>', render('p(foo=((("bar"))))= ((("baz")))'));
-    },
-    
-    'test code attrs': function(assert){
-        assert.equal('<p></p>', render('p(id= name)', { locals: { name: undefined }}));
-        assert.equal('<p></p>', render('p(id= name)', { locals: { name: null }}));
-        assert.equal('<p></p>', render('p(id= name)', { locals: { name: false }}));
-        assert.equal('<p id=""></p>', render('p(id= name)', { locals: { name: '' }}));
-        assert.equal('<p id="tj"></p>', render('p(id= name)', { locals: { name: 'tj' }}));
-        assert.equal('<p id="default"></p>', render('p(id= name || "default")', { locals: { name: null }}));
-        assert.equal('<p id="something"></p>', render("p(id= 'something')", { locals: { name: null }}));
-        assert.equal('<p id="something"></p>', render("p(id = 'something')", { locals: { name: null }}));
-        assert.equal('<p id="foo"></p>', render("p(id= (true ? 'foo' : 'bar'))"));
-        assert.equal('<option value="">Foo</option>', render("option(value='') Foo"));
-    },
-    
-    'test code attrs class': function(assert){
-        assert.equal('<p class="tj"></p>', render('p(class= name)', { locals: { name: 'tj' }}));
-        assert.equal('<p class="tj"></p>', render('p( class= name )', { locals: { name: 'tj' }}));
-        assert.equal('<p class="default"></p>', render('p(class= name || "default")', { locals: { name: null }}));
-        assert.equal('<p class="foo default"></p>', render('p.foo(class= name || "default")', { locals: { name: null }}));
-        assert.equal('<p class="default foo"></p>', render('p(class= name || "default").foo', { locals: { name: null }}));
-        assert.equal('<p id="default"></p>', render('p(id = name || "default")', { locals: { name: null }}));
-        assert.equal('<p id="user-1"></p>', render('p(id = "user-" + 1)'));
-        assert.equal('<p class="user-1"></p>', render('p(class = "user-" + 1)'));
-    },
-
-    'test code buffering': function(assert){
-        assert.equal('<p></p>', render('p= null'));
-        assert.equal('<p></p>', render('p= undefined'));
-        assert.equal('<p>0</p>', render('p= 0'));
-        assert.equal('<p>false</p>', render('p= false'));
-    },
-    
-    'test comments': function(assert){
-        // Regular
-        var str = [
-            '//foo',
-            'p bar'
-        ].join('\n');
-
-        var html = [
-            '<!--foo-->',
-            '<p>bar</p>'
-        ].join('');
-
-        assert.equal(html, render(str));
-        
-        // Arbitrary indentation
-        
-        var str = [
-            '     //foo',
-            'p bar'
-        ].join('\n');
-
-        var html = [
-            '<!--foo-->',
-            '<p>bar</p>'
-        ].join('');
-
-        assert.equal(html, render(str));
-        
-        // Between tags
-        
-        var str = [
-            'p foo',
-            '// bar ',
-            'p baz'
-        ].join('\n');
-
-        var html = [
-            '<p>foo</p>',
-            '<!-- bar -->',
-            '<p>baz</p>'
-        ].join('');
-
-        assert.equal(html, render(str));
-
-        // Quotes
-
-        var str = "<!-- script(src: '/js/validate.js') -->",
-            js = "// script(src: '/js/validate.js') ";
-        assert.equal(str, render(js));
-    },
-    
-    'test unbuffered comments': function(assert){
-        var str = [
-            '//- foo',
-            'p bar'
-        ].join('\n');
-
-        var html = [
-            '<p>bar</p>'
-        ].join('');
-
-        assert.equal(html, render(str));
-        
-        var str = [
-            'p foo',
-            '//- bar ',
-            'p baz'
-        ].join('\n');
-
-        var html = [
-            '<p>foo</p>',
-            '<p>baz</p>'
-        ].join('');
-
-        assert.equal(html, render(str));
-    },
-    
-    'test literal html': function(assert){
-        assert.equal('<!--[if IE lt 9]>weeee<![endif]-->\n', render('<!--[if IE lt 9]>weeee<![endif]-->'));
-    },
-    
-    'test code': function(assert){
-        assert.equal('test', render('!= "test"'));
-        assert.equal('test', render('= "test"'));
-        assert.equal('test', render('- var foo = "test"\n=foo'));
-        assert.equal('foo\n<em>test</em>bar\n', render('- var foo = "test"\n| foo\nem= foo\n| bar'));
-        assert.equal('test<h2>something</h2>', render('!= "test"\nh2 something'));
-
-        var str = [
-            '- var foo = "<script>";',
-            '= foo',
-            '!= foo'
-        ].join('\n');
-
-        var html = [
-            '&lt;script&gt;',
-            '<script>'
-        ].join('');
-
-        assert.equal(html, render(str));
-        
-        var str = [
-            '- var foo = "<script>";',
-            '- if (foo)',
-            '  p= foo'
-        ].join('\n');
-
-        var html = [
-            '<p>&lt;script&gt;</p>'
-        ].join('');
-
-        assert.equal(html, render(str));
-        
-        var str = [
-            '- var foo = "<script>";',
-            '- if (foo)',
-            '  p!= foo'
-        ].join('\n');
-
-        var html = [
-            '<p><script></p>'
-        ].join('');
-
-        assert.equal(html, render(str));
-        
-        var str = [
-            '- var foo;',
-            '- if (foo)',
-            '  p.hasFoo= foo',
-            '- else',
-            '  p.noFoo no foo'
-        ].join('\n');
-
-        var html = [
-            '<p class="noFoo">no foo</p>'
-        ].join('');
-
-        assert.equal(html, render(str));
-        
-        var str = [
-            '- var foo;',
-            '- if (foo)',
-            '  p.hasFoo= foo',
-            '- else if (true)',
-            '  p kinda foo',
-            '- else',
-            '  p.noFoo no foo'
-        ].join('\n');
-
-        var html = [
-            '<p>kinda foo</p>'
-        ].join('');
-
-        assert.equal(html, render(str));
-
-        var str = [
-            'p foo',
-            '= "bar"',
-        ].join('\n');
-
-        var html = [
-            '<p>foo</p>bar'
-        ].join('');
-
-        assert.equal(html, render(str));
-
-        var str = [
-            'title foo',
-            '- if (true)',
-            '  p something',
-        ].join('\n');
-        
-        var html = [
-            '<title>foo</title><p>something</p>'
-        ].join('');
-        
-        assert.equal(html, render(str));
-
-        var str = [
-            'foo',
-            '  bar= "bar"',
-            '    baz= "baz"',
-        ].join('\n');
-
-        var html = [
-            '<foo>',
-            '<bar>bar',
-            '<baz>baz</baz>',
-            '</bar>',
-            '</foo>'
-        ].join('');
-
-        assert.equal(html, render(str));
-    },
-    
-    'test - each': function(assert){
-        // Array
-        var str = [
-            '- var items = ["one", "two", "three"];',
-            '- each item in items',
-            '  li= item'
-        ].join('\n');
-    
-        var html = [
-            '<li>one</li>',
-            '<li>two</li>',
-            '<li>three</li>'
-        ].join('');
-        
-        assert.equal(html, render(str));
-
-        // Any enumerable (length property)
-        var str = [
-            '- var jQuery = { length: 3, 0: 1, 1: 2, 2: 3 };',
-            '- each item in jQuery',
-            '  li= item'
-        ].join('\n');
-
-        var html = [
-            '<li>1</li>',
-            '<li>2</li>',
-            '<li>3</li>'
-        ].join('');
-
-        assert.equal(html, render(str));
-        
-        // Empty array
-        var str = [
-            '- var items = [];',
-            '- each item in items',
-            '  li= item'
-        ].join('\n');
-    
-        assert.equal('', render(str));
-
-        // Object
-        var str = [
-            '- var obj = { foo: "bar", baz: "raz" };',
-            '- each val in obj',
-            '  li= val'
-        ].join('\n');
-    
-        var html = [
-            '<li>bar</li>',
-            '<li>raz</li>'
-        ].join('');
-        
-        assert.equal(html, render(str));
-        
-        // Complex 
-        var str = [
-            '- var obj = { foo: "bar", baz: "raz" };',
-            '- each key in Object.keys(obj)',
-            '  li= key'
-        ].join('\n');
-    
-        var html = [
-            '<li>foo</li>',
-            '<li>baz</li>'
-        ].join('');
-        
-        assert.equal(html, render(str));
-        
-        // Keys
-        var str = [
-            '- var obj = { foo: "bar", baz: "raz" };',
-            '- each val, key in obj',
-            '  li #{key}: #{val}'
-        ].join('\n');
-    
-        var html = [
-            '<li>foo: bar</li>',
-            '<li>baz: raz</li>'
-        ].join('');
-        
-        assert.equal(html, render(str));
-        
-        // Nested
-        var str = [
-            '- var users = [{ name: "tj" }]',
-            '- each user in users',
-            '  - each val, key in user',
-            '    li #{key} #{val}',
-        ].join('\n');
-    
-        var html = [
-            '<li>name tj</li>'
-        ].join('');
-
-        assert.equal(html, render(str));
-    },
-    
-    'test renderFile() fs exception': function(assert, beforeExit){
-        var called;
-        jade.renderFile('foo', function(err, str){
-            called = true;
-            assert.equal(ENOENT, err.errno);
-            assert.equal(undefined, str);
-        });
-        beforeExit(function(){
-            assert.ok(called);
-        });
-    },
-    
-    'test renderFile() with valid path': function(assert, beforeExit){
-        var called;
-        jade.renderFile(__dirname + '/fixtures/layout.jade', function(err, str){
-            called = true;
-            assert.equal(null, err);
-            assert.equal('<html><body><h1>Jade</h1></body></html>', str);
-        });
-        beforeExit(function(){
-            assert.ok(called);
-        });
-    },
-    
-    'test renderFile() with options': function(assert, beforeExit){
-        var called = 0;
-        jade.renderFile(__dirname + '/fixtures/layout.jade', { cache: true }, function(err, str){
-            ++called;
-            assert.equal(null, err);
-            assert.equal('<html><body><h1>Jade</h1></body></html>', str);
-
-            jade.renderFile(__dirname + '/fixtures/layout.jade', { cache: true }, function(err, str){
-                ++called;
-                assert.equal(null, err);
-                assert.equal('<html><body><h1>Jade</h1></body></html>', str);
-            });
-        });
-        beforeExit(function(){
-            assert.equal(2, called);
-        });
-    },
-    
-    'test renderFile() passing of exceptions': function(assert, beforeExit){
-        var called = 0;
-        jade.renderFile(__dirname + '/fixtures/invalid.jade', { cache: true }, function(err, str){
-            ++called;
-            assert.ok(typeof err.message === 'string', 'Test passing of exceptions to renderFile() callback');
-            assert.equal(undefined, str);
-        });
-        beforeExit(function(){
-            assert.equal(1, called);
-        });
-    },
-    
-    'test .compile()': function(assert){
-        var fn = jade.compile('p foo');
-        assert.equal('<p>foo</p>', fn());
-    },
-    
-    'test .compile() locals': function(assert){
-        var fn = jade.compile('p= foo');
-        assert.equal('<p>bar</p>', fn({ foo: 'bar' }));
-    },
-    
-    'test .compile() scope': function(assert){
-        var fn = jade.compile('p= this.foo');
-        assert.equal('<p>bar</p>', fn.call({ foo: 'bar' }));
-    },
-    
-    'test null attrs on tag': function(assert){
-        var tag = new jade.nodes.Tag('a'),
-            name = 'href',
-            val = '"/"';
-        tag.setAttribute(name, val)
-        assert.equal(tag.getAttribute(name), val)
-        tag.removeAttribute(name)
-        assert.isUndefined(tag.getAttribute(name))
-    }
+  'test .version': function(assert){
+      assert.ok(/^\d+\.\d+\.\d+$/.test(jade.version), "Invalid version format");
+  },
+  
+  'test exports': function(assert){
+      assert.equal('object', typeof jade.selfClosing, 'exports.selfClosing missing');
+      assert.equal('object', typeof jade.doctypes, 'exports.doctypes missing');
+      assert.equal('object', typeof jade.filters, 'exports.filters missing');
+      assert.equal('object', typeof jade.utils, 'exports.utils missing');
+      assert.equal('function', typeof jade.Compiler, 'exports.Compiler missing');
+  },
+  
+  'test doctypes': function(assert){
+      assert.equal('<?xml version="1.0" encoding="utf-8" ?>', render('!!! xml'));
+      assert.equal('<!DOCTYPE html>', render('doctype html'));
+      assert.equal('<!DOCTYPE html>', render('doctype HTML'));
+      assert.equal('<!DOCTYPE html>', render('!!! 5'));
+      assert.equal('<!DOCTYPE html>', render('!!!', { doctype:'html' }));
+      assert.equal('<!DOCTYPE html>', render('!!! html', { doctype:'xml' }));
+      assert.equal('<html></html>', render('html'));
+      assert.equal('<!DOCTYPE html><html></html>', render('html', { doctype:'html' }));
+  },
+  
+  'test Buffers': function(assert){
+      assert.equal('<p>foo</p>', render(new Buffer('p foo')));
+  },
+  
+  'test line endings': function(assert){
+      var str = [
+          'p',
+          'div',
+          'img'
+      ].join('\r\n');
+  
+      var html = [
+          '<p></p>',
+          '<div></div>',
+          '<img/>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+      
+      var str = [
+          'p',
+          'div',
+          'img'
+      ].join('\r');
+          
+      var html = [
+          '<p></p>',
+          '<div></div>',
+          '<img/>'
+      ].join('');
+          
+      assert.equal(html, render(str));
+      
+      var str = [
+          'p',
+          'div',
+          'img'
+      ].join('\r\n');
+          
+      var html = [
+          '<p></p>',
+          '<div></div>',
+          '<img>'
+      ].join('');
+          
+      assert.equal(html, render(str, { doctype:'html' }));
+  },
+  
+  'test single quotes': function(assert){
+      assert.equal("<p>'foo'</p>", render("p 'foo'"));
+      assert.equal("<p>'foo'\n</p>", render("p\n  | 'foo'"));
+      assert.equal('<a href="/foo"></a>', render("- var path = 'foo';\na(href='/' + path)"));
+  },
+  
+  'test block-expansion': function(assert){
+      assert.equal("<li><a>foo</a></li><li><a>bar</a></li><li><a>baz</a></li>", render("li: a foo\nli: a bar\nli: a baz"));
+      assert.equal("<li class=\"first\"><a>foo</a></li><li><a>bar</a></li><li><a>baz</a></li>", render("li.first: a foo\nli: a bar\nli: a baz"));
+  },
+  
+  'test tags': function(assert){
+      var str = [
+          'p',
+          'div',
+          'img'
+      ].join('\n');
+  
+      var html = [
+          '<p></p>',
+          '<div></div>',
+          '<img/>'
+      ].join('');
+  
+      assert.equal(html, render(str), 'Test basic tags');
+      assert.equal('<fb:foo-bar></fb:foo-bar>', render('fb:foo-bar'), 'Test hyphens');
+      assert.equal('<div class="something"></div>', render('div.something'), 'Test classes');
+      assert.equal('<div id="something"></div>', render('div#something'), 'Test ids');
+      assert.equal('<div class="something"></div>', render('.something'), 'Test stand-alone classes');
+      assert.equal('<div id="something"></div>', render('#something'), 'Test stand-alone ids');
+      assert.equal('<div id="foo" class="bar"></div>', render('#foo.bar'));
+      assert.equal('<div id="foo" class="bar"></div>', render('.bar#foo'));
+      assert.equal('<div id="foo" class="bar"></div>', render('div#foo(class="bar")'));
+      assert.equal('<div id="foo" class="bar"></div>', render('div(class="bar")#foo'));
+      assert.equal('<div id="bar" class="foo"></div>', render('div(id="bar").foo'));
+      assert.equal('<div class="foo bar baz"></div>', render('div.foo.bar.baz'));
+      assert.equal('<div class="foo bar baz"></div>', render('div(class="foo").bar.baz'));
+      assert.equal('<div class="foo bar baz"></div>', render('div.foo(class="bar").baz'));
+      assert.equal('<div class="foo bar baz"></div>', render('div.foo.bar(class="baz")'));
+      assert.equal('<div class="a-b2"></div>', render('div.a-b2'));
+      assert.equal('<div class="a_b2"></div>', render('div.a_b2'));
+      assert.equal('<fb:user></fb:user>', render('fb:user'));
+      assert.equal('<fb:user:role></fb:user:role>', render('fb:user:role'));
+      assert.equal('<colgroup><col class="test"/></colgroup>', render('colgroup\n  col.test'));
+  },
+  
+  'test nested tags': function(assert){
+      var str = [
+          'ul',
+          '  li a',
+          '  li b',
+          '  li',
+          '    ul',
+          '      li c',
+          '      li d',
+          '  li e',
+      ].join('\n');
+  
+      var html = [
+          '<ul>',
+          '<li>a</li>',
+          '<li>b</li>',
+          '<li><ul><li>c</li><li>d</li></ul></li>',
+          '<li>e</li>',
+          '</ul>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+      
+      var str = [
+          'a(href="#")',
+          '  | foo ',
+          '  | bar ',
+          '  | baz'
+      ].join('\n');
+      
+      assert.equal('<a href="#">foo \nbar \nbaz\n</a>', render(str));
+      
+      var str = [
+          'ul',
+          '  li one',
+          '  ul',
+          '    | two',
+          '    li three'
+      ].join('\n');
+      
+      var html = [
+          '<ul>',
+          '<li>one</li>',
+          '<ul>two\n',
+          '<li>three</li>',
+          '</ul>',
+          '</ul>'
+      ].join('');
+      
+      assert.equal(html, render(str));
+  },
+  
+  'test variable length newlines': function(assert){
+      var str = [
+          'ul',
+          '  li a',
+          '  ',
+          '  li b',
+          ' ',
+          '         ',
+          '  li',
+          '    ul',
+          '      li c',
+          '',
+          '      li d',
+          '  li e',
+      ].join('\n');
+  
+      var html = [
+          '<ul>',
+          '<li>a</li>',
+          '<li>b</li>',
+          '<li><ul><li>c</li><li>d</li></ul></li>',
+          '<li>e</li>',
+          '</ul>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+  },
+  
+  'test tab conversion': function(assert){
+      var str = [
+          'ul',
+          '\tli a',
+          '\t',
+          '\tli b',
+          '\t\t',
+          '\t\t\t\t\t\t',
+          '\tli',
+          '\t\tul',
+          '\t\t\tli c',
+          '',
+          '\t\t\tli d',
+          '\tli e',
+      ].join('\n');
+  
+      var html = [
+          '<ul>',
+          '<li>a</li>',
+          '<li>b</li>',
+          '<li><ul><li>c</li><li>d</li></ul></li>',
+          '<li>e</li>',
+          '</ul>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+  },
+  
+  'test newlines': function(assert){
+      var str = [
+          'ul',
+          '  li a',
+          '  ',
+          '    ',
+          '',
+          ' ',
+          '  li b',
+          '  li',
+          '    ',
+          '        ',
+          ' ',
+          '    ul',
+          '      ',
+          '      li c',
+          '      li d',
+          '  li e',
+      ].join('\n');
+  
+      var html = [
+          '<ul>',
+          '<li>a</li>',
+          '<li>b</li>',
+          '<li><ul><li>c</li><li>d</li></ul></li>',
+          '<li>e</li>',
+          '</ul>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+      
+      var str = [
+          'html',
+          ' ',
+          '  head',
+          '    != "test"',
+          '  ',
+          '  ',
+          '  ',
+          '  body'
+      ].join('\n');
+  
+      var html = [
+          '<html>',
+          '<head>',
+          'test',
+          '</head>',
+          '<body></body>',
+          '</html>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+      assert.equal('<foo></foo>something<bar></bar>', render('foo\n= "something"\nbar'));
+      assert.equal('<foo></foo>something<bar></bar>else', render('foo\n= "something"\nbar\n= "else"'));
+  },
+  
+  'test text': function(assert){
+      assert.equal('foo\nbar\nbaz\n', render('| foo\n| bar\n| baz'));
+      assert.equal('foo \nbar \nbaz\n', render('| foo \n| bar \n| baz'));
+      assert.equal('(hey)\n', render('| (hey)'));
+      assert.equal('some random text\n', render('| some random text'));
+      assert.equal('  foo\n', render('|   foo'));
+      assert.equal('  foo  \n', render('|   foo  '));
+      assert.equal('  foo  \n bar    \n', render('|   foo  \n|  bar    '));
+  },
+  
+  'test pipe-less text': function(assert){
+    assert.equal('<pre><code>foo\n\nbar\n</code></pre>', render('pre\n  code\n    foo\n\n    bar'));
+    assert.equal('<p>foo\n\nbar\n</p>', render('p.\n  foo\n\n  bar'));
+    assert.equal('<p>foo\n\n\n\nbar\n</p>', render('p.\n  foo\n\n\n\n  bar'));
+    assert.equal('<p>foo\n  bar\nfoo\n</p>', render('p.\n  foo\n    bar\n  foo'));
+    assert.equal('<script>s.parentNode.insertBefore(g,s)\n</script>', render('script\n  s.parentNode.insertBefore(g,s)\n'));
+    assert.equal('<script>s.parentNode.insertBefore(g,s)\n</script>', render('script\n  s.parentNode.insertBefore(g,s)'));
+  },
+  
+  'test tag text': function(assert){
+      assert.equal('<p>some random text</p>', render('p some random text'));
+      assert.equal('<p>click\n<a>Google</a>.\n</p>', render('p\n  | click\n  a Google\n  | .'));
+      assert.equal('<p>(parens)</p>', render('p (parens)'));
+      assert.equal('<p foo="bar">(parens)</p>', render('p(foo="bar") (parens)'));
+      assert.equal('<option value="">-- (optional) foo --</option>', render('option(value="") -- (optional) foo --'));
+  },
+  
+  'test tag text block': function(assert){
+      assert.equal('<p>foo \nbar \nbaz\n</p>', render('p\n  | foo \n  | bar \n  | baz'));
+      assert.equal('<label>Password:\n<input/></label>', render('label\n  | Password:\n  input'));
+      assert.equal('<label>Password:<input/></label>', render('label Password:\n  input'));
+  },
+  
+  'test tag text interpolation': function(assert){
+      assert.equal('yo, jade is cool\n', render('| yo, #{name} is cool\n', { name: 'jade' }));
+      assert.equal('<p>yo, jade is cool</p>', render('p yo, #{name} is cool', { name: 'jade' }));
+      assert.equal('yo, jade is cool\n', render('| yo, #{name || "jade"} is cool', { name: null }));
+      assert.equal('yo, \'jade\' is cool\n', render('| yo, #{name || "\'jade\'"} is cool', { name: null }));
+      assert.equal('foo &lt;script&gt; bar\n', render('| foo #{code} bar', { code: '<script>' }));
+      assert.equal('foo <script> bar\n', render('| foo !{code} bar', { code: '<script>' }));
+  },
+  
+  'test flexible indentation': function(assert){
+      assert.equal('<html><body><h1>Wahoo</h1><p>test</p></body></html>', render('html\n  body\n   h1 Wahoo\n   p test'));
+  },
+  
+  'test interpolation values': function(assert){
+      assert.equal('<p>Users: 15</p>', render('p Users: #{15}'));
+      assert.equal('<p>Users: </p>', render('p Users: #{null}'));
+      assert.equal('<p>Users: </p>', render('p Users: #{undefined}'));
+      assert.equal('<p>Users: none</p>', render('p Users: #{undefined || "none"}'));
+      assert.equal('<p>Users: 0</p>', render('p Users: #{0}'));
+      assert.equal('<p>Users: false</p>', render('p Users: #{false}'));
+  },
+  
+  'test html 5 mode': function(assert){
+      assert.equal('<!DOCTYPE html><input type="checkbox" checked>', render('!!! 5\ninput(type="checkbox", checked)'));
+      assert.equal('<!DOCTYPE html><input type="checkbox" checked>', render('!!! 5\ninput(type="checkbox", checked=true)'));
+      assert.equal('<!DOCTYPE html><input type="checkbox">', render('!!! 5\ninput(type="checkbox", checked= false)'));
+  },
+  
+  'test multi-line attrs': function(assert){
+      assert.equal('<a foo="bar" bar="baz" checked="checked">foo</a>', render('a(foo="bar"\n  bar="baz"\n  checked) foo'));
+      assert.equal('<a foo="bar" bar="baz" checked="checked">foo</a>', render('a(foo="bar"\nbar="baz"\nchecked) foo'));
+      assert.equal('<a foo="bar" bar="baz" checked="checked">foo</a>', render('a(foo="bar"\n,bar="baz"\n,checked) foo'));
+      assert.equal('<a foo="bar" bar="baz" checked="checked">foo</a>', render('a(foo="bar",\nbar="baz",\nchecked) foo'));
+  },
+  
+  'test attrs': function(assert){
+      assert.equal('<img src="&lt;script&gt;"/>', render('img(src="<script>")'), 'Test attr escaping');
+      
+      assert.equal('<a data-attr="bar"></a>', render('a(data-attr="bar")'));
+      assert.equal('<a data-attr="bar" data-attr-2="baz"></a>', render('a(data-attr="bar", data-attr-2="baz")'));
+      
+      assert.equal('<a title="foo,bar"></a>', render('a(title= "foo,bar")'));
+      assert.equal('<a title="foo,bar" href="#"></a>', render('a(title= "foo,bar", href="#")'));
+      
+      assert.equal('<p class="foo"></p>', render("p(class='foo')"), 'Test single quoted attrs');
+      assert.equal('<input type="checkbox" checked="checked"/>', render('input( type="checkbox", checked )'));
+      assert.equal('<input type="checkbox" checked="checked"/>', render('input( type="checkbox", checked = true )'));
+      assert.equal('<input type="checkbox"/>', render('input(type="checkbox", checked= false)'));
+      assert.equal('<input type="checkbox"/>', render('input(type="checkbox", checked= null)'));
+      assert.equal('<input type="checkbox"/>', render('input(type="checkbox", checked= undefined)'));
+      
+      assert.equal('<img src="/foo.png"/>', render('img(src="/foo.png")'), 'Test attr =');
+      assert.equal('<img src="/foo.png"/>', render('img(src  =  "/foo.png")'), 'Test attr = whitespace');
+      assert.equal('<img src="/foo.png"/>', render('img(src="/foo.png")'), 'Test attr :');
+      assert.equal('<img src="/foo.png"/>', render('img(src  =  "/foo.png")'), 'Test attr : whitespace');
+      
+      assert.equal('<img src="/foo.png" alt="just some foo"/>', render('img(src="/foo.png", alt="just some foo")'));
+      assert.equal('<img src="/foo.png" alt="just some foo"/>', render('img(src = "/foo.png", alt = "just some foo")'));
+      
+      assert.equal('<p class="foo,bar,baz"></p>', render('p(class="foo,bar,baz")'));
+      assert.equal('<a href="http://google.com" title="Some : weird = title"></a>', render('a(href= "http://google.com", title= "Some : weird = title")'));
+      assert.equal('<label for="name"></label>', render('label(for="name")'));
+      assert.equal('<meta name="viewport" content="width=device-width"/>', render("meta(name= 'viewport', content='width=device-width')"), 'Test attrs that contain attr separators');
+      assert.equal('<div style="color= white"></div>', render("div(style='color= white')"));
+      assert.equal('<div style="color: white"></div>', render("div(style='color: white')"));
+      assert.equal('<p class="foo"></p>', render("p('class'='foo')"), 'Test keys with single quotes');
+      assert.equal('<p class="foo"></p>', render("p(\"class\"= 'foo')"), 'Test keys with double quotes');
+  
+      assert.equal('<p data-lang="en"></p>', render('p(data-lang = "en")'));
+      assert.equal('<p data-dynamic="true"></p>', render('p("data-dynamic"= "true")'));
+      assert.equal('<p data-dynamic="true" class="name"></p>', render('p("class"= "name", "data-dynamic"= "true")'));
+      assert.equal('<p data-dynamic="true"></p>', render('p(\'data-dynamic\'= "true")'));
+      assert.equal('<p data-dynamic="true" class="name"></p>', render('p(\'class\'= "name", \'data-dynamic\'= "true")'));
+      assert.equal('<p data-dynamic="true" yay="yay" class="name"></p>', render('p(\'class\'= "name", \'data-dynamic\'= "true", yay)'));
+  
+      assert.equal('<input checked="checked" type="checkbox"/>', render('input(checked, type="checkbox")'));
+  
+      assert.equal('<a data-foo="{ foo: \'bar\', bar= \'baz\' }"></a>', render('a(data-foo  = "{ foo: \'bar\', bar= \'baz\' }")'));
+  
+      assert.equal('<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>', render('meta(http-equiv="X-UA-Compatible", content="IE=edge,chrome=1")'));
+  
+      assert.equal('<div style="background: url(/images/test.png)">Foo</div>', render("div(style= 'background: url(/images/test.png)') Foo"));
+      assert.equal('<div style="background = url(/images/test.png)">Foo</div>', render("div(style= 'background = url(/images/test.png)') Foo"));
+      assert.equal('<div style="foo">Foo</div>', render("div(style= ['foo', 'bar'][0]) Foo"));
+      assert.equal('<div style="bar">Foo</div>', render("div(style= { foo: 'bar', baz: 'raz' }['foo']) Foo"));
+      assert.equal('<a href="def">Foo</a>', render("a(href='abcdefg'.substr(3,3)) Foo"));
+      assert.equal('<a href="def">Foo</a>', render("a(href={test: 'abcdefg'}.test.substr(3,3)) Foo"));
+      assert.equal('<a href="def">Foo</a>', render("a(href={test: 'abcdefg'}.test.substr(3,[0,3][1])) Foo"));
+      
+      assert.equal('<rss xmlns:atom="atom"></rss>', render("rss(xmlns:atom=\"atom\")"));
+      assert.equal('<rss xmlns:atom="atom"></rss>', render("rss('xmlns:atom'=\"atom\")"));
+      assert.equal('<rss xmlns:atom="atom"></rss>', render("rss(\"xmlns:atom\"='atom')"));
+      assert.equal('<rss xmlns:atom="atom" foo="bar"></rss>', render("rss('xmlns:atom'=\"atom\", 'foo'= 'bar')"));
+      assert.equal('<a data-obj="{ foo: \'bar\' }"></a>', render("a(data-obj= \"{ foo: 'bar' }\")"));
+      
+      assert.equal('<meta content="what\'s up? \'weee\'"/>', render('meta(content="what\'s up? \'weee\'")'));
+  },
+  
+  'test colons option': function(assert){
+      assert.equal('<a href="/bar"></a>', render('a(href:"/bar")', { colons: true }));
+  },
+  
+  'test class attr array': function(assert){
+      assert.equal('<body class="foo bar baz"></body>', render('body(class=["foo", "bar", "baz"])'));
+  },
+  
+  'test attr interpolation': function(assert){
+      // Test single quote interpolation
+      assert.equal('<a href="/user/12">tj</a>'
+        , render("a(href='/user/#{id}') #{name}", { name: 'tj', id: 12 }));
+  
+      assert.equal('<a href="/user/12-tj">tj</a>'
+        , render("a(href='/user/#{id}-#{name}') #{name}", { name: 'tj', id: 12 }));
+  
+      assert.equal('<a href="/user/&lt;script&gt;">tj</a>'
+        , render("a(href='/user/#{id}') #{name}", { name: 'tj', id: '<script>' }));
+  
+      // Test double quote interpolation
+      assert.equal('<a href="/user/13">ds</a>'
+        , render('a(href="/user/#{id}") #{name}', { name: 'ds', id: 13 }));
+  
+      assert.equal('<a href="/user/13-ds">ds</a>'
+        , render('a(href="/user/#{id}-#{name}") #{name}', { name: 'ds', id: 13 }));
+  
+      assert.equal('<a href="/user/&lt;script&gt;">ds</a>'
+        , render('a(href="/user/#{id}") #{name}', { name: 'ds', id: '<script>' }));
+  },
+  
+  'test attr parens': function(assert){
+      assert.equal('<p foo="bar">baz</p>', render('p(foo=((("bar"))))= ((("baz")))'));
+  },
+  
+  'test code attrs': function(assert){
+      assert.equal('<p></p>', render('p(id= name)', { name: undefined }));
+      assert.equal('<p></p>', render('p(id= name)', { name: null }));
+      assert.equal('<p></p>', render('p(id= name)', { name: false }));
+      assert.equal('<p id=""></p>', render('p(id= name)', { name: '' }));
+      assert.equal('<p id="tj"></p>', render('p(id= name)', { name: 'tj' }));
+      assert.equal('<p id="default"></p>', render('p(id= name || "default")', { name: null }));
+      assert.equal('<p id="something"></p>', render("p(id= 'something')", { name: null }));
+      assert.equal('<p id="something"></p>', render("p(id = 'something')", { name: null }));
+      assert.equal('<p id="foo"></p>', render("p(id= (true ? 'foo' : 'bar'))"));
+      assert.equal('<option value="">Foo</option>', render("option(value='') Foo"));
+  },
+  
+  'test code attrs class': function(assert){
+      assert.equal('<p class="tj"></p>', render('p(class= name)', { name: 'tj' }));
+      assert.equal('<p class="tj"></p>', render('p( class= name )', { name: 'tj' }));
+      assert.equal('<p class="default"></p>', render('p(class= name || "default")', { name: null }));
+      assert.equal('<p class="foo default"></p>', render('p.foo(class= name || "default")', { name: null }));
+      assert.equal('<p class="default foo"></p>', render('p(class= name || "default").foo', { name: null }));
+      assert.equal('<p id="default"></p>', render('p(id = name || "default")', { name: null }));
+      assert.equal('<p id="user-1"></p>', render('p(id = "user-" + 1)'));
+      assert.equal('<p class="user-1"></p>', render('p(class = "user-" + 1)'));
+  },
+  
+  'test code buffering': function(assert){
+      assert.equal('<p></p>', render('p= null'));
+      assert.equal('<p></p>', render('p= undefined'));
+      assert.equal('<p>0</p>', render('p= 0'));
+      assert.equal('<p>false</p>', render('p= false'));
+  },
+
+  'test script text': function(assert){
+    var str = [
+      'script',
+      '  p foo',
+      '',
+      'script(type="text/template")',
+      '  p foo',
+      '',
+      'script(type="text/template").',
+      '  p foo'
+    ].join('\n');
+
+    var html = [
+      '<script>p foo\n\n</script>',
+      '<script type="text/template"><p>foo</p></script>',
+      '<script type="text/template">p foo\n</script>'
+    ].join('');
+
+    assert.equal(html, render(str));
+  },
+
+  'test comments': function(assert){
+      // Regular
+      var str = [
+          '//foo',
+          'p bar'
+      ].join('\n');
+  
+      var html = [
+          '<!--foo-->',
+          '<p>bar</p>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+      
+      // Arbitrary indentation
+      
+      var str = [
+          '     //foo',
+          'p bar'
+      ].join('\n');
+  
+      var html = [
+          '<!--foo-->',
+          '<p>bar</p>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+      
+      // Between tags
+      
+      var str = [
+          'p foo',
+          '// bar ',
+          'p baz'
+      ].join('\n');
+  
+      var html = [
+          '<p>foo</p>',
+          '<!-- bar -->',
+          '<p>baz</p>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+  
+      // Quotes
+  
+      var str = "<!-- script(src: '/js/validate.js') -->",
+          js = "// script(src: '/js/validate.js') ";
+      assert.equal(str, render(js));
+  },
+  
+  'test unbuffered comments': function(assert){
+      var str = [
+          '//- foo',
+          'p bar'
+      ].join('\n');
+  
+      var html = [
+          '<p>bar</p>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+      
+      var str = [
+          'p foo',
+          '//- bar ',
+          'p baz'
+      ].join('\n');
+  
+      var html = [
+          '<p>foo</p>',
+          '<p>baz</p>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+  },
+  
+  'test literal html': function(assert){
+      assert.equal('<!--[if IE lt 9]>weeee<![endif]-->\n', render('<!--[if IE lt 9]>weeee<![endif]-->'));
+  },
+  
+  'test code': function(assert){
+      assert.equal('test', render('!= "test"'));
+      assert.equal('test', render('= "test"'));
+      assert.equal('test', render('- var foo = "test"\n=foo'));
+      assert.equal('foo\n<em>test</em>bar\n', render('- var foo = "test"\n| foo\nem= foo\n| bar'));
+      assert.equal('test<h2>something</h2>', render('!= "test"\nh2 something'));
+  
+      var str = [
+          '- var foo = "<script>";',
+          '= foo',
+          '!= foo'
+      ].join('\n');
+  
+      var html = [
+          '&lt;script&gt;',
+          '<script>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+      
+      var str = [
+          '- var foo = "<script>";',
+          '- if (foo)',
+          '  p= foo'
+      ].join('\n');
+  
+      var html = [
+          '<p>&lt;script&gt;</p>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+      
+      var str = [
+          '- var foo = "<script>";',
+          '- if (foo)',
+          '  p!= foo'
+      ].join('\n');
+  
+      var html = [
+          '<p><script></p>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+      
+      var str = [
+          '- var foo;',
+          '- if (foo)',
+          '  p.hasFoo= foo',
+          '- else',
+          '  p.noFoo no foo'
+      ].join('\n');
+  
+      var html = [
+          '<p class="noFoo">no foo</p>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+      
+      var str = [
+          '- var foo;',
+          '- if (foo)',
+          '  p.hasFoo= foo',
+          '- else if (true)',
+          '  p kinda foo',
+          '- else',
+          '  p.noFoo no foo'
+      ].join('\n');
+  
+      var html = [
+          '<p>kinda foo</p>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+  
+      var str = [
+          'p foo',
+          '= "bar"',
+      ].join('\n');
+  
+      var html = [
+          '<p>foo</p>bar'
+      ].join('');
+  
+      assert.equal(html, render(str));
+  
+      var str = [
+          'title foo',
+          '- if (true)',
+          '  p something',
+      ].join('\n');
+      
+      var html = [
+          '<title>foo</title><p>something</p>'
+      ].join('');
+      
+      assert.equal(html, render(str));
+  
+      var str = [
+          'foo',
+          '  bar= "bar"',
+          '    baz= "baz"',
+      ].join('\n');
+  
+      var html = [
+          '<foo>',
+          '<bar>bar',
+          '<baz>baz</baz>',
+          '</bar>',
+          '</foo>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+  },
+  
+  'test - each': function(assert){
+      // Array
+      var str = [
+          '- var items = ["one", "two", "three"];',
+          '- each item in items',
+          '  li= item'
+      ].join('\n');
+  
+      var html = [
+          '<li>one</li>',
+          '<li>two</li>',
+          '<li>three</li>'
+      ].join('');
+      
+      assert.equal(html, render(str));
+  
+      // Any enumerable (length property)
+      var str = [
+          '- var jQuery = { length: 3, 0: 1, 1: 2, 2: 3 };',
+          '- each item in jQuery',
+          '  li= item'
+      ].join('\n');
+  
+      var html = [
+          '<li>1</li>',
+          '<li>2</li>',
+          '<li>3</li>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+      
+      // Empty array
+      var str = [
+          '- var items = [];',
+          '- each item in items',
+          '  li= item'
+      ].join('\n');
+  
+      assert.equal('', render(str));
+  
+      // Object
+      var str = [
+          '- var obj = { foo: "bar", baz: "raz" };',
+          '- each val in obj',
+          '  li= val'
+      ].join('\n');
+  
+      var html = [
+          '<li>bar</li>',
+          '<li>raz</li>'
+      ].join('');
+      
+      assert.equal(html, render(str));
+      
+      // Complex 
+      var str = [
+          '- var obj = { foo: "bar", baz: "raz" };',
+          '- each key in Object.keys(obj)',
+          '  li= key'
+      ].join('\n');
+  
+      var html = [
+          '<li>foo</li>',
+          '<li>baz</li>'
+      ].join('');
+      
+      assert.equal(html, render(str));
+      
+      // Keys
+      var str = [
+          '- var obj = { foo: "bar", baz: "raz" };',
+          '- each val, key in obj',
+          '  li #{key}: #{val}'
+      ].join('\n');
+  
+      var html = [
+          '<li>foo: bar</li>',
+          '<li>baz: raz</li>'
+      ].join('');
+      
+      assert.equal(html, render(str));
+      
+      // Nested
+      var str = [
+          '- var users = [{ name: "tj" }]',
+          '- each user in users',
+          '  - each val, key in user',
+          '    li #{key} #{val}',
+      ].join('\n');
+  
+      var html = [
+          '<li>name tj</li>'
+      ].join('');
+  
+      assert.equal(html, render(str));
+  
+      var str = [
+          '- var users = ["tobi", "loki", "jane"]',
+          'each user in users',
+          '  li= user',
+      ].join('\n');
+  
+      var html = [
+          '<li>tobi</li>',
+          '<li>loki</li>',
+          '<li>jane</li>',
+      ].join('');
+  
+      assert.equal(html, render(str));
+  
+      var str = [
+          '- var users = ["tobi", "loki", "jane"]',
+          'for user in users',
+          '  li= user',
+      ].join('\n');
+  
+      var html = [
+          '<li>tobi</li>',
+          '<li>loki</li>',
+          '<li>jane</li>',
+      ].join('');
+  
+      assert.equal(html, render(str));
+  },
+  
+  'test if': function(assert){
+    var str = [
+        '- var users = ["tobi", "loki", "jane"]',
+        'if users.length',
+        '  p users: #{users.length}',
+    ].join('\n');
+    
+    assert.equal('<p>users: 3</p>', render(str));
+
+    assert.equal('<iframe foo="bar"></iframe>', render('iframe(foo="bar")'));
+  },
+  
+  'test unless': function(assert){
+    var str = [
+        '- var users = ["tobi", "loki", "jane"]',
+        'unless users.length',
+        '  p no users',
+    ].join('\n');
+    
+    assert.equal('', render(str));
+  
+    var str = [
+        '- var users = []',
+        'unless users.length',
+        '  p no users',
+    ].join('\n');
+    
+    assert.equal('<p>no users</p>', render(str));
+  },
+  
+  'test else': function(assert){
+    var str = [
+        '- var users = []',
+        'if users.length',
+        '  p users: #{users.length}',
+        'else',
+        '  p users: none',
+    ].join('\n');
+    
+    assert.equal('<p>users: none</p>', render(str));
+  },
+  
+  'test else if': function(assert){
+    var str = [
+        '- var users = ["tobi", "jane", "loki"]',
+        'for user in users',
+        '  if user == "tobi"',
+        '    p awesome #{user}',
+        '  else if user == "jane"',
+        '    p lame #{user}',
+        '  else',
+        '    p #{user}',
+    ].join('\n');
+    
+    assert.equal('<p>awesome tobi</p><p>lame jane</p><p>loki</p>', render(str));
+  },
+  
+  'test .compile()': function(assert){
+      var fn = jade.compile('p foo');
+      assert.equal('<p>foo</p>', fn());
+  },
+  
+  'test .compile() locals': function(assert){
+      var fn = jade.compile('p= foo');
+      assert.equal('<p>bar</p>', fn({ foo: 'bar' }));
+  },
+  
+  'test .compile() no debug': function(assert){
+      var fn = jade.compile('p foo\np #{bar}', {compileDebug: false});
+      assert.equal('<p>foo</p><p>baz</p>', fn({bar: 'baz'}));
+  },
+  
+  'test .compile() no debug and global helpers': function(assert){
+      var fn = jade.compile('p foo\np #{bar}', {compileDebug: false, helpers: 'global'});
+      assert.equal('<p>foo</p><p>baz</p>', fn({bar: 'baz'}));
+  },
+  
+  'test null attrs on tag': function(assert){
+      var tag = new jade.nodes.Tag('a'),
+          name = 'href',
+          val = '"/"';
+      tag.setAttribute(name, val)
+      assert.equal(tag.getAttribute(name), val)
+      tag.removeAttribute(name)
+      assert.isUndefined(tag.getAttribute(name))
+  }
 };
index ef8ad5a3dc59128498b6117a055f4cc430331f6f..93992576f0049d0b15afcfb1012b61a7906b3732 100644 (file)
@@ -6,7 +6,7 @@ var fs = require('fs'),
     url = require('url'),
     path = require('path');
 
-this.version = [0, 5, 6];
+this.version = [0, 5, 9];
 
 var mime = require('./node-static/mime');
 var util = require('./node-static/util');
@@ -20,7 +20,7 @@ this.indexStore = {};
 this.Server = function (root, options) {
     if (root && (typeof(root) === 'object')) { options = root, root = null }
 
-    this.root    = path.normalize(root || '.');
+    this.root    = path.resolve(root || '.');
     this.options = options || {};
     this.cache   = 3600;
 
@@ -77,7 +77,7 @@ this.Server.prototype.serveFile = function (pathname, status, headers, req, res)
     var that = this;
     var promise = new(events.EventEmitter);
 
-    pathname = this.normalize(pathname);
+    pathname = this.resolve(pathname);
 
     fs.stat(pathname, function (e, stat) {
         if (e) {
@@ -124,7 +124,7 @@ this.Server.prototype.servePath = function (pathname, status, headers, req, res,
     var that = this,
         promise = new(events.EventEmitter);
 
-    pathname = this.normalize(pathname);
+    pathname = this.resolve(pathname);
 
     // Only allow GET and HEAD requests
     if (req.method !== 'GET' && req.method !== 'HEAD') {
@@ -134,7 +134,7 @@ this.Server.prototype.servePath = function (pathname, status, headers, req, res,
 
     // Make sure we're not trying to access a
     // file outside of the root.
-    if (new(RegExp)('^' + that.root).test(pathname)) {
+    if (pathname.indexOf(that.root) === 0) {
         fs.stat(pathname, function (e, stat) {
             if (e) {
                 finish(404, {});
@@ -152,14 +152,14 @@ this.Server.prototype.servePath = function (pathname, status, headers, req, res,
     }
     return promise;
 };
-this.Server.prototype.normalize = function (pathname) {
-    return path.normalize(path.join(this.root, pathname));
+this.Server.prototype.resolve = function (pathname) {
+    return path.resolve(path.join(this.root, pathname));
 };
 this.Server.prototype.serve = function (req, res, callback) {
     var that = this,
         promise = new(events.EventEmitter);
-
-    var pathname = url.parse(req.url).pathname;
+    
+    var pathname = decodeURI(url.parse(req.url).pathname);
 
     var finish = function (status, headers) {
         that.finish(status, headers, req, res, promise, callback);
@@ -188,9 +188,9 @@ this.Server.prototype.respond = function (pathname, status, _headers, files, sta
     headers['Last-Modified'] = new(Date)(stat.mtime).toUTCString();
 
     // Conditional GET
-    // If both the "If-Modified-Since" and "If-None-Match" headers
+    // If the "If-Modified-Since" or "If-None-Match" headers
     // match the conditions, send a 304 Not Modified.
-    if (req.headers['if-none-match'] === headers['Etag'] &&
+    if (req.headers['if-none-match'] === headers['Etag'] ||
         Date.parse(req.headers['if-modified-since']) >= mtime) {
         finish(304, headers);
     } else if (req.method === 'HEAD') {
@@ -200,16 +200,16 @@ this.Server.prototype.respond = function (pathname, status, _headers, files, sta
         headers['Content-Type']   = mime.contentTypes[path.extname(files[0]).slice(1)] ||
                                    'application/octet-stream';
 
-        for (var k in headers) { _headers[k] = headers[k] }
+        for (var k in _headers) { headers[k] = _headers[k] }
 
-        res.writeHead(status, _headers);
+        res.writeHead(status, headers);
 
         // If the file was cached and it's not older
         // than what's on disk, serve the cached version.
         if (this.cache && (key in exports.store) &&
             exports.store[key].stat.mtime >= stat.mtime) {
             res.end(exports.store[key].buffer);
-            finish(status, _headers);
+            finish(status, headers);
         } else {
             this.stream(pathname, files, new(buffer.Buffer)(stat.size), res, function (e, buffer) {
                 if (e) { return finish(500, {}) }
@@ -218,7 +218,7 @@ this.Server.prototype.respond = function (pathname, status, _headers, files, sta
                     buffer:    buffer,
                     timestamp: Date.now()
                 };
-                finish(status, _headers);
+                finish(status, headers);
             });
         }
     }
index f79326a4ec0e8ea81d67c29e9e8490caa06bd443..b1ce2f4597848bf748b65f06dc9c22a2337b514d 100644 (file)
@@ -9,7 +9,7 @@
   "dependencies"  : [],
   "lib"           : "lib",
   "main"          : "./lib/node-static",
-  "version"       : "0.5.6",
+  "version"       : "0.5.9",
   "directories"   : { "test": "./test" },
   "engines"       : { "node": ">= 0.4.1" }
 }
index 1e59d0d1af89c60e4fae35af973724caf8bb5604..57812b47ae4bed9a89873429fd15b129e3f8c9a1 100644 (file)
@@ -1,4 +1,65 @@
 
+0.8.3 / 2011-09-03
+==================
+
+  * Fixed `\n` parsing for non-JSON packets.
+  * Fixed; make Socket.IO XHTML doctype compatible (fixes #460 from server)
+  * Fixed support for Node.JS running `socket.io-client`.
+  * Updated repository name in `package.json`.
+  * Added support for different policy file ports without having to port
+    forward 843 on the server side [3rd-Eden]
+
+0.8.2 / 2011-08-29
+==================
+
+  * Fixed flashsocket detection.
+
+0.8.1 / 2011-08-29
+==================
+
+  * Bump version.
+
+0.8.0 / 2011-08-28
+==================
+
+  * Added MozWebSocket support (hybi-10 doesn't require API changes) [einaros].
+
+0.7.11 / 2011-08-27
+===================
+
+  * Corrected previous release (missing build).
+
+0.7.10 / 2011-08-27
+===================
+
+  * Fix for failing fallback in websockets
+
+0.7.9 / 2011-08-12
+==================
+
+  * Added check on `Socket#onConnect` to prevent double `connect` events on the main manager.
+  * Fixed socket namespace connect test. Remove broken alternative namespace connect test.
+  * Removed test handler for removed test.
+  * Bumped version to match `socket.io` server.
+
+0.7.5 / 2011-08-08
+==================
+
+  * Added querystring support for `connect` [3rd-Eden]
+  * Added partial Node.JS transports support [3rd-Eden, josephg]
+  * Fixed builder test.
+  * Changed `util.inherit` to replicate Object.create / __proto__.
+  * Changed and cleaned up some acceptance tests.
+  * Fixed race condition with a test that could not be run multiple times.
+  * Added test for encoding a payload.
+  * Added the ability to override the transport to use in acceptance test [3rd-Eden]
+  * Fixed multiple connect packets [DanielBaulig]
+  * Fixed jsonp-polling over-buffering [3rd-Eden]
+  * Fixed ascii preservation in minified socket.io client [3rd-Eden]
+  * Fixed socket.io in situations where the page is not served through utf8.
+  * Fixed namespaces not reconnecting after disconnect [3rd-Eden]
+  * Fixed default port for secure connections.
+
 0.7.4 / 2011-07-12
 ==================
 
index 5592fe1ee3630539083526115aa6f1518d9fdc98..f2d2f41a9c4dd63ea4e94d51f915c5442f63168a 100644 (file)
@@ -2,7 +2,6 @@
 ALL_TESTS = $(shell find test/ -name '*.test.js')
 
 run-tests:
-       @npm link --local > /dev/null
        @./node_modules/.bin/expresso \
                -I lib \
                -I support \
@@ -13,8 +12,7 @@ test:
        @$(MAKE) TESTS="$(ALL_TESTS)" run-tests
 
 test-acceptance:
-       @npm link --local > /dev/null
-       @node support/test-runner/app
+       @node support/test-runner/app $(TRANSPORT)
 
 build:
        @node ./bin/builder.js
index ad15fd0bdf6a2100d666212875e0943b759c8042..3206f043c30577e3b92bfee334160a7d0eca9cd4 100755 (executable)
@@ -3,7 +3,7 @@
  * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  * MIT Licensed
  */
+
 /**
  * Module dependencies.
  */
@@ -14,20 +14,22 @@ var fs = require('fs')
 
 /**
  * License headers.
+ *
  * @api private
  */
+
 var template = '/*! Socket.IO.%ext% build:' + socket.version + ', %type%. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */\n'
   , development = template.replace('%type%', 'development').replace('%ext%', 'js')
   , production = template.replace('%type%', 'production').replace('%ext%', 'min.js');
 
 /**
- * If statements, these allows you to create serveride & client side compatible code
- * using specially designed `if` statements that remove serverside designed code from
- * the source files
+ * If statements, these allows you to create serveride & client side compatible
+ * code using specially designed `if` statements that remove serverside
+ * designed code from the source files
  *
  * @api private
  */
+
 var starttagIF = '// if node'
   , endtagIF = '// end node';
 
@@ -38,7 +40,7 @@ var starttagIF = '// if node'
  * @type {Array}
  * @api private
  */
+
 var base = [
     'io.js'
   , 'util.js'
@@ -60,47 +62,56 @@ var base = [
  * @type {Object}
  * @api public
  */
- var baseTransports = {
+
+var baseTransports = {
     'websocket': ['transports/websocket.js']
   , 'flashsocket': [
-      'transports/websocket.js'
-    , 'transports/flashsocket.js'
-    , 'vendor/web-socket-js/swfobject.js'
-    , 'vendor/web-socket-js/web_socket.js'
+        'transports/websocket.js'
+      , 'transports/flashsocket.js'
+      , 'vendor/web-socket-js/swfobject.js'
+      , 'vendor/web-socket-js/web_socket.js'
     ] 
   , 'htmlfile': ['transports/xhr.js', 'transports/htmlfile.js']
   /* FIXME: re-enable me once we have multi-part support
   , 'xhr-multipart': ['transports/xhr.js', 'transports/xhr-multipart.js'] */
   , 'xhr-polling': ['transports/xhr.js', 'transports/xhr-polling.js']
-  , 'jsonp-polling': ['transports/xhr.js', 'transports/jsonp-polling.js']
-  };
+  , 'jsonp-polling': [
+        'transports/xhr.js'
+      , 'transports/xhr-polling.js'
+      , 'transports/jsonp-polling.js'
+    ]
+};
 
 /**
- * Builds a custom Socket.IO distribution based on the transports that you need. You
- * can configure the build to create development build or production build (minified).
+ * Builds a custom Socket.IO distribution based on the transports that you
+ * need. You can configure the build to create development build or production
+ * build (minified).
  *
  * @param {Array} transports The transports that needs to be bundled.
  * @param {Object} [options] Options to configure the building process.
- * @param {Function} callback The argument is always the callback, because the options are.. optional:D.
- * @callback {String|Boolean} err An optional argument, if it exists than an error occurred during the build process.
+ * @param {Function} callback Last argument should always be the callback
+ * @callback {String|Boolean} err An optional argument, if it exists than an error
+ *    occurred during the build process.
  * @callback {String} result The result of the build process.
  * @api public
  */
-var builder = module.exports = function(){
+
+var builder = module.exports = function () {
   var transports, options, callback, error = null
-    , args = Array.prototype.slice.call(arguments,0)
+    , args = Array.prototype.slice.call(arguments, 0)
     , settings = {
         minify: true
       , node: false
       , custom: []
       };
-  
-  // Fancy pancy argument support
-  // this makes any pattern possible mainly because we require only one of each type
-  args.forEach(function(arg){
-    switch(Object.prototype.toString.call(arg).replace(/\[object\s(\w+)\]/gi , '$1' ).toLowerCase()){
+
+  // Fancy pancy argument support this makes any pattern possible mainly
+  // because we require only one of each type
+  args.forEach(function (arg) {
+    var type = Object.prototype.toString.call(arg)
+        .replace(/\[object\s(\w+)\]/gi , '$1' ).toLowerCase();
+
+    switch (type) {
       case 'array':
         return transports = arg;
       case 'object':
@@ -109,90 +120,109 @@ var builder = module.exports = function(){
         return callback = arg;
     }
   });
-  
+
   // Add defaults
   options = options || {};
   transports = transports || Object.keys(baseTransports);
-  
+
   // Merge the data
-  for(var option in options) settings[option] = options[option];
-  
-  // Start creating a dependencies chain with all the required files for the custom Socket.IO bundle.
+  for(var option in options) {
+    settings[option] = options[option];
+  }
+
+  // Start creating a dependencies chain with all the required files for the
+  // custom Socket.IO bundle.
   var files = [];
-  base.forEach(function(file){
+  base.forEach(function (file) {
     files.push(__dirname + '/../lib/' + file);
   });
-  
-  transports.forEach(function(transport){
+
+  transports.forEach(function (transport) {
     var dependencies = baseTransports[transport];
-    if (!dependencies) return error = 'Unsupported transport `' + transport + '` supplied as argument.';
-    
+    if (!dependencies) {
+      error = 'Unsupported transport `' + transport + '` supplied as argument.';
+      return;
+    }
+
     // Add the files to the files list, but only if they are not added before
-    dependencies.forEach(function(file){
+    dependencies.forEach(function (file) {
       var path = __dirname + '/../lib/' + file;
       if (!~files.indexOf(path)) files.push(path);
     })
   });
-  
+
   // check to see if the files tree compilation generated any errors.
   if (error) return callback(error);
-  
+
   var results = {};
-  files.forEach(function(file){
-    fs.readFile(file, function(err, content){
+  files.forEach(function (file) {
+    fs.readFile(file, function (err, content) {
       if (err) error = err;
       results[file] = content;
-      
+
       // check if we are done yet, or not.. Just by checking the size of the result
       // object.
       if (Object.keys(results).length !== files.length) return;
-      
+
       // we are done, did we error?
       if (error) return callback(error);
-      
+
       // concatinate the file contents in order
       var code = development
         , ignore = 0;
-      
-      files.forEach(function(file){
+
+      files.forEach(function (file) {
         code += results[file];
       });
-      
+
       // check if we need to add custom code
-      if (settings.custom.length){
-        settings.custom.forEach(function(content){
+      if (settings.custom.length) {
+        settings.custom.forEach(function (content) {
           code += content;
-        })
+        });
       }
-      
-      // Search for conditional code blocks that need to be removed as they where designed for
-      // a server side env. but only if we don't want to make this build node compatible
-      if (!settings.node){
-        code = code.split('\n').filter(function(line){
+
+      // Search for conditional code blocks that need to be removed as they
+      // where designed for a server side env. but only if we don't want to
+      // make this build node compatible.
+      if (!settings.node) {
+        code = code.split('\n').filter(function (line) {
           // check if there are tags in here
           var start = line.indexOf(starttagIF) >= 0
             , end = line.indexOf(endtagIF) >= 0
             , ret = ignore;
-          
+
           // ignore the current line
-          if (start) ignore++,ret = ignore;
-          
+          if (start) {
+            ignore++;
+            ret = ignore;
+          }
+
           // stop ignoring the next line
-          if (end) ignore--;
-          
+          if (end) {
+            ignore--;
+          }
+
           return ret == 0;
-        }).join('\n')
+        }).join('\n');
       }
-      
+
       // check if we need to process it any further
-      if (settings.minify){
+      if (settings.minify) {
+        // uglify hate unicode chars... 
+        var separator = '@@OMGYUCHANGEME@@@';
+        code = code.replace(/(\\ufffd)/g, separator);
+
         var ast = uglify.parser.parse(code);
         ast = uglify.uglify.ast_mangle(ast);
         ast = uglify.uglify.ast_squeeze(ast);
-        
+
         code = production + uglify.uglify.gen_code(ast);
+
+        // restore the code
+        code = code.replace(new RegExp('('+ separator + ')', 'g'), '\\ufffd');
       }
-      
+
       callback(error, code);
     })
   })
@@ -224,21 +254,32 @@ builder.transports = baseTransports;
  */
  
 if (!module.parent){
-  var args = process.argv.slice(2); // the first 2 are `node` and the path to this file, we don't need them
-  
+  // the first 2 are `node` and the path to this file, we don't need them
+  var args = process.argv.slice(2);
+
   // build a development build
-  builder(args.length ? args : false, {minify:false},function(err, content){
+  builder(args.length ? args : false, { minify:false }, function (err, content) {
     if (err) return console.error(err);
-    
-    fs.write(fs.openSync(__dirname + '/../dist/socket.io.js', 'w'), content, 0, 'utf8');
+
+    fs.write(
+        fs.openSync(__dirname + '/../dist/socket.io.js', 'w')
+      , content
+      , 0
+      , 'utf8'
+    );
     console.log('Successfully generated the development build: socket.io.js');
   });
-  
+
   // and build a production build
-  builder(args.length ? args : false, function(err, content){
+  builder(args.length ? args : false, function (err, content) {
     if (err) return console.error(err);
-    
-    fs.write(fs.openSync(__dirname + '/../dist/socket.io.min.js', 'w'), content, 0, 'utf8');
+    fs.write(
+        fs.openSync(__dirname + '/../dist/socket.io.min.js', 'w')
+      , content
+      , 0
+      , 'utf8'
+    );
     console.log('Successfully generated the production build: socket.io.min.js');
   });
 }
index a05d262bc83456cdaff9263d366acd1a117d063b..5a8e8e2efcc33b0b42bc9e5f318e0fff9f0289b2 100644 (file)
@@ -1,4 +1,4 @@
-/*! Socket.IO.js build:0.7.4, development. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */
+/*! Socket.IO.js build:0.8.4, development. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */
 
 /**
  * socket.io
@@ -22,7 +22,7 @@
    * @api public
    */
 
-  io.version = '0.7.4';
+  io.version = '0.8.4';
 
   /**
    * Protocol implemented.
 
     var options = {
         host: uri.host
-      , secure: uri.protocol == 'https'
-      , port: uri.port || 80
+      , secure: 'https' == uri.protocol
+      , port: uri.port || ('https' == uri.protocol ? 443 : 80)
+      , query: uri.query || ''
     };
+
     io.util.merge(options, details);
 
     if (options['force new connection'] || !io.sockets[uuri]) {
  * MIT Licensed
  */
 
-(function (exports) {
+(function (exports, global) {
 
   /**
    * Utilities namespace.
       , host = uri.host
       , port = uri.port;
 
-    if ('undefined' != typeof document) {
+    if ('document' in global) {
       host = host || document.domain;
       port = port || (protocol == 'https'
         && document.location.protocol !== 'https:' ? 443 : document.location.port);
     return (protocol || 'http') + '://' + host + ':' + (port || 80);
   };
 
+  /**
+   * Mergest 2 query strings in to once unique query string
+   *
+   * @param {String} base
+   * @param {String} addition
+   * @api public
+   */
+
+  util.query = function (base, addition) {
+    var query = util.chunkQuery(base || '')
+      , components = [];
+
+    util.merge(query, util.chunkQuery(addition || ''));
+    for (var part in query) {
+      if (query.hasOwnProperty(part)) {
+        components.push(part + '=' + query[part]);
+      }
+    }
+
+    return components.length ? '?' + components.join('&') : '';
+  };
+
+  /**
+   * Transforms a querystring in to an object
+   *
+   * @param {String} qs
+   * @api public
+   */
+
+  util.chunkQuery = function (qs) {
+    var query = {}
+      , params = qs.split('&')
+      , i = 0
+      , l = params.length
+      , kv;
+
+    for (; i < l; ++i) {
+      kv = params[i].split('=');
+      if (kv[0]) {
+        query[kv[0]] = decodeURIComponent(kv[1]);
+      }
+    }
+
+    return query;
+  };
+
   /**
    * Executes the given function when the page is loaded.
    *
   var pageLoaded = false;
 
   util.load = function (fn) {
-    if (document.readyState === 'complete' || pageLoaded) {
+    if ('document' in global && document.readyState === 'complete' || pageLoaded) {
       return fn();
     }
 
-    util.on(window, 'load', fn, false);
+    util.on(global, 'load', fn, false);
   };
 
   /**
   util.on = function (element, event, fn, capture) {
     if (element.attachEvent) {
       element.attachEvent('on' + event, fn);
-    } else {
+    } else if (element.addEventListener) {
       element.addEventListener(event, fn, capture);
     }
   };
    */
 
   util.request = function (xdomain) {
+
     if ('undefined' != typeof window) {
       if (xdomain && window.XDomainRequest) {
         return new XDomainRequest();
-      };
+      }
 
       if (window.XMLHttpRequest && (!xdomain || util.ua.hasCORS)) {
         return new XMLHttpRequest();
-      };
+      }
 
       if (!xdomain) {
         try {
    */
 
   util.inherit = function (ctor, ctor2) {
-    ctor.prototype = new ctor2;
-    util.merge(ctor, ctor2);
+    function f() {};
+    f.prototype = ctor2.prototype;
+    ctor.prototype = new f;
   };
 
   /**
   util.intersect = function (arr, arr2) {
     var ret = []
       , longest = arr.length > arr2.length ? arr : arr2
-      , shortest = arr.length > arr2.length ? arr2 : arr
+      , shortest = arr.length > arr2.length ? arr2 : arr;
 
     for (var i = 0, l = shortest.length; i < l; i++) {
       if (~util.indexOf(longest, shortest[i]))
       return Array.prototype.indexOf.call(arr, o, i);
     }
 
-    for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0
-        ; i < j && arr[i] !== o; i++);
+    for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0
+         i < j && arr[i] !== o; i++);
 
     return j <= i ? -1 : i;
   };
   util.ua.webkit = 'undefined' != typeof navigator
     && /webkit/i.test(navigator.userAgent);
 
-})('undefined' != typeof window ? io : module.exports);
+})(
+    'undefined' != typeof window ? io : module.exports
+  , this
+);
 
 /**
  * socket.io
     switch (packet.type) {
       case 'error':
         var reason = packet.reason ? indexOf(reasons, packet.reason) : ''
-          , adv = packet.advice ? indexOf(advice, packet.advice) : ''
+          , adv = packet.advice ? indexOf(advice, packet.advice) : '';
 
         if (reason !== '' || adv !== '')
-          data = reason + (adv !== '' ? ('+' + adv) : '')
+          data = reason + (adv !== '' ? ('+' + adv) : '');
 
         break;
 
 
     for (var i = 0, l = packets.length; i < l; i++) {
       var packet = packets[i];
-      decoded += '\ufffd' + packet.length + '\ufffd' + packets[i]
+      decoded += '\ufffd' + packet.length + '\ufffd' + packets[i];
     }
 
     return decoded;
    * @api private
    */
 
-  var regexp = /^([^:]+):([0-9]+)?(\+)?:([^:]+)?:?(.*)?$/;
+  var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/;
 
   parser.decodePacket = function (data) {
     var pieces = data.match(regexp);
       + options.resource + '/' + io.protocol
       + '/' + this.name + '/' + this.sessid;
   };
+
+  /**
+   * Checks if the transport is ready to start a connection.
+   *
+   * @param {Socket} socket The socket instance that needs a transport
+   * @param {Function} fn The callback
+   * @api private
+   */
+
+  Transport.prototype.ready = function (socket, fn) {
+    fn.call(this);
+  };
 })(
     'undefined' != typeof io ? io : module.exports
   , 'undefined' != typeof io ? io : module.parent.exports
  * MIT Licensed
  */
 
-(function (exports, io) {
+(function (exports, io, global) {
 
   /**
    * Expose constructor.
   exports.Socket = Socket;
 
   /**
-   * Create a new `Socket.IO client` which can establish a persisent
+   * Create a new `Socket.IO client` which can establish a persistent
    * connection with a Socket.IO enabled server.
    *
    * @api public
     this.options = {
         port: 80
       , secure: false
-      , document: document
+      , document: 'document' in global ? document : false
       , resource: 'socket.io'
       , transports: io.transports
       , 'connect timeout': 10000
       , 'try multiple transports': true
       , 'reconnect': true
       , 'reconnection delay': 500
+      , 'reconnection limit': Infinity
       , 'reopen delay': 3000
       , 'max reconnection attempts': 10
       , 'sync disconnect on unload': true
       , 'auto connect': true
+      , 'flash policy port': 10843
     };
 
     io.util.merge(this.options, options);
         (!this.isXDomain() || io.util.ua.hasCORS)) {
       var self = this;
 
-      io.util.on(window, 'beforeunload', function () {
+      io.util.on(global, 'beforeunload', function () {
         self.disconnectSync();
       }, false);
     }
         , options.host + ':' + options.port
         , this.options.resource
         , io.protocol
-        , '?t=' + + new Date
+        , io.util.query(this.options.query, 't=' + +new Date)
       ].join('/');
 
     if (this.isXDomain()) {
       var insertAt = document.getElementsByTagName('script')[0]
-        , script = document.createElement('SCRIPT');
+        , script = document.createElement('script');
 
       script.src = url + '&jsonp=' + io.j.length;
       insertAt.parentNode.insertBefore(script, insertAt);
     } else {
       var xhr = io.util.request();
 
-      xhr.open('GET', url);
+      xhr.open('GET', url, true);
       xhr.onreadystatechange = function () {
         if (xhr.readyState == 4) {
           xhr.onreadystatechange = empty;
       );
 
       function connect (transports){
+        if (self.transport) self.transport.clearTimeouts();
+
         self.transport = self.getTransport(transports);
         if (!self.transport) return self.publish('connect_failed');
 
-        self.connecting = true;
-        self.publish('connecting', self.transport.name);
-        self.transport.open();
+        // once the transport is ready
+        self.transport.ready(self, function () {
+          self.connecting = true;
+          self.publish('connecting', self.transport.name);
+          self.transport.open();
 
-        if (self.options['connect timeout']) {
-          self.connectTimeoutTimer = setTimeout(function () {
-            if (!self.connected) {
-              self.connecting = false;
+          if (self.options['connect timeout']) {
+            self.connectTimeoutTimer = setTimeout(function () {
+              if (!self.connected) {
+                self.connecting = false;
 
-              if (self.options['try multiple transports']) {
-                if (!self.remainingTransports) {
-                  self.remainingTransports = self.transports.slice(0);
-                }
+                if (self.options['try multiple transports']) {
+                  if (!self.remainingTransports) {
+                    self.remainingTransports = self.transports.slice(0);
+                  }
 
-                var remaining = self.remainingTransports;
+                  var remaining = self.remainingTransports;
 
-                while (remaining.length > 0 && remaining.splice(0,1)[0] !=
-                  self.transport.name) {}
+                  while (remaining.length > 0 && remaining.splice(0,1)[0] !=
+                         self.transport.name) {}
 
-                if (remaining.length){
-                  connect(remaining);
-                } else {
-                  self.publish('connect_failed');
+                    if (remaining.length){
+                      connect(remaining);
+                    } else {
+                      self.publish('connect_failed');
+                    }
                 }
               }
-            }
-          }, self.options['connect timeout']);
-        }
+            }, self.options['connect timeout']);
+          }
+        });
       }
 
       connect();
    */
 
   Socket.prototype.isXDomain = function () {
-    var locPort = window.location.port || 80;
-    return this.options.host !== document.domain || this.options.port != locPort;
+
+    var port = window.location.port ||
+      ('https:' == window.location.protocol ? 443 : 80);
+
+    return this.options.host !== document.domain || this.options.port != port;
   };
 
   /**
    */
 
   Socket.prototype.onConnect = function () {
-    this.connected = true;
-    this.connecting = false;
-    if (!this.doBuffer) {
-      // make sure to flush the buffer
-      this.setBuffer(false);
+    if (!this.connected) {
+      this.connected = true;
+      this.connecting = false;
+      if (!this.doBuffer) {
+        // make sure to flush the buffer
+        this.setBuffer(false);
+      }
+      this.emit('connect');
     }
-    this.emit('connect');
   };
 
   /**
     var self = this
       , maxAttempts = this.options['max reconnection attempts']
       , tryMultiple = this.options['try multiple transports']
+      , limit = this.options['reconnection limit'];
 
     function reset () {
       if (self.connected) {
+        for (var i in self.namespaces) {
+          if (self.namespaces.hasOwnProperty(i) && '' !== i) {
+              self.namespaces[i].packet({ type: 'connect' });
+          }
+        }
         self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
       }
 
           reset();
         }
       } else {
-        self.reconnectionDelay *= 2; // exponential back off
+        if (self.reconnectionDelay < limit) {
+          self.reconnectionDelay *= 2; // exponential back off
+        }
+
         self.connect();
         self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
         self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
 })(
     'undefined' != typeof io ? io : module.exports
   , 'undefined' != typeof io ? io : module.parent.exports
+  , this
 );
 /**
  * socket.io
    */
 
   WS.prototype.open = function () {
-    this.websocket = new WebSocket(this.prepareUrl());
+    var query = io.util.query(this.socket.options.query)
+      , self = this
+      , Socket
+
+
+    if (!Socket) {
+      Socket = window.MozWebSocket || window.WebSocket;
+    }
+
+    this.websocket = new Socket(this.prepareUrl() + query);
 
-    var self = this;
     this.websocket.onopen = function () {
       self.onOpen();
       self.socket.setBuffer(false);
    */
 
   WS.check = function () {
-    return 'WebSocket' in window && !('__addTask' in WebSocket);
+    return ('WebSocket' in window && !('__addTask' in WebSocket))
+          || 'MozWebSocket' in window;
   };
 
   /**
   exports.flashsocket = Flashsocket;
 
   /**
-   * The Flashsocket transport. This is a API wrapper for the HTML5 WebSocket
+   * The FlashSocket transport. This is a API wrapper for the HTML5 WebSocket
    * specification. It uses a .swf file to communicate with the server. If you want
    * to serve the .swf file from a other server than where the Socket.IO script is
    * coming from you need to use the insecure version of the .swf. More information
   Flashsocket.prototype.name = 'flashsocket';
 
   /**
-   *Disconnect the established `Flashsocket` connection. This is done by adding a 
-   * new task to the Flashsocket. The rest will be handled off by the `WebSocket` 
+   * Disconnect the established `FlashSocket` connection. This is done by adding a 
+   * new task to the FlashSocket. The rest will be handled off by the `WebSocket` 
    * transport.
    *
    * @returns {Transport}
    */
 
   Flashsocket.prototype.open = function () {
-    var self = this, args = arguments;
+    var self = this
+      , args = arguments;
+
     WebSocket.__addTask(function () {
       io.Transport.websocket.prototype.open.apply(self, args);
     });
   
   /**
    * Sends a message to the Socket.IO server. This is done by adding a new
-   * task to the Flashsocket. The rest will be handled off by the `WebSocket` 
+   * task to the FlashSocket. The rest will be handled off by the `WebSocket` 
    * transport.
    *
    * @returns {Transport}
   };
 
   /**
-   * Disconnects the established `Flashsocket` connection.
+   * Disconnects the established `FlashSocket` connection.
    *
    * @returns {Transport}
    * @api public
   };
 
   /**
-   * Check if the Flashsocket transport is supported as it requires that the Adobe
-   * Flash Player plugin version `10.0.0` or greater is installed. And also check if
+   * The WebSocket fall back needs to append the flash container to the body
+   * element, so we need to make sure we have access to it. Or defer the call
+   * until we are sure there is a body element.
+   *
+   * @param {Socket} socket The socket instance that needs a transport
+   * @param {Function} fn The callback
+   * @api private
+   */
+
+  Flashsocket.prototype.ready = function (socket, fn) {
+    function init () {
+      var options = socket.options
+        , port = options['flash policy port']
+        , path = [
+              'http' + (options.secure ? 's' : '') + ':/'
+            , options.host + ':' + options.port
+            , options.resource
+            , 'static/flashsocket'
+            , 'WebSocketMain' + (socket.isXDomain() ? 'Insecure' : '') + '.swf'
+          ];
+
+      // Only start downloading the swf file when the checked that this browser
+      // actually supports it
+      if (!Flashsocket.loaded) {
+        if (typeof WEB_SOCKET_SWF_LOCATION === 'undefined') {
+          // Set the correct file based on the XDomain settings
+          WEB_SOCKET_SWF_LOCATION = path.join('/');
+        }
+
+        if (port !== 843) {
+          WebSocket.loadFlashPolicyFile('xmlsocket://' + options.host + ':' + port);
+        }
+
+        WebSocket.__initialize();
+        Flashsocket.loaded = true;
+      }
+
+      fn.call(self);
+    }
+
+    var self = this;
+    if (document.body) return init();
+
+    io.util.load(init);
+  };
+
+  /**
+   * Check if the FlashSocket transport is supported as it requires that the Adobe
+   * Flash Player plug-in version `10.0.0` or greater is installed. And also check if
    * the polyfill is correctly loaded.
    *
    * @returns {Boolean}
    * @api public
    */
 
-  Flashsocket.check = function (socket) {
+  Flashsocket.check = function () {
     if (
         typeof WebSocket == 'undefined'
       || !('__initialize' in WebSocket) || !swfobject
     ) return false;
 
-    var supported = swfobject.getFlashPlayerVersion().major >= 10
-      , options = socket.options
-      , path = [
-          'http' + (options.secure ? 's' : '') + ':/'
-        , options.host + ':' + options.port
-        , options.resource
-        , 'static/flashsocket'
-        , 'WebSocketMain' + (socket.isXDomain() ? 'Insecure' : '') + '.swf'
-      ];
-
-    // Only start downloading the swf file when the checked that this browser
-    // actually supports it
-    if (supported && !Flashsocket.loaded) {
-      if (typeof WEB_SOCKET_SWF_LOCATION === 'undefined') {
-        // Set the correct file based on the XDomain settings
-        WEB_SOCKET_SWF_LOCATION = path.join('/');
-      }
-
-      WebSocket.__initialize();
-      Flashsocket.loaded = true;
-    }
-
-    return supported;
+    return swfobject.getFlashPlayerVersion().major >= 10;
   };
 
   /**
-   * Check if the Flashsocket transport can be used as cross domain / cross origin 
+   * Check if the FlashSocket transport can be used as cross domain / cross origin 
    * transport. Because we can't see which type (secure or insecure) of .swf is used
    * we will just return true.
    *
@@ -2832,7 +2955,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
  * MIT Licensed
  */
 
-(function (exports, io) {
+(function (exports, io, global) {
 
   /**
    * Expose constructor.
@@ -2944,7 +3067,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
 
     this.sendXHR = this.request('POST');
 
-    if (window.XDomainRequest && this.sendXHR instanceof XDomainRequest) {
+    if (global.XDomainRequest && this.sendXHR instanceof XDomainRequest) {
       this.sendXHR.onload = this.sendXHR.onerror = onload;
     } else {
       this.sendXHR.onreadystatechange = stateChange;
@@ -2975,8 +3098,10 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
    */
 
   XHR.prototype.request = function (method) {
-    var req = io.util.request(this.socket.isXDomain());
-    req.open(method || 'GET', this.prepareUrl() + '?t' + (+ new Date));
+    var req = io.util.request(this.socket.isXDomain())
+      , query = io.util.query(this.socket.options.query, 't=' + +new Date);
+
+    req.open(method || 'GET', this.prepareUrl() + query, true);
 
     if (method == 'POST') {
       try {
@@ -3019,7 +3144,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
 
     return false;
   };
-  
+
   /**
    * Check if the XHR transport supports corss domain requests.
    * 
@@ -3034,6 +3159,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
 })(
     'undefined' != typeof io ? io.Transport : module.exports
   , 'undefined' != typeof io ? io : module.parent.exports
+  , this
 );
 
 /**
@@ -3102,9 +3228,10 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
 
     iframeC.appendChild(this.iframe);
 
-    this.iframe.src = this.prepareUrl() + '/?t=' + (+ new Date);
+    var self = this
+      , query = io.util.query(this.socket.options.query, 't='+ +new Date);
 
-    var self = this;
+    this.iframe.src = this.prepareUrl() + query;
 
     io.util.on(window, 'unload', function () {
       self.destroy();
@@ -3213,7 +3340,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
  * MIT Licensed
  */
 
-(function (exports, io) {
+(function (exports, io, global) {
 
   /**
    * Expose constructor.
@@ -3239,6 +3366,12 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
 
   io.util.inherit(XHRPolling, io.Transport.XHR);
 
+  /**
+   * Merge the properties from XHR transport
+   */
+
+  io.util.merge(XHRPolling, io.Transport.XHR);
+
   /**
    * Transport name
    *
@@ -3258,10 +3391,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
   XHRPolling.prototype.open = function () {
     var self = this;
 
-    io.util.defer(function () {
-      io.Transport.XHR.prototype.open.call(self);
-    });
-
+    io.Transport.XHR.prototype.open.call(self);
     return false;
   };
 
@@ -3299,7 +3429,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
 
     this.xhr = this.request();
 
-    if (window.XDomainRequest && this.xhr instanceof XDomainRequest) {
+    if (global.XDomainRequest && this.xhr instanceof XDomainRequest) {
       this.xhr.onload = this.xhr.onerror = onload;
     } else {
       this.xhr.onreadystatechange = stateChange;
@@ -3326,6 +3456,25 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
     }
   };
 
+  /**
+   * Webkit based browsers show a infinit spinner when you start a XHR request
+   * before the browsers onload event is called so we need to defer opening of
+   * the transport until the onload event is called. Wrapping the cb in our
+   * defer method solve this.
+   *
+   * @param {Socket} socket The socket instance that needs a transport
+   * @param {Function} fn The callback
+   * @api private
+   */
+
+  XHRPolling.prototype.ready = function (socket, fn) {
+    var self = this;
+
+    io.util.defer(function () {
+      fn.call(self);
+    });
+  };
+
   /**
    * Add the transport to your public io.transports array.
    *
@@ -3337,6 +3486,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
 })(
     'undefined' != typeof io ? io.Transport : module.exports
   , 'undefined' != typeof io ? io : module.parent.exports
+  , this
 );
 
 /**
@@ -3401,11 +3551,15 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
    */
 
   JSONPPolling.prototype.post = function (data) {
-    var self = this;
+    var self = this
+      , query = io.util.query(
+             this.socket.options.query
+          , 't='+ (+new Date) + '&i=' + this.index
+        );
 
     if (!this.form) {
-      var form = document.createElement('FORM')
-        , area = document.createElement('TEXTAREA')
+      var form = document.createElement('form')
+        , area = document.createElement('textarea')
         , id = this.iframeId = 'socketio_iframe_' + this.index
         , iframe;
 
@@ -3415,6 +3569,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
       form.style.left = '-1000px';
       form.target = id;
       form.method = 'POST';
+      form.setAttribute('accept-charset', 'utf-8');
       area.name = 'd';
       form.appendChild(area);
       document.body.appendChild(form);
@@ -3423,7 +3578,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
       this.area = area;
     }
 
-    this.form.action = this.prepareUrl() + '?t=' + (+new Date) + '&i=' + this.index;
+    this.form.action = this.prepareUrl() + query;
 
     function complete () {
       initIframe();
@@ -3466,6 +3621,8 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
     } else {
       this.iframe.onload = complete;
     }
+
+    this.socket.setBuffer(true);
   };
   
   /**
@@ -3477,7 +3634,11 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
 
   JSONPPolling.prototype.get = function () {
     var self = this
-      , script = document.createElement('SCRIPT');
+      , script = document.createElement('script')
+      , query = io.util.query(
+             this.socket.options.query
+          , 't='+ (+new Date) + '&i=' + this.index
+        );
 
     if (this.script) {
       this.script.parentNode.removeChild(this.script);
@@ -3485,7 +3646,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
     }
 
     script.async = true;
-    script.src = this.prepareUrl() + '/?t=' + (+new Date) + '&i=' + this.index;
+    script.src = this.prepareUrl() + query;
     script.onerror = function () {
       self.onClose();
     };
index c7d9b6dfd43759d82d41490a6d765b9aa4e66bd3..d4a9e7b85a9a1ecf3f2861494e98cca5f831b141 100644 (file)
@@ -1,2 +1,2 @@
-/*! Socket.IO.min.js build:0.7.4, production. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */
-(function(a){var b=a;b.version="0.7.4",b.protocol=1,b.transports=[],b.j=[],b.sockets={},b.connect=function(a,c){var d=b.util.parseUri(a),e,f;"undefined"!=typeof document&&(d.protocol=d.protocol||document.location.protocol.slice(0,-1),d.host=d.host||document.domain,d.port=d.port||document.location.port),e=b.util.uniqueUri(d);var g={host:d.host,secure:d.protocol=="https",port:d.port||80};b.util.merge(g,c);if(g["force new connection"]||!b.sockets[e])f=new b.Socket(g);!g["force new connection"]&&f&&(b.sockets[e]=f),f=f||b.sockets[e];return f.of(d.path.length>1?d.path:"")}})("object"==typeof module?module.exports:window.io={}),function(a){var b=a.util={},c=/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,d=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];b.parseUri=function(a){var b=c.exec(a||""),e={},f=14;while(f--)e[d[f]]=b[f]||"";return e},b.uniqueUri=function(a){var b=a.protocol,c=a.host,d=a.port;"undefined"!=typeof document?(c=c||document.domain,d=d||(b=="https"&&document.location.protocol!=="https:"?443:document.location.port)):(c=c||"localhost",!d&&b=="https"&&(d=443));return(b||"http")+"://"+c+":"+(d||80)};var e=!1;b.load=function(a){if(document.readyState==="complete"||e)return a();b.on(window,"load",a,!1)},b.on=function(a,b,c,d){a.attachEvent?a.attachEvent("on"+b,c):a.addEventListener(b,c,d)},b.request=function(a){if("undefined"!=typeof window){if(a&&window.XDomainRequest)return new XDomainRequest;if(window.XMLHttpRequest&&(!a||b.ua.hasCORS))return new XMLHttpRequest;if(!a)try{return new window.ActiveXObject("Microsoft.XMLHTTP")}catch(c){}}return null},"undefined"!=typeof window&&b.load(function(){e=!0}),b.defer=function(a){if(!b.ua.webkit)return a();b.load(function(){setTimeout(a,100)})},b.merge=function f(c,d,e,f){var g=f||[],h=typeof e=="undefined"?2:e,i;for(i in d)d.hasOwnProperty(i)&&b.indexOf(g,i)<0&&(typeof c[i]!="object"||!h?(c[i]=d[i],g.push(d[i])):b.merge(c[i],d[i],h-1,g));return c},b.mixin=function(a,c){b.merge(a.prototype,c.prototype)},b.inherit=function(a,c){a.prototype=new c,b.merge(a,c)},b.isArray=Array.isArray||function(a){return Object.prototype.toString.call(a)==="[object Array]"},b.intersect=function(a,c){var d=[],e=a.length>c.length?a:c,f=a.length>c.length?c:a;for(var g=0,h=f.length;g<h;g++)~b.indexOf(e,f[g])&&d.push(f[g]);return d},b.indexOf=function(a,b,c){if(Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b,c);for(var d=a.length,c=c<0?c+d<0?0:c+d:c||0;c<d&&a[c]!==b;c++);return d<=c?-1:c},b.toArray=function(a){var b=[];for(var c=0,d=a.length;c<d;c++)b.push(a[c]);return b},b.ua={},b.ua.hasCORS="undefined"!=typeof window&&window.XMLHttpRequest&&function(){try{var a=new XMLHttpRequest}catch(b){return!1}return a.withCredentials!=undefined}(),b.ua.webkit="undefined"!=typeof navigator&&/webkit/i.test(navigator.userAgent)}("undefined"!=typeof window?io:module.exports),function(a,b){function c(){}a.EventEmitter=c,c.prototype.on=function(a,c){this.$events||(this.$events={}),this.$events[a]?b.util.isArray(this.$events[a])?this.$events[a].push(c):this.$events[a]=[this.$events[a],c]:this.$events[a]=c;return this},c.prototype.addListener=c.prototype.on,c.prototype.once=function(a,b){function d(){c.removeListener(a,d),b.apply(this,arguments)}var c=this;d.listener=b,this.on(a,d);return this},c.prototype.removeListener=function(a,c){if(this.$events&&this.$events[a]){var d=this.$events[a];if(b.util.isArray(d)){var e=-1;for(var f=0,g=d.length;f<g;f++)if(d[f]===c||d[f].listener&&d[f].listener===c){e=f;break}if(e<0)return this;d.splice(e,1),d.length||delete this.$events[a]}else(d===c||d.listener&&d.listener===c)&&delete this.$events[a]}return this},c.prototype.removeAllListeners=function(a){this.$events&&this.$events[a]&&(this.$events[a]=null);return this},c.prototype.listeners=function(a){this.$events||(this.$events={}),this.$events[a]||(this.$events[a]=[]),b.util.isArray(this.$events[a])||(this.$events[a]=[this.$events[a]]);return this.$events[a]},c.prototype.emit=function(a){if(!this.$events)return!1;var c=this.$events[a];if(!c)return!1;var d=Array.prototype.slice.call(arguments,1);if("function"==typeof c)c.apply(this,d);else{if(!b.util.isArray(c))return!1;var e=c.slice();for(var f=0,g=e.length;f<g;f++)e[f].apply(this,d)}return!0}}("undefined"!=typeof io?io:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(exports,nativeJSON){function str(a,b){var c,d,e,f,g=gap,h,i=b[a];i instanceof Date&&(i=date(a)),typeof rep=="function"&&(i=rep.call(b,a,i));switch(typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";gap+=indent,h=[];if(Object.prototype.toString.apply(i)==="[object Array]"){f=i.length;for(c=0;c<f;c+=1)h[c]=str(c,i)||"null";e=h.length===0?"[]":gap?"[\n"+gap+h.join(",\n"+gap)+"\n"+g+"]":"["+h.join(",")+"]",gap=g;return e}if(rep&&typeof rep=="object"){f=rep.length;for(c=0;c<f;c+=1)typeof rep[c]=="string"&&(d=rep[c],e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e))}else for(d in i)Object.prototype.hasOwnProperty.call(i,d)&&(e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e));e=h.length===0?"{}":gap?"{\n"+gap+h.join(",\n"+gap)+"\n"+g+"}":"{"+h.join(",")+"}",gap=g;return e}}function quote(a){escapable.lastIndex=0;return escapable.test(a)?'"'+a.replace(escapable,function(a){var b=meta[a];return typeof b=="string"?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function date(a,b){return isFinite(a.valueOf())?a.getUTCFullYear()+"-"+f(a.getUTCMonth()+1)+"-"+f(a.getUTCDate())+"T"+f(a.getUTCHours())+":"+f(a.getUTCMinutes())+":"+f(a.getUTCSeconds())+"Z":null}function f(a){return a<10?"0"+a:a}"use strict";if(nativeJSON&&nativeJSON.parse)return exports.JSON={parse:nativeJSON.parse,stringify:nativeJSON.stringify};var JSON=exports.JSON={},cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;JSON.stringify=function(a,b,c){var d;gap="",indent="";if(typeof c=="number")for(d=0;d<c;d+=1)indent+=" ";else typeof c=="string"&&(indent=c);rep=b;if(b&&typeof b!="function"&&(typeof b!="object"||typeof b.length!="number"))throw new Error("JSON.stringify");return str("",{"":a})},JSON.parse=function(text,reviver){function walk(a,b){var c,d,e=a[b];if(e&&typeof e=="object")for(c in e)Object.prototype.hasOwnProperty.call(e,c)&&(d=walk(e,c),d!==undefined?e[c]=d:delete e[c]);return reviver.call(a,b,e)}var j;text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver=="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}("undefined"!=typeof io?io:module.exports,typeof JSON!="undefined"?JSON:undefined),function(a,b){var c=a.parser={},d=c.packets=["disconnect","connect","heartbeat","message","json","event","ack","error","noop"],e=c.reasons=["transport not supported","client not handshaken","unauthorized"],f=c.advice=["reconnect"],g=b.JSON,h=b.util.indexOf;c.encodePacket=function(a){var b=h(d,a.type),c=a.id||"",i=a.endpoint||"",j=a.ack,k=null;switch(a.type){case"error":var l=a.reason?h(e,a.reason):"",m=a.advice?h(f,a.advice):"";if(l!==""||m!=="")k=l+(m!==""?"+"+m:"");break;case"message":a.data!==""&&(k=a.data);break;case"event":var n={name:a.name};a.args&&a.args.length&&(n.args=a.args),k=g.stringify(n);break;case"json":k=g.stringify(a.data);break;case"connect":a.qs&&(k=a.qs);break;case"ack":k=a.ackId+(a.args&&a.args.length?"+"+g.stringify(a.args):"")}var o=[b,c+(j=="data"?"+":""),i];k!==null&&k!==undefined&&o.push(k);return o.join(":")},c.encodePayload=function(a){var b="";if(a.length==1)return a[0];for(var c=0,d=a.length;c<d;c++){var e=a[c];b+="�"+e.length+"�"+a[c]}return b};var i=/^([^:]+):([0-9]+)?(\+)?:([^:]+)?:?(.*)?$/;c.decodePacket=function(a){var b=a.match(i);if(!b)return{};var c=b[2]||"",a=b[5]||"",h={type:d[b[1]],endpoint:b[4]||""};c&&(h.id=c,b[3]?h.ack="data":h.ack=!0);switch(h.type){case"error":var b=a.split("+");h.reason=e[b[0]]||"",h.advice=f[b[1]]||"";break;case"message":h.data=a||"";break;case"event":try{var j=g.parse(a);h.name=j.name,h.args=j.args}catch(k){}h.args=h.args||[];break;case"json":try{h.data=g.parse(a)}catch(k){}break;case"connect":h.qs=a||"";break;case"ack":var b=a.match(/^([0-9]+)(\+)?(.*)/);if(b){h.ackId=b[1],h.args=[];if(b[3])try{h.args=b[3]?g.parse(b[3]):[]}catch(k){}}break;case"disconnect":case"heartbeat":}return h},c.decodePayload=function(a){if(a.charAt(0)=="�"){var b=[];for(var d=1,e="";d<a.length;d++)a.charAt(d)=="�"?(b.push(c.decodePacket(a.substr(d+1).substr(0,e))),d+=Number(e)+1,e=""):e+=a.charAt(d);return b}return[c.decodePacket(a)]}}("undefined"!=typeof io?io:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(a,b){function c(a,b){this.socket=a,this.sessid=b}a.Transport=c,b.util.mixin(c,b.EventEmitter),c.prototype.onData=function(a){this.clearCloseTimeout(),this.setCloseTimeout();if(a!==""){var c=b.parser.decodePayload(a);if(c&&c.length)for(var d=0,e=c.length;d<e;d++)this.onPacket(c[d])}return this},c.prototype.onPacket=function(a){if(a.type=="heartbeat")return this.onHeartbeat();a.type=="connect"&&a.endpoint==""&&this.onConnect(),this.socket.onPacket(a);return this},c.prototype.setCloseTimeout=function(){if(!this.closeTimeout){var a=this;this.closeTimeout=setTimeout(function(){a.onDisconnect()},this.socket.closeTimeout)}},c.prototype.onDisconnect=function(){this.close&&this.close(),this.clearTimeouts(),this.socket.onDisconnect();return this},c.prototype.onConnect=function(){this.socket.onConnect();return this},c.prototype.clearCloseTimeout=function(){this.closeTimeout&&(clearTimeout(this.closeTimeout),this.closeTimeout=null)},c.prototype.clearTimeouts=function(){this.clearCloseTimeout(),this.reopenTimeout&&clearTimeout(this.reopenTimeout)},c.prototype.packet=function(a){this.send(b.parser.encodePacket(a))},c.prototype.onHeartbeat=function(a){this.packet({type:"heartbeat"})},c.prototype.onOpen=function(){this.open=!0,this.clearCloseTimeout(),this.socket.onOpen()},c.prototype.onClose=function(){var a=this;this.open=!1,this.setCloseTimeout(),this.socket.onClose()},c.prototype.prepareUrl=function(){var a=this.socket.options;return this.scheme()+"://"+a.host+":"+a.port+"/"+a.resource+"/"+b.protocol+"/"+this.name+"/"+this.sessid}}("undefined"!=typeof io?io:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(a,b){function d(){}function c(a){this.options={port:80,secure:!1,document:document,resource:"socket.io",transports:b.transports,"connect timeout":1e4,"try multiple transports":!0,reconnect:!0,"reconnection delay":500,"reopen delay":3e3,"max reconnection attempts":10,"sync disconnect on unload":!0,"auto connect":!0},b.util.merge(this.options,a),this.connected=!1,this.open=!1,this.connecting=!1,this.reconnecting=!1,this.namespaces={},this.buffer=[],this.doBuffer=!1;if(this.options["sync disconnect on unload"]&&(!this.isXDomain()||b.util.ua.hasCORS)){var c=this;b.util.on(window,"beforeunload",function(){c.disconnectSync()},!1)}this.options["auto connect"]&&this.connect()}a.Socket=c,b.util.mixin(c,b.EventEmitter),c.prototype.of=function(a){this.namespaces[a]||(this.namespaces[a]=new b.SocketNamespace(this,a),a!==""&&this.namespaces[a].packet({type:"connect"}));return this.namespaces[a]},c.prototype.publish=function(){this.emit.apply(this,arguments);var a;for(var b in this.namespaces)this.namespaces.hasOwnProperty(b)&&(a=this.of(b),a.$emit.apply(a,arguments))},c.prototype.handshake=function(a){function f(b){b instanceof Error?c.onError(b.message):a.apply(null,b.split(":"))}var c=this,e=this.options,g=["http"+(e.secure?"s":"")+":/",e.host+":"+e.port,this.options.resource,b.protocol,"?t="+ +(new Date)].join("/");if(this.isXDomain()){var h=document.getElementsByTagName("script")[0],i=document.createElement("SCRIPT");i.src=g+"&jsonp="+b.j.length,h.parentNode.insertBefore(i,h),b.j.push(function(a){f(a),i.parentNode.removeChild(i)})}else{var j=b.util.request();j.open("GET",g),j.onreadystatechange=function(){j.readyState==4&&(j.onreadystatechange=d,j.status==200?f(j.responseText):!c.reconnecting&&c.onError(j.responseText))},j.send(null)}},c.prototype.getTransport=function(a){var c=a||this.transports,d;for(var e=0,f;f=c[e];e++)if(b.Transport[f]&&b.Transport[f].check(this)&&(!this.isXDomain()||b.Transport[f].xdomainCheck()))return new b.Transport[f](this,this.sessionid);return null},c.prototype.connect=function(a){if(this.connecting)return this;var c=this;this.handshake(function(d,e,f,g){function h(a){c.transport=c.getTransport(a);if(!c.transport)return c.publish("connect_failed");c.connecting=!0,c.publish("connecting",c.transport.name),c.transport.open(),c.options["connect timeout"]&&(c.connectTimeoutTimer=setTimeout(function(){if(!c.connected){c.connecting=!1;if(c.options["try multiple transports"]){c.remainingTransports||(c.remainingTransports=c.transports.slice(0));var a=c.remainingTransports;while(a.length>0&&a.splice(0,1)[0]!=c.transport.name);a.length?h(a):c.publish("connect_failed")}}},c.options["connect timeout"]))}c.sessionid=d,c.closeTimeout=f*1e3,c.heartbeatTimeout=e*1e3,c.transports=b.util.intersect(g.split(","),c.options.transports),h(),c.once("connect",function(){clearTimeout(c.connectTimeoutTimer),a&&typeof a=="function"&&a()})});return this},c.prototype.packet=function(a){this.connected&&!this.doBuffer?this.transport.packet(a):this.buffer.push(a);return this},c.prototype.setBuffer=function(a){this.doBuffer=a,!a&&this.connected&&this.buffer.length&&(this.transport.payload(this.buffer),this.buffer=[])},c.prototype.disconnect=function(){this.connected&&(this.open&&this.of("").packet({type:"disconnect"}),this.onDisconnect("booted"));return this},c.prototype.disconnectSync=function(){var a=b.util.request(),c=this.resource+"/"+b.protocol+"/"+this.sessionid;a.open("GET",c,!0),this.onDisconnect("booted")},c.prototype.isXDomain=function(){var a=window.location.port||80;return this.options.host!==document.domain||this.options.port!=a},c.prototype.onConnect=function(){this.connected=!0,this.connecting=!1,this.doBuffer||this.setBuffer(!1),this.emit("connect")},c.prototype.onOpen=function(){this.open=!0},c.prototype.onClose=function(){this.open=!1},c.prototype.onPacket=function(a){this.of(a.endpoint).onPacket(a)},c.prototype.onError=function(a){a&&a.advice&&a.advice==="reconnect"&&this.connected&&(this.disconnect(),this.reconnect()),this.publish("error",a&&a.reason?a.reason:a)},c.prototype.onDisconnect=function(a){var b=this.connected;this.connected=!1,this.connecting=!1,this.open=!1,b&&(this.transport.close(),this.transport.clearTimeouts(),this.publish("disconnect",a),"booted"!=a&&this.options.reconnect&&!this.reconnecting&&this.reconnect())},c.prototype.reconnect=function(){function e(){if(!!a.reconnecting){if(a.connected)return d();if(a.connecting&&a.reconnecting)return a.reconnectionTimer=setTimeout(e,1e3);a.reconnectionAttempts++>=b?a.redoTransports?(a.publish("reconnect_failed"),d()):(a.on("connect_failed",e),a.options["try multiple transports"]=!0,a.transport=a.getTransport(),a.redoTransports=!0,a.connect()):(a.reconnectionDelay*=2,a.connect(),a.publish("reconnecting",a.reconnectionDelay,a.reconnectionAttempts),a.reconnectionTimer=setTimeout(e,a.reconnectionDelay))}}function d(){a.connected&&a.publish("reconnect",a.transport.name,a.reconnectionAttempts),a.removeListener("connect_failed",e),a.removeListener("connect",e),a.reconnecting=!1,delete a.reconnectionAttempts,delete a.reconnectionDelay,delete a.reconnectionTimer,delete a.redoTransports,a.options["try multiple transports"]=c}this.reconnecting=!0,this.reconnectionAttempts=0,this.reconnectionDelay=this.options["reconnection delay"];var a=this,b=this.options["max reconnection attempts"],c=this.options["try multiple transports"];this.options["try multiple transports"]=!1,this.reconnectionTimer=setTimeout(e,this.reconnectionDelay),this.on("connect",e)}}("undefined"!=typeof io?io:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(a,b){function d(a,b){this.namespace=a,this.name=b}function c(a,b){this.socket=a,this.name=b||"",this.flags={},this.json=new d(this,"json"),this.ackPackets=0,this.acks={}}a.SocketNamespace=c,b.util.mixin(c,b.EventEmitter),c.prototype.$emit=b.EventEmitter.prototype.emit,c.prototype.of=function(){return this.socket.of.apply(this.socket,arguments)},c.prototype.packet=function(a){a.endpoint=this.name,this.socket.packet(a),this.flags={};return this},c.prototype.send=function(a,b){var c={type:this.flags.json?"json":"message",data:a};"function"==typeof b&&(c.id=++this.ackPackets,c.ack=!0,this.acks[c.id]=b);return this.packet(c)},c.prototype.emit=function(a){var b=Array.prototype.slice.call(arguments,1),c=b[b.length-1],d={type:"event",name:a};"function"==typeof c&&(d.id=++this.ackPackets,d.ack="data",this.acks[d.id]=c,b=b.slice(0,b.length-1)),d.args=b;return this.packet(d)},c.prototype.disconnect=function(){this.name===""?this.socket.disconnect():(this.packet({type:"disconnect"}),this.$emit("disconnect"));return this},c.prototype.onPacket=function(a){function d(){c.packet({type:"ack",args:b.util.toArray(arguments),ackId:a.id})}var c=this;switch(a.type){case"connect":this.$emit("connect");break;case"disconnect":this.name===""?this.socket.onDisconnect(a.reason||"booted"):this.$emit("disconnect",a.reason);break;case"message":case"json":var e=["message",a.data];a.ack=="data"?e.push(d):a.ack&&this.packet({type:"ack",ackId:a.id}),this.$emit.apply(this,e);break;case"event":var e=[a.name].concat(a.args);a.ack=="data"&&e.push(d),this.$emit.apply(this,e);break;case"ack":this.acks[a.ackId]&&(this.acks[a.ackId].apply(this,a.args),delete this.acks[a.ackId]);break;case"error":a.advice?this.socket.onError(a):a.reason=="unauthorized"?this.$emit("connect_failed",a.reason):this.$emit("error",a.reason)}},d.prototype.send=function(){this.namespace.flags[this.name]=!0,this.namespace.send.apply(this.namespace,arguments)},d.prototype.emit=function(){this.namespace.flags[this.name]=!0,this.namespace.emit.apply(this.namespace,arguments)}}("undefined"!=typeof io?io:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(a,b){function c(a){b.Transport.apply(this,arguments)}a.websocket=c,b.util.inherit(c,b.Transport),c.prototype.name="websocket",c.prototype.open=function(){this.websocket=new WebSocket(this.prepareUrl());var a=this;this.websocket.onopen=function(){a.onOpen(),a.socket.setBuffer(!1)},this.websocket.onmessage=function(b){a.onData(b.data)},this.websocket.onclose=function(){a.onClose(),a.socket.setBuffer(!0)},this.websocket.onerror=function(b){a.onError(b)};return this},c.prototype.send=function(a){this.websocket.send(a);return this},c.prototype.payload=function(a){for(var b=0,c=a.length;b<c;b++)this.packet(a[b]);return this},c.prototype.close=function(){this.websocket.close();return this},c.prototype.onError=function(a){this.socket.onError(a)},c.prototype.scheme=function(){return this.socket.options.secure?"wss":"ws"},c.check=function(){return"WebSocket"in window&&!("__addTask"in WebSocket)},c.xdomainCheck=function(){return!0},b.transports.push("websocket")}("undefined"!=typeof io?io.Transport:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(a,b){function c(){b.Transport.websocket.apply(this,arguments)}a.flashsocket=c,b.util.inherit(c,b.Transport.websocket),c.prototype.name="flashsocket",c.prototype.open=function(){var a=this,c=arguments;WebSocket.__addTask(function(){b.Transport.websocket.prototype.open.apply(a,c)});return this},c.prototype.send=function(){var a=this,c=arguments;WebSocket.__addTask(function(){b.Transport.websocket.prototype.send.apply(a,c)});return this},c.prototype.close=function(){WebSocket.__tasks.length=0,b.Transport.websocket.prototype.close.call(this);return this},c.check=function(a){if(typeof WebSocket=="undefined"||!("__initialize"in WebSocket)||!swfobject)return!1;var b=swfobject.getFlashPlayerVersion().major>=10,d=a.options,e=["http"+(d.secure?"s":"")+":/",d.host+":"+d.port,d.resource,"static/flashsocket","WebSocketMain"+(a.isXDomain()?"Insecure":"")+".swf"];b&&!c.loaded&&(typeof WEB_SOCKET_SWF_LOCATION=="undefined"&&(WEB_SOCKET_SWF_LOCATION=e.join("/")),WebSocket.__initialize(),c.loaded=!0);return b},c.xdomainCheck=function(){return!0},typeof window!="undefined"&&(WEB_SOCKET_DISABLE_AUTO_INITIALIZATION=!0),b.transports.push("flashsocket")}("undefined"!=typeof io?io.Transport:module.exports,"undefined"!=typeof io?io:module.parent.exports);var swfobject=function(){function V(b){var c=/[\\\"<>\.;]/,d=c.exec(b)!=null;return d&&typeof encodeURIComponent!=a?encodeURIComponent(b):b}function U(a,b){if(!!x){var c=b?"visible":"hidden";t&&P(a)?P(a).style.visibility=c:T("#"+a,"visibility:"+c)}}function T(c,d,e,f){if(!y.ie||!y.mac){var g=i.getElementsByTagName("head")[0];if(!g)return;var h=e&&typeof e=="string"?e:"screen";f&&(v=null,w=null);if(!v||w!=h){var j=Q("style");j.setAttribute("type","text/css"),j.setAttribute("media",h),v=g.appendChild(j),y.ie&&y.win&&typeof i.styleSheets!=a&&i.styleSheets.length>0&&(v=i.styleSheets[i.styleSheets.length-1]),w=h}y.ie&&y.win?v&&typeof v.addRule==b&&v.addRule(c,d):v&&typeof i.createTextNode!=a&&v.appendChild(i.createTextNode(c+" {"+d+"}"))}}function S(a){var b=y.pv,c=a.split(".");c[0]=parseInt(c[0],10),c[1]=parseInt(c[1],10)||0,c[2]=parseInt(c[2],10)||0;return b[0]>c[0]||b[0]==c[0]&&b[1]>c[1]||b[0]==c[0]&&b[1]==c[1]&&b[2]>=c[2]?!0:!1}function R(a,b,c){a.attachEvent(b,c),o[o.length]=[a,b,c]}function Q(a){return i.createElement(a)}function P(a){var b=null;try{b=i.getElementById(a)}catch(c){}return b}function O(a){var b=P(a);if(b){for(var c in b)typeof b[c]=="function"&&(b[c]=null);b.parentNode.removeChild(b)}}function N(a){var b=P(a);b&&b.nodeName=="OBJECT"&&(y.ie&&y.win?(b.style.display="none",function(){b.readyState==4?O(a):setTimeout(arguments.callee,10)}()):b.parentNode.removeChild(b))}function M(a,b,c){var d=Q("param");d.setAttribute("name",b),d.setAttribute("value",c),a.appendChild(d)}function L(c,d,f){var g,h=P(f);if(y.wk&&y.wk<312)return g;if(h){typeof c.id==a&&(c.id=f);if(y.ie&&y.win){var i="";for(var j in c)c[j]!=Object.prototype[j]&&(j.toLowerCase()=="data"?d.movie=c[j]:j.toLowerCase()=="styleclass"?i+=' class="'+c[j]+'"':j.toLowerCase()!="classid"&&(i+=" "+j+'="'+c[j]+'"'));var k="";for(var l in d)d[l]!=Object.prototype[l]&&(k+='<param name="'+l+'" value="'+d[l]+'" />');h.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+i+">"+k+"</object>",n[n.length]=c.id,g=P(c.id)}else{var m=Q(b);m.setAttribute("type",e);for(var o in c)c[o]!=Object.prototype[o]&&(o.toLowerCase()=="styleclass"?m.setAttribute("class",c[o]):o.toLowerCase()!="classid"&&m.setAttribute(o,c[o]));for(var p in d)d[p]!=Object.prototype[p]&&p.toLowerCase()!="movie"&&M(m,p,d[p]);h.parentNode.replaceChild(m,h),g=m}}return g}function K(a){var c=Q("div");if(y.win&&y.ie)c.innerHTML=a.innerHTML;else{var d=a.getElementsByTagName(b)[0];if(d){var e=d.childNodes;if(e){var f=e.length;for(var g=0;g<f;g++)(e[g].nodeType!=1||e[g].nodeName!="PARAM")&&e[g].nodeType!=8&&c.appendChild(e[g].cloneNode(!0))}}}return c}function J(a){if(y.ie&&y.win&&a.readyState!=4){var b=Q("div");a.parentNode.insertBefore(b,a),b.parentNode.replaceChild(K(a),b),a.style.display="none",function(){a.readyState==4?a.parentNode.removeChild(a):setTimeout(arguments.callee,10)}()}else a.parentNode.replaceChild(K(a),a)}function I(b,c,d,e){u=!0,r=e||null,s={success:!1,id:d};var g=P(d);if(g){g.nodeName=="OBJECT"?(p=K(g),q=null):(p=g,q=d),b.id=f;if(typeof b.width==a||!/%$/.test(b.width)&&parseInt(b.width,10)<310)b.width="310";if(typeof b.height==a||!/%$/.test(b.height)&&parseInt(b.height,10)<137)b.height="137";i.title=i.title.slice(0,47)+" - Flash Player Installation";var j=y.ie&&y.win?"ActiveX":"PlugIn",k="MMredirectURL="+h.location.toString().replace(/&/g,"%26")+"&MMplayerType="+j+"&MMdoctitle="+i.title;typeof c.flashvars!=a?c.flashvars+="&"+k:c.flashvars=k;if(y.ie&&y.win&&g.readyState!=4){var l=Q("div");d+="SWFObjectNew",l.setAttribute("id",d),g.parentNode.insertBefore(l,g),g.style.display="none",function(){g.readyState==4?g.parentNode.removeChild(g):setTimeout(arguments.callee,10)}()}L(b,c,d)}}function H(){return!u&&S("6.0.65")&&(y.win||y.mac)&&!(y.wk&&y.wk<312)}function G(c){var d=null,e=P(c);if(e&&e.nodeName=="OBJECT")if(typeof e.SetVariable!=a)d=e;else{var f=e.getElementsByTagName(b)[0];f&&(d=f)}return d}function F(){var b=m.length;if(b>0)for(var c=0;c<b;c++){var d=m[c].id,e=m[c].callbackFn,f={success:!1,id:d};if(y.pv[0]>0){var g=P(d);if(g)if(S(m[c].swfVersion)&&!(y.wk&&y.wk<312))U(d,!0),e&&(f.success=!0,f.ref=G(d),e(f));else if(m[c].expressInstall&&H()){var h={};h.data=m[c].expressInstall,h.width=g.getAttribute("width")||"0",h.height=g.getAttribute("height")||"0",g.getAttribute("class")&&(h.styleclass=g.getAttribute("class")),g.getAttribute("align")&&(h.align=g.getAttribute("align"));var i={},j=g.getElementsByTagName("param"),k=j.length;for(var l=0;l<k;l++)j[l].getAttribute("name").toLowerCase()!="movie"&&(i[j[l].getAttribute("name")]=j[l].getAttribute("value"));I(h,i,d,e)}else J(g),e&&e(f)}else{U(d,!0);if(e){var n=G(d);n&&typeof n.SetVariable!=a&&(f.success=!0,f.ref=n),e(f)}}}}function E(){var c=i.getElementsByTagName("body")[0],d=Q(b);d.setAttribute("type",e);var f=c.appendChild(d);if(f){var g=0;(function(){if(typeof f.GetVariable!=a){var b=f.GetVariable("$version");b&&(b=b.split(" ")[1].split(","),y.pv=[parseInt(b[0],10),parseInt(b[1],10),parseInt(b[2],10)])}else if(g<10){g++,setTimeout(arguments.callee,10);return}c.removeChild(d),f=null,F()})()}else F()}function D(){k?E():F()}function C(b){if(typeof h.addEventListener!=a)h.addEventListener("load",b,!1);else if(typeof i.addEventListener!=a)i.addEventListener("load",b,!1);else if(typeof h.attachEvent!=a)R(h,"onload",b);else if(typeof h.onload=="function"){var c=h.onload;h.onload=function(){c(),b()}}else h.onload=b}function B(a){t?a():l[l.length]=a}function A(){if(!t){try{var a=i.getElementsByTagName("body")[0].appendChild(Q("span"));a.parentNode.removeChild(a)}catch(b){return}t=!0;var c=l.length;for(var d=0;d<c;d++)l[d]()}}var a="undefined",b="object",c="Shockwave Flash",d="ShockwaveFlash.ShockwaveFlash",e="application/x-shockwave-flash",f="SWFObjectExprInst",g="onreadystatechange",h=window,i=document,j=navigator,k=!1,l=[D],m=[],n=[],o=[],p,q,r,s,t=!1,u=!1,v,w,x=!0,y=function(){var f=typeof i.getElementById!=a&&typeof i.getElementsByTagName!=a&&typeof i.createElement!=a,g=j.userAgent.toLowerCase(),l=j.platform.toLowerCase(),m=l?/win/.test(l):/win/.test(g),n=l?/mac/.test(l):/mac/.test(g),o=/webkit/.test(g)?parseFloat(g.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):!1,p=!1,q=[0,0,0],r=null;if(typeof j.plugins!=a&&typeof j.plugins[c]==b)r=j.plugins[c].description,r&&(typeof j.mimeTypes==a||!j.mimeTypes[e]||!!j.mimeTypes[e].enabledPlugin)&&(k=!0,p=!1,r=r.replace(/^.*\s+(\S+\s+\S+$)/,"$1"),q[0]=parseInt(r.replace(/^(.*)\..*$/,"$1"),10),q[1]=parseInt(r.replace(/^.*\.(.*)\s.*$/,"$1"),10),q[2]=/[a-zA-Z]/.test(r)?parseInt(r.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0);else if(typeof h.ActiveXObject!=a)try{var s=new ActiveXObject(d);s&&(r=s.GetVariable("$version"),r&&(p=!0,r=r.split(" ")[1].split(","),q=[parseInt(r[0],10),parseInt(r[1],10),parseInt(r[2],10)]))}catch(t){}return{w3:f,pv:q,wk:o,ie:p,win:m,mac:n}}(),z=function(){!y.w3||((typeof i.readyState!=a&&i.readyState=="complete"||typeof i.readyState==a&&(i.getElementsByTagName("body")[0]||i.body))&&A(),t||(typeof i.addEventListener!=a&&i.addEventListener("DOMContentLoaded",A,!1),y.ie&&y.win&&(i.attachEvent(g,function(){i.readyState=="complete"&&(i.detachEvent(g,arguments.callee),A())}),h==top&&function(){if(!t){try{i.documentElement.doScroll("left")}catch(a){setTimeout(arguments.callee,0);return}A()}}()),y.wk&&function(){if(!t){if(!/loaded|complete/.test(i.readyState)){setTimeout(arguments.callee,0);return}A()}}(),C(A)))}(),W=function(){y.ie&&y.win&&window.attachEvent("onunload",function(){var a=o.length;for(var b=0;b<a;b++)o[b][0].detachEvent(o[b][1],o[b][2]);var c=n.length;for(var d=0;d<c;d++)N(n[d]);for(var e in y)y[e]=null;y=null;for(var f in swfobject)swfobject[f]=null;swfobject=null})}();return{registerObject:function(a,b,c,d){if(y.w3&&a&&b){var e={};e.id=a,e.swfVersion=b,e.expressInstall=c,e.callbackFn=d,m[m.length]=e,U(a,!1)}else d&&d({success:!1,id:a})},getObjectById:function(a){if(y.w3)return G(a)},embedSWF:function(c,d,e,f,g,h,i,j,k,l){var m={success:!1,id:d};y.w3&&!(y.wk&&y.wk<312)&&c&&d&&e&&f&&g?(U(d,!1),B(function(){e+="",f+="";var n={};if(k&&typeof k===b)for(var o in k)n[o]=k[o];n.data=c,n.width=e,n.height=f;var p={};if(j&&typeof j===b)for(var q in j)p[q]=j[q];if(i&&typeof i===b)for(var r in i)typeof p.flashvars!=a?p.flashvars+="&"+r+"="+i[r]:p.flashvars=r+"="+i[r];if(S(g)){var s=L(n,p,d);n.id==d&&U(d,!0),m.success=!0,m.ref=s}else{if(h&&H()){n.data=h,I(n,p,d,l);return}U(d,!0)}l&&l(m)})):l&&l(m)},switchOffAutoHideShow:function(){x=!1},ua:y,getFlashPlayerVersion:function(){return{major:y.pv[0],minor:y.pv[1],release:y.pv[2]}},hasFlashPlayerVersion:S,createSWF:function(a,b,c){return y.w3?L(a,b,c):undefined},showExpressInstall:function(a,b,c,d){y.w3&&H()&&I(a,b,c,d)},removeSWF:function(a){y.w3&&N(a)},createCSS:function(a,b,c,d){y.w3&&T(a,b,c,d)},addDomLoadEvent:B,addLoadEvent:C,getQueryParamValue:function(a){var b=i.location.search||i.location.hash;if(b){/\?/.test(b)&&(b=b.split("?")[1]);if(a==null)return V(b);var c=b.split("&");for(var d=0;d<c.length;d++)if(c[d].substring(0,c[d].indexOf("="))==a)return V(c[d].substring(c[d].indexOf("=")+1))}return""},expressInstallCallback:function(){if(u){var a=P(f);a&&p&&(a.parentNode.replaceChild(p,a),q&&(U(q,!0),y.ie&&y.win&&(p.style.display="block")),r&&r(s)),u=!1}}}}();(function(){if(!window.WebSocket){var a=window.console;if(!a||!a.log||!a.error)a={log:function(){},error:function(){}};if(!swfobject.hasFlashPlayerVersion("10.0.0")){a.error("Flash Player >= 10.0.0 is required.");return}location.protocol=="file:"&&a.error("WARNING: web-socket-js doesn't work in file:///... URL unless you set Flash Security Settings properly. Open the page via Web server i.e. http://..."),WebSocket=function(a,b,c,d,e){var f=this;f.__id=WebSocket.__nextId++,WebSocket.__instances[f.__id]=f,f.readyState=WebSocket.CONNECTING,f.bufferedAmount=0,f.__events={},b?typeof b=="string"&&(b=[b]):b=[],setTimeout(function(){WebSocket.__addTask(function(){WebSocket.__flash.create(f.__id,a,b,c||null,d||0,e||null)})},0)},WebSocket.prototype.send=function(a){if(this.readyState==WebSocket.CONNECTING)throw"INVALID_STATE_ERR: Web Socket connection has not been established";var b=WebSocket.__flash.send(this.__id,encodeURIComponent(a));if(b<0)return!0;this.bufferedAmount+=b;return!1},WebSocket.prototype.close=function(){this.readyState!=WebSocket.CLOSED&&this.readyState!=WebSocket.CLOSING&&(this.readyState=WebSocket.CLOSING,WebSocket.__flash.close(this.__id))},WebSocket.prototype.addEventListener=function(a,b,c){a in this.__events||(this.__events[a]=[]),this.__events[a].push(b)},WebSocket.prototype.removeEventListener=function(a,b,c){if(a in this.__events){var d=this.__events[a];for(var e=d.length-1;e>=0;--e)if(d[e]===b){d.splice(e,1);break}}},WebSocket.prototype.dispatchEvent=function(a){var b=this.__events[a.type]||[];for(var c=0;c<b.length;++c)b[c](a);var d=this["on"+a.type];d&&d(a)},WebSocket.prototype.__handleEvent=function(a){"readyState"in a&&(this.readyState=a.readyState),"protocol"in a&&(this.protocol=a.protocol);var b;if(a.type=="open"||a.type=="error")b=this.__createSimpleEvent(a.type);else if(a.type=="close")b=this.__createSimpleEvent("close");else{if(a.type!="message")throw"unknown event type: "+a.type;var c=decodeURIComponent(a.message);b=this.__createMessageEvent("message",c)}this.dispatchEvent(b)},WebSocket.prototype.__createSimpleEvent=function(a){if(document.createEvent&&window.Event){var b=document.createEvent("Event");b.initEvent(a,!1,!1);return b}return{type:a,bubbles:!1,cancelable:!1}},WebSocket.prototype.__createMessageEvent=function(a,b){if(document.createEvent&&window.MessageEvent&&!window.opera){var c=document.createEvent("MessageEvent");c.initMessageEvent("message",!1,!1,b,null,null,window,null);return c}return{type:a,data:b,bubbles:!1,cancelable:!1}},WebSocket.CONNECTING=0,WebSocket.OPEN=1,WebSocket.CLOSING=2,WebSocket.CLOSED=3,WebSocket.__flash=null,WebSocket.__instances={},WebSocket.__tasks=[],WebSocket.__nextId=0,WebSocket.loadFlashPolicyFile=function(a){WebSocket.__addTask(function(){WebSocket.__flash.loadManualPolicyFile(a)})},WebSocket.__initialize=function(){if(!WebSocket.__flash){WebSocket.__swfLocation&&(window.WEB_SOCKET_SWF_LOCATION=WebSocket.__swfLocation);if(!window.WEB_SOCKET_SWF_LOCATION){a.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");return}var b=document.createElement("div");b.id="webSocketContainer",b.style.position="absolute",WebSocket.__isFlashLite()?(b.style.left="0px",b.style.top="0px"):(b.style.left="-100px",b.style.top="-100px");var c=document.createElement("div");c.id="webSocketFlash",b.appendChild(c),document.body.appendChild(b),swfobject.embedSWF(WEB_SOCKET_SWF_LOCATION,"webSocketFlash","1","1","10.0.0",null,null,{hasPriority:!0,swliveconnect:!0,allowScriptAccess:"always"},null,function(b){b.success||a.error("[WebSocket] swfobject.embedSWF failed")})}},WebSocket.__onFlashInitialized=function(){setTimeout(function(){WebSocket.__flash=document.getElementById("webSocketFlash"),WebSocket.__flash.setCallerUrl(location.href),WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);for(var a=0;a<WebSocket.__tasks.length;++a)WebSocket.__tasks[a]();WebSocket.__tasks=[]},0)},WebSocket.__onFlashEvent=function(){setTimeout(function(){try{var b=WebSocket.__flash.receiveEvents();for(var c=0;c<b.length;++c)WebSocket.__instances[b[c].webSocketId].__handleEvent(b[c])}catch(d){a.error(d)}},0);return!0},WebSocket.__log=function(b){a.log(decodeURIComponent(b))},WebSocket.__error=function(b){a.error(decodeURIComponent(b))},WebSocket.__addTask=function(a){WebSocket.__flash?a():WebSocket.__tasks.push(a)},WebSocket.__isFlashLite=function(){if(!window.navigator||!window.navigator.mimeTypes)return!1;var a=window.navigator.mimeTypes["application/x-shockwave-flash"];if(!a||!a.enabledPlugin||!a.enabledPlugin.filename)return!1;return a.enabledPlugin.filename.match(/flashlite/i)?!0:!1},window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION||(window.addEventListener?window.addEventListener("load",function(){WebSocket.__initialize()},!1):window.attachEvent("onload",function(){WebSocket.__initialize()}))}})(),function(a,b){function d(){}function c(a){!a||(b.Transport.apply(this,arguments),this.sendBuffer=[])}a.XHR=c,b.util.inherit(c,b.Transport),c.prototype.open=function(){this.socket.setBuffer(!1),this.onOpen(),this.get(),this.setCloseTimeout();return this},c.prototype.payload=function(a){var c=[];for(var d=0,e=a.length;d<e;d++)c.push(b.parser.encodePacket(a[d]));this.send(b.parser.encodePayload(c))},c.prototype.send=function(a){this.post(a);return this},c.prototype.post=function(a){function e(){this.onload=d,b.socket.setBuffer(!1)}function c(){this.readyState==4&&(this.onreadystatechange=d,b.posting=!1,this.status==200?b.socket.setBuffer(!1):b.onClose())}var b=this;this.socket.setBuffer(!0),this.sendXHR=this.request("POST"),window.XDomainRequest&&this.sendXHR instanceof XDomainRequest?this.sendXHR.onload=this.sendXHR.onerror=e:this.sendXHR.onreadystatechange=c,this.sendXHR.send(a)},c.prototype.close=function(){this.onClose();return this},c.prototype.request=function(a){var c=b.util.request(this.socket.isXDomain());c.open(a||"GET",this.prepareUrl()+"?t"+ +(new Date));if(a=="POST")try{c.setRequestHeader?c.setRequestHeader("Content-type","text/plain;charset=UTF-8"):c.contentType="text/plain"}catch(d){}return c},c.prototype.scheme=function(){return this.socket.options.secure?"https":"http"},c.check=function(a,c){try{if(b.util.request(c))return!0}catch(d){}return!1},c.xdomainCheck=function(){return c.check(null,!0)}}("undefined"!=typeof io?io.Transport:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(a,b){function c(a){b.Transport.XHR.apply(this,arguments)}a.htmlfile=c,b.util.inherit(c,b.Transport.XHR),c.prototype.name="htmlfile",c.prototype.get=function(){this.doc=new ActiveXObject("htmlfile"),this.doc.open(),this.doc.write("<html></html>"),this.doc.close(),this.doc.parentWindow.s=this;var a=this.doc.createElement("div");a.className="socketio",this.doc.body.appendChild(a),this.iframe=this.doc.createElement("iframe"),a.appendChild(this.iframe),this.iframe.src=this.prepareUrl()+"/?t="+ +(new Date);var c=this;b.util.on(window,"unload",function(){c.destroy()})},c.prototype._=function(a,b){this.onData(a);try{var c=b.getElementsByTagName("script")[0];c.parentNode.removeChild(c)}catch(d){}},c.prototype.destroy=function(){if(this.iframe){try{this.iframe.src="about:blank"}catch(a){}this.doc=null,this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,CollectGarbage()}},c.prototype.close=function(){this.destroy();return b.Transport.XHR.prototype.close.call(this)},c.check=function(){if("ActiveXObject"in window)try{var a=new ActiveXObject("htmlfile");return a&&b.Transport.XHR.check()}catch(c){}return!1},c.xdomainCheck=function(){return!1},b.transports.push("htmlfile")}("undefined"!=typeof io?io.Transport:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(a,b){function d(){}function c(){b.Transport.XHR.apply(this,arguments)}a["xhr-polling"]=c,b.util.inherit(c,b.Transport.XHR),c.prototype.name="xhr-polling",c.prototype.open=function(){var a=this;b.util.defer(function(){b.Transport.XHR.prototype.open.call(a)});return!1},c.prototype.get=function(){function c(){this.onload=d,a.onData(this.responseText),a.get()}function b(){this.readyState==4&&(this.onreadystatechange=d,this.status==200?(a.onData(this.responseText),a.get()):a.onClose())}if(!!this.open){var a=this;this.xhr=this.request(),window.XDomainRequest&&this.xhr instanceof XDomainRequest?this.xhr.onload=this.xhr.onerror=c:this.xhr.onreadystatechange=b,this.xhr.send(null)}},c.prototype.onClose=function(){b.Transport.XHR.prototype.onClose.call(this);if(this.xhr){this.xhr.onreadystatechange=this.xhr.onload=d;try{this.xhr.abort()}catch(a){}this.xhr=null}},b.transports.push("xhr-polling")}("undefined"!=typeof io?io.Transport:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(a,b){function c(a){b.Transport["xhr-polling"].apply(this,arguments),this.index=b.j.length;var c=this;b.j.push(function(a){c._(a)})}a["jsonp-polling"]=c,b.util.inherit(c,b.Transport["xhr-polling"]),c.prototype.name="jsonp-polling",c.prototype.post=function(a){function h(){b.iframe&&b.form.removeChild(b.iframe);try{f=document.createElement('<iframe name="'+b.iframeId+'">')}catch(a){f=document.createElement("iframe"),f.name=b.iframeId}f.id=b.iframeId,b.form.appendChild(f),b.iframe=f}function g(){h(),b.socket.setBuffer(!1)}var b=this;if(!this.form){var c=document.createElement("FORM"),d=document.createElement("TEXTAREA"),e=this.iframeId="socketio_iframe_"+this.index,f;c.className="socketio",c.style.position="absolute",c.style.top="-1000px",c.style.left="-1000px",c.target=e,c.method="POST",d.name="d",c.appendChild(d),document.body.appendChild(c),this.form=c,this.area=d}this.form.action=this.prepareUrl()+"?t="+ +(new Date)+"&i="+this.index,h(),this.area.value=a;try{this.form.submit()}catch(i){}this.iframe.attachEvent?f.onreadystatechange=function(){b.iframe.readyState=="complete"&&g()}:this.iframe.onload=g},c.prototype.get=function(){var a=this,b=document.createElement("SCRIPT");this.script&&(this.script.parentNode.removeChild(this.script),this.script=null),b.async=!0,b.src=this.prepareUrl()+"/?t="+ +(new Date)+"&i="+this.index,b.onerror=function(){a.onClose()};var c=document.getElementsByTagName("script")[0];c.parentNode.insertBefore(b,c),this.script=b},c.prototype._=function(a){this.onData(a),this.open&&this.get();return this},c.check=function(){return!0},c.xdomainCheck=function(){return!0},b.transports.push("jsonp-polling")}("undefined"!=typeof io?io.Transport:module.exports,"undefined"!=typeof io?io:module.parent.exports)
\ No newline at end of file
+/*! Socket.IO.min.js build:0.8.4, production. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */
+(function(a){var b=a;b.version="0.8.4",b.protocol=1,b.transports=[],b.j=[],b.sockets={},b.connect=function(a,c){var d=b.util.parseUri(a),e,f;"undefined"!=typeof document&&(d.protocol=d.protocol||document.location.protocol.slice(0,-1),d.host=d.host||document.domain,d.port=d.port||document.location.port),e=b.util.uniqueUri(d);var g={host:d.host,secure:"https"==d.protocol,port:d.port||("https"==d.protocol?443:80),query:d.query||""};b.util.merge(g,c);if(g["force new connection"]||!b.sockets[e])f=new b.Socket(g);!g["force new connection"]&&f&&(b.sockets[e]=f),f=f||b.sockets[e];return f.of(d.path.length>1?d.path:"")}})("object"==typeof module?module.exports:window.io={}),function(a,b){var c=a.util={},d=/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,e=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];c.parseUri=function(a){var b=d.exec(a||""),c={},f=14;while(f--)c[e[f]]=b[f]||"";return c},c.uniqueUri=function(a){var c=a.protocol,d=a.host,e=a.port;"document"in b?(d=d||document.domain,e=e||(c=="https"&&document.location.protocol!=="https:"?443:document.location.port)):(d=d||"localhost",!e&&c=="https"&&(e=443));return(c||"http")+"://"+d+":"+(e||80)},c.query=function(a,b){var d=c.chunkQuery(a||""),e=[];c.merge(d,c.chunkQuery(b||""));for(var f in d)d.hasOwnProperty(f)&&e.push(f+"="+d[f]);return e.length?"?"+e.join("&"):""},c.chunkQuery=function(a){var b={},c=a.split("&"),d=0,e=c.length,f;for(;d<e;++d)f=c[d].split("="),f[0]&&(b[f[0]]=decodeURIComponent(f[1]));return b};var f=!1;c.load=function(a){if("document"in b&&document.readyState==="complete"||f)return a();c.on(b,"load",a,!1)},c.on=function(a,b,c,d){a.attachEvent?a.attachEvent("on"+b,c):a.addEventListener&&a.addEventListener(b,c,d)},c.request=function(a){if("undefined"!=typeof window){if(a&&window.XDomainRequest)return new XDomainRequest;if(window.XMLHttpRequest&&(!a||c.ua.hasCORS))return new XMLHttpRequest;if(!a)try{return new window.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}return null},"undefined"!=typeof window&&c.load(function(){f=!0}),c.defer=function(a){if(!c.ua.webkit)return a();c.load(function(){setTimeout(a,100)})},c.merge=function g(a,b,d,e){var f=e||[],g=typeof d=="undefined"?2:d,h;for(h in b)b.hasOwnProperty(h)&&c.indexOf(f,h)<0&&(typeof a[h]!="object"||!g?(a[h]=b[h],f.push(b[h])):c.merge(a[h],b[h],g-1,f));return a},c.mixin=function(a,b){c.merge(a.prototype,b.prototype)},c.inherit=function(a,b){function c(){}c.prototype=b.prototype,a.prototype=new c},c.isArray=Array.isArray||function(a){return Object.prototype.toString.call(a)==="[object Array]"},c.intersect=function(a,b){var d=[],e=a.length>b.length?a:b,f=a.length>b.length?b:a;for(var g=0,h=f.length;g<h;g++)~c.indexOf(e,f[g])&&d.push(f[g]);return d},c.indexOf=function(a,b,c){if(Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b,c);for(var d=a.length,c=c<0?c+d<0?0:c+d:c||0;c<d&&a[c]!==b;c++);return d<=c?-1:c},c.toArray=function(a){var b=[];for(var c=0,d=a.length;c<d;c++)b.push(a[c]);return b},c.ua={},c.ua.hasCORS="undefined"!=typeof window&&window.XMLHttpRequest&&function(){try{var a=new XMLHttpRequest}catch(b){return!1}return a.withCredentials!=undefined}(),c.ua.webkit="undefined"!=typeof navigator&&/webkit/i.test(navigator.userAgent)}("undefined"!=typeof window?io:module.exports,this),function(a,b){function c(){}a.EventEmitter=c,c.prototype.on=function(a,c){this.$events||(this.$events={}),this.$events[a]?b.util.isArray(this.$events[a])?this.$events[a].push(c):this.$events[a]=[this.$events[a],c]:this.$events[a]=c;return this},c.prototype.addListener=c.prototype.on,c.prototype.once=function(a,b){function d(){c.removeListener(a,d),b.apply(this,arguments)}var c=this;d.listener=b,this.on(a,d);return this},c.prototype.removeListener=function(a,c){if(this.$events&&this.$events[a]){var d=this.$events[a];if(b.util.isArray(d)){var e=-1;for(var f=0,g=d.length;f<g;f++)if(d[f]===c||d[f].listener&&d[f].listener===c){e=f;break}if(e<0)return this;d.splice(e,1),d.length||delete this.$events[a]}else(d===c||d.listener&&d.listener===c)&&delete this.$events[a]}return this},c.prototype.removeAllListeners=function(a){this.$events&&this.$events[a]&&(this.$events[a]=null);return this},c.prototype.listeners=function(a){this.$events||(this.$events={}),this.$events[a]||(this.$events[a]=[]),b.util.isArray(this.$events[a])||(this.$events[a]=[this.$events[a]]);return this.$events[a]},c.prototype.emit=function(a){if(!this.$events)return!1;var c=this.$events[a];if(!c)return!1;var d=Array.prototype.slice.call(arguments,1);if("function"==typeof c)c.apply(this,d);else{if(!b.util.isArray(c))return!1;var e=c.slice();for(var f=0,g=e.length;f<g;f++)e[f].apply(this,d)}return!0}}("undefined"!=typeof io?io:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(exports,nativeJSON){function str(a,b){var c,d,e,f,g=gap,h,i=b[a];i instanceof Date&&(i=date(a)),typeof rep=="function"&&(i=rep.call(b,a,i));switch(typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";gap+=indent,h=[];if(Object.prototype.toString.apply(i)==="[object Array]"){f=i.length;for(c=0;c<f;c+=1)h[c]=str(c,i)||"null";e=h.length===0?"[]":gap?"[\n"+gap+h.join(",\n"+gap)+"\n"+g+"]":"["+h.join(",")+"]",gap=g;return e}if(rep&&typeof rep=="object"){f=rep.length;for(c=0;c<f;c+=1)typeof rep[c]=="string"&&(d=rep[c],e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e))}else for(d in i)Object.prototype.hasOwnProperty.call(i,d)&&(e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e));e=h.length===0?"{}":gap?"{\n"+gap+h.join(",\n"+gap)+"\n"+g+"}":"{"+h.join(",")+"}",gap=g;return e}}function quote(a){escapable.lastIndex=0;return escapable.test(a)?'"'+a.replace(escapable,function(a){var b=meta[a];return typeof b=="string"?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function date(a,b){return isFinite(a.valueOf())?a.getUTCFullYear()+"-"+f(a.getUTCMonth()+1)+"-"+f(a.getUTCDate())+"T"+f(a.getUTCHours())+":"+f(a.getUTCMinutes())+":"+f(a.getUTCSeconds())+"Z":null}function f(a){return a<10?"0"+a:a}"use strict";if(nativeJSON&&nativeJSON.parse)return exports.JSON={parse:nativeJSON.parse,stringify:nativeJSON.stringify};var JSON=exports.JSON={},cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;JSON.stringify=function(a,b,c){var d;gap="",indent="";if(typeof c=="number")for(d=0;d<c;d+=1)indent+=" ";else typeof c=="string"&&(indent=c);rep=b;if(!b||typeof b=="function"||typeof b=="object"&&typeof b.length=="number")return str("",{"":a});throw new Error("JSON.stringify")},JSON.parse=function(text,reviver){function walk(a,b){var c,d,e=a[b];if(e&&typeof e=="object")for(c in e)Object.prototype.hasOwnProperty.call(e,c)&&(d=walk(e,c),d!==undefined?e[c]=d:delete e[c]);return reviver.call(a,b,e)}var j;text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver=="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}("undefined"!=typeof io?io:module.exports,typeof JSON!="undefined"?JSON:undefined),function(a,b){var c=a.parser={},d=c.packets=["disconnect","connect","heartbeat","message","json","event","ack","error","noop"],e=c.reasons=["transport not supported","client not handshaken","unauthorized"],f=c.advice=["reconnect"],g=b.JSON,h=b.util.indexOf;c.encodePacket=function(a){var b=h(d,a.type),c=a.id||"",i=a.endpoint||"",j=a.ack,k=null;switch(a.type){case"error":var l=a.reason?h(e,a.reason):"",m=a.advice?h(f,a.advice):"";if(l!==""||m!=="")k=l+(m!==""?"+"+m:"");break;case"message":a.data!==""&&(k=a.data);break;case"event":var n={name:a.name};a.args&&a.args.length&&(n.args=a.args),k=g.stringify(n);break;case"json":k=g.stringify(a.data);break;case"connect":a.qs&&(k=a.qs);break;case"ack":k=a.ackId+(a.args&&a.args.length?"+"+g.stringify(a.args):"")}var o=[b,c+(j=="data"?"+":""),i];k!==null&&k!==undefined&&o.push(k);return o.join(":")},c.encodePayload=function(a){var b="";if(a.length==1)return a[0];for(var c=0,d=a.length;c<d;c++){var e=a[c];b+="\ufffd"+e.length+"\ufffd"+a[c]}return b};var i=/([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/;c.decodePacket=function(a){var b=a.match(i);if(!b)return{};var c=b[2]||"",a=b[5]||"",h={type:d[b[1]],endpoint:b[4]||""};c&&(h.id=c,b[3]?h.ack="data":h.ack=!0);switch(h.type){case"error":var b=a.split("+");h.reason=e[b[0]]||"",h.advice=f[b[1]]||"";break;case"message":h.data=a||"";break;case"event":try{var j=g.parse(a);h.name=j.name,h.args=j.args}catch(k){}h.args=h.args||[];break;case"json":try{h.data=g.parse(a)}catch(k){}break;case"connect":h.qs=a||"";break;case"ack":var b=a.match(/^([0-9]+)(\+)?(.*)/);if(b){h.ackId=b[1],h.args=[];if(b[3])try{h.args=b[3]?g.parse(b[3]):[]}catch(k){}}break;case"disconnect":case"heartbeat":}return h},c.decodePayload=function(a){if(a.charAt(0)=="\ufffd"){var b=[];for(var d=1,e="";d<a.length;d++)a.charAt(d)=="\ufffd"?(b.push(c.decodePacket(a.substr(d+1).substr(0,e))),d+=Number(e)+1,e=""):e+=a.charAt(d);return b}return[c.decodePacket(a)]}}("undefined"!=typeof io?io:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(a,b){function c(a,b){this.socket=a,this.sessid=b}a.Transport=c,b.util.mixin(c,b.EventEmitter),c.prototype.onData=function(a){this.clearCloseTimeout(),this.setCloseTimeout();if(a!==""){var c=b.parser.decodePayload(a);if(c&&c.length)for(var d=0,e=c.length;d<e;d++)this.onPacket(c[d])}return this},c.prototype.onPacket=function(a){if(a.type=="heartbeat")return this.onHeartbeat();a.type=="connect"&&a.endpoint==""&&this.onConnect(),this.socket.onPacket(a);return this},c.prototype.setCloseTimeout=function(){if(!this.closeTimeout){var a=this;this.closeTimeout=setTimeout(function(){a.onDisconnect()},this.socket.closeTimeout)}},c.prototype.onDisconnect=function(){this.close&&this.close(),this.clearTimeouts(),this.socket.onDisconnect();return this},c.prototype.onConnect=function(){this.socket.onConnect();return this},c.prototype.clearCloseTimeout=function(){this.closeTimeout&&(clearTimeout(this.closeTimeout),this.closeTimeout=null)},c.prototype.clearTimeouts=function(){this.clearCloseTimeout(),this.reopenTimeout&&clearTimeout(this.reopenTimeout)},c.prototype.packet=function(a){this.send(b.parser.encodePacket(a))},c.prototype.onHeartbeat=function(a){this.packet({type:"heartbeat"})},c.prototype.onOpen=function(){this.open=!0,this.clearCloseTimeout(),this.socket.onOpen()},c.prototype.onClose=function(){var a=this;this.open=!1,this.setCloseTimeout(),this.socket.onClose()},c.prototype.prepareUrl=function(){var a=this.socket.options;return this.scheme()+"://"+a.host+":"+a.port+"/"+a.resource+"/"+b.protocol+"/"+this.name+"/"+this.sessid},c.prototype.ready=function(a,b){b.call(this)}}("undefined"!=typeof io?io:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(a,b,c){function e(){}function d(a){this.options={port:80,secure:!1,document:"document"in c?document:!1,resource:"socket.io",transports:b.transports,"connect timeout":1e4,"try multiple transports":!0,reconnect:!0,"reconnection delay":500,"reconnection limit":Infinity,"reopen delay":3e3,"max reconnection attempts":10,"sync disconnect on unload":!0,"auto connect":!0,"flash policy port":10843},b.util.merge(this.options,a),this.connected=!1,this.open=!1,this.connecting=!1,this.reconnecting=!1,this.namespaces={},this.buffer=[],this.doBuffer=!1;if(this.options["sync disconnect on unload"]&&(!this.isXDomain()||b.util.ua.hasCORS)){var d=this;b.util.on(c,"beforeunload",function(){d.disconnectSync()},!1)}this.options["auto connect"]&&this.connect()}a.Socket=d,b.util.mixin(d,b.EventEmitter),d.prototype.of=function(a){this.namespaces[a]||(this.namespaces[a]=new b.SocketNamespace(this,a),a!==""&&this.namespaces[a].packet({type:"connect"}));return this.namespaces[a]},d.prototype.publish=function(){this.emit.apply(this,arguments);var a;for(var b in this.namespaces)this.namespaces.hasOwnProperty(b)&&(a=this.of(b),a.$emit.apply(a,arguments))},d.prototype.handshake=function(a){function f(b){b instanceof Error?c.onError(b.message):a.apply(null,b.split(":"))}var c=this,d=this.options,g=["http"+(d.secure?"s":"")+":/",d.host+":"+d.port,this.options.resource,b.protocol,b.util.query(this.options.query,"t="+ +(new Date))].join("/");if(this.isXDomain()){var h=document.getElementsByTagName("script")[0],i=document.createElement("script");i.src=g+"&jsonp="+b.j.length,h.parentNode.insertBefore(i,h),b.j.push(function(a){f(a),i.parentNode.removeChild(i)})}else{var j=b.util.request();j.open("GET",g,!0),j.onreadystatechange=function(){j.readyState==4&&(j.onreadystatechange=e,j.status==200?f(j.responseText):!c.reconnecting&&c.onError(j.responseText))},j.send(null)}},d.prototype.getTransport=function(a){var c=a||this.transports,d;for(var e=0,f;f=c[e];e++)if(b.Transport[f]&&b.Transport[f].check(this)&&(!this.isXDomain()||b.Transport[f].xdomainCheck()))return new b.Transport[f](this,this.sessionid);return null},d.prototype.connect=function(a){if(this.connecting)return this;var c=this;this.handshake(function(d,e,f,g){function h(a){c.transport&&c.transport.clearTimeouts(),c.transport=c.getTransport(a);if(!c.transport)return c.publish("connect_failed");c.transport.ready(c,function(){c.connecting=!0,c.publish("connecting",c.transport.name),c.transport.open(),c.options["connect timeout"]&&(c.connectTimeoutTimer=setTimeout(function(){if(!c.connected){c.connecting=!1;if(c.options["try multiple transports"]){c.remainingTransports||(c.remainingTransports=c.transports.slice(0));var a=c.remainingTransports;while(a.length>0&&a.splice(0,1)[0]!=c.transport.name);a.length?h(a):c.publish("connect_failed")}}},c.options["connect timeout"]))})}c.sessionid=d,c.closeTimeout=f*1e3,c.heartbeatTimeout=e*1e3,c.transports=b.util.intersect(g.split(","),c.options.transports),h(),c.once("connect",function(){clearTimeout(c.connectTimeoutTimer),a&&typeof a=="function"&&a()})});return this},d.prototype.packet=function(a){this.connected&&!this.doBuffer?this.transport.packet(a):this.buffer.push(a);return this},d.prototype.setBuffer=function(a){this.doBuffer=a,!a&&this.connected&&this.buffer.length&&(this.transport.payload(this.buffer),this.buffer=[])},d.prototype.disconnect=function(){this.connected&&(this.open&&this.of("").packet({type:"disconnect"}),this.onDisconnect("booted"));return this},d.prototype.disconnectSync=function(){var a=b.util.request(),c=this.resource+"/"+b.protocol+"/"+this.sessionid;a.open("GET",c,!0),this.onDisconnect("booted")},d.prototype.isXDomain=function(){var a=window.location.port||("https:"==window.location.protocol?443:80);return this.options.host!==document.domain||this.options.port!=a},d.prototype.onConnect=function(){this.connected||(this.connected=!0,this.connecting=!1,this.doBuffer||this.setBuffer(!1),this.emit("connect"))},d.prototype.onOpen=function(){this.open=!0},d.prototype.onClose=function(){this.open=!1},d.prototype.onPacket=function(a){this.of(a.endpoint).onPacket(a)},d.prototype.onError=function(a){a&&a.advice&&a.advice==="reconnect"&&this.connected&&(this.disconnect(),this.reconnect()),this.publish("error",a&&a.reason?a.reason:a)},d.prototype.onDisconnect=function(a){var b=this.connected;this.connected=!1,this.connecting=!1,this.open=!1,b&&(this.transport.close(),this.transport.clearTimeouts(),this.publish("disconnect",a),"booted"!=a&&this.options.reconnect&&!this.reconnecting&&this.reconnect())},d.prototype.reconnect=function(){function f(){if(!!a.reconnecting){if(a.connected)return e();if(a.connecting&&a.reconnecting)return a.reconnectionTimer=setTimeout(f,1e3);a.reconnectionAttempts++>=b?a.redoTransports?(a.publish("reconnect_failed"),e()):(a.on("connect_failed",f),a.options["try multiple transports"]=!0,a.transport=a.getTransport(),a.redoTransports=!0,a.connect()):(a.reconnectionDelay<d&&(a.reconnectionDelay*=2),a.connect(),a.publish("reconnecting",a.reconnectionDelay,a.reconnectionAttempts),a.reconnectionTimer=setTimeout(f,a.reconnectionDelay))}}function e(){if(a.connected){for(var b in a.namespaces)a.namespaces.hasOwnProperty(b)&&""!==b&&a.namespaces[b].packet({type:"connect"});a.publish("reconnect",a.transport.name,a.reconnectionAttempts)}a.removeListener("connect_failed",f),a.removeListener("connect",f),a.reconnecting=!1,delete a.reconnectionAttempts,delete a.reconnectionDelay,delete a.reconnectionTimer,delete a.redoTransports,a.options["try multiple transports"]=c}this.reconnecting=!0,this.reconnectionAttempts=0,this.reconnectionDelay=this.options["reconnection delay"];var a=this,b=this.options["max reconnection attempts"],c=this.options["try multiple transports"],d=this.options["reconnection limit"];this.options["try multiple transports"]=!1,this.reconnectionTimer=setTimeout(f,this.reconnectionDelay),this.on("connect",f)}}("undefined"!=typeof io?io:module.exports,"undefined"!=typeof io?io:module.parent.exports,this),function(a,b){function d(a,b){this.namespace=a,this.name=b}function c(a,b){this.socket=a,this.name=b||"",this.flags={},this.json=new d(this,"json"),this.ackPackets=0,this.acks={}}a.SocketNamespace=c,b.util.mixin(c,b.EventEmitter),c.prototype.$emit=b.EventEmitter.prototype.emit,c.prototype.of=function(){return this.socket.of.apply(this.socket,arguments)},c.prototype.packet=function(a){a.endpoint=this.name,this.socket.packet(a),this.flags={};return this},c.prototype.send=function(a,b){var c={type:this.flags.json?"json":"message",data:a};"function"==typeof b&&(c.id=++this.ackPackets,c.ack=!0,this.acks[c.id]=b);return this.packet(c)},c.prototype.emit=function(a){var b=Array.prototype.slice.call(arguments,1),c=b[b.length-1],d={type:"event",name:a};"function"==typeof c&&(d.id=++this.ackPackets,d.ack="data",this.acks[d.id]=c,b=b.slice(0,b.length-1)),d.args=b;return this.packet(d)},c.prototype.disconnect=function(){this.name===""?this.socket.disconnect():(this.packet({type:"disconnect"}),this.$emit("disconnect"));return this},c.prototype.onPacket=function(a){function d(){c.packet({type:"ack",args:b.util.toArray(arguments),ackId:a.id})}var c=this;switch(a.type){case"connect":this.$emit("connect");break;case"disconnect":this.name===""?this.socket.onDisconnect(a.reason||"booted"):this.$emit("disconnect",a.reason);break;case"message":case"json":var e=["message",a.data];a.ack=="data"?e.push(d):a.ack&&this.packet({type:"ack",ackId:a.id}),this.$emit.apply(this,e);break;case"event":var e=[a.name].concat(a.args);a.ack=="data"&&e.push(d),this.$emit.apply(this,e);break;case"ack":this.acks[a.ackId]&&(this.acks[a.ackId].apply(this,a.args),delete this.acks[a.ackId]);break;case"error":a.advice?this.socket.onError(a):a.reason=="unauthorized"?this.$emit("connect_failed",a.reason):this.$emit("error",a.reason)}},d.prototype.send=function(){this.namespace.flags[this.name]=!0,this.namespace.send.apply(this.namespace,arguments)},d.prototype.emit=function(){this.namespace.flags[this.name]=!0,this.namespace.emit.apply(this.namespace,arguments)}}("undefined"!=typeof io?io:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(a,b){function c(a){b.Transport.apply(this,arguments)}a.websocket=c,b.util.inherit(c,b.Transport),c.prototype.name="websocket",c.prototype.open=function(){var a=b.util.query(this.socket.options.query),c=this,d;d||(d=window.MozWebSocket||window.WebSocket),this.websocket=new d(this.prepareUrl()+a),this.websocket.onopen=function(){c.onOpen(),c.socket.setBuffer(!1)},this.websocket.onmessage=function(a){c.onData(a.data)},this.websocket.onclose=function(){c.onClose(),c.socket.setBuffer(!0)},this.websocket.onerror=function(a){c.onError(a)};return this},c.prototype.send=function(a){this.websocket.send(a);return this},c.prototype.payload=function(a){for(var b=0,c=a.length;b<c;b++)this.packet(a[b]);return this},c.prototype.close=function(){this.websocket.close();return this},c.prototype.onError=function(a){this.socket.onError(a)},c.prototype.scheme=function(){return this.socket.options.secure?"wss":"ws"},c.check=function(){return"WebSocket"in window&&!("__addTask"in WebSocket)||"MozWebSocket"in window},c.xdomainCheck=function(){return!0},b.transports.push("websocket")}("undefined"!=typeof io?io.Transport:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(a,b){function c(){b.Transport.websocket.apply(this,arguments)}a.flashsocket=c,b.util.inherit(c,b.Transport.websocket),c.prototype.name="flashsocket",c.prototype.open=function(){var a=this,c=arguments;WebSocket.__addTask(function(){b.Transport.websocket.prototype.open.apply(a,c)});return this},c.prototype.send=function(){var a=this,c=arguments;WebSocket.__addTask(function(){b.Transport.websocket.prototype.send.apply(a,c)});return this},c.prototype.close=function(){WebSocket.__tasks.length=0,b.Transport.websocket.prototype.close.call(this);return this},c.prototype.ready=function(a,d){function e(){var b=a.options,e=b["flash policy port"],g=["http"+(b.secure?"s":"")+":/",b.host+":"+b.port,b.resource,"static/flashsocket","WebSocketMain"+(a.isXDomain()?"Insecure":"")+".swf"];c.loaded||(typeof WEB_SOCKET_SWF_LOCATION=="undefined"&&(WEB_SOCKET_SWF_LOCATION=g.join("/")),e!==843&&WebSocket.loadFlashPolicyFile("xmlsocket://"+b.host+":"+e),WebSocket.__initialize(),c.loaded=!0),d.call(f)}var f=this;if(document.body)return e();b.util.load(e)},c.check=function(){return typeof WebSocket!="undefined"&&"__initialize"in WebSocket&&!!swfobject?swfobject.getFlashPlayerVersion().major>=10:!1},c.xdomainCheck=function(){return!0},typeof window!="undefined"&&(WEB_SOCKET_DISABLE_AUTO_INITIALIZATION=!0),b.transports.push("flashsocket")}("undefined"!=typeof io?io.Transport:module.exports,"undefined"!=typeof io?io:module.parent.exports);var swfobject=function(){function V(b){var c=/[\\\"<>\.;]/,d=c.exec(b)!=null;return d&&typeof encodeURIComponent!=a?encodeURIComponent(b):b}function U(a,b){if(!!x){var c=b?"visible":"hidden";t&&P(a)?P(a).style.visibility=c:T("#"+a,"visibility:"+c)}}function T(c,d,e,f){if(!y.ie||!y.mac){var g=i.getElementsByTagName("head")[0];if(!g)return;var h=e&&typeof e=="string"?e:"screen";f&&(v=null,w=null);if(!v||w!=h){var j=Q("style");j.setAttribute("type","text/css"),j.setAttribute("media",h),v=g.appendChild(j),y.ie&&y.win&&typeof i.styleSheets!=a&&i.styleSheets.length>0&&(v=i.styleSheets[i.styleSheets.length-1]),w=h}y.ie&&y.win?v&&typeof v.addRule==b&&v.addRule(c,d):v&&typeof i.createTextNode!=a&&v.appendChild(i.createTextNode(c+" {"+d+"}"))}}function S(a){var b=y.pv,c=a.split(".");c[0]=parseInt(c[0],10),c[1]=parseInt(c[1],10)||0,c[2]=parseInt(c[2],10)||0;return b[0]>c[0]||b[0]==c[0]&&b[1]>c[1]||b[0]==c[0]&&b[1]==c[1]&&b[2]>=c[2]?!0:!1}function R(a,b,c){a.attachEvent(b,c),o[o.length]=[a,b,c]}function Q(a){return i.createElement(a)}function P(a){var b=null;try{b=i.getElementById(a)}catch(c){}return b}function O(a){var b=P(a);if(b){for(var c in b)typeof b[c]=="function"&&(b[c]=null);b.parentNode.removeChild(b)}}function N(a){var b=P(a);b&&b.nodeName=="OBJECT"&&(y.ie&&y.win?(b.style.display="none",function(){b.readyState==4?O(a):setTimeout(arguments.callee,10)}()):b.parentNode.removeChild(b))}function M(a,b,c){var d=Q("param");d.setAttribute("name",b),d.setAttribute("value",c),a.appendChild(d)}function L(c,d,f){var g,h=P(f);if(y.wk&&y.wk<312)return g;if(h){typeof c.id==a&&(c.id=f);if(y.ie&&y.win){var i="";for(var j in c)c[j]!=Object.prototype[j]&&(j.toLowerCase()=="data"?d.movie=c[j]:j.toLowerCase()=="styleclass"?i+=' class="'+c[j]+'"':j.toLowerCase()!="classid"&&(i+=" "+j+'="'+c[j]+'"'));var k="";for(var l in d)d[l]!=Object.prototype[l]&&(k+='<param name="'+l+'" value="'+d[l]+'" />');h.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+i+">"+k+"</object>",n[n.length]=c.id,g=P(c.id)}else{var m=Q(b);m.setAttribute("type",e);for(var o in c)c[o]!=Object.prototype[o]&&(o.toLowerCase()=="styleclass"?m.setAttribute("class",c[o]):o.toLowerCase()!="classid"&&m.setAttribute(o,c[o]));for(var p in d)d[p]!=Object.prototype[p]&&p.toLowerCase()!="movie"&&M(m,p,d[p]);h.parentNode.replaceChild(m,h),g=m}}return g}function K(a){var c=Q("div");if(y.win&&y.ie)c.innerHTML=a.innerHTML;else{var d=a.getElementsByTagName(b)[0];if(d){var e=d.childNodes;if(e){var f=e.length;for(var g=0;g<f;g++)(e[g].nodeType!=1||e[g].nodeName!="PARAM")&&e[g].nodeType!=8&&c.appendChild(e[g].cloneNode(!0))}}}return c}function J(a){if(y.ie&&y.win&&a.readyState!=4){var b=Q("div");a.parentNode.insertBefore(b,a),b.parentNode.replaceChild(K(a),b),a.style.display="none",function(){a.readyState==4?a.parentNode.removeChild(a):setTimeout(arguments.callee,10)}()}else a.parentNode.replaceChild(K(a),a)}function I(b,c,d,e){u=!0,r=e||null,s={success:!1,id:d};var g=P(d);if(g){g.nodeName=="OBJECT"?(p=K(g),q=null):(p=g,q=d),b.id=f;if(typeof b.width==a||!/%$/.test(b.width)&&parseInt(b.width,10)<310)b.width="310";if(typeof b.height==a||!/%$/.test(b.height)&&parseInt(b.height,10)<137)b.height="137";i.title=i.title.slice(0,47)+" - Flash Player Installation";var j=y.ie&&y.win?"ActiveX":"PlugIn",k="MMredirectURL="+h.location.toString().replace(/&/g,"%26")+"&MMplayerType="+j+"&MMdoctitle="+i.title;typeof c.flashvars!=a?c.flashvars+="&"+k:c.flashvars=k;if(y.ie&&y.win&&g.readyState!=4){var l=Q("div");d+="SWFObjectNew",l.setAttribute("id",d),g.parentNode.insertBefore(l,g),g.style.display="none",function(){g.readyState==4?g.parentNode.removeChild(g):setTimeout(arguments.callee,10)}()}L(b,c,d)}}function H(){return!u&&S("6.0.65")&&(y.win||y.mac)&&!(y.wk&&y.wk<312)}function G(c){var d=null,e=P(c);if(e&&e.nodeName=="OBJECT")if(typeof e.SetVariable!=a)d=e;else{var f=e.getElementsByTagName(b)[0];f&&(d=f)}return d}function F(){var b=m.length;if(b>0)for(var c=0;c<b;c++){var d=m[c].id,e=m[c].callbackFn,f={success:!1,id:d};if(y.pv[0]>0){var g=P(d);if(g)if(S(m[c].swfVersion)&&!(y.wk&&y.wk<312))U(d,!0),e&&(f.success=!0,f.ref=G(d),e(f));else if(m[c].expressInstall&&H()){var h={};h.data=m[c].expressInstall,h.width=g.getAttribute("width")||"0",h.height=g.getAttribute("height")||"0",g.getAttribute("class")&&(h.styleclass=g.getAttribute("class")),g.getAttribute("align")&&(h.align=g.getAttribute("align"));var i={},j=g.getElementsByTagName("param"),k=j.length;for(var l=0;l<k;l++)j[l].getAttribute("name").toLowerCase()!="movie"&&(i[j[l].getAttribute("name")]=j[l].getAttribute("value"));I(h,i,d,e)}else J(g),e&&e(f)}else{U(d,!0);if(e){var n=G(d);n&&typeof n.SetVariable!=a&&(f.success=!0,f.ref=n),e(f)}}}}function E(){var c=i.getElementsByTagName("body")[0],d=Q(b);d.setAttribute("type",e);var f=c.appendChild(d);if(f){var g=0;(function(){if(typeof f.GetVariable!=a){var b=f.GetVariable("$version");b&&(b=b.split(" ")[1].split(","),y.pv=[parseInt(b[0],10),parseInt(b[1],10),parseInt(b[2],10)])}else if(g<10){g++,setTimeout(arguments.callee,10);return}c.removeChild(d),f=null,F()})()}else F()}function D(){k?E():F()}function C(b){if(typeof h.addEventListener!=a)h.addEventListener("load",b,!1);else if(typeof i.addEventListener!=a)i.addEventListener("load",b,!1);else if(typeof h.attachEvent!=a)R(h,"onload",b);else if(typeof h.onload=="function"){var c=h.onload;h.onload=function(){c(),b()}}else h.onload=b}function B(a){t?a():l[l.length]=a}function A(){if(!t){try{var a=i.getElementsByTagName("body")[0].appendChild(Q("span"));a.parentNode.removeChild(a)}catch(b){return}t=!0;var c=l.length;for(var d=0;d<c;d++)l[d]()}}var a="undefined",b="object",c="Shockwave Flash",d="ShockwaveFlash.ShockwaveFlash",e="application/x-shockwave-flash",f="SWFObjectExprInst",g="onreadystatechange",h=window,i=document,j=navigator,k=!1,l=[D],m=[],n=[],o=[],p,q,r,s,t=!1,u=!1,v,w,x=!0,y=function(){var f=typeof i.getElementById!=a&&typeof i.getElementsByTagName!=a&&typeof i.createElement!=a,g=j.userAgent.toLowerCase(),l=j.platform.toLowerCase(),m=l?/win/.test(l):/win/.test(g),n=l?/mac/.test(l):/mac/.test(g),o=/webkit/.test(g)?parseFloat(g.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):!1,p=!1,q=[0,0,0],r=null;if(typeof j.plugins!=a&&typeof j.plugins[c]==b)r=j.plugins[c].description,r&&(typeof j.mimeTypes==a||!j.mimeTypes[e]||!!j.mimeTypes[e].enabledPlugin)&&(k=!0,p=!1,r=r.replace(/^.*\s+(\S+\s+\S+$)/,"$1"),q[0]=parseInt(r.replace(/^(.*)\..*$/,"$1"),10),q[1]=parseInt(r.replace(/^.*\.(.*)\s.*$/,"$1"),10),q[2]=/[a-zA-Z]/.test(r)?parseInt(r.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0);else if(typeof h.ActiveXObject!=a)try{var s=new ActiveXObject(d);s&&(r=s.GetVariable("$version"),r&&(p=!0,r=r.split(" ")[1].split(","),q=[parseInt(r[0],10),parseInt(r[1],10),parseInt(r[2],10)]))}catch(t){}return{w3:f,pv:q,wk:o,ie:p,win:m,mac:n}}(),z=function(){!y.w3||((typeof i.readyState!=a&&i.readyState=="complete"||typeof i.readyState==a&&(i.getElementsByTagName("body")[0]||i.body))&&A(),t||(typeof i.addEventListener!=a&&i.addEventListener("DOMContentLoaded",A,!1),y.ie&&y.win&&(i.attachEvent(g,function(){i.readyState=="complete"&&(i.detachEvent(g,arguments.callee),A())}),h==top&&function(){if(!t){try{i.documentElement.doScroll("left")}catch(a){setTimeout(arguments.callee,0);return}A()}}()),y.wk&&function(){if(!t){if(!/loaded|complete/.test(i.readyState)){setTimeout(arguments.callee,0);return}A()}}(),C(A)))}(),W=function(){y.ie&&y.win&&window.attachEvent("onunload",function(){var a=o.length;for(var b=0;b<a;b++)o[b][0].detachEvent(o[b][1],o[b][2]);var c=n.length;for(var d=0;d<c;d++)N(n[d]);for(var e in y)y[e]=null;y=null;for(var f in swfobject)swfobject[f]=null;swfobject=null})}();return{registerObject:function(a,b,c,d){if(y.w3&&a&&b){var e={};e.id=a,e.swfVersion=b,e.expressInstall=c,e.callbackFn=d,m[m.length]=e,U(a,!1)}else d&&d({success:!1,id:a})},getObjectById:function(a){if(y.w3)return G(a)},embedSWF:function(c,d,e,f,g,h,i,j,k,l){var m={success:!1,id:d};y.w3&&!(y.wk&&y.wk<312)&&c&&d&&e&&f&&g?(U(d,!1),B(function(){e+="",f+="";var n={};if(k&&typeof k===b)for(var o in k)n[o]=k[o];n.data=c,n.width=e,n.height=f;var p={};if(j&&typeof j===b)for(var q in j)p[q]=j[q];if(i&&typeof i===b)for(var r in i)typeof p.flashvars!=a?p.flashvars+="&"+r+"="+i[r]:p.flashvars=r+"="+i[r];if(S(g)){var s=L(n,p,d);n.id==d&&U(d,!0),m.success=!0,m.ref=s}else{if(h&&H()){n.data=h,I(n,p,d,l);return}U(d,!0)}l&&l(m)})):l&&l(m)},switchOffAutoHideShow:function(){x=!1},ua:y,getFlashPlayerVersion:function(){return{major:y.pv[0],minor:y.pv[1],release:y.pv[2]}},hasFlashPlayerVersion:S,createSWF:function(a,b,c){return y.w3?L(a,b,c):undefined},showExpressInstall:function(a,b,c,d){y.w3&&H()&&I(a,b,c,d)},removeSWF:function(a){y.w3&&N(a)},createCSS:function(a,b,c,d){y.w3&&T(a,b,c,d)},addDomLoadEvent:B,addLoadEvent:C,getQueryParamValue:function(a){var b=i.location.search||i.location.hash;if(b){/\?/.test(b)&&(b=b.split("?")[1]);if(a==null)return V(b);var c=b.split("&");for(var d=0;d<c.length;d++)if(c[d].substring(0,c[d].indexOf("="))==a)return V(c[d].substring(c[d].indexOf("=")+1))}return""},expressInstallCallback:function(){if(u){var a=P(f);a&&p&&(a.parentNode.replaceChild(p,a),q&&(U(q,!0),y.ie&&y.win&&(p.style.display="block")),r&&r(s)),u=!1}}}}();(function(){if(!window.WebSocket){var a=window.console;if(!a||!a.log||!a.error)a={log:function(){},error:function(){}};if(!swfobject.hasFlashPlayerVersion("10.0.0")){a.error("Flash Player >= 10.0.0 is required.");return}location.protocol=="file:"&&a.error("WARNING: web-socket-js doesn't work in file:///... URL unless you set Flash Security Settings properly. Open the page via Web server i.e. http://..."),WebSocket=function(a,b,c,d,e){var f=this;f.__id=WebSocket.__nextId++,WebSocket.__instances[f.__id]=f,f.readyState=WebSocket.CONNECTING,f.bufferedAmount=0,f.__events={},b?typeof b=="string"&&(b=[b]):b=[],setTimeout(function(){WebSocket.__addTask(function(){WebSocket.__flash.create(f.__id,a,b,c||null,d||0,e||null)})},0)},WebSocket.prototype.send=function(a){if(this.readyState==WebSocket.CONNECTING)throw"INVALID_STATE_ERR: Web Socket connection has not been established";var b=WebSocket.__flash.send(this.__id,encodeURIComponent(a));if(b<0)return!0;this.bufferedAmount+=b;return!1},WebSocket.prototype.close=function(){this.readyState!=WebSocket.CLOSED&&this.readyState!=WebSocket.CLOSING&&(this.readyState=WebSocket.CLOSING,WebSocket.__flash.close(this.__id))},WebSocket.prototype.addEventListener=function(a,b,c){a in this.__events||(this.__events[a]=[]),this.__events[a].push(b)},WebSocket.prototype.removeEventListener=function(a,b,c){if(a in this.__events){var d=this.__events[a];for(var e=d.length-1;e>=0;--e)if(d[e]===b){d.splice(e,1);break}}},WebSocket.prototype.dispatchEvent=function(a){var b=this.__events[a.type]||[];for(var c=0;c<b.length;++c)b[c](a);var d=this["on"+a.type];d&&d(a)},WebSocket.prototype.__handleEvent=function(a){"readyState"in a&&(this.readyState=a.readyState),"protocol"in a&&(this.protocol=a.protocol);var b;if(a.type=="open"||a.type=="error")b=this.__createSimpleEvent(a.type);else if(a.type=="close")b=this.__createSimpleEvent("close");else{if(a.type!="message")throw"unknown event type: "+a.type;var c=decodeURIComponent(a.message);b=this.__createMessageEvent("message",c)}this.dispatchEvent(b)},WebSocket.prototype.__createSimpleEvent=function(a){if(document.createEvent&&window.Event){var b=document.createEvent("Event");b.initEvent(a,!1,!1);return b}return{type:a,bubbles:!1,cancelable:!1}},WebSocket.prototype.__createMessageEvent=function(a,b){if(document.createEvent&&window.MessageEvent&&!window.opera){var c=document.createEvent("MessageEvent");c.initMessageEvent("message",!1,!1,b,null,null,window,null);return c}return{type:a,data:b,bubbles:!1,cancelable:!1}},WebSocket.CONNECTING=0,WebSocket.OPEN=1,WebSocket.CLOSING=2,WebSocket.CLOSED=3,WebSocket.__flash=null,WebSocket.__instances={},WebSocket.__tasks=[],WebSocket.__nextId=0,WebSocket.loadFlashPolicyFile=function(a){WebSocket.__addTask(function(){WebSocket.__flash.loadManualPolicyFile(a)})},WebSocket.__initialize=function(){if(!WebSocket.__flash){WebSocket.__swfLocation&&(window.WEB_SOCKET_SWF_LOCATION=WebSocket.__swfLocation);if(!window.WEB_SOCKET_SWF_LOCATION){a.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");return}var b=document.createElement("div");b.id="webSocketContainer",b.style.position="absolute",WebSocket.__isFlashLite()?(b.style.left="0px",b.style.top="0px"):(b.style.left="-100px",b.style.top="-100px");var c=document.createElement("div");c.id="webSocketFlash",b.appendChild(c),document.body.appendChild(b),swfobject.embedSWF(WEB_SOCKET_SWF_LOCATION,"webSocketFlash","1","1","10.0.0",null,null,{hasPriority:!0,swliveconnect:!0,allowScriptAccess:"always"},null,function(b){b.success||a.error("[WebSocket] swfobject.embedSWF failed")})}},WebSocket.__onFlashInitialized=function(){setTimeout(function(){WebSocket.__flash=document.getElementById("webSocketFlash"),WebSocket.__flash.setCallerUrl(location.href),WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);for(var a=0;a<WebSocket.__tasks.length;++a)WebSocket.__tasks[a]();WebSocket.__tasks=[]},0)},WebSocket.__onFlashEvent=function(){setTimeout(function(){try{var b=WebSocket.__flash.receiveEvents();for(var c=0;c<b.length;++c)WebSocket.__instances[b[c].webSocketId].__handleEvent(b[c])}catch(d){a.error(d)}},0);return!0},WebSocket.__log=function(b){a.log(decodeURIComponent(b))},WebSocket.__error=function(b){a.error(decodeURIComponent(b))},WebSocket.__addTask=function(a){WebSocket.__flash?a():WebSocket.__tasks.push(a)},WebSocket.__isFlashLite=function(){if(!window.navigator||!window.navigator.mimeTypes)return!1;var a=window.navigator.mimeTypes["application/x-shockwave-flash"];return!a||!a.enabledPlugin||!a.enabledPlugin.filename?!1:a.enabledPlugin.filename.match(/flashlite/i)?!0:!1},window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION||(window.addEventListener?window.addEventListener("load",function(){WebSocket.__initialize()},!1):window.attachEvent("onload",function(){WebSocket.__initialize()}))}})(),function(a,b,c){function e(){}function d(a){!a||(b.Transport.apply(this,arguments),this.sendBuffer=[])}a.XHR=d,b.util.inherit(d,b.Transport),d.prototype.open=function(){this.socket.setBuffer(!1),this.onOpen(),this.get(),this.setCloseTimeout();return this},d.prototype.payload=function(a){var c=[];for(var d=0,e=a.length;d<e;d++)c.push(b.parser.encodePacket(a[d]));this.send(b.parser.encodePayload(c))},d.prototype.send=function(a){this.post(a);return this},d.prototype.post=function(a){function f(){this.onload=e,b.socket.setBuffer(!1)}function d(){this.readyState==4&&(this.onreadystatechange=e,b.posting=!1,this.status==200?b.socket.setBuffer(!1):b.onClose())}var b=this;this.socket.setBuffer(!0),this.sendXHR=this.request("POST"),c.XDomainRequest&&this.sendXHR instanceof XDomainRequest?this.sendXHR.onload=this.sendXHR.onerror=f:this.sendXHR.onreadystatechange=d,this.sendXHR.send(a)},d.prototype.close=function(){this.onClose();return this},d.prototype.request=function(a){var c=b.util.request(this.socket.isXDomain()),d=b.util.query(this.socket.options.query,"t="+ +(new Date));c.open(a||"GET",this.prepareUrl()+d,!0);if(a=="POST")try{c.setRequestHeader?c.setRequestHeader("Content-type","text/plain;charset=UTF-8"):c.contentType="text/plain"}catch(e){}return c},d.prototype.scheme=function(){return this.socket.options.secure?"https":"http"},d.check=function(a,c){try{if(b.util.request(c))return!0}catch(d){}return!1},d.xdomainCheck=function(){return d.check(null,!0)}}("undefined"!=typeof io?io.Transport:module.exports,"undefined"!=typeof io?io:module.parent.exports,this),function(a,b){function c(a){b.Transport.XHR.apply(this,arguments)}a.htmlfile=c,b.util.inherit(c,b.Transport.XHR),c.prototype.name="htmlfile",c.prototype.get=function(){this.doc=new ActiveXObject("htmlfile"),this.doc.open(),this.doc.write("<html></html>"),this.doc.close(),this.doc.parentWindow.s=this;var a=this.doc.createElement("div");a.className="socketio",this.doc.body.appendChild(a),this.iframe=this.doc.createElement("iframe"),a.appendChild(this.iframe);var c=this,d=b.util.query(this.socket.options.query,"t="+ +(new Date));this.iframe.src=this.prepareUrl()+d,b.util.on(window,"unload",function(){c.destroy()})},c.prototype._=function(a,b){this.onData(a);try{var c=b.getElementsByTagName("script")[0];c.parentNode.removeChild(c)}catch(d){}},c.prototype.destroy=function(){if(this.iframe){try{this.iframe.src="about:blank"}catch(a){}this.doc=null,this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,CollectGarbage()}},c.prototype.close=function(){this.destroy();return b.Transport.XHR.prototype.close.call(this)},c.check=function(){if("ActiveXObject"in window)try{var a=new ActiveXObject("htmlfile");return a&&b.Transport.XHR.check()}catch(c){}return!1},c.xdomainCheck=function(){return!1},b.transports.push("htmlfile")}("undefined"!=typeof io?io.Transport:module.exports,"undefined"!=typeof io?io:module.parent.exports),function(a,b,c){function e(){}function d(){b.Transport.XHR.apply(this,arguments)}a["xhr-polling"]=d,b.util.inherit(d,b.Transport.XHR),b.util.merge(d,b.Transport.XHR),d.prototype.name="xhr-polling",d.prototype.open=function(){var a=this;b.Transport.XHR.prototype.open.call(a);return!1},d.prototype.get=function(){function d(){this.onload=e,a.onData(this.responseText),a.get()}function b(){this.readyState==4&&(this.onreadystatechange=e,this.status==200?(a.onData(this.responseText),a.get()):a.onClose())}if(!!this.open){var a=this;this.xhr=this.request(),c.XDomainRequest&&this.xhr instanceof XDomainRequest?this.xhr.onload=this.xhr.onerror=d:this.xhr.onreadystatechange=b,this.xhr.send(null)}},d.prototype.onClose=function(){b.Transport.XHR.prototype.onClose.call(this);if(this.xhr){this.xhr.onreadystatechange=this.xhr.onload=e;try{this.xhr.abort()}catch(a){}this.xhr=null}},d.prototype.ready=function(a,c){var d=this;b.util.defer(function(){c.call(d)})},b.transports.push("xhr-polling")}("undefined"!=typeof io?io.Transport:module.exports,"undefined"!=typeof io?io:module.parent.exports,this),function(a,b){function c(a){b.Transport["xhr-polling"].apply(this,arguments),this.index=b.j.length;var c=this;b.j.push(function(a){c._(a)})}a["jsonp-polling"]=c,b.util.inherit(c,b.Transport["xhr-polling"]),c.prototype.name="jsonp-polling",c.prototype.post=function(a){function j(){c.iframe&&c.form.removeChild(c.iframe);try{h=document.createElement('<iframe name="'+c.iframeId+'">')}catch(a){h=document.createElement("iframe"),h.name=c.iframeId}h.id=c.iframeId,c.form.appendChild(h),c.iframe=h}function i(){j(),c.socket.setBuffer(!1)}var c=this,d=b.util.query(this.socket.options.query,"t="+ +(new Date)+"&i="+this.index);if(!this.form){var e=document.createElement("form"),f=document.createElement("textarea"),g=this.iframeId="socketio_iframe_"+this.index,h;e.className="socketio",e.style.position="absolute",e.style.top="-1000px",e.style.left="-1000px",e.target=g,e.method="POST",e.setAttribute("accept-charset","utf-8"),f.name="d",e.appendChild(f),document.body.appendChild(e),this.form=e,this.area=f}this.form.action=this.prepareUrl()+d,j(),this.area.value=a;try{this.form.submit()}catch(k){}this.iframe.attachEvent?h.onreadystatechange=function(){c.iframe.readyState=="complete"&&i()}:this.iframe.onload=i,this.socket.setBuffer(!0)},c.prototype.get=function(){var a=this,c=document.createElement("script"),d=b.util.query(this.socket.options.query,"t="+ +(new Date)+"&i="+this.index);this.script&&(this.script.parentNode.removeChild(this.script),this.script=null),c.async=!0,c.src=this.prepareUrl()+d,c.onerror=function(){a.onClose()};var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(c,e),this.script=c},c.prototype._=function(a){this.onData(a),this.open&&this.get();return this},c.check=function(){return!0},c.xdomainCheck=function(){return!0},b.transports.push("jsonp-polling")}("undefined"!=typeof io?io.Transport:module.exports,"undefined"!=typeof io?io:module.parent.exports)
\ No newline at end of file
index 81be4a5c7445dcc621bc090ce3c84a5d9b4bfb8b..100787aad0042e064b09877855b1ea81563abd62 100644 (file)
@@ -21,7 +21,7 @@
    * @api public
    */
 
-  io.version = '0.7.4';
+  io.version = '0.8.4';
 
   /**
    * Protocol implemented.
 
     io.EventEmitter = process.EventEmitter;
 
+    /**
+     * Expose SocketNamespace
+     *
+     * @api private
+     */
+
+     io.SocketNamespace = require('./namespace').SocketNamespace;
+
     /**
      * Expose Transport
      *
 
     io.Transport = require('./transport').Transport;
 
+    /**
+     * Default enabled transports
+     *
+     * @api public
+     */
+
+    io.transports = ['websocket', 'xhr-polling'];
+
     /**
      * Expose all transports
+     *
+     * @api public
      */
 
+    io.Transport.XHR = require('./transports/xhr').XHR;
+
     io.transports.forEach(function (t) {
-      //io.Transport[t] = require('./transports/node/' + t);
+      io.Transport[t] = require('./transports/' + t)[t];
     });
 
     /**
 
     var options = {
         host: uri.host
-      , secure: uri.protocol == 'https'
-      , port: uri.port || 80
+      , secure: 'https' == uri.protocol
+      , port: uri.port || ('https' == uri.protocol ? 443 : 80)
+      , query: uri.query || ''
     };
+
     io.util.merge(options, details);
 
     if (options['force new connection'] || !io.sockets[uuri]) {
index e937c1500951ff14bdb51bb4d6d7f8cd30aae1ed..62308cf52aebe7d8a0661215de6b5a3fe858c606 100644 (file)
     switch (packet.type) {
       case 'error':
         var reason = packet.reason ? indexOf(reasons, packet.reason) : ''
-          , adv = packet.advice ? indexOf(advice, packet.advice) : ''
+          , adv = packet.advice ? indexOf(advice, packet.advice) : '';
 
         if (reason !== '' || adv !== '')
-          data = reason + (adv !== '' ? ('+' + adv) : '')
+          data = reason + (adv !== '' ? ('+' + adv) : '');
 
         break;
 
 
     for (var i = 0, l = packets.length; i < l; i++) {
       var packet = packets[i];
-      decoded += '\ufffd' + packet.length + '\ufffd' + packets[i]
+      decoded += '\ufffd' + packet.length + '\ufffd' + packets[i];
     }
 
     return decoded;
    * @api private
    */
 
-  var regexp = /^([^:]+):([0-9]+)?(\+)?:([^:]+)?:?(.*)?$/;
+  var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/;
 
   parser.decodePacket = function (data) {
     var pieces = data.match(regexp);
index 3a6fde6806330cbfd59ba01753cf82c39be2681c..8f770c1013d02ccfb1a546f3da6ec0524bc083d7 100644 (file)
@@ -5,7 +5,7 @@
  * MIT Licensed
  */
 
-(function (exports, io) {
+(function (exports, io, global) {
 
   /**
    * Expose constructor.
@@ -14,7 +14,7 @@
   exports.Socket = Socket;
 
   /**
-   * Create a new `Socket.IO client` which can establish a persisent
+   * Create a new `Socket.IO client` which can establish a persistent
    * connection with a Socket.IO enabled server.
    *
    * @api public
     this.options = {
         port: 80
       , secure: false
-      , document: document
+      , document: 'document' in global ? document : false
       , resource: 'socket.io'
       , transports: io.transports
       , 'connect timeout': 10000
       , 'try multiple transports': true
       , 'reconnect': true
       , 'reconnection delay': 500
+      , 'reconnection limit': Infinity
       , 'reopen delay': 3000
       , 'max reconnection attempts': 10
       , 'sync disconnect on unload': true
       , 'auto connect': true
+      , 'flash policy port': 10843
     };
 
     io.util.merge(this.options, options);
@@ -51,7 +53,7 @@
         (!this.isXDomain() || io.util.ua.hasCORS)) {
       var self = this;
 
-      io.util.on(window, 'beforeunload', function () {
+      io.util.on(global, 'beforeunload', function () {
         self.disconnectSync();
       }, false);
     }
         , options.host + ':' + options.port
         , this.options.resource
         , io.protocol
-        , '?t=' + + new Date
+        , io.util.query(this.options.query, 't=' + +new Date)
       ].join('/');
 
     if (this.isXDomain()) {
       var insertAt = document.getElementsByTagName('script')[0]
-        , script = document.createElement('SCRIPT');
+        , script = document.createElement('script');
 
       script.src = url + '&jsonp=' + io.j.length;
       insertAt.parentNode.insertBefore(script, insertAt);
     } else {
       var xhr = io.util.request();
 
-      xhr.open('GET', url);
+      xhr.open('GET', url, true);
       xhr.onreadystatechange = function () {
         if (xhr.readyState == 4) {
           xhr.onreadystatechange = empty;
       );
 
       function connect (transports){
+        if (self.transport) self.transport.clearTimeouts();
+
         self.transport = self.getTransport(transports);
         if (!self.transport) return self.publish('connect_failed');
 
-        self.connecting = true;
-        self.publish('connecting', self.transport.name);
-        self.transport.open();
+        // once the transport is ready
+        self.transport.ready(self, function () {
+          self.connecting = true;
+          self.publish('connecting', self.transport.name);
+          self.transport.open();
 
-        if (self.options['connect timeout']) {
-          self.connectTimeoutTimer = setTimeout(function () {
-            if (!self.connected) {
-              self.connecting = false;
+          if (self.options['connect timeout']) {
+            self.connectTimeoutTimer = setTimeout(function () {
+              if (!self.connected) {
+                self.connecting = false;
 
-              if (self.options['try multiple transports']) {
-                if (!self.remainingTransports) {
-                  self.remainingTransports = self.transports.slice(0);
-                }
+                if (self.options['try multiple transports']) {
+                  if (!self.remainingTransports) {
+                    self.remainingTransports = self.transports.slice(0);
+                  }
 
-                var remaining = self.remainingTransports;
+                  var remaining = self.remainingTransports;
 
-                while (remaining.length > 0 && remaining.splice(0,1)[0] !=
-                  self.transport.name) {}
+                  while (remaining.length > 0 && remaining.splice(0,1)[0] !=
+                         self.transport.name) {}
 
-                if (remaining.length){
-                  connect(remaining);
-                } else {
-                  self.publish('connect_failed');
+                    if (remaining.length){
+                      connect(remaining);
+                    } else {
+                      self.publish('connect_failed');
+                    }
                 }
               }
-            }
-          }, self.options['connect timeout']);
-        }
+            }, self.options['connect timeout']);
+          }
+        });
       }
 
       connect();
    */
 
   Socket.prototype.isXDomain = function () {
-    var locPort = window.location.port || 80;
-    return this.options.host !== document.domain || this.options.port != locPort;
+    // if node
+    return false;
+    // end node
+
+    var port = window.location.port ||
+      ('https:' == window.location.protocol ? 443 : 80);
+
+    return this.options.host !== document.domain || this.options.port != port;
   };
 
   /**
    */
 
   Socket.prototype.onConnect = function () {
-    this.connected = true;
-    this.connecting = false;
-    if (!this.doBuffer) {
-      // make sure to flush the buffer
-      this.setBuffer(false);
+    if (!this.connected) {
+      this.connected = true;
+      this.connecting = false;
+      if (!this.doBuffer) {
+        // make sure to flush the buffer
+        this.setBuffer(false);
+      }
+      this.emit('connect');
     }
-    this.emit('connect');
   };
 
   /**
     var self = this
       , maxAttempts = this.options['max reconnection attempts']
       , tryMultiple = this.options['try multiple transports']
+      , limit = this.options['reconnection limit'];
 
     function reset () {
       if (self.connected) {
+        for (var i in self.namespaces) {
+          if (self.namespaces.hasOwnProperty(i) && '' !== i) {
+              self.namespaces[i].packet({ type: 'connect' });
+          }
+        }
         self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
       }
 
           reset();
         }
       } else {
-        self.reconnectionDelay *= 2; // exponential back off
+        if (self.reconnectionDelay < limit) {
+          self.reconnectionDelay *= 2; // exponential back off
+        }
+
         self.connect();
         self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
         self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
 })(
     'undefined' != typeof io ? io : module.exports
   , 'undefined' != typeof io ? io : module.parent.exports
+  , this
 );
index b843ab1890d3e97b09adfc045c3b95e839984917..8212839370ca99389c3f9799cecdd24957483abe 100644 (file)
       + options.resource + '/' + io.protocol
       + '/' + this.name + '/' + this.sessid;
   };
+
+  /**
+   * Checks if the transport is ready to start a connection.
+   *
+   * @param {Socket} socket The socket instance that needs a transport
+   * @param {Function} fn The callback
+   * @api private
+   */
+
+  Transport.prototype.ready = function (socket, fn) {
+    fn.call(this);
+  };
 })(
     'undefined' != typeof io ? io : module.exports
   , 'undefined' != typeof io ? io : module.parent.exports
index 2c451f145c6f5e9460c76368c7457622bb577a61..a1c29fac1e185a28eeeb55d6e5bb780eee789c90 100644 (file)
@@ -14,7 +14,7 @@
   exports.flashsocket = Flashsocket;
 
   /**
-   * The Flashsocket transport. This is a API wrapper for the HTML5 WebSocket
+   * The FlashSocket transport. This is a API wrapper for the HTML5 WebSocket
    * specification. It uses a .swf file to communicate with the server. If you want
    * to serve the .swf file from a other server than where the Socket.IO script is
    * coming from you need to use the insecure version of the .swf. More information
@@ -44,8 +44,8 @@
   Flashsocket.prototype.name = 'flashsocket';
 
   /**
-   *Disconnect the established `Flashsocket` connection. This is done by adding a 
-   * new task to the Flashsocket. The rest will be handled off by the `WebSocket` 
+   * Disconnect the established `FlashSocket` connection. This is done by adding a 
+   * new task to the FlashSocket. The rest will be handled off by the `WebSocket` 
    * transport.
    *
    * @returns {Transport}
@@ -53,7 +53,9 @@
    */
 
   Flashsocket.prototype.open = function () {
-    var self = this, args = arguments;
+    var self = this
+      , args = arguments;
+
     WebSocket.__addTask(function () {
       io.Transport.websocket.prototype.open.apply(self, args);
     });
@@ -62,7 +64,7 @@
   
   /**
    * Sends a message to the Socket.IO server. This is done by adding a new
-   * task to the Flashsocket. The rest will be handled off by the `WebSocket` 
+   * task to the FlashSocket. The rest will be handled off by the `WebSocket` 
    * transport.
    *
    * @returns {Transport}
@@ -78,7 +80,7 @@
   };
 
   /**
-   * Disconnects the established `Flashsocket` connection.
+   * Disconnects the established `FlashSocket` connection.
    *
    * @returns {Transport}
    * @api public
   };
 
   /**
-   * Check if the Flashsocket transport is supported as it requires that the Adobe
-   * Flash Player plugin version `10.0.0` or greater is installed. And also check if
+   * The WebSocket fall back needs to append the flash container to the body
+   * element, so we need to make sure we have access to it. Or defer the call
+   * until we are sure there is a body element.
+   *
+   * @param {Socket} socket The socket instance that needs a transport
+   * @param {Function} fn The callback
+   * @api private
+   */
+
+  Flashsocket.prototype.ready = function (socket, fn) {
+    function init () {
+      var options = socket.options
+        , port = options['flash policy port']
+        , path = [
+              'http' + (options.secure ? 's' : '') + ':/'
+            , options.host + ':' + options.port
+            , options.resource
+            , 'static/flashsocket'
+            , 'WebSocketMain' + (socket.isXDomain() ? 'Insecure' : '') + '.swf'
+          ];
+
+      // Only start downloading the swf file when the checked that this browser
+      // actually supports it
+      if (!Flashsocket.loaded) {
+        if (typeof WEB_SOCKET_SWF_LOCATION === 'undefined') {
+          // Set the correct file based on the XDomain settings
+          WEB_SOCKET_SWF_LOCATION = path.join('/');
+        }
+
+        if (port !== 843) {
+          WebSocket.loadFlashPolicyFile('xmlsocket://' + options.host + ':' + port);
+        }
+
+        WebSocket.__initialize();
+        Flashsocket.loaded = true;
+      }
+
+      fn.call(self);
+    }
+
+    var self = this;
+    if (document.body) return init();
+
+    io.util.load(init);
+  };
+
+  /**
+   * Check if the FlashSocket transport is supported as it requires that the Adobe
+   * Flash Player plug-in version `10.0.0` or greater is installed. And also check if
    * the polyfill is correctly loaded.
    *
    * @returns {Boolean}
    * @api public
    */
 
-  Flashsocket.check = function (socket) {
+  Flashsocket.check = function () {
     if (
         typeof WebSocket == 'undefined'
       || !('__initialize' in WebSocket) || !swfobject
     ) return false;
 
-    var supported = swfobject.getFlashPlayerVersion().major >= 10
-      , options = socket.options
-      , path = [
-          'http' + (options.secure ? 's' : '') + ':/'
-        , options.host + ':' + options.port
-        , options.resource
-        , 'static/flashsocket'
-        , 'WebSocketMain' + (socket.isXDomain() ? 'Insecure' : '') + '.swf'
-      ];
-
-    // Only start downloading the swf file when the checked that this browser
-    // actually supports it
-    if (supported && !Flashsocket.loaded) {
-      if (typeof WEB_SOCKET_SWF_LOCATION === 'undefined') {
-        // Set the correct file based on the XDomain settings
-        WEB_SOCKET_SWF_LOCATION = path.join('/');
-      }
-
-      WebSocket.__initialize();
-      Flashsocket.loaded = true;
-    }
-
-    return supported;
+    return swfobject.getFlashPlayerVersion().major >= 10;
   };
 
   /**
-   * Check if the Flashsocket transport can be used as cross domain / cross origin 
+   * Check if the FlashSocket transport can be used as cross domain / cross origin 
    * transport. Because we can't see which type (secure or insecure) of .swf is used
    * we will just return true.
    *
index e47e762d078483d3fc77524212c7be51f3cf890d..57db53dea4741cca5132fb5ea56b89eb955cb38b 100644 (file)
 
     iframeC.appendChild(this.iframe);
 
-    this.iframe.src = this.prepareUrl() + '/?t=' + (+ new Date);
+    var self = this
+      , query = io.util.query(this.socket.options.query, 't='+ +new Date);
 
-    var self = this;
+    this.iframe.src = this.prepareUrl() + query;
 
     io.util.on(window, 'unload', function () {
       self.destroy();
index 782329b4058b8e2a70836d5483ca1ca032372b8e..c69643bddad127b1108de5a1b0f61fbed32a7040 100644 (file)
    */
 
   JSONPPolling.prototype.post = function (data) {
-    var self = this;
+    var self = this
+      , query = io.util.query(
+             this.socket.options.query
+          , 't='+ (+new Date) + '&i=' + this.index
+        );
 
     if (!this.form) {
-      var form = document.createElement('FORM')
-        , area = document.createElement('TEXTAREA')
+      var form = document.createElement('form')
+        , area = document.createElement('textarea')
         , id = this.iframeId = 'socketio_iframe_' + this.index
         , iframe;
 
@@ -75,6 +79,7 @@
       form.style.left = '-1000px';
       form.target = id;
       form.method = 'POST';
+      form.setAttribute('accept-charset', 'utf-8');
       area.name = 'd';
       form.appendChild(area);
       document.body.appendChild(form);
@@ -83,7 +88,7 @@
       this.area = area;
     }
 
-    this.form.action = this.prepareUrl() + '?t=' + (+new Date) + '&i=' + this.index;
+    this.form.action = this.prepareUrl() + query;
 
     function complete () {
       initIframe();
     } else {
       this.iframe.onload = complete;
     }
+
+    this.socket.setBuffer(true);
   };
   
   /**
 
   JSONPPolling.prototype.get = function () {
     var self = this
-      , script = document.createElement('SCRIPT');
+      , script = document.createElement('script')
+      , query = io.util.query(
+             this.socket.options.query
+          , 't='+ (+new Date) + '&i=' + this.index
+        );
 
     if (this.script) {
       this.script.parentNode.removeChild(this.script);
     }
 
     script.async = true;
-    script.src = this.prepareUrl() + '/?t=' + (+new Date) + '&i=' + this.index;
+    script.src = this.prepareUrl() + query;
     script.onerror = function () {
       self.onClose();
     };
index b0314736c9df93d6c40551f023a005b8d8146c99..25c5ac18c06bc174c8f53a114d14f1877ffc271b 100644 (file)
    */
 
   WS.prototype.open = function () {
-    this.websocket = new WebSocket(this.prepareUrl());
+    var query = io.util.query(this.socket.options.query)
+      , self = this
+      , Socket
+
+    // if node
+    Socket = require('websocket-client').WebSocket;
+    // end node
+
+    if (!Socket) {
+      Socket = window.MozWebSocket || window.WebSocket;
+    }
+
+    this.websocket = new Socket(this.prepareUrl() + query);
 
-    var self = this;
     this.websocket.onopen = function () {
       self.onOpen();
       self.socket.setBuffer(false);
    */
 
   WS.check = function () {
-    return 'WebSocket' in window && !('__addTask' in WebSocket);
+    // if node
+    return true;
+    // end node
+    return ('WebSocket' in window && !('__addTask' in WebSocket))
+          || 'MozWebSocket' in window;
   };
 
   /**
index 2cc49fef198905e08f23df9a3ced7d9645a8f201..1677ce82e388cdcb0fdbddc1f81f3488ac8e00cd 100644 (file)
@@ -5,7 +5,7 @@
  * MIT Licensed
  */
 
-(function (exports, io) {
+(function (exports, io, global) {
 
   /**
    * Expose constructor.
 
   io.util.inherit(XHRPolling, io.Transport.XHR);
 
+  /**
+   * Merge the properties from XHR transport
+   */
+
+  io.util.merge(XHRPolling, io.Transport.XHR);
+
   /**
    * Transport name
    *
   XHRPolling.prototype.open = function () {
     var self = this;
 
-    io.util.defer(function () {
-      io.Transport.XHR.prototype.open.call(self);
-    });
-
+    io.Transport.XHR.prototype.open.call(self);
     return false;
   };
 
@@ -91,7 +94,7 @@
 
     this.xhr = this.request();
 
-    if (window.XDomainRequest && this.xhr instanceof XDomainRequest) {
+    if (global.XDomainRequest && this.xhr instanceof XDomainRequest) {
       this.xhr.onload = this.xhr.onerror = onload;
     } else {
       this.xhr.onreadystatechange = stateChange;
     }
   };
 
+  /**
+   * Webkit based browsers show a infinit spinner when you start a XHR request
+   * before the browsers onload event is called so we need to defer opening of
+   * the transport until the onload event is called. Wrapping the cb in our
+   * defer method solve this.
+   *
+   * @param {Socket} socket The socket instance that needs a transport
+   * @param {Function} fn The callback
+   * @api private
+   */
+
+  XHRPolling.prototype.ready = function (socket, fn) {
+    var self = this;
+
+    io.util.defer(function () {
+      fn.call(self);
+    });
+  };
+
   /**
    * Add the transport to your public io.transports array.
    *
 })(
     'undefined' != typeof io ? io.Transport : module.exports
   , 'undefined' != typeof io ? io : module.parent.exports
+  , this
 );
index dbb9e3b6e63ff3bcee2b531d986db853dc1c6889..ad3c9750f6596974f1c2d9eb9e90620c511f8721 100644 (file)
@@ -5,7 +5,7 @@
  * MIT Licensed
  */
 
-(function (exports, io) {
+(function (exports, io, global) {
 
   /**
    * Expose constructor.
 
     this.sendXHR = this.request('POST');
 
-    if (window.XDomainRequest && this.sendXHR instanceof XDomainRequest) {
+    if (global.XDomainRequest && this.sendXHR instanceof XDomainRequest) {
       this.sendXHR.onload = this.sendXHR.onerror = onload;
     } else {
       this.sendXHR.onreadystatechange = stateChange;
    */
 
   XHR.prototype.request = function (method) {
-    var req = io.util.request(this.socket.isXDomain());
-    req.open(method || 'GET', this.prepareUrl() + '?t' + (+ new Date));
+    var req = io.util.request(this.socket.isXDomain())
+      , query = io.util.query(this.socket.options.query, 't=' + +new Date);
+
+    req.open(method || 'GET', this.prepareUrl() + query, true);
 
     if (method == 'POST') {
       try {
 
     return false;
   };
-  
+
   /**
    * Check if the XHR transport supports corss domain requests.
    * 
 })(
     'undefined' != typeof io ? io.Transport : module.exports
   , 'undefined' != typeof io ? io : module.parent.exports
+  , this
 );
index 210e147cb6971f292419b522f610fe2325da05d6..06d66aa0a88579e8293be3fe04aa6acdd36f3d2e 100644 (file)
@@ -5,7 +5,7 @@
  * MIT Licensed
  */
 
-(function (exports) {
+(function (exports, global) {
 
   /**
    * Utilities namespace.
@@ -52,7 +52,7 @@
       , host = uri.host
       , port = uri.port;
 
-    if ('undefined' != typeof document) {
+    if ('document' in global) {
       host = host || document.domain;
       port = port || (protocol == 'https'
         && document.location.protocol !== 'https:' ? 443 : document.location.port);
     return (protocol || 'http') + '://' + host + ':' + (port || 80);
   };
 
+  /**
+   * Mergest 2 query strings in to once unique query string
+   *
+   * @param {String} base
+   * @param {String} addition
+   * @api public
+   */
+
+  util.query = function (base, addition) {
+    var query = util.chunkQuery(base || '')
+      , components = [];
+
+    util.merge(query, util.chunkQuery(addition || ''));
+    for (var part in query) {
+      if (query.hasOwnProperty(part)) {
+        components.push(part + '=' + query[part]);
+      }
+    }
+
+    return components.length ? '?' + components.join('&') : '';
+  };
+
+  /**
+   * Transforms a querystring in to an object
+   *
+   * @param {String} qs
+   * @api public
+   */
+
+  util.chunkQuery = function (qs) {
+    var query = {}
+      , params = qs.split('&')
+      , i = 0
+      , l = params.length
+      , kv;
+
+    for (; i < l; ++i) {
+      kv = params[i].split('=');
+      if (kv[0]) {
+        query[kv[0]] = decodeURIComponent(kv[1]);
+      }
+    }
+
+    return query;
+  };
+
   /**
    * Executes the given function when the page is loaded.
    *
   var pageLoaded = false;
 
   util.load = function (fn) {
-    if (document.readyState === 'complete' || pageLoaded) {
+    if ('document' in global && document.readyState === 'complete' || pageLoaded) {
       return fn();
     }
 
-    util.on(window, 'load', fn, false);
+    util.on(global, 'load', fn, false);
   };
 
   /**
   util.on = function (element, event, fn, capture) {
     if (element.attachEvent) {
       element.attachEvent('on' + event, fn);
-    } else {
+    } else if (element.addEventListener) {
       element.addEventListener(event, fn, capture);
     }
   };
    */
 
   util.request = function (xdomain) {
+    // if node
+    var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
+    return new XMLHttpRequest();
+    // end node
+
     if ('undefined' != typeof window) {
       if (xdomain && window.XDomainRequest) {
         return new XDomainRequest();
-      };
+      }
 
       if (window.XMLHttpRequest && (!xdomain || util.ua.hasCORS)) {
         return new XMLHttpRequest();
-      };
+      }
 
       if (!xdomain) {
         try {
    */
 
   util.inherit = function (ctor, ctor2) {
-    ctor.prototype = new ctor2;
-    util.merge(ctor, ctor2);
+    function f() {};
+    f.prototype = ctor2.prototype;
+    ctor.prototype = new f;
   };
 
   /**
   util.intersect = function (arr, arr2) {
     var ret = []
       , longest = arr.length > arr2.length ? arr : arr2
-      , shortest = arr.length > arr2.length ? arr2 : arr
+      , shortest = arr.length > arr2.length ? arr2 : arr;
 
     for (var i = 0, l = shortest.length; i < l; i++) {
       if (~util.indexOf(longest, shortest[i]))
       return Array.prototype.indexOf.call(arr, o, i);
     }
 
-    for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0
-        ; i < j && arr[i] !== o; i++);
+    for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0
+         i < j && arr[i] !== o; i++);
 
     return j <= i ? -1 : i;
   };
   util.ua.webkit = 'undefined' != typeof navigator
     && /webkit/i.test(navigator.userAgent);
 
-})('undefined' != typeof window ? io : module.exports);
+})(
+    'undefined' != typeof window ? io : module.exports
+  , this
+);
index 294bbba8d1590f52674399f35a12323f30183402..5ebfdf6560e73a6a759fbac468961b072d7b298c 100644 (file)
@@ -1,7 +1,7 @@
 {
     "name": "socket.io-client"
   , "description": "Socket.IO client for the browser and node.js"
-  , "version": "0.7.4"
+  , "version": "0.8.4"
   , "main" : "./lib/io.js"
   , "browserify": "./dist/socket.io.js"
   , "homepage": "http://socket.io"
         { "name": "Guillermo Rauch", "email": "rauchg@gmail.com" }
       , { "name": "Arnout Kazemier", "email": "info@3rd-eden.com" }
       , { "name": "Vladimir Dronnikov", "email": "dronnikov@gmail.com" }
+      , { "name": "Einar Otto Stangvik", "email": "einaros@gmail.com" }
     ]
   , "repository": {
         "type": "git"
-      , "url": "https://github.com/LearnBoost/Socket.IO.git"
+      , "url": "https://github.com/LearnBoost/socket.io-client.git"
     }
   , "dependencies": {
-        "uglify-js": "1.0.3"
+        "uglify-js": "1.0.6"
+      , "websocket-client": "1.0.0"
+      , "xmlhttprequest": "1.2.2"
     }
   , "devDependencies": {
         "expresso": "0.7.7"
       , "express": "2.3.11"
       , "jade": "0.12.1"
       , "stylus": "0.13.3"
-      , "socket.io": "0.7.7"
-      , "socket.io-client": "0.7.4"
+      , "socket.io": "0.8.4"
+      , "socket.io-client": "0.8.4"
     }
   , "engines": { "node": ">= 0.4.0" }
 }
diff --git a/node/node_modules/socket.io-client/support/should.js b/node/node_modules/socket.io-client/support/should.js
new file mode 100644 (file)
index 0000000..2a8fb97
--- /dev/null
@@ -0,0 +1,1238 @@
+
+/**
+ * should.js by TJ Holowaychuk (MIT), adapted to run in browser and node.
+ */
+
+(function (should) {
+
+  if ('undefined' != typeof exports) {
+    module.exports = exports = should = require('assert');
+  }
+
+  /**
+   * Expose constructor.
+   */
+
+  should.Assertion = Assertion;
+
+  /**
+   * Possible assertion flags.
+   */
+
+  var flags = {
+      not: ['be', 'have', 'include']
+    , an: ['instance']
+    , and: ['be', 'have', 'include', 'an']
+    , be: ['an']
+    , have: ['an', 'own']
+    , include: ['an']
+    , not: ['include', 'have', 'be']
+    , own: []
+    , instance: []
+  };
+
+  /**
+   * Extend Object.prototype.
+   */
+
+  if ('object' == typeof process) {
+    Object.defineProperty(
+        Object.prototype
+      , 'should'
+      , {
+            get: function () {
+              var self = this.valueOf()
+                , fn = function () {
+                    return new Assertion(self);
+                  };
+
+              if ('undefined' != typeof exports) {
+                fn.__proto__ = exports;
+                fn.exports = exports;
+              }
+
+              return fn;
+            }
+          , enumerable: false
+        }
+    );
+  } else {
+    Object.prototype.should = function () {
+      return new Assertion(this.valueOf());
+    };
+  }
+
+  /**
+   * Constructor
+   *
+   * @api private
+   */
+
+  function Assertion (obj) {
+    if (obj !== undefined) {
+      this.obj = obj;
+      this.flags = {};
+
+      var $flags = keys(flags);
+
+      for (var i = 0, l = $flags.length; i < l; i++) {
+        this[$flags[i]] = new FlaggedAssertion(this, $flags[i]);
+      }
+    }
+  };
+
+  /**
+   * Performs an assertion
+   *
+   * @api private
+   */
+
+  Assertion.prototype.assert = function (truth, msg, error) {
+    var msg = this.flags.not ? error : msg
+      , ok = this.flags.not ? !truth : truth;
+
+    if (!ok) {
+      throw new Error(msg);
+    }
+
+    this.flags = {};
+  };
+
+  /**
+   * Checks if the value is true
+   *
+   * @api public
+   */
+
+  Assertion.prototype.be_true = function () {
+    this.assert(
+        this.obj === true
+      , 'expected ' + i(this.obj) + ' to be true'
+      , 'expected ' + i(this.obj) + ' to not be true');
+    return this;
+  };
+
+  /**
+   * Checks if the value is true
+   *
+   * @api public
+   */
+
+  Assertion.prototype.be_false = function () {
+    this.assert(
+        this.obj === false
+      , 'expected ' + i(this.obj) + ' to be false'
+      , 'expected ' + i(this.obj) + ' to not be false'
+    );
+    return this;
+  };
+
+  /**
+   * Check if the value is truthy
+   *
+   * @api public
+   */
+
+  Assertion.prototype.ok = function () {
+    this.assert(
+        this.obj == true
+      , 'expected ' + i(this.obj) + ' to be true'
+      , 'expected ' + i(this.obj) + ' to not be true');
+  };
+
+  /**
+   * Checks if the array is empty.
+   *
+   * @api public
+   */
+
+  Assertion.prototype.empty = function () {
+    this.obj.should().have.property('length');
+    this.assert(
+        0 === this.obj.length
+      , 'expected ' + i(this.obj) + ' to be empty'
+      , 'expected ' + i(this.obj) + ' to not be empty');
+    return this;
+  };
+
+  /**
+   * Checks if the obj is arguments.
+   *
+   * @api public
+   */
+
+  Assertion.prototype.arguments = function () {
+    this.assert(
+        '[object Arguments]' == Object.prototype.toString.call(this.obj)
+      , 'expected ' + i(this.obj) + ' to be arguments'
+      , 'expected ' + i(this.obj) + ' to not be arguments');
+    return this;
+  };
+
+  /**
+   * Checks if the obj exactly equals another.
+   *
+   * @api public
+   */
+
+  Assertion.prototype.equal = function (obj) {
+    this.assert(
+        obj === this.obj
+      , 'expected ' + i(this.obj) + ' to equal ' + i(obj)
+      , 'expected ' + i(this.obj) + ' to not equal ' + i(obj));
+    return this;
+  };
+
+  /**
+   * Checks if the obj sortof equals another.
+   *
+   * @api public
+   */
+
+  Assertion.prototype.eql = function (obj) {
+    this.assert(
+        should.eql(obj, this.obj)
+      , 'expected ' + i(this.obj) + ' to sort of equal ' + i(obj)
+      , 'expected ' + i(this.obj) + ' to sort of not equal ' + i(obj));
+    return this;
+  };
+
+  /**
+   * Assert within start to finish (inclusive). 
+   *
+   * @param {Number} start
+   * @param {Number} finish
+   * @api public
+   */
+
+  Assertion.prototype.within = function (start, finish) {
+    var range = start + '..' + finish;
+    this.assert(
+        this.obj >= start && this.obj <= finish
+      , 'expected ' + i(this.obj) + ' to be within ' + range
+      , 'expected ' + i(this.obj) + ' to not be within ' + range);
+    return this;
+  };
+
+  /**
+   * Assert typeof. 
+   *
+   * @api public
+   */
+
+  Assertion.prototype.a = function (type) {
+    this.assert(
+        type == typeof this.obj
+      , 'expected ' + i(this.obj) + ' to be a ' + type
+      , 'expected ' + i(this.obj) + ' not to be a ' + type);
+    return this;
+  };
+
+  /**
+   * Assert instanceof. 
+   *
+   * @api public
+   */
+
+  Assertion.prototype.of = function (constructor) {
+    var name = constructor.name;
+    this.assert(
+        this.obj instanceof constructor
+      , 'expected ' + i(this.obj) + ' to be an instance of ' + name
+      , 'expected ' + i(this.obj) + ' not to be an instance of ' + name);
+    return this;
+  };
+
+  /**
+   * Assert numeric value above _n_.
+   *
+   * @param {Number} n
+   * @api public
+   */
+
+  Assertion.prototype.greaterThan =
+  Assertion.prototype.above = function (n) {
+    this.assert(
+        this.obj > n
+      , 'expected ' + i(this.obj) + ' to be above ' + n
+      , 'expected ' + i(this.obj) + ' to be below ' + n);
+    return this;
+  };
+
+  /**
+   * Assert numeric value below _n_.
+   *
+   * @param {Number} n
+   * @api public
+   */
+
+  Assertion.prototype.lessThan =
+  Assertion.prototype.below = function (n) {
+    this.assert(
+        this.obj < n
+      , 'expected ' + i(this.obj) + ' to be below ' + n
+      , 'expected ' + i(this.obj) + ' to be above ' + n);
+    return this;
+  };
+  
+  /**
+   * Assert string value matches _regexp_.
+   *
+   * @param {RegExp} regexp
+   * @api public
+   */
+
+  Assertion.prototype.match = function (regexp) {
+    this.assert(
+        regexp.exec(this.obj)
+      , 'expected ' + i(this.obj) + ' to match ' + regexp
+      , 'expected ' + i(this.obj) + ' not to match ' + regexp);
+    return this;
+  };
+
+  /**
+   * Assert property "length" exists and has value of _n_.
+   *
+   * @param {Number} n
+   * @api public
+   */
+
+  Assertion.prototype.length = function (n) {
+    this.obj.should().have.property('length');
+    var len = this.obj.length;
+    this.assert(
+        n == len
+      , 'expected ' + i(this.obj) + ' to have a length of ' + n + ' but got ' + len
+      , 'expected ' + i(this.obj) + ' to not have a length of ' + len);
+    return this;
+  };
+
+  /**
+   * Assert substring.
+   *
+   * @param {String} str
+   * @api public
+   */
+
+  Assertion.prototype.string = function(str){
+    this.obj.should().be.a('string');
+    this.assert(
+        ~this.obj.indexOf(str)
+      , 'expected ' + i(this.obj) + ' to include ' + i(str)
+      , 'expected ' + i(this.obj) + ' to not include ' + i(str));
+    return this;
+  };
+
+  /**
+   * Assert inclusion of object.
+   *
+   * @param {Object} obj
+   * @api public
+   */
+
+  Assertion.prototype.object = function(obj){
+    this.obj.should().be.a('object');
+    var included = true;
+    for (var key in obj) {
+      if (obj.hasOwnProperty(key) && !should.eql(obj[key], this.obj[key])) {
+        included = false;
+        break;
+      }
+    }
+    this.assert(
+        included
+      , 'expected ' + i(this.obj) + ' to include ' + i(obj)
+      , 'expected ' + i(this.obj) + ' to not include ' + i(obj));
+    return this;
+  };
+
+  /**
+   * Assert property _name_ exists, with optional _val_.
+   *
+   * @param {String} name
+   * @param {Mixed} val
+   * @api public
+   */
+
+  Assertion.prototype.property = function (name, val) {
+    if (this.flags.own) {
+      this.assert(
+          this.obj.hasOwnProperty(name)
+        , 'expected ' + i(this.obj) + ' to have own property ' + i(name)
+        , 'expected ' + i(this.obj) + ' to not have own property ' + i(name));
+      return this;
+    }
+
+    if (this.flags.not && undefined !== val) {
+      if (undefined === this.obj[name]) {
+        throw new Error(i(this.obj) + ' has no property ' + i(name));
+      }
+    } else {
+      this.assert(
+          undefined !== this.obj[name]
+        , 'expected ' + i(this.obj) + ' to have a property ' + i(name)
+        , 'expected ' + i(this.obj) + ' to not have a property ' + i(name));
+    }
+    
+    if (undefined !== val) {
+      this.assert(
+          val === this.obj[name]
+        , 'expected ' + i(this.obj) + ' to have a property ' + i(name)
+          + ' of ' + i(val) + ', but got ' + i(this.obj[name])
+        , 'expected ' + i(this.obj) + ' to not have a property ' + i(name)
+          + ' of ' + i(val));
+    }
+
+    this.obj = this.obj[name];
+    return this;
+  };
+
+  /**
+   * Assert that the array contains _obj_.
+   *
+   * @param {Mixed} obj
+   * @api public
+   */
+
+  Assertion.prototype.contain = function (obj) {
+    this.obj.should().be.an.instance.of(Array);
+    this.assert(
+        ~indexOf(this.obj, obj)
+      , 'expected ' + i(this.obj) + ' to contain ' + i(obj)
+      , 'expected ' + i(this.obj) + ' to not contain ' + i(obj));
+    return this;
+  };
+
+  /**
+   * Assert exact keys or inclusion of keys by using
+   * the `.include` modifier.
+   *
+   * @param {Array|String ...} keys
+   * @api public
+   */
+
+  Assertion.prototype.key =
+  Assertion.prototype.keys = function (keys) {
+    var str
+      , ok = true;
+
+    keys = keys instanceof Array
+      ? keys
+      : Array.prototype.slice.call(arguments);
+
+    if (!keys.length) throw new Error('keys required');
+
+    var actual = keys(this.obj)
+      , len = keys.length;
+
+    // Inclusion
+    ok = every(keys, function(key){
+      return ~indexOf(actual, key);
+    });
+
+    // Strict
+    if (!this.flags.not && !this.flags.include) {
+      ok = ok && keys.length == actual.length;
+    }
+
+    // Key string
+    if (len > 1) {
+      keys = map(keys, function(key){
+        return i(key);
+      });
+      var last = keys.pop();
+      str = keys.join(', ') + ', and ' + last;
+    } else {
+      str = i(keys[0]);
+    }
+
+    // Form
+    str = (len > 1 ? 'keys ' : 'key ') + str;
+
+    // Have / include
+    str = (this.flag.include ? 'include ' : 'have ') + str;
+
+    // Assertion
+    this.assert(
+        ok
+      , 'expected ' + i(this.obj) + ' to ' + str
+      , 'expected ' + i(this.obj) + ' to not ' + str);
+
+    return this;
+  };
+
+  /**
+   * Assertion with a flag.
+   *
+   * @api private
+   */
+
+  function FlaggedAssertion (parent, flag) {
+    this.parent = parent;
+    this.obj = parent.obj;
+
+    this.flag = flag;
+    this.flags = {};
+    this.flags[flag] = true;
+
+    for (var i in parent.flags) {
+      if (parent.flags.hasOwnProperty(i)) {
+        this.flags[i] = true;
+      }
+    }
+
+    var $flags = flags[flag];
+
+    for (var i = 0, l = $flags.length; i < l; i++) {
+      this[$flags[i]] = new FlaggedAssertion(this, $flags[i]);
+    }
+  };
+
+  /**
+   * Inherits from assertion
+   */
+
+  FlaggedAssertion.prototype = new Assertion;
+
+  /**
+   * Array every compatibility
+   *
+   * @see bit.ly/5Fq1N2
+   * @api public
+   */
+
+  function every (arr, fn, thisObj) {
+    var scope = thisObj || window;
+    for (var i = 0, j = arr.length; i < j; ++i) {
+      if (!fn.call(scope, arr[i], i, arr)) {
+        return false;
+      }
+    }
+    return true;
+  };
+
+  /**
+   * Array indexOf compatibility.
+   *
+   * @see bit.ly/a5Dxa2
+   * @api public
+   */
+
+  function indexOf (arr, o, i) {
+    if (Array.prototype.indexOf) {
+      return Array.prototype.indexOf.call(arr, o, i);
+    }
+
+    for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0
+        ; i < j && arr[i] !== o; i++);
+
+    return j <= i ? -1 : i;
+  };
+
+  /**
+   * Inspects an object.
+   *
+   * @see taken from node.js `util` module (copyright Joyent, MIT license)
+   * @api private
+   */
+
+  function i (obj, showHidden, depth) {
+    var seen = [];
+
+    function stylize (str) {
+      return str;
+    };
+
+    function format (value, recurseTimes) {
+      // Provide a hook for user-specified inspect functions.
+      // Check that value is an object with an inspect function on it
+      if (value && typeof value.inspect === 'function' &&
+          // Filter out the util module, it's inspect function is special
+          value !== exports &&
+          // Also filter out any prototype objects using the circular check.
+          !(value.constructor && value.constructor.prototype === value)) {
+        return value.inspect(recurseTimes);
+      }
+
+      // Primitive types cannot have properties
+      switch (typeof value) {
+        case 'undefined':
+          return stylize('undefined', 'undefined');
+
+        case 'string':
+          var simple = '\'' + json.stringify(value).replace(/^"|"$/g, '')
+                                                   .replace(/'/g, "\\'")
+                                                   .replace(/\\"/g, '"') + '\'';
+          return stylize(simple, 'string');
+
+        case 'number':
+          return stylize('' + value, 'number');
+
+        case 'boolean':
+          return stylize('' + value, 'boolean');
+      }
+      // For some reason typeof null is "object", so special case here.
+      if (value === null) {
+        return stylize('null', 'null');
+      }
+
+      // Look up the keys of the object.
+      var visible_keys = keys(value);
+      var $keys = showHidden ? Object.getOwnPropertyNames(value) : visible_keys;
+
+      // Functions without properties can be shortcutted.
+      if (typeof value === 'function' && $keys.length === 0) {
+        if (isRegExp(value)) {
+          return stylize('' + value, 'regexp');
+        } else {
+          var name = value.name ? ': ' + value.name : '';
+          return stylize('[Function' + name + ']', 'special');
+        }
+      }
+
+      // Dates without properties can be shortcutted
+      if (isDate(value) && $keys.length === 0) {
+        return stylize(value.toUTCString(), 'date');
+      }
+
+      var base, type, braces;
+      // Determine the object type
+      if (isArray(value)) {
+        type = 'Array';
+        braces = ['[', ']'];
+      } else {
+        type = 'Object';
+        braces = ['{', '}'];
+      }
+
+      // Make functions say that they are functions
+      if (typeof value === 'function') {
+        var n = value.name ? ': ' + value.name : '';
+        base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']';
+      } else {
+        base = '';
+      }
+
+      // Make dates with properties first say the date
+      if (isDate(value)) {
+        base = ' ' + value.toUTCString();
+      }
+
+      if ($keys.length === 0) {
+        return braces[0] + base + braces[1];
+      }
+
+      if (recurseTimes < 0) {
+        if (isRegExp(value)) {
+          return stylize('' + value, 'regexp');
+        } else {
+          return stylize('[Object]', 'special');
+        }
+      }
+
+      seen.push(value);
+
+      var output = map($keys, function(key) {
+        var name, str;
+        if (value.__lookupGetter__) {
+          if (value.__lookupGetter__(key)) {
+            if (value.__lookupSetter__(key)) {
+              str = stylize('[Getter/Setter]', 'special');
+            } else {
+              str = stylize('[Getter]', 'special');
+            }
+          } else {
+            if (value.__lookupSetter__(key)) {
+              str = stylize('[Setter]', 'special');
+            }
+          }
+        }
+        if (indexOf(visible_keys, key) < 0) {
+          name = '[' + key + ']';
+        }
+        if (!str) {
+          if (indexOf(seen, value[key]) < 0) {
+            if (recurseTimes === null) {
+              str = format(value[key]);
+            } else {
+              str = format(value[key], recurseTimes - 1);
+            }
+            if (str.indexOf('\n') > -1) {
+              if (isArray(value)) {
+                str = map(str.split('\n'), function(line) {
+                  return '  ' + line;
+                }).join('\n').substr(2);
+              } else {
+                str = '\n' + map(str.split('\n'), function(line) {
+                  return '   ' + line;
+                }).join('\n');
+              }
+            }
+          } else {
+            str = stylize('[Circular]', 'special');
+          }
+        }
+        if (typeof name === 'undefined') {
+          if (type === 'Array' && key.match(/^\d+$/)) {
+            return str;
+          }
+          name = json.stringify('' + key);
+          if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
+            name = name.substr(1, name.length - 2);
+            name = stylize(name, 'name');
+          } else {
+            name = name.replace(/'/g, "\\'")
+                       .replace(/\\"/g, '"')
+                       .replace(/(^"|"$)/g, "'");
+            name = stylize(name, 'string');
+          }
+        }
+
+        return name + ': ' + str;
+      });
+
+      seen.pop();
+
+      var numLinesEst = 0;
+      var length = reduce(output, function(prev, cur) {
+        numLinesEst++;
+        if (indexOf(cur, '\n') >= 0) numLinesEst++;
+        return prev + cur.length + 1;
+      }, 0);
+
+      if (length > 50) {
+        output = braces[0] +
+                 (base === '' ? '' : base + '\n ') +
+                 ' ' +
+                 output.join(',\n  ') +
+                 ' ' +
+                 braces[1];
+
+      } else {
+        output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
+      }
+
+      return output;
+    }
+    return format(obj, (typeof depth === 'undefined' ? 2 : depth));
+  };
+
+  function isArray (ar) {
+    return ar instanceof Array ||
+      Object.prototype.toString.call(ar) == '[object Array]';
+  };
+
+  function isRegExp(re) {
+    var s = '' + re;
+    return re instanceof RegExp || // easy case
+           // duck-type for context-switching evalcx case
+           typeof(re) === 'function' &&
+           re.constructor.name === 'RegExp' &&
+           re.compile &&
+           re.test &&
+           re.exec &&
+           s.match(/^\/.*\/[gim]{0,3}$/);
+  };
+
+  function isDate(d) {
+    if (d instanceof Date) return true;
+    return false;
+  };
+
+  function keys (obj) {
+    if (Object.keys) {
+      return Object.keys(obj);
+    }
+
+    var keys = [];
+
+    for (var i in obj) {
+      if (obj.hasOwnProperty(i)) {
+        keys.push(i);
+      }
+    }
+
+    return keys;
+  }
+
+  function map (arr, mapper, that) {
+    if (Array.prototype.map) {
+      return Array.prototype.map.call(arr, mapper, that);
+    }
+
+    var other= new Array(arr.length);
+
+    for (var i= 0, n = arr.length; i<n; i++)
+      if (i in arr)
+        other[i] = mapper.call(that, arr[i], i, arr);
+
+    return other;
+  };
+
+  function reduce (arr, fun) {
+    if (Array.prototype.reduce) {
+      return Array.prototype.reduce.apply(
+          arr
+        , Array.prototype.slice.call(arguments, 1)
+      );
+    }
+
+    var len = +this.length;
+
+    if (typeof fun !== "function")
+      throw new TypeError();
+
+    // no value to return if no initial value and an empty array
+    if (len === 0 && arguments.length === 1)
+      throw new TypeError();
+
+    var i = 0;
+    if (arguments.length >= 2) {
+      var rv = arguments[1];
+    } else {
+      do {
+        if (i in this) {
+          rv = this[i++];
+          break;
+        }
+
+        // if array contains no values, no initial value to return
+        if (++i >= len)
+          throw new TypeError();
+      } while (true);
+    }
+
+    for (; i < len; i++) {
+      if (i in this)
+        rv = fun.call(null, rv, this[i], i, this);
+    }
+
+    return rv;
+  };
+
+  /**
+   * Strict equality
+   *
+   * @api public
+   */
+
+  should.equal = function (a, b) {
+    if (a !== b) {
+      should.fail('expected ' + i(a) + ' to equal ' + i(b));
+    }
+  };
+
+  /**
+   * Fails with msg
+   *
+   * @param {String} msg
+   * @api public
+   */
+
+  should.fail = function (msg) {
+    throw new Error(msg);
+  };
+
+  /**
+   * Asserts deep equality
+   *
+   * @see taken from node.js `assert` module (copyright Joyent, MIT license)
+   * @api private
+   */
+
+  should.eql = function eql (actual, expected) {
+    // 7.1. All identical values are equivalent, as determined by ===.
+    if (actual === expected) { 
+      return true;
+    } else if ('undefined' != typeof Buffer 
+        && Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
+      if (actual.length != expected.length) return false;
+
+      for (var i = 0; i < actual.length; i++) {
+        if (actual[i] !== expected[i]) return false;
+      }
+
+      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.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 should.eql(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 (!should.eql(a[key], b[key]))
+         return false;
+    }
+    return true;
+  }
+
+  var json = (function () {
+    "use strict";
+
+    if ('object' == typeof JSON && JSON.parse && JSON.stringify) {
+      return {
+          parse: nativeJSON.parse
+        , stringify: nativeJSON.stringify
+      }
+    }
+
+    var JSON = {};
+
+    function f(n) {
+        // Format integers to have at least two digits.
+        return n < 10 ? '0' + n : n;
+    }
+
+    function date(d, key) {
+      return isFinite(d.valueOf()) ?
+          d.getUTCFullYear()     + '-' +
+          f(d.getUTCMonth() + 1) + '-' +
+          f(d.getUTCDate())      + 'T' +
+          f(d.getUTCHours())     + ':' +
+          f(d.getUTCMinutes())   + ':' +
+          f(d.getUTCSeconds())   + 'Z' : null;
+    };
+
+    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        gap,
+        indent,
+        meta = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        },
+        rep;
+
+
+    function quote(string) {
+
+  // If the string contains no control characters, no quote characters, and no
+  // backslash characters, then we can safely slap some quotes around it.
+  // Otherwise we must also replace the offending characters with safe escape
+  // sequences.
+
+        escapable.lastIndex = 0;
+        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
+            var c = meta[a];
+            return typeof c === 'string' ? c :
+                '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+        }) + '"' : '"' + string + '"';
+    }
+
+
+    function str(key, holder) {
+
+  // Produce a string from holder[key].
+
+        var i,          // The loop counter.
+            k,          // The member key.
+            v,          // The member value.
+            length,
+            mind = gap,
+            partial,
+            value = holder[key];
+
+  // If the value has a toJSON method, call it to obtain a replacement value.
+
+        if (value instanceof Date) {
+            value = date(key);
+        }
+
+  // If we were called with a replacer function, then call the replacer to
+  // obtain a replacement value.
+
+        if (typeof rep === 'function') {
+            value = rep.call(holder, key, value);
+        }
+
+  // What happens next depends on the value's type.
+
+        switch (typeof value) {
+        case 'string':
+            return quote(value);
+
+        case 'number':
+
+  // JSON numbers must be finite. Encode non-finite numbers as null.
+
+            return isFinite(value) ? String(value) : 'null';
+
+        case 'boolean':
+        case 'null':
+
+  // If the value is a boolean or null, convert it to a string. Note:
+  // typeof null does not produce 'null'. The case is included here in
+  // the remote chance that this gets fixed someday.
+
+            return String(value);
+
+  // If the type is 'object', we might be dealing with an object or an array or
+  // null.
+
+        case 'object':
+
+  // Due to a specification blunder in ECMAScript, typeof null is 'object',
+  // so watch out for that case.
+
+            if (!value) {
+                return 'null';
+            }
+
+  // Make an array to hold the partial results of stringifying this object value.
+
+            gap += indent;
+            partial = [];
+
+  // Is the value an array?
+
+            if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+  // The value is an array. Stringify every element. Use null as a placeholder
+  // for non-JSON values.
+
+                length = value.length;
+                for (i = 0; i < length; i += 1) {
+                    partial[i] = str(i, value) || 'null';
+                }
+
+  // Join all of the elements together, separated with commas, and wrap them in
+  // brackets.
+
+                v = partial.length === 0 ? '[]' : gap ?
+                    '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
+                    '[' + partial.join(',') + ']';
+                gap = mind;
+                return v;
+            }
+
+  // If the replacer is an array, use it to select the members to be stringified.
+
+            if (rep && typeof rep === 'object') {
+                length = rep.length;
+                for (i = 0; i < length; i += 1) {
+                    if (typeof rep[i] === 'string') {
+                        k = rep[i];
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            } else {
+
+  // Otherwise, iterate through all of the keys in the object.
+
+                for (k in value) {
+                    if (Object.prototype.hasOwnProperty.call(value, k)) {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            }
+
+  // Join all of the member texts together, separated with commas,
+  // and wrap them in braces.
+
+            v = partial.length === 0 ? '{}' : gap ?
+                '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
+                '{' + partial.join(',') + '}';
+            gap = mind;
+            return v;
+        }
+    }
+
+  // If the JSON object does not yet have a stringify method, give it one.
+
+    JSON.stringify = function (value, replacer, space) {
+
+  // The stringify method takes a value and an optional replacer, and an optional
+  // space parameter, and returns a JSON text. The replacer can be a function
+  // that can replace values, or an array of strings that will select the keys.
+  // A default replacer method can be provided. Use of the space parameter can
+  // produce text that is more easily readable.
+
+        var i;
+        gap = '';
+        indent = '';
+
+  // If the space parameter is a number, make an indent string containing that
+  // many spaces.
+
+        if (typeof space === 'number') {
+            for (i = 0; i < space; i += 1) {
+                indent += ' ';
+            }
+
+  // If the space parameter is a string, it will be used as the indent string.
+
+        } else if (typeof space === 'string') {
+            indent = space;
+        }
+
+  // If there is a replacer, it must be a function or an array.
+  // Otherwise, throw an error.
+
+        rep = replacer;
+        if (replacer && typeof replacer !== 'function' &&
+                (typeof replacer !== 'object' ||
+                typeof replacer.length !== 'number')) {
+            throw new Error('JSON.stringify');
+        }
+
+  // Make a fake root object containing our value under the key of ''.
+  // Return the result of stringifying the value.
+
+        return str('', {'': value});
+    };
+
+  // If the JSON object does not yet have a parse method, give it one.
+
+    JSON.parse = function (text, reviver) {
+    // The parse method takes a text and an optional reviver function, and returns
+    // a JavaScript value if the text is a valid JSON text.
+
+        var j;
+
+        function walk(holder, key) {
+
+    // The walk method is used to recursively walk the resulting structure so
+    // that modifications can be made.
+
+            var k, v, value = holder[key];
+            if (value && typeof value === 'object') {
+                for (k in value) {
+                    if (Object.prototype.hasOwnProperty.call(value, k)) {
+                        v = walk(value, k);
+                        if (v !== undefined) {
+                            value[k] = v;
+                        } else {
+                            delete value[k];
+                        }
+                    }
+                }
+            }
+            return reviver.call(holder, key, value);
+        }
+
+
+    // Parsing happens in four stages. In the first stage, we replace certain
+    // Unicode characters with escape sequences. JavaScript handles many characters
+    // incorrectly, either silently deleting them, or treating them as line endings.
+
+        text = String(text);
+        cx.lastIndex = 0;
+        if (cx.test(text)) {
+            text = text.replace(cx, function (a) {
+                return '\\u' +
+                    ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+            });
+        }
+
+    // In the second stage, we run the text against regular expressions that look
+    // for non-JSON patterns. We are especially concerned with '()' and 'new'
+    // because they can cause invocation, and '=' because it can cause mutation.
+    // But just to be safe, we want to reject all unexpected forms.
+
+    // We split the second stage into 4 regexp operations in order to work around
+    // crippling inefficiencies in IE's and Safari's regexp engines. First we
+    // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+    // replace all simple value tokens with ']' characters. Third, we delete all
+    // open brackets that follow a colon or comma or that begin the text. Finally,
+    // we look to see that the remaining characters are only whitespace or ']' or
+    // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+        if (/^[\],:{}\s]*$/
+                .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
+                    .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
+                    .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+    // In the third stage we use the eval function to compile the text into a
+    // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+    // in JavaScript: it can begin a block or an object literal. We wrap the text
+    // in parens to eliminate the ambiguity.
+
+            j = eval('(' + text + ')');
+
+    // In the optional fourth stage, we recursively walk the new structure, passing
+    // each name/value pair to a reviver function for possible transformation.
+
+            return typeof reviver === 'function' ?
+                walk({'': j}, '') : j;
+        }
+
+    // If the text is not JSON parseable, then a SyntaxError is thrown.
+
+        throw new SyntaxError('JSON.parse');
+    };
+
+    return JSON;
+  })();
+
+})('undefined' != typeof exports ? exports : (should = {}));
diff --git a/node/node_modules/socket.io-client/support/test-runner/app.js b/node/node_modules/socket.io-client/support/test-runner/app.js
new file mode 100644 (file)
index 0000000..167430a
--- /dev/null
@@ -0,0 +1,309 @@
+
+/**
+ * Module dependencies.
+ */
+
+var express = require('express')
+  , stylus = require('stylus')
+  , sio = require('socket.io')
+  , path = require('path')
+  , fs = require('fs');
+
+/**
+ * App.
+ */
+
+var app = express.createServer();
+
+/**
+ * Initial port to listen to.
+ */
+
+var port = 3000;
+
+/**
+ * Transport to test with.
+ */
+
+var args = process.argv.slice(2)
+  , transport = args.length ? args[0] : 'xhr-polling';
+
+/**
+ * A map of tests to socket.io ports we're listening on.
+ */
+
+var testsPorts = {};
+
+/**
+ * App configuration.
+ */
+
+app.configure(function () {
+  app.use(stylus.middleware({ src: __dirname + '/public' }))
+  app.use(express.static(__dirname + '/public'));
+  app.set('views', __dirname);
+  app.set('view engine', 'jade');
+});
+
+/**
+ * App routes.
+ */
+
+app.get('/', function (req, res) {
+  res.render('index', {
+      layout: false
+    , testsPorts: testsPorts
+  });
+});
+
+/**
+ * Sends test files.
+ */
+
+app.get('/test/:file', function (req, res) {
+  res.sendfile(path.normalize(__dirname + '/../../test/' + req.params.file));
+});
+
+/**
+ * App listen.
+ */
+
+app.listen(port++, function () {
+  var addr = app.address();
+  console.error('   listening on http://' + addr.address + ':' + addr.port);
+});
+
+/**
+ * Override handler to simplify development
+ */
+
+function handler (req, res) {
+  fs.readFile(__dirname + '/../../dist/socket.io.js', 'utf8', function (err, b) {
+    if (err) {
+      res.writeHead(404);
+      res.end('Error');
+      return;
+    }
+
+    res.writeHead(200, { 'Content-Type': 'application/javascript' });
+    res.end(b);
+  });
+};
+
+/**
+ * Socket.IO default server (to serve client)
+ */
+
+var io = sio.listen(app);
+
+io.configure(function () {
+  io.set('browser client handler', handler);
+  io.set('transports', [
+      transport
+  ]);
+});
+
+/**
+ * Scopes servers for a given test suite.
+ */
+
+var currentSuite;
+
+function suite (name, fn) {
+  currentSuite = testsPorts[name] = {};
+  fn();
+};
+
+/**
+ * Creates a socket io server
+ */
+
+function server (name, fn) {
+  currentSuite[name] = port;
+
+  var io = sio.listen(port);
+  io.configure(function () {
+    io.set('transports', [transport]);
+  });
+
+  fn(io);
+  port++;
+};
+
+/**
+ * Socket.IO servers.
+ */
+
+suite('socket.test.js', function () {
+
+  server('test connecting the socket and disconnecting', function (io) {
+    io.sockets.on('connection', function () {});
+  });
+
+  server('test receiving messages', function (io) {
+    io.sockets.on('connection', function (socket) {
+      var messages = 0;
+      var interval = setInterval(function () {
+        socket.send(++messages);
+
+        if (messages == 3) {
+          clearInterval(interval);
+          setTimeout(function () {
+            socket.disconnect();
+          }, 500);
+        }
+      }, 50);
+    });
+  });
+
+  server('test sending messages', function (io) {
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        socket.send(msg);
+      });
+    });
+  });
+
+  server('test acks sent from client', function (io) {
+    io.sockets.on('connection', function (socket) {
+      socket.send('tobi', function () {
+        socket.send('tobi 2');
+      });
+    });
+  });
+
+  server('test acks sent from server', function (io) {
+    io.sockets.on('connection', function (socket) {});
+  });
+
+  server('test connecting to namespaces', function (io) {
+    io.of('/woot').on('connection', function (socket) {
+      socket.send('connected to woot');
+    });
+
+    io.of('/chat').on('connection', function (socket) {
+      socket.send('connected to chat');
+    });
+  });
+
+  server('test disconnecting from namespaces', function (io) {
+    io.of('/a').on('connection', function (socket) {});
+    io.of('/b').on('connection', function (socket) {});
+  });
+
+  server('test authorizing for namespaces', function (io) {
+    io.of('/a')
+      .authorization(function (data, fn) {
+        fn(null, false);
+      })
+      .on('connection', function (socket) {});
+  });
+
+  server('test sending json from server', function (io) {
+    io.sockets.on('connection', function (socket) {
+      io.sockets.json.send(3141592);
+    });
+  });
+
+  server('test sending json from client', function (io) {
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (arr) {
+        if (Array.isArray(arr) && arr.length == 3) {
+          socket.send('echo');
+        }
+      });
+    });
+  });
+
+  server('test emitting an event from server', function (io) {
+    io.sockets.on('connection', function (socket) {
+      socket.emit('woot');
+    });
+  });
+
+  server('test emitting multiple events at once to the server', function (io) {
+    io.sockets.on('connection', function (socket) {
+      var messages = [];
+
+      socket.on('print', function (msg) {
+        if (messages.indexOf(msg) >= 0) {
+          console.error('duplicate message');
+        }
+
+        messages.push(msg);
+        if (messages.length == 2) {
+          socket.emit('done');
+        }
+      });
+    });
+  });
+
+  server('test emitting an event to server', function (io) {
+    io.sockets.on('connection', function (socket) {
+      socket.on('woot', function () {
+        socket.emit('echo');
+      });
+    });
+  });
+
+  server('test emitting an event from server and sending back data', function (io) {
+    io.sockets.on('connection', function (socket) {
+      socket.emit('woot', 1, function (a) {
+        if (a === 'test') {
+          socket.emit('done');
+        }
+      });
+    });
+  });
+
+  server('test emitting an event to server and sending back data', function (io) {
+    io.sockets.on('connection', function (socket) {
+      socket.on('tobi', function (a, b, fn) {
+        if (a === 1 && b === 2) {
+          fn({ hello: 'world' });
+        }
+      });
+    });
+  });
+
+  server('test encoding a payload', function (io) {
+    io.of('/woot').on('connection', function (socket) {
+      var count = 0;
+
+      socket.on('message', function (a) {
+        if (a == 'ñ') {
+          if (++count == 4) {
+            socket.emit('done');
+          }
+        }
+      });
+    });
+  });
+
+  server('test sending query strings to the server', function (io) {
+    io.sockets.on('connection', function (socket) {
+      socket.json.send(socket.handshake);
+    })
+  });
+
+  server('test sending newline', function (io) {
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        if (msg == '\n') {
+          socket.emit('done');
+        }
+      });
+    });
+  });
+
+  server('test sending unicode', function (io) {
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        if (msg.test == "\u2028") {
+          socket.emit('done');
+        }
+      });
+    });
+  });
+
+});
diff --git a/node/node_modules/socket.io-client/support/test-runner/index.jade b/node/node_modules/socket.io-client/support/test-runner/index.jade
new file mode 100644 (file)
index 0000000..50ccce2
--- /dev/null
@@ -0,0 +1,28 @@
+doctype 5
+html
+  head
+    link(href='/stylesheets/main.css', rel='stylesheet', media='all')
+    script(src='/socket.io/socket.io.js')
+    script(src='/javascript/jquery.js')
+    script(src='/javascript/should.js')
+    script(src='/javascript/script.js')
+    script(src='/javascript/runner.js')
+
+    - var json = JSON.stringify(testsPorts);
+    script
+      var testsPorts = !{json}
+
+    script
+      $(function () {
+        run(
+            'io.test.js'
+          , 'parser.test.js'
+          , 'util.test.js'
+          , 'events.test.js'
+          , 'socket.test.js'
+        );
+      });
+
+    title Socket.IO tests runner
+  body
+    h2 Socket.IO test runner
diff --git a/node/node_modules/socket.io-client/support/test-runner/public/javascript/jquery.js b/node/node_modules/socket.io-client/support/test-runner/public/javascript/jquery.js
new file mode 100644 (file)
index 0000000..3a8cd46
--- /dev/null
@@ -0,0 +1,18 @@
+/*!
+ * jQuery JavaScript Library v1.6.1
+ * http://jquery.com/
+ *
+ * Copyright 2011, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Thu May 12 15:04:36 2011 -0400
+ */
+(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!cj[a]){var b=f("<"+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),c.body.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write("<!doctype><html><body></body></html>");b=cl.createElement(a),cl.body.appendChild(b),d=f.css(b,"display"),c.body.removeChild(ck)}cj[a]=d}return cj[a]}function cu(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function ct(){cq=b}function cs(){setTimeout(ct,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function ca(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function b_(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bF.test(a)?d(a,e):b_(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)b_(a+"["+e+"]",b[e],c,d);else d(a,b)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bU,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=b$(a,c,d,e,"*",g));return l}function bZ(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bQ),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bD(a,b,c){var d=b==="width"?bx:by,e=b==="width"?a.offsetWidth:a.offsetHeight;if(c==="border")return e;f.each(d,function(){c||(e-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?e+=parseFloat(f.css(a,"margin"+this))||0:e-=parseFloat(f.css(a,"border"+this+"Width"))||0});return e}function bn(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bm(a){f.nodeName(a,"input")?bl(a):a.getElementsByTagName&&f.grep(a.getElementsByTagName("input"),bl)}function bl(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bk(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bj(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bi(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)f.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function bh(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function X(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(S.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function W(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function O(a,b){return(a&&a!=="*"?a+".":"")+b.replace(A,"`").replace(B,"&")}function N(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;i<s.length;i++)g=s[i],g.origType.replace(y,"")===a.type?q.push(g.selector):s.splice(i--,1);e=f(a.target).closest(q,a.currentTarget);for(j=0,k=e.length;j<k;j++){m=e[j];for(i=0;i<s.length;i++){g=s[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,d=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,d=f(a.relatedTarget).closest(g.selector)[0],d&&f.contains(h,d)&&(d=h);(!d||d!==h)&&p.push({elem:h,handleObj:g,level:m.level})}}}for(j=0,k=p.length;j<k;j++){e=p[j];if(c&&e.level>c)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function L(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function F(){return!0}function E(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function H(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(H,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=d.userAgent,x,y,z,A=Object.prototype.toString,B=Object.prototype.hasOwnProperty,C=Array.prototype.push,D=Array.prototype.slice,E=String.prototype.trim,F=Array.prototype.indexOf,G={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.1",length:0,size:function(){return this.length},toArray:function(){return D.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?C.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),y.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(D.apply(this,arguments),"slice",D.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:C,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;y.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!y){y=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",z,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",z),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&H()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):G[A.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!B.call(a,"constructor")&&!B.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||B.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:E?function(a){return a==null?"":E.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?C.call(c,a):e.merge(c,a)}return c},inArray:function(a,b){if(F)return F.call(b,a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=D.call(arguments,2),g=function(){return a.apply(c,f.concat(D.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=s.exec(a)||t.exec(a)||u.exec(a)||a.indexOf("compatible")<0&&v.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){G["[object "+b+"]"]=b.toLowerCase()}),x=e.uaMatch(w),x.browser&&(e.browser[x.browser]=!0,e.browser.version=x.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?z=function(){c.removeEventListener("DOMContentLoaded",z,!1),e.ready()}:c.attachEvent&&(z=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",z),e.ready())});return e}(),g="done fail isResolved isRejected promise then always pipe".split(" "),h=[].slice;f.extend({_Deferred:function(){var a=[],b,c,d,e={done:function(){if(!d){var c=arguments,g,h,i,j,k;b&&(k=b,b=0);for(g=0,h=c.length;g<h;g++)i=c[g],j=f.type(i),j==="array"?e.done.apply(e,i):j==="function"&&a.push(i);k&&e.resolveWith(k[0],k[1])}return this},resolveWith:function(e,f){if(!d&&!b&&!c){f=f||[],c=1;try{while(a[0])a.shift().apply(e,f)}finally{b=[e,f],c=0}}return this},resolve:function(){e.resolveWith(this,arguments);return this},isResolved:function(){return!!c||!!b},cancel:function(){d=1,a=[];return this}};return e},Deferred:function(a){var b=f._Deferred(),c=f._Deferred(),d;f.extend(b,{then:function(a,c){b.done(a).fail(c);return this},always:function(){return b.done.apply(b,arguments).fail.apply(this,arguments)},fail:c.done,rejectWith:c.resolveWith,reject:c.resolve,isRejected:c.isResolved,pipe:function(a,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[c,"reject"]},function(a,c){var e=c[0],g=c[1],h;f.isFunction(e)?b[a](function(){h=e.apply(this,arguments),h&&f.isFunction(h.promise)?h.promise().then(d.resolve,d.reject):d[g](h)}):b[a](d[g])})}).promise()},promise:function(a){if(a==null){if(d)return d;d=a={}}var c=g.length;while(c--)a[g[c]]=b[g[c]];return a}}),b.done(c.cancel).fail(b.cancel),delete b.cancel,a&&a.call(b,b);return b},when:function(a){function i(a){return function(c){b[a]=arguments.length>1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c<d;c++)b[c]&&f.isFunction(b[c].promise)?b[c].promise().then(i(c),g.reject):--e;e||g.resolveWith(g,b)}else g!==a&&g.resolveWith(g,d?[a]:[]);return g.promise()}}),f.support=function(){var a=c.createElement("div"),b=c.documentElement,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r;a.setAttribute("className","t"),a.innerHTML="   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};f=c.createElement("select"),g=f.appendChild(c.createElement("option")),h=a.getElementsByTagName("input")[0],j={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},h.checked=!0,j.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,j.optDisabled=!g.disabled;try{delete a.test}catch(s){j.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function b(){j.noCloneEvent=!1,a.detachEvent("onclick",b)}),a.cloneNode(!0).fireEvent("onclick")),h=c.createElement("input"),h.value="t",h.setAttribute("type","radio"),j.radioValue=h.value==="t",h.setAttribute("checked","checked"),a.appendChild(h),k=c.createDocumentFragment(),k.appendChild(a.firstChild),j.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",l=c.createElement("body"),m={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"};for(q in m)l.style[q]=m[q];l.appendChild(a),b.insertBefore(l,b.firstChild),j.appendChecked=h.checked,j.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,j.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="<div style='width:4px;'></div>",j.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",n=a.getElementsByTagName("td"),r=n[0].offsetHeight===0,n[0].style.display="",n[1].style.display="none",j.reliableHiddenOffsets=r&&n[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(i=c.createElement("div"),i.style.width="0",i.style.marginRight="0",a.appendChild(i),j.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(i,null)||{marginRight:0}).marginRight,10)||0)===0),l.innerHTML="",b.removeChild(l);if(a.attachEvent)for(q in{submit:1,change:1,focusin:1})p="on"+q,r=p in a,r||(a.setAttribute(p,"return;"),r=typeof a[p]=="function"),j[q+"Bubbles"]=r;return j}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h<i;h++)g=e[h].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),k(this[0],g,d[g]))}}return d}if(typeof a=="object")return this.each(function(){f.data(this,a)});var j=a.split(".");j[1]=j[1]?"."+j[1]:"";if(c===b){d=this.triggerHandler("getData"+j[1]+"!",[j[0]]),d===b&&this.length&&(d=f.data(this[0],a),d=k(this[0],a,d));return d===b&&j[1]?this.data(j[0]):d}return this.each(function(){var b=f(this),d=[j[0],c];b.triggerHandler("setData"+j[1]+"!",d),f.data(this,a,c),b.triggerHandler("changeData"+j[1]+"!",d)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,c){a&&(c=(c||"fx")+"mark",f.data(a,c,(f.data(a,c,b,!0)||0)+1,!0))},_unmark:function(a,c,d){a!==!0&&(d=c,c=a,a=!1);if(c){d=d||"fx";var e=d+"mark",g=a?0:(f.data(c,e,b,!0)||1)-1;g?f.data(c,e,g,!0):(f.removeData(c,e,!0),m(c,d,"mark"))}},queue:function(a,c,d){if(a){c=(c||"fx")+"queue";var e=f.data(a,c,b,!0);d&&(!e||f.isArray(d)?e=f.data(a,c,f.makeArray(d),!0):e.push(d));return e||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e;d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),d.call(a,function(){f.dequeue(a,b)})),c.length||(f.removeData(a,b+"queue",!0),m(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(){var c=this;setTimeout(function(){f.dequeue(c,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f._Deferred(),!0))h++,l.done(m);m();return d.promise()}});var n=/[\n\t\r]/g,o=/\s+/,p=/\r/g,q=/^(?:button|input)$/i,r=/^(?:button|input|object|select|textarea)$/i,s=/^a(?:rea)?$/i,t=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,u=/\:/,v,w;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.addClass(a.call(this,b,c.attr("class")||""))});if(a&&typeof a=="string"){var b=(a||"").split(o);for(var c=0,d=this.length;c<d;c++){var e=this[c];if(e.nodeType===1)if(!e.className)e.className=a;else{var g=" "+e.className+" ",h=e.className;for(var i=0,j=b.length;i<j;i++)g.indexOf(" "+b[i]+" ")<0&&(h+=" "+b[i]);e.className=f.trim(h)}}}return this},removeClass:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.removeClass(a.call(this,b,c.attr("class")))});if(a&&typeof a=="string"||a===b){var c=(a||"").split(o);for(var d=0,e=this.length;d<e;d++){var g=this[d];if(g.nodeType===1&&g.className)if(a){var h=(" "+g.className+" ").replace(n," ");for(var i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){var d=f(this);d.toggleClass(a.call(this,c,d.attr("class"),b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(o);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ";for(var c=0,d=this.length;c<d;c++)if((" "+this[c].className+" ").replace(n," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;return(e.value||"").replace(p,"")}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h<i;h++){var j=e[h];if(j.selected&&(f.support.optDisabled?!j.disabled:j.getAttribute("disabled")===null)&&(!j.parentNode.disabled||!f.nodeName(j.parentNode,"optgroup"))){b=f(j).val();if(g)return b;d.push(b)}}if(g&&!d.length&&e.length)return f(e[c]).val();return d},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);c=j&&f.attrFix[c]||c,i=f.attrHooks[c],i||(!t.test(c)||typeof d!="boolean"&&d!==b&&d.toLowerCase()!==c.toLowerCase()?v&&(f.nodeName(a,"form")||u.test(c))&&(i=v):i=w);if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j)return i.get(a,c);h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);c=i&&f.propFix[c]||c,h=f.propHooks[c];return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return a[f.propFix[c]||c]?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=b),a.setAttribute(c,c.toLowerCase()));return c}},f.attrHooks.value={get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return a.value},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=Object.prototype.hasOwnProperty,y=/\.(.*)$/,z=/^(?:textarea|input|select)$/i,A=/\./g,B=/ /g,C=/[^\w\s.|`]/g,D=function(a){return a.replace(C,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=E;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=E);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),D).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j<p.length;j++){q=p[j];if(l||n.test(q.namespace))f.event.remove(a,r,q.handler,j),p.splice(j--,1)}continue}o=f.event.special[h]||{};for(j=e||0;j<p.length;j++){q=p[j];if(d.guid===q.guid){if(l||n.test(q.namespace))e==null&&p.splice(j--,1),o.remove&&o.remove.call(a,q);if(e!=null)break}}if(p.length===0||e!=null&&p.length===1)(!o.teardown||o.teardown.call(a,m)===!1)&&f.removeEvent(a,h,s.handle),g=null,delete t[h]}if(f.isEmptyObject(t)){var u=s.handle;u&&(u.elem=null),delete s.events,delete s.handle,f.isEmptyObject(s)&&f.removeData(a,b,!0)}}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){var h=c.type||c,i=[],j;h.indexOf("!")>=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem
+)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h<i;h++){var j=d[h];if(e||c.namespace_re.test(j.namespace)){c.handler=j.handler,c.data=j.data,c.handleObj=j;var k=j.handler.apply(this,g);k!==b&&(c.result=k,k===!1&&(c.preventDefault(),c.stopPropagation()));if(c.isImmediatePropagationStopped())break}}return c.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[f.expando])return a;var d=a;a=f.Event(d);for(var e=this.props.length,g;e;)g=this.props[--e],a[g]=d[g];a.target||(a.target=a.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),!a.relatedTarget&&a.fromElement&&(a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement);if(a.pageX==null&&a.clientX!=null){var h=a.target.ownerDocument||c,i=h.documentElement,j=h.body;a.pageX=a.clientX+(i&&i.scrollLeft||j&&j.scrollLeft||0)-(i&&i.clientLeft||j&&j.clientLeft||0),a.pageY=a.clientY+(i&&i.scrollTop||j&&j.scrollTop||0)-(i&&i.clientTop||j&&j.clientTop||0)}a.which==null&&(a.charCode!=null||a.keyCode!=null)&&(a.which=a.charCode!=null?a.charCode:a.keyCode),!a.metaKey&&a.ctrlKey&&(a.metaKey=a.ctrlKey),!a.which&&a.button!==b&&(a.which=a.button&1?1:a.button&2?3:a.button&4?2:0);return a},guid:1e8,proxy:f.proxy,special:{ready:{setup:f.bindReady,teardown:f.noop},live:{add:function(a){f.event.add(this,O(a.origType,a.selector),f.extend({},a,{handler:N,guid:a.handler.guid}))},remove:function(a){f.event.remove(this,O(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}}},f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!this.preventDefault)return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?F:E):this.type=a,b&&f.extend(this,b),this.timeStamp=f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=F;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=F;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=F,this.stopPropagation()},isDefaultPrevented:E,isPropagationStopped:E,isImmediatePropagationStopped:E};var G=function(a){var b=a.relatedTarget;a.type=a.data;try{if(b&&b!==c&&!b.parentNode)return;while(b&&b!==this)b=b.parentNode;b!==this&&f.event.handle.apply(this,arguments)}catch(d){}},H=function(a){a.type=a.data,f.event.handle.apply(this,arguments)};f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={setup:function(c){f.event.add(this,b,c&&c.selector?H:G,a)},teardown:function(a){f.event.remove(this,b,a&&a.selector?H:G)}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(a,b){if(!f.nodeName(this,"form"))f.event.add(this,"click.specialSubmit",function(a){var b=a.target,c=b.type;(c==="submit"||c==="image")&&f(b).closest("form").length&&L("submit",this,arguments)}),f.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,c=b.type;(c==="text"||c==="password")&&f(b).closest("form").length&&a.keyCode===13&&L("submit",this,arguments)});else return!1},teardown:function(a){f.event.remove(this,".specialSubmit")}});if(!f.support.changeBubbles){var I,J=function(a){var b=a.type,c=a.value;b==="radio"||b==="checkbox"?c=a.checked:b==="select-multiple"?c=a.selectedIndex>-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},K=function(c){var d=c.target,e,g;if(!!z.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=J(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:K,beforedeactivate:K,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&K.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&K.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",J(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in I)f.event.add(this,c+".specialChange",I[c]);return z.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return z.test(this.nodeName)}},I=f.event.special.change.filters,I.focus=I.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i<j;i++)f.event.add(this[i],a,g,d);return this}}),f.fn.extend({unbind:function(a,b){if(typeof a=="object"&&!a.preventDefault)for(var c in a)this.unbind(c,a[c]);else for(var d=0,e=this.length;d<e;d++)f.event.remove(this[d],a,b);return this},delegate:function(a,b,c,d){return this.live(b,c,d,a)},undelegate:function(a,b,c){return arguments.length===0?this.unbind("live"):this.die(b,null,c,a)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f.data(this,"lastToggle"+a.guid)||0)%d;f.data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var M={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};f.each(["live","die"],function(a,c){f.fn[c]=function(a,d,e,g){var h,i=0,j,k,l,m=g||this.selector,n=g?this:f(this.context);if(typeof a=="object"&&!a.preventDefault){for(var o in a)n[c](o,d,a[o],m);return this}if(c==="die"&&!a&&g&&g.charAt(0)==="."){n.unbind(g);return this}if(d===!1||f.isFunction(d))e=d||E,d=b;a=(a||"").split(" ");while((h=a[i++])!=null){j=y.exec(h),k="",j&&(k=j[0],h=h.replace(y,""));if(h==="hover"){a.push("mouseenter"+k,"mouseleave"+k);continue}l=h,M[h]?(a.push(M[h]+k),h=h+k):h=(M[h]||h)+k;if(c==="live")for(var p=0,q=n.length;p<q;p++)f.event.add(n[p],"live."+O(h,m),{data:d,selector:m,handler:e,origType:h,origHandler:e,preType:l});else n.unbind("live."+O(h,m),e)}return this}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}if(i.nodeType===1){f||(i.sizcache=c,i.sizset=g);if(typeof b!="string"){if(i===b){j=!0;break}}else if(k.filter(b,[i]).length>0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}i.nodeType===1&&!f&&(i.sizcache=c,i.sizset=g);if(i.nodeName.toLowerCase()===b){j=i;break}i=i[a]}d[g]=j}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},k.matches=function(a,b){return k(a,null,null,b)},k.matchesSelector=function(a,b){return k(b,null,null,[a]).length>0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e<f;e++){var g,h=l.order[e];if(g=l.leftMatch[h].exec(a)){var j=g[1];g.splice(1,1);if(j.substr(j.length-1)!=="\\"){g[1]=(g[1]||"").replace(i,""),d=l.find[h](g,b,c);if(d!=null){a=a.replace(l.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},k.filter=function(a,c,d,e){var f,g,h=a,i=[],j=c,m=c&&c[0]&&k.isXML(c[0]);while(a&&c.length){for(var n in l.filter)if((f=l.leftMatch[n].exec(a))!=null&&f[2]){var o,p,q=l.filter[n],r=f[1];g=!1,f.splice(1,1);if(r.substr(r.length-1)==="\\")continue;j===i&&(i=[]);if(l.preFilter[n]){f=l.preFilter[n](f,j,d,i,e,m);if(!f)g=o=!0;else if(f===!0)continue}if(f)for(var s=0;(p=j[s])!=null;s++)if(p){o=q(p,f,s,j);var t=e^!!o;d&&o!=null?t?g=!0:j[s]=!1:t&&(i.push(p),g=!0)}if(o!==b){d||(j=i),a=a.replace(l.match[n],"");if(!g)return[];break}}if(a===h)if(g==null)k.error(a);else break;h=a}return j},k.error=function(a){throw"Syntax error, unrecognized expression: "+a};var l=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!j.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&k.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&k.filter(b,a,!0)}},"":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("parentNode",b,f,a,e,c)},"~":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("previousSibling",b,f,a,e,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(i,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}k.error(e)},CHILD:function(a,b){var c=b[1],d=a;switch(c){case"only":case"first":while(d=d.previousSibling)if(d.nodeType===1)return!1;if(c==="first")return!0;d=a;case"last":while(d=d.nextSibling)if(d.nodeType===1)return!1;return!0;case"nth":var e=b[2],f=b[3];if(e===1&&f===0)return!0;var g=b[0],h=a.parentNode;if(h&&(h.sizcache!==g||!a.nodeIndex)){var i=0;for(d=h.firstChild;d;d=d.nextSibling)d.nodeType===1&&(d.nodeIndex=++i);h.sizcache=g}var j=a.nodeIndex-f;return e===0?j===0:j%e===0&&j/e>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c<f;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var r,s;c.documentElement.compareDocumentPosition?r=function(a,b){if(a===b){g=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(r=function(a,b){if(a===b){g=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],h=a.parentNode,i=b.parentNode,j=h;if(h===i)return s(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return s(e[k],f[k]);return k===c?s(a,f[k],-1):s(e[k],b,1)},s=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),k.getText=function(a){var b="",c;for(var d=0;a[d];d++)c=a[d],c.nodeType===3||c.nodeType===4?b+=c.nodeValue:c.nodeType!==8&&(b+=k.getText(c.childNodes));return b},function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g<h;g++)k(a,f[g],d);return k.filter(e,d)};f.find=k,f.expr=k.selectors,f.expr[":"]=f.expr.filters,f.unique=k.uniqueSort,f.text=k.getText,f.isXMLDoc=k.isXML,f.contains=k.contains}();var P=/Until$/,Q=/^(?:parents|prevUntil|prevAll)/,R=/,/,S=/^.[^:#\[\.,]*$/,T=Array.prototype.slice,U=f.expr.match.POS,V={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(X(this,a,!1),"not",a)},filter:function(a){return this.pushStack(X(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d<e;d++)i=a[d],j[i]||(j[i]=U.test(i)?f(i,b||this.context):i);while(g&&g.ownerDocument&&g!==b){for(i in j)h=j[i],(h.jquery?h.index(g)>-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=U.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(l?l.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(W(c[0])||W(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=T.call(arguments);P.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!V[a]?f.unique(e):e,(this.length>1||R.test(d))&&Q.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var Y=/ jQuery\d+="(?:\d+|null)"/g,Z=/^\s+/,$=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,_=/<([\w:]+)/,ba=/<tbody/i,bb=/<|&#?\w+;/,bc=/<(?:script|object|embed|option|style)/i,bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(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,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Y,""):null;if(typeof a=="string"&&!bc.test(a)&&(f.support.leadingWhitespace||!Z.test(a))&&!bg[(_.exec(a)||["",""])[1].toLowerCase()]){a=a.replace($,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bh(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bn)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i=b&&b[0]?b[0].ownerDocument||b[0]:c;a.length===1&&typeof a[0]=="string"&&a[0].length<512&&i===c&&a[0].charAt(0)==="<"&&!bc.test(a[0])&&(f.support.checkClone||!bd.test(a[0]))&&(g=!0,h=f.fragments[a[0]],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[a[0]]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bj(a,d),e=bk(a),g=bk(d);for(h=0;e[h];++h)bj(e[h],g[h])}if(b){bi(a,d);if(c){e=bk(a),g=bk(d);for(h=0;e[h];++h)bi(e[h],g[h])}}return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||
+b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!bb.test(k))k=b.createTextNode(k);else{k=k.replace($,"<$1></$2>");var l=(_.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=ba.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Z.test(k)&&o.insertBefore(b.createTextNode(Z.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bm(k[i]);else bm(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.expando,g=f.event.special,h=f.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&f.noData[j.nodeName.toLowerCase()])continue;c=j[f.expando];if(c){b=d[c]&&d[c][e];if(b&&b.events){for(var k in b.events)g[k]?f.event.remove(j,k):f.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[f.expando]:j.removeAttribute&&j.removeAttribute(f.expando),delete d[c]}}}});var bo=/alpha\([^)]*\)/i,bp=/opacity=([^)]*)/,bq=/-([a-z])/ig,br=/([A-Z]|^ms)/g,bs=/^-?\d+(?:px)?$/i,bt=/^-?\d/,bu=/^[+\-]=/,bv=/[^+\-\.\de]+/g,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Left","Right"],by=["Top","Bottom"],bz,bA,bB,bC=function(a,b){return b.toUpperCase()};f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bz(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{zIndex:!0,fontWeight:!0,opacity:!0,zoom:!0,lineHeight:!0,widows:!0,orphans:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d;if(h==="number"&&isNaN(d)||d==null)return;h==="string"&&bu.test(d)&&(d=+d.replace(bv,"")+parseFloat(f.css(a,c))),h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bz)return bz(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]},camelCase:function(a){return a.replace(bq,bC)}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){a.offsetWidth!==0?e=bD(a,b,d):f.swap(a,bw,function(){e=bD(a,b,d)});if(e<=0){e=bz(a,b,b),e==="0px"&&bB&&(e=bB(a,b,b));if(e!=null)return e===""||e==="auto"?"0px":e}if(e<0||e==null){e=a.style[b];return e===""||e==="auto"?"0px":e}return typeof e=="string"?e:e+"px"}},set:function(a,b){if(!bs.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bp.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bo.test(g)?g.replace(bo,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,c){var d,e,g;c=c.replace(br,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bs.test(d)&&bt.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bE=/%20/g,bF=/\[\]$/,bG=/\r?\n/g,bH=/#.*$/,bI=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bJ=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bK=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bL=/^(?:GET|HEAD)$/,bM=/^\/\//,bN=/\?/,bO=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bP=/^(?:select|textarea)/i,bQ=/\s+/,bR=/([?&])_=[^&]*/,bS=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bT=f.fn.load,bU={},bV={},bW,bX;try{bW=e.href}catch(bY){bW=c.createElement("a"),bW.href="",bW=bW.href}bX=bS.exec(bW.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bT)return bT.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bO,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bP.test(this.nodeName)||bJ.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bG,"\r\n")}}):{name:b.name,value:c.replace(bG,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bW,isLocal:bK.test(bX[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bZ(bU),ajaxTransport:bZ(bV),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?ca(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=cb(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bI.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bH,"").replace(bM,bX[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bQ),d.crossDomain==null&&(r=bS.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bX[1]&&r[2]==bX[2]&&(r[3]||(r[1]==="http:"?80:443))==(bX[3]||(bX[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bU,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bL.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bN.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bR,"$1_="+x);d.url=y+(y===d.url?(bN.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bV,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bE,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq,cr=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cv(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cu("hide",3),a,b,c);for(var d=0,e=this.length;d<e;d++)if(this[d].style){var g=f.css(this[d],"display");g!=="none"&&!f._data(this[d],"olddisplay")&&f._data(this[d],"olddisplay",g)}for(d=0;d<e;d++)this[d].style&&(this[d].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cu("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return this[e.queue===!1?"each":"queue"](function(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(f.support.inlineBlockNeedsLayout?(j=cv(this.nodeName),j==="inline"?this.style.display="inline-block":(this.style.display="inline",this.style.zoom=1)):this.style.display="inline-block"))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)k=new f.fx(this,b,i),h=a[i],cm.test(h)?k[h==="toggle"?d?"show":"hide":h]():(l=cn.exec(h),m=k.cur(),l?(n=parseFloat(l[2]),o=l[3]||(f.cssNumber[i]?"":"px"),o!=="px"&&(f.style(this,i,(n||1)+o),m=(n||1)/k.cur()*m,f.style(this,i,m+o)),l[1]&&(n=(l[1]==="-="?-1:1)*n+m),k.custom(m,n,o)):k.custom(m,h,""));return!0})},stop:function(a,b){a&&this.queue([]),this.each(function(){var a=f.timers,c=a.length;b||f._unmark(!0,this);while(c--)a[c].elem===this&&(b&&a[c](!0),a.splice(c,1))}),b||this.dequeue();return this}}),f.each({slideDown:cu("show",1),slideUp:cu("hide",1),slideToggle:cu("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default,d.old=d.complete,d.complete=function(a){d.queue!==!1?f.dequeue(this):a!==!1&&f._unmark(this),f.isFunction(d.old)&&d.old.call(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.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,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function h(a){return d.step(a)}var d=this,e=f.fx,g;this.startTime=cq||cs(),this.start=a,this.end=b,this.unit=c||this.unit||(f.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,h.elem=this.elem,h()&&f.timers.push(h)&&!co&&(cr?(co=1,g=function(){co&&(cr(g),e.tick())},cr(g)):co=setInterval(e.tick,e.interval))},show:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=cq||cs(),c=!0,d=this.elem,e=this.options,g,h;if(a||b>=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b<a.length;++b)a[b]()||a.splice(b--,1);a.length||f.fx.stop()},interval:13,stop:function(){clearInterval(co),co=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit:a.elem[a.prop]=a.now}}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cy(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);f.offset.initialize();var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.offset.supportsFixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.offset.doesNotAddBorder&&(!f.offset.doesAddBorderForTableAndCells||!cw.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.offset.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.offset.supportsFixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={initialize:function(){var a=c.body,b=c.createElement("div"),d,e,g,h,i=parseFloat(f.css(a,"marginTop"))||0,j="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){return this[0]?parseFloat(f.css(this[0],d,"padding")):null},f.fn["outer"+c]=function(a){return this[0]?parseFloat(f.css(this[0],d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window);
diff --git a/node/node_modules/socket.io-client/support/test-runner/public/javascript/runner.js b/node/node_modules/socket.io-client/support/test-runner/public/javascript/runner.js
new file mode 100644 (file)
index 0000000..5059601
--- /dev/null
@@ -0,0 +1,211 @@
+// useful globals
+
+var currentSuite, currentCase;
+
+// loads common.js module
+function load (test, fn) {
+  module = {};
+  $script('/test/' + test, function () {
+    fn(module.exports);
+  });
+};
+
+// load all tests
+function run () {
+  var tests = Array.prototype.slice.call(arguments)
+    , i = 0;
+
+  function complete () {
+    $('body').append('<p>All suites completed</p>');
+  };
+
+  if (tests.length) {
+    // load dom
+    $('body').append('<ul class="test-list">');
+
+    // run suites
+    suite(tests[i], function check (res) {
+      if (tests[++i]) {
+        suite(tests[i], check);
+      } else {
+        complete();
+      }
+    });
+  } else {
+    complete();
+  }
+};
+
+// gets keys for an object
+function keys (obj) {
+  if (Object.keys) return Object.keys(obj);
+
+  var keys = [];
+
+  for (var i in obj) {
+    if (obj.hasOwnProperty(i)) {
+      keys.push(i);
+    }
+  }
+
+  return keys;
+};
+
+// runs a suite
+function suite (file, fn) {
+  var passed = {}
+    , failed = {};
+
+  // register current suite
+  currentSuite = file;
+
+  // inject test case
+  var li = $('<li class="loading">').append(
+    $('<span class="name">').append(
+      $('<a>').attr('href', '/test/' + file).text(file)
+    )
+  ).appendTo('.test-list');
+
+  // dynamically load module
+  load(file, function (suite) {
+    if (!suite) return;
+
+    var start = new Date;
+
+    function complete () {
+      var ok = !keys(failed).length
+        , elapsed = Math.round((new Date - start) / 1000);
+
+      // update dom
+      li.removeClass('loading');
+      li.append('<span class="bullet">&bull;</span>');
+
+      if (ok) {
+        li.append(' all passed');
+      } else {
+        li.append(' failing test');
+        li.addClass('test-failure');
+      }
+
+      li.append(
+        $('<div class="details">')
+          .html(
+              'Passed: ' + keys(passed).length
+            + ' &mdash; Failed: <em>' + keys(failed).length
+            + '</em> &mdash; Elapsed: <em>' + elapsed
+            + '</em> seconds &mdash; '
+          )
+          .append(
+            $('<a>Show details</a>')
+              .attr('href', '#')
+              .click(function () {
+                li.toggleClass('cases');
+                $(this).text(
+                  li.hasClass('cases')
+                    ? 'Hide details'
+                    : 'Show details'
+                );
+                return false;
+              })
+          )
+      );
+
+      var casesUl = $('<ul class="cases">').appendTo(li);
+      for (var i = 0, l = cases.length; i < l; i++) {
+        var detail = $('<li>')
+          .text(cases[i])
+          .addClass(failed[cases[i]] ? 'failed' : '')
+          .appendTo(casesUl);
+
+        if (failed[cases[i]]) {
+          if (window.console && console.log) {
+            console.log(failed[cases[i]]);
+          }
+
+          detail.append($('<span class="error">').text(String(failed[cases[i]])));
+        }
+      }
+
+      // fire callback
+      fn({
+          status: ok
+        , passed: passed
+        , failed: failed
+      });
+    };
+
+    var cases = keys(suite)
+      , i = 0;
+
+    if (!cases.length) {
+      return complete();
+    }
+
+    currentCase = cases[i];
+
+    test(suite[cases[i]], function check (err) {
+      if (err) {
+        failed[cases[i]] = err;
+      } else {
+        passed[cases[i]] = true;
+      }
+
+      if (cases[++i]) {
+        currentCase = cases[i];
+        test(suite[cases[i]], check);
+      } else {
+        complete();
+      }
+    });
+  });
+};
+
+// runs a test
+function test (testcase, fn) {
+  var timer;
+
+  window.onerror = function (err) {
+    complete(err);
+  };
+
+  function complete (err) {
+    if (complete.run) return;
+    if (timer) clearTimeout(timer);
+    complete.run = true;
+    window.onerror = null;
+    fn(err);
+  };
+
+  try {
+    if (testcase.length > 0) {
+      var timer = setTimeout(function () {
+        complete(new Error('Timeout'));
+      }, 2000);
+
+      testcase(complete);
+    } else {
+      testcase();
+      complete();
+    }
+  } catch (e) {
+    complete(e);
+  }
+};
+
+// exposes a function to easily create a server for the current test
+
+function create (nsp) {
+  if (!testsPorts[currentSuite]) {
+    throw new Error('No socket server defined for suite "' + currentSuite + '"');
+  }
+
+  if (!testsPorts[currentSuite][currentCase]) {
+    throw new Error('No socket server defined for suite "' + currentSuite
+      + '" and case "' + currentCase + '"');
+  }
+
+  return io.connect(
+      document.location.protocol + '//' + document.location.hostname
+    + ':' + testsPorts[currentSuite][currentCase] + (nsp || '')
+  );
+};
diff --git a/node/node_modules/socket.io-client/support/test-runner/public/javascript/script.js b/node/node_modules/socket.io-client/support/test-runner/public/javascript/script.js
new file mode 100644 (file)
index 0000000..075e4f4
--- /dev/null
@@ -0,0 +1,107 @@
+!function(win, doc, timeout) {
+  var head = doc.getElementsByTagName('head')[0],
+      list = {}, ids = {}, delay = {},
+      scripts = {}, s = 'string', f = false,
+      push = 'push', domContentLoaded = 'DOMContentLoaded', readyState = 'readyState',
+      addEventListener = 'addEventListener', onreadystatechange = 'onreadystatechange',
+      every = function(ar, fn) {
+        for (var i = 0, j = ar.length; i < j; ++i) {
+          if (!fn(ar[i])) {
+            return f;
+          }
+        }
+        return 1;
+      };
+      function each(ar, fn) {
+        every(ar, function(el) {
+          return !fn(el);
+        });
+      }
+
+  if (!doc[readyState] && doc[addEventListener]) {
+    doc[addEventListener](domContentLoaded, function fn() {
+      doc.removeEventListener(domContentLoaded, fn, f);
+      doc[readyState] = "complete";
+    }, f);
+    doc[readyState] = "loading";
+  }
+
+  var $script = function(paths, idOrDone, optDone) {
+    paths = paths[push] ? paths : [paths];
+    var idOrDoneIsDone = idOrDone && idOrDone.call,
+        done = idOrDoneIsDone ? idOrDone : optDone,
+        id = idOrDoneIsDone ? paths.join('') : idOrDone,
+        queue = paths.length;
+        function loopFn(item) {
+          return item.call ? item() : list[item];
+        }
+        function callback() {
+          if (!--queue) {
+            list[id] = 1;
+            done && done();
+            for (var dset in delay) {
+              every(dset.split('|'), loopFn) && !each(delay[dset], loopFn) && (delay[dset] = []);
+            }
+          }
+        }
+    timeout(function() {
+      each(paths, function(path) {
+        if (scripts[path]) {
+          id && (ids[id] = 1);
+          callback();
+          return;
+        }
+        scripts[path] = 1;
+        id && (ids[id] = 1);
+        create($script.path ?
+          $script.path + path + '.js' :
+          path, callback);
+      });
+    }, 0);
+    return $script;
+  };
+
+  function create(path, fn) {
+    var el = doc.createElement("script"),
+        loaded = f;
+    el.onload = el.onerror = el[onreadystatechange] = function () {
+      if ((el[readyState] && !(/^c|loade/.test(el[readyState]))) || loaded) {
+        return;
+      }
+      el.onload = el[onreadystatechange] = null;
+      loaded = 1;
+      fn();
+    };
+    el.async = 1;
+    el.src = path;
+    head.insertBefore(el, head.firstChild);
+  }
+
+  $script.get = create;
+
+  $script.ready = function(deps, ready, req) {
+    deps = deps[push] ? deps : [deps];
+    var missing = [];
+    !each(deps, function(dep) {
+      list[dep] || missing[push](dep);
+    }) && every(deps, function(dep) {
+      return list[dep];
+    }) ? ready() : !function(key) {
+      delay[key] = delay[key] || [];
+      delay[key][push](ready);
+      req && req(missing);
+    }(deps.join('|'));
+    return $script;
+  };
+
+  var old = win.$script;
+  $script.noConflict = function () {
+    win.$script = old;
+    return this;
+  };
+
+  (typeof module !== 'undefined' && module.exports) ?
+    (module.exports = $script) :
+    (win['$script'] = $script);
+
+}(this, document, setTimeout);
diff --git a/node/node_modules/socket.io-client/support/test-runner/public/stylesheets/main.css b/node/node_modules/socket.io-client/support/test-runner/public/stylesheets/main.css
new file mode 100644 (file)
index 0000000..9ff44d5
--- /dev/null
@@ -0,0 +1,116 @@
+body {
+  font-family: "Helvetica", "Helvetica Neue", sans-serif;
+  margin: 0;
+  color: #333;
+  font-size: 16px;
+  line-height: 1.5em;
+  word-spacing: 0.1em;
+  font-weight: 400;
+  background: #f9f9f9;
+  padding: 50px;
+}
+a {
+  border-bottom: 1px solid #999;
+  text-decoration: none;
+}
+a:hover {
+  border-color: transparent;
+  background: #eaeaea;
+}
+h2 {
+  font-weight: normal;
+  font-size: 28px;
+  margin: 24px 0 32px;
+}
+h2 a {
+  color: #666;
+  font-style: normal;
+}
+.test-list {
+  margin: 0;
+  padding: 0;
+  list-style: none;
+}
+.test-list > li {
+  margin-left: 36px;
+  margin-bottom: 12px;
+  position: relative;
+}
+.test-list > li::before {
+  content: "✔";
+  background: #acd843;
+  padding: 1px 6px;
+  position: absolute;
+  top: -2px;
+  right: 100%;
+  margin-right: 8px;
+  color: #fff;
+}
+.test-list > li.loading::before {
+  content: "…";
+  font-size: 18px;
+  line-height: 16px;
+  vertical-align: middle;
+  padding: 0px 4px 10px;
+  background: #ccc;
+}
+.test-list > li.test-failure::before {
+  content: "✘";
+  font-size: 18px;
+  padding: 1px 7px;
+  background: #cd3a33;
+}
+.test-list > li span.name {
+  display: inline-block;
+  width: 150px;
+}
+.test-list > li span.bullet {
+  display: inline-block;
+  width: 20px;
+  font-size: 20px;
+  vertical-align: middle;
+}
+.test-list > li a {
+  color: #333;
+}
+.test-list > li .details {
+  font-size: 12px;
+  color: #666;
+}
+.test-list > li .details em {
+  font-style: normal;
+  color: #333;
+}
+.test-list > li ul.cases {
+  font-size: 11px;
+  padding: 0;
+  display: none;
+}
+.test-list > li ul.cases li {
+  list-style-type: none;
+  color: #000;
+}
+.test-list > li ul.cases li::before {
+  content: "✔";
+  color: #acd843;
+  margin-right: 5px;
+}
+.test-list > li ul.cases li.failed::before {
+  content: "✘";
+  color: #cd3a33;
+  margin-right: 6px;
+  margin-left: 1px;
+}
+.test-list > li ul.cases li.failed {
+  color: #cd3a33;
+}
+.test-list > li.cases ul.cases {
+  display: block;
+}
+.test-list > li.cases ul.cases span.error {
+  color: #cd3a33;
+  display: block;
+  line-height: 5px;
+  padding-left: 14px;
+  padding-bottom: 5px;
+}
diff --git a/node/node_modules/socket.io-client/support/test-runner/public/stylesheets/main.styl b/node/node_modules/socket.io-client/support/test-runner/public/stylesheets/main.styl
new file mode 100644 (file)
index 0000000..ca3eeca
--- /dev/null
@@ -0,0 +1,101 @@
+// design heavily based on https://github.com/kkaefer/overlord, released under MIT
+// Copyright (c) 2010-2011 Konstantin Käfer
+
+body
+  font-family 'Helvetica', 'Helvetica Neue', sans-serif
+  margin 0
+  color #333
+  font-size 16px
+  line-height 1.5em
+  word-spacing 0.1em
+  font-weight 400
+  background #F9F9F9
+  padding 50px
+
+a
+  border-bottom 1px solid #999
+  text-decoration none
+  &:hover
+    border-color transparent
+    background #EAEAEA
+
+h2
+  font-weight normal
+  font-size 28px
+  margin 24px 0 32px
+  a
+    color #666
+    font-style normal
+
+.test-list
+  margin 0
+  padding 0
+  list-style none
+  > li
+    margin-left 36px
+    margin-bottom 12px
+    position relative
+    &::before
+      content "✔"
+      background #ACD843
+      padding 1px 6px
+      position absolute
+      top -2px
+      right 100%
+      margin-right 8px
+      color white
+    &.loading::before
+      content "…"
+      font-size 18px
+      line-height 16px
+      vertical-align middle
+      padding 0px 4px 10px
+      background #ccc
+    &.test-failure::before
+      content "✘"
+      font-size 18px
+      padding 1px 7px
+      background #CD3A33
+    span.name
+      display inline-block
+      width 150px
+    span.bullet
+      display inline-block
+      width 20px
+      font-size 20px
+      vertical-align middle
+    a
+      color #333
+    .details
+      font-size 12px
+      color #666
+      em
+        font-style normal
+        color #333
+    ul.cases
+      font-size 11px
+      padding 0
+      display none
+      li
+        list-style-type none
+        color #000
+        &::before
+          content "✔"
+          color #ACD843
+          margin-right 5px
+        &.failed::before
+          content "✘"
+          color #CD3A33
+          margin-right 6px
+          margin-left 1px
+        &.failed
+          color #CD3A33
+  > li.cases
+    ul.cases
+      display block
+      span.error
+        color #CD3A33
+        display block
+        line-height 5px
+        padding-left 14px
+        padding-bottom 5px
index fef12c84c008a6e06b63795d910106a1dec70e0b..989e2bc562c78f74b0167c3e0aed8422522ef71b 100644 (file)
@@ -30,7 +30,7 @@ module.exports = {
       var lines = result.split('\n');
       lines.length.should().be.below(5);
       lines[0].should().match(/production/gi);
-      Buffer.byteLength(result).should().be.below(41000);
+      Buffer.byteLength(result).should().be.below(43000);
     });
   },
 
@@ -99,6 +99,14 @@ module.exports = {
     });
   },
 
+  'preserve the encoding during minification': function () {
+    builder(function (err, result) {
+      should.strictEqual(err, null);
+
+      result.should().match(/(\\ufffd)/g);
+    })
+  },
+
   'globals': function () {
     builder(function (err, result) {
       should.strictEqual(err, null);
index 6714585e9ff913ef1817b74f8a9ac933a2fce2b1..0022afb23517d9d18b856944170874585f23f144 100644 (file)
           parser.encodePacket({ type: 'message', data: '5', endpoint: '' })
         , parser.encodePacket({ type: 'message', data: '53d', endpoint: '' })
       ]).should().eql('\ufffd5\ufffd3:::5\ufffd7\ufffd3:::53d')
+    },
+
+    'test decoding newline': function () {
+      parser.decodePacket('3:::\n').should().eql({
+          type: 'message'
+        , endpoint: ''
+        , data: '\n'
+      });
     }
 
   };
index 8fd1637bffcc681441dd97e78d1b39263894ff21..53c967e456bf74eb99cb32cc470ea48607847403 100644 (file)
         next();
       }
 
-      io.on('connect', function(){
+      socket.on('connect', function(){
         connect++;
       });
 
       }).on('error', function (msg) {
         throw new Error(msg || 'Received an error');
       });
-
-    },
-
-    'test different namespace connection methods': function (next) {
-      var io = create('/a')
-        , connect = 0
-        , message = 0
-        , socket = io.socket;
-
-      function finish () {
-        socket.of('').disconnect();
-        connect.should().equal(3);
-        message.should().equal(3);
-        next();
-      }
-
-      io.on('connect', function () {
-        ++connect;
-      }).on('message', function (data) {
-        data.should().eql('a');
-
-        if (++message === 3) finish();
-      }).on('error', function (msg) {
-        throw new Error(msg || 'Received an error');
-      });
-
-      socket.of('/b').on('connect', function () {
-        ++connect;
-      }).on('message', function (data) {
-        data.should().eql('b');
-
-        if (++message === 3) finish();
-      }).on('error', function (msg) {
-        throw new Error(msg || 'Received an error');
-      });
-
-      io.of('/c').on('connect', function () {
-        ++connect;
-      }).on('message', function (data) {
-        data.should().eql('c');
-
-        if (++message === 3) finish();
-      }).on('error', function (msg) {
-        throw new Error(msg || 'Received an error');
-      });
-
     },
 
     'test disconnecting from namespaces': function (next) {
       })
     },
 
+    'test emitting multiple events at once to the server': function (next) {
+      var socket = create();
+
+      socket.on('connect', function () {
+        socket.emit('print', 'foo');
+        socket.emit('print', 'bar');
+      });
+
+      socket.on('done', function () {
+        socket.disconnect();
+        next();
+      });
+    },
+
     'test emitting an event from server and sending back data': function (next) {
       var socket = create();
 
         socket.disconnect();
         next();
       });
+    },
+
+    'test encoding a payload': function (next) {
+      var socket = create('/woot');
+
+      socket.on('error', function (msg) {
+        throw new Error(msg || 'Received an error');
+      });
+
+      socket.on('connect', function () {
+        socket.socket.setBuffer(true);
+        socket.send('ñ');
+        socket.send('ñ');
+        socket.send('ñ');
+        socket.send('ñ');
+        socket.socket.setBuffer(false);
+      });
+
+      socket.on('done', function () {
+        socket.disconnect();
+        next();
+      });
+    },
+
+    'test sending query strings to the server': function (next) {
+      var socket = create('?foo=bar');
+
+      socket.on('error', function (msg) {
+        throw new Error(msg || 'Received an error');
+      });
+
+      socket.on('message', function (data) {
+        data.query.foo.should().eql('bar');
+
+        socket.disconnect();
+        next();
+      });
+    },
+
+    'test sending newline': function (next) {
+      var socket = create();
+
+      socket.on('error', function (msg) {
+        throw new Error(msg || 'Received an error');
+      });
+
+      socket.send('\n');
+
+      socket.on('done', function () {
+        socket.disconnect();
+        next();
+      });
+    },
+
+    'test sending unicode': function (next) {
+      var socket = create();
+
+      socket.on('error', function (msg) {
+        throw new Error(msg || 'Received an error');
+      });
+
+      socket.json.send({ test: "\u2028" });
+
+      socket.on('done', function () {
+        socket.disconnect();
+        next();
+      });
     }
 
   };
index 6ba47ac31eb8f8948bb2a8a19a2fe0cefb2a93f9..30db5a63c78f288ab296248030aa460055dad697 100644 (file)
       io.util.uniqueUri(path).should().eql('https://google.com:443');
     },
 
+    'chunk query string': function () {
+      io.util.chunkQuery('foo=bar').should().be.a('object');
+      io.util.chunkQuery('foo=bar').foo.should().eql('bar');
+    },
+
+    'merge query strings': function () {
+      var base = io.util.query('foo=bar', 'foo=baz')
+        , add = io.util.query('foo=bar', 'bar=foo')
+
+      base.should().eql('?foo=baz');
+      add.should().eql('?foo=bar&bar=foo');
+
+      io.util.query('','').should().eql('');
+      io.util.query('foo=bar', '').should().eql('?foo=bar');
+      io.util.query('', 'foo=bar').should().eql('?foo=bar');
+    },
+
     'request': function () {
-      if ('undefined' == typeof window) {
-        should.equal(io.util.request(), null);
-      } else {
-        io.util.request().should().be.a('object');
-      }
+      var type = typeof io.util.request();
+      type.should().eql('object');
     },
 
     'is array': function () {
index 2a4a8102afe9f6f4d7cda1dbd7f441e450a58716..caa757d531cdb8f025f2d6359da72707c36956a7 100644 (file)
@@ -1,4 +1,73 @@
 
+0.8.3 / 2011-09-03
+==================
+
+  * Fixed `\n` parsing for non-JSON packets (fixes #479).
+  * Fixed parsing of certain unicode characters (fixes #451).
+  * Fixed transport message packet logging.
+  * Fixed emission of `error` event resulting in an uncaught exception if unhandled (fixes #476).
+  * Fixed; allow for falsy values as the configuration value of `log level` (fixes #491).
+  * Fixed repository URI in `package.json`. Fixes #504.
+  * Added text/plain content-type to handshake responses [einaros]
+  * Improved single byte writes [einaros]
+  * Updated socket.io-flashsocket default port from 843 to 10843 [3rd-Eden]
+  * Updated client.
+
+0.8.2 / 2011-08-29
+==================
+
+  * Updated client.
+
+0.8.1 / 2011-08-29
+==================
+
+  * Fixed utf8 bug in send framing in websocket [einaros]
+  * Fixed typo in docs [Znarkus]
+  * Fixed bug in send framing for over 64kB of data in websocket [einaros]
+  * Corrected ping handling in websocket transport [einaros]
+
+0.8.0 / 2011-08-28
+==================
+
+  * Updated to work with two-level websocket versioning. [einaros]
+  * Added hybi07 support. [einaros]
+  * Added hybi10 support. [einaros]
+  * Added http referrer verification to manager.js verifyOrigin. [einaors]
+
+0.7.11 / 2011-08-27
+===================
+
+  * Updated socket.io-client.
+
+0.7.10 / 2011-08-27
+===================
+
+  * Updated socket.io-client.
+
+0.7.9 / 2011-08-12
+==================
+
+  * Updated socket.io-client.
+  * Make sure we only do garbage collection when the server we receive is actually run.
+
+0.7.8 / 2011-08-08
+==================
+
+  * Changed; make sure sio#listen passes options to both HTTP server and socket.io manager.
+  * Added docs for sio#listen.
+  * Added options parameter support for Manager constructor.
+  * Added memory leaks tests and test-leaks Makefile task.
+  * Removed auto npm-linking from make test.
+  * Make sure that you can disable heartbeats. [3rd-Eden]
+  * Fixed rooms memory leak [3rd-Eden]
+  * Send response once we got all POST data, not immediately [Pita]
+  * Fixed onLeave behavior with missing clientsk [3rd-Eden]
+  * Prevent duplicate references in rooms.
+  * Added alias for `to` to `in` and `in` to `to`.
+  * Fixed roomClients definition.
+  * Removed dependency on redis for installation without npm [3rd-Eden]
+  * Expose path and querystring in handshakeData [3rd-Eden]
+
 0.7.7 / 2011-07-12
 ==================
 
index 6899cb262df87eb05a2018cbe792a4c3a5ff1271..79817058c3beaa79981b9afccb40c1dbdf465480 100644 (file)
@@ -2,7 +2,6 @@
 ALL_TESTS = $(shell find test/ -name '*.test.js')
 
 run-tests:
-       @npm link > /dev/null --local
        @./node_modules/.bin/expresso \
                -t 3000 \
                -I support \
@@ -17,4 +16,7 @@ test:
 test-cov:
        @TESTFLAGS=--cov $(MAKE) test
 
+test-leaks:
+       @ls test/leaks/* | xargs node --expose_debug_as=debug --expose_gc
+
 .PHONY: test
index a52e4b61b44b31aeea288df5439d8c437931622a..86c023333ea9fc478f9f6ac2ed4675b0b2fa5b6f 100644 (file)
@@ -20,7 +20,7 @@ Next, attach it to a HTTP/HTTPS server. If you're using the fantastic `express`
 web framework:
 
 ```js
-var app = express.createServer();
+var app = express.createServer()
   , io = io.listen(app);
 
 app.listen(80);
@@ -60,7 +60,7 @@ Besides `connect`, `message` and `disconnect`, you can emit custom events:
 var io = require('socket.io').listen(80);
 
 io.sockets.on('connection', function (socket) {
-  io.sockets.emit('this', { will: 'be received by everyone');
+  io.sockets.emit('this', { will: 'be received by everyone' });
 
   socket.on('private message', function (from, msg) {
     console.log('I received a private message by ', from, ' saying ', msg);
diff --git a/node/node_modules/socket.io/TODO b/node/node_modules/socket.io/TODO
deleted file mode 100644 (file)
index a97b07a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-Initialize the Socket object upon handshake.
-Pass it to authorization function(s).
-When a transport opens, publish the transport name with the 'open' channel
-Set the transport name to the Socket object.
-Upon handshake, set a timeout of x seconds to GC that Socket object.
diff --git a/node/node_modules/socket.io/examples/chat/app.js b/node/node_modules/socket.io/examples/chat/app.js
new file mode 100644 (file)
index 0000000..23f09f0
--- /dev/null
@@ -0,0 +1,87 @@
+
+/**
+ * Bootstrap app.
+ */
+
+require.paths.unshift(__dirname + '/../../lib/');
+
+/**
+ * Module dependencies.
+ */
+
+var express = require('express')
+  , stylus = require('stylus')
+  , nib = require('nib')
+  , sio = require('socket.io');
+
+/**
+ * App.
+ */
+
+var app = express.createServer();
+
+/**
+ * App configuration.
+ */
+
+app.configure(function () {
+  app.use(stylus.middleware({ src: __dirname + '/public', compile: compile }))
+  app.use(express.static(__dirname + '/public'));
+  app.set('views', __dirname);
+  app.set('view engine', 'jade');
+
+  function compile (str, path) {
+    return stylus(str)
+      .set('filename', path)
+      .use(nib());
+  };
+});
+
+/**
+ * App routes.
+ */
+
+app.get('/', function (req, res) {
+  res.render('index', { layout: false });
+});
+
+/**
+ * App listen.
+ */
+
+app.listen(3000, function () {
+  var addr = app.address();
+  console.log('   app listening on http://' + addr.address + ':' + addr.port);
+});
+
+/**
+ * Socket.IO server (single process only)
+ */
+
+var io = sio.listen(app)
+  , nicknames = {};
+
+io.sockets.on('connection', function (socket) {
+  socket.on('user message', function (msg) {
+    socket.broadcast.emit('user message', socket.nickname, msg);
+  });
+
+  socket.on('nickname', function (nick, fn) {
+    if (nicknames[nick]) {
+      fn(true);
+    } else {
+      fn(false);
+      nicknames[nick] = socket.nickname = nick;
+      socket.broadcast.emit('announcement', nick + ' connected');
+      io.sockets.emit('nicknames', nicknames);
+    }
+  });
+
+  socket.on('disconnect', function () {
+    if (!socket.nickname) return;
+
+    delete nicknames[socket.nickname];
+    socket.broadcast.emit('announcement', socket.nickname + ' disconnected');
+    socket.broadcast.emit('nicknames', nicknames);
+  });
+});
diff --git a/node/node_modules/socket.io/examples/chat/index.jade b/node/node_modules/socket.io/examples/chat/index.jade
new file mode 100644 (file)
index 0000000..0633d8b
--- /dev/null
@@ -0,0 +1,83 @@
+doctype 5
+html
+  head
+    link(href='/stylesheets/style.css', rel='stylesheet')
+    script(src='http://code.jquery.com/jquery-1.6.1.min.js')
+    script(src='/socket.io/socket.io.js')
+    script
+      // socket.io specific code
+      var socket = io.connect();
+
+      socket.on('connect', function () {
+        $('#chat').addClass('connected');
+      });
+
+      socket.on('announcement', function (msg) {
+        $('#lines').append($('<p>').append($('<em>').text(msg)));
+      });
+
+      socket.on('nicknames', function (nicknames) {
+        $('#nicknames').empty().append($('<span>Online: </span>'));
+        for (var i in nicknames) {
+          $('#nicknames').append($('<b>').text(nicknames[i]));
+        }
+      });
+
+      socket.on('user message', message);
+      socket.on('reconnect', function () {
+        $('#lines').remove();
+        message('System', 'Reconnected to the server');
+      });
+
+      socket.on('reconnecting', function () {
+        message('System', 'Attempting to re-connect to the server');
+      });
+
+      socket.on('error', function (e) {
+        message('System', e ? e : 'A unknown error occurred');
+      });
+
+      function message (from, msg) {
+        $('#lines').append($('<p>').append($('<b>').text(from), msg));
+      }
+
+      // dom manipulation
+      $(function () {
+        $('#set-nickname').submit(function (ev) {
+          socket.emit('nickname', $('#nick').val(), function (set) {
+            if (!set) {
+              clear();
+              return $('#chat').addClass('nickname-set');
+            }
+            $('#nickname-err').css('visibility', 'visible');
+          });
+          return false;
+        });
+
+        $('#send-message').submit(function () {
+          message('me', $('#message').val());
+          socket.emit('user message', $('#message').val());
+          clear();
+          $('#lines').get(0).scrollTop = 10000000;
+          return false;
+        });
+
+        function clear () {
+          $('#message').val('').focus();
+        };
+      });
+  body
+    #chat
+      #nickname
+        form.wrap#set-nickname
+          p Please type in your nickname and press enter.
+          input#nick
+          p#nickname-err Nickname already in use
+      #connecting
+        .wrap Connecting to socket.io server
+      #messages
+        #nicknames
+        #lines
+      form#send-message
+        input#message
+        button Send
diff --git a/node/node_modules/socket.io/examples/chat/package.json b/node/node_modules/socket.io/examples/chat/package.json
new file mode 100644 (file)
index 0000000..f095e85
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "name": "chat.io"
+  , "description": "example chat application with socket.io"
+  , "version": "0.0.1"
+  , "dependencies": {
+        "express": "2.3.11"
+      , "jade": "0.12.1"
+      , "stylus": "0.13.3"
+      , "nib": "0.0.8"
+    }
+}
diff --git a/node/node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl b/node/node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl
new file mode 100644 (file)
index 0000000..fb5644c
--- /dev/null
@@ -0,0 +1,96 @@
+border-radius(n)
+  -webkit-border-radius n
+  -moz-border-radius n
+  border-radius n
+
+// replace str with val
+
+replace(expr, str, val)
+  expr = clone(expr)
+  for e, i in expr
+    if str == e
+      expr[i] = val
+  expr
+
+// normalize gradient point (webkit)
+
+grad-point(pos)
+  if length(pos) == 1
+    return left pos if pos in (top bottom)
+    return pos top if pos in (left right)
+  else if pos[0] in (top bottom)
+    pos[1] pos[0]
+  else
+    pos
+
+// implicit color stop position
+
+pos-in-stops(i, stops)
+  len = length(stops)
+  if len - 1 == i
+    100%
+  else if i
+    unit(i / len * 100, '%')
+  else
+    0%
+
+// normalize color stops
+//   - (color pos) -> (pos color)
+//   - (color) -> (implied-pos color)
+
+normalize-stops(stops)
+  stops = clone(stops)
+  for stop, i in stops
+    if length(stop) == 1
+      color = stop[0]
+      stop[0] = pos-in-stops(i, stops)
+      stop[1] = color
+    else if typeof(stop[1]) == 'unit'
+      pos = stop[1]
+      stop[1] = stop[0]
+      stop[0] = pos
+  stops
+
+// join color stops with the given translation function
+
+join-stops(stops, translate)
+  str = ''
+  len = length(stops)
+  for stop, i in stops
+    str += ', ' if i
+    pos = stop[0]
+    color = stop[1]
+    str += translate(color, pos)
+  unquote(str)
+
+// webkit translation function
+
+webkit-stop(color, pos)
+  s('color-stop(%d, %s)', pos / 100, color)
+
+// mozilla translation function
+
+moz-stop(color, pos)
+  s('%s %s', color, pos)
+
+// create a linear gradient with the given start
+// position, followed by color stops
+
+linear-gradient(start, stops...)
+  error('color stops required') unless length(stops)
+  prop = current-property[0]
+  val = current-property[1]
+  stops = normalize-stops(stops)
+
+  // webkit
+  end = grad-point(opposite-position(start))
+  webkit = s('-webkit-gradient(linear, %s, %s, %s)', grad-point(start), end, join-stops(stops, webkit-stop))
+  add-property(prop, replace(val, '__CALL__', webkit))
+
+  // moz
+  stops = join-stops(stops, moz-stop)
+  moz = s('-moz-linear-gradient(%s, %s)', start, stops)
+  add-property(prop, replace(val, '__CALL__', moz))
+
+  // literal
+  s('linear-gradient(%s, %s)', start, stops)
diff --git a/node/node_modules/socket.io/examples/chat/public/stylesheets/style.css b/node/node_modules/socket.io/examples/chat/public/stylesheets/style.css
new file mode 100644 (file)
index 0000000..42cf98f
--- /dev/null
@@ -0,0 +1,188 @@
+#chat,
+#nickname,
+#messages {
+  width: 600px;
+}
+#chat {
+  position: relative;
+  border: 1px solid #ccc;
+}
+#nickname,
+#connecting {
+  position: absolute;
+  height: 410px;
+  z-index: 100;
+  left: 0;
+  top: 0;
+  background: #fff;
+  text-align: center;
+  width: 600px;
+  font: 15px Georgia;
+  color: #666;
+  display: block;
+}
+#nickname .wrap,
+#connecting .wrap {
+  padding-top: 150px;
+}
+#nickname input {
+  border: 1px solid #ccc;
+  padding: 10px;
+}
+#nickname input:focus {
+  border-color: #999;
+  outline: 0;
+}
+#nickname #nickname-err {
+  color: #8b0000;
+  font-size: 12px;
+  visibility: hidden;
+}
+.connected #connecting {
+  display: none;
+}
+.nickname-set #nickname {
+  display: none;
+}
+#messages {
+  height: 380px;
+  background: #eee;
+}
+#messages em {
+  text-shadow: 0 1px 0 #fff;
+  color: #999;
+}
+#messages p {
+  padding: 0;
+  margin: 0;
+  font: 12px Helvetica, Arial;
+  padding: 5px 10px;
+}
+#messages p b {
+  display: inline-block;
+  padding-right: 10px;
+}
+#messages p:nth-child(even) {
+  background: #fafafa;
+}
+#messages #nicknames {
+  background: #ccc;
+  padding: 2px 4px 4px;
+  font: 11px Helvetica;
+}
+#messages #nicknames span {
+  color: #000;
+}
+#messages #nicknames b {
+  display: inline-block;
+  color: #fff;
+  background: #999;
+  padding: 3px 6px;
+  margin-right: 5px;
+  -webkit-border-radius: 10px;
+  -moz-border-radius: 10px;
+  border-radius: 10px;
+  text-shadow: 0 1px 0 #666;
+}
+#messages #lines {
+  height: 355px;
+  overflow: auto;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+#messages #lines::-webkit-scrollbar {
+  width: 6px;
+  height: 6px;
+}
+#messages #lines::-webkit-scrollbar-button:start:decrement,
+#messages #lines ::-webkit-scrollbar-button:end:increment {
+  display: block;
+  height: 10px;
+}
+#messages #lines::-webkit-scrollbar-button:vertical:increment {
+  background-color: #fff;
+}
+#messages #lines::-webkit-scrollbar-track-piece {
+  background-color: #fff;
+  -webkit-border-radius: 3px;
+}
+#messages #lines::-webkit-scrollbar-thumb:vertical {
+  height: 50px;
+  background-color: #ccc;
+  -webkit-border-radius: 3px;
+}
+#messages #lines::-webkit-scrollbar-thumb:horizontal {
+  width: 50px;
+  background-color: #fff;
+  -webkit-border-radius: 3px;
+}
+#send-message {
+  background: #fff;
+  position: relative;
+}
+#send-message input {
+  border: none;
+  height: 30px;
+  padding: 0 10px;
+  line-height: 30px;
+  vertical-align: middle;
+  width: 580px;
+}
+#send-message input:focus {
+  outline: 0;
+}
+#send-message button {
+  position: absolute;
+  top: 5px;
+  right: 5px;
+}
+button {
+  margin: 0;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  user-select: none;
+  display: inline-block;
+  text-decoration: none;
+  background: #43a1f7;
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #43a1f7), color-stop(1, #377ad0));
+  background: -webkit-linear-gradient(top, #43a1f7 0%, #377ad0 100%);
+  background: -moz-linear-gradient(top, #43a1f7 0%, #377ad0 100%);
+  background: linear-gradient(top, #43a1f7 0%, #377ad0 100%);
+  border: 1px solid #2e70c4;
+  -webkit-border-radius: 16px;
+  -moz-border-radius: 16px;
+  border-radius: 16px;
+  color: #fff;
+  font-family: "lucida grande", sans-serif;
+  font-size: 11px;
+  font-weight: normal;
+  line-height: 1;
+  padding: 3px 10px 5px 10px;
+  text-align: center;
+  text-shadow: 0 -1px 1px #2d6dc0;
+}
+button:hover,
+button.hover {
+  background: darker;
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #43a1f7), color-stop(1, #2e70c4));
+  background: -webkit-linear-gradient(top, #43a1f7 0%, #2e70c4 100%);
+  background: -moz-linear-gradient(top, #43a1f7 0%, #2e70c4 100%);
+  background: linear-gradient(top, #43a1f7 0%, #2e70c4 100%);
+  border: 1px solid #2e70c4;
+  cursor: pointer;
+  text-shadow: 0 -1px 1px #2c6bbb;
+}
+button:active,
+button.active {
+  background: #2e70c4;
+  border: 1px solid #2e70c4;
+  border-bottom: 1px solid #2861aa;
+  text-shadow: 0 -1px 1px #2b67b5;
+}
+button:focus,
+button.focus {
+  outline: none;
+  -webkit-box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0;
+  -moz-box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0;
+  box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0;
+}
diff --git a/node/node_modules/socket.io/examples/chat/public/stylesheets/style.styl b/node/node_modules/socket.io/examples/chat/public/stylesheets/style.styl
new file mode 100644 (file)
index 0000000..6289c94
--- /dev/null
@@ -0,0 +1,118 @@
+@import 'nib'
+
+#chat, #nickname, #messages
+  width 600px
+
+#chat
+  position relative
+  border 1px solid #ccc
+
+#nickname, #connecting
+  position absolute
+  height 410px
+  z-index 100
+  left 0
+  top 0
+  background #fff
+  text-align center
+  width 600px
+  font 15px Georgia
+  color #666
+  display block
+  .wrap
+    padding-top 150px
+
+#nickname
+  input
+    border 1px solid #ccc
+    padding 10px
+    &:focus
+      border-color #999
+      outline 0
+  #nickname-err
+    color darkred
+    font-size 12px
+    visibility hidden
+
+.connected
+  #connecting
+    display none
+
+.nickname-set
+  #nickname
+    display none
+
+#messages
+  height 380px
+  background #eee
+  em
+    text-shadow 0 1px 0 #fff
+    color #999
+  p
+    padding 0
+    margin 0
+    font 12px Helvetica, Arial
+    padding 5px 10px
+    b
+      display inline-block
+      padding-right 10px
+  p:nth-child(even)
+    background #fafafa
+  #nicknames
+    background #ccc
+    padding 2px 4px 4px
+    font 11px Helvetica
+    span
+      color black
+    b
+      display inline-block
+      color #fff
+      background #999
+      padding 3px 6px
+      margin-right 5px
+      border-radius 10px
+      text-shadow 0 1px 0 #666
+  #lines
+    height 355px
+    overflow auto
+    overflow-x hidden
+    overflow-y auto
+    &::-webkit-scrollbar
+      width 6px
+      height 6px
+    &::-webkit-scrollbar-button:start:decrement, ::-webkit-scrollbar-button:end:increment
+      display block
+      height 10px
+    &::-webkit-scrollbar-button:vertical:increment
+      background-color #fff
+    &::-webkit-scrollbar-track-piece
+      background-color #fff
+      -webkit-border-radius 3px
+    &::-webkit-scrollbar-thumb:vertical
+      height 50px
+      background-color #ccc
+      -webkit-border-radius 3px
+    &::-webkit-scrollbar-thumb:horizontal
+      width 50px
+      background-color #fff
+      -webkit-border-radius 3px
+
+#send-message
+  background #fff
+  position relative
+  input
+    border none
+    height 30px
+    padding 0 10px
+    line-height 30px
+    vertical-align middle
+    width 580px
+    &:focus
+      outline 0
+  button
+    position absolute
+    top 5px
+    right 5px
+
+button
+  download-button()
diff --git a/node/node_modules/socket.io/examples/irc-output/app.js b/node/node_modules/socket.io/examples/irc-output/app.js
new file mode 100644 (file)
index 0000000..591ec2a
--- /dev/null
@@ -0,0 +1,81 @@
+
+/**
+ * Bootstrap app.
+ */
+
+require.paths.unshift(__dirname + '/../../lib/');
+
+/**
+ * Module dependencies.
+ */
+
+var express = require('express')
+  , stylus = require('stylus')
+  , nib = require('nib')
+  , sio = require('socket.io')
+  , irc = require('./irc');
+
+/**
+ * App.
+ */
+
+var app = express.createServer();
+
+/**
+ * App configuration.
+ */
+
+app.configure(function () {
+  app.use(stylus.middleware({ src: __dirname + '/public', compile: compile }))
+  app.use(express.static(__dirname + '/public'));
+  app.set('views', __dirname);
+  app.set('view engine', 'jade');
+
+  function compile (str, path) {
+    return stylus(str)
+      .set('filename', path)
+      .use(nib());
+  };
+});
+
+/**
+ * App routes.
+ */
+
+app.get('/', function (req, res) {
+  res.render('index', { layout: false });
+});
+
+/**
+ * App listen.
+ */
+
+app.listen(3000, function () {
+  var addr = app.address();
+  console.log('   app listening on http://' + addr.address + ':' + addr.port);
+});
+
+/**
+ * Socket.IO server
+ */
+
+var io = sio.listen(app)
+
+/**
+ * Connect to IRC.
+ */
+
+var client = new irc.Client('irc.freenode.net', 6667);
+client.connect('socketio\\test\\' + String(Math.random()).substr(-3));
+client.on('001', function () {
+  this.send('JOIN', '#node.js');
+});
+client.on('PART', function (prefix) {
+  io.sockets.emit('announcement', irc.user(prefix) + ' left the channel');
+});
+client.on('JOIN', function (prefix) {
+  io.sockets.emit('announcement', irc.user(prefix) + ' joined the channel');
+});
+client.on('PRIVMSG', function (prefix, channel, text) {
+  io.sockets.emit('irc message', irc.user(prefix), text);
+});
diff --git a/node/node_modules/socket.io/examples/irc-output/index.jade b/node/node_modules/socket.io/examples/irc-output/index.jade
new file mode 100644 (file)
index 0000000..5468632
--- /dev/null
@@ -0,0 +1,28 @@
+doctype 5
+html
+  head
+    link(href='/stylesheets/style.css', rel='stylesheet')
+    script(src='http://code.jquery.com/jquery-1.6.1.min.js')
+    script(src='/socket.io/socket.io.js')
+    script
+      var socket = io.connect();
+
+      socket.on('connect', function () {
+        $('#irc').addClass('connected');
+      });
+
+      socket.on('announcement', function (msg) {
+        $('#messages').append($('<p>').append($('<em>').text(msg)));
+        $('#messages').get(0).scrollTop = 10000000;
+      });
+
+      socket.on('irc message', function (user, msg) {
+        $('#messages').append($('<p>').append($('<b>').text(user), msg));
+        $('#messages').get(0).scrollTop = 10000000;
+      });
+  body
+    h2 Node.JS IRC
+    #irc
+      #connecting
+        .wrap Connecting to socket.io server
+      #messages
diff --git a/node/node_modules/socket.io/examples/irc-output/irc.js b/node/node_modules/socket.io/examples/irc-output/irc.js
new file mode 100644 (file)
index 0000000..c89ddb0
--- /dev/null
@@ -0,0 +1,164 @@
+/**
+ * From https://github.com/felixge/nodelog/
+ */
+
+var sys = require('sys');
+var tcp = require('net');
+var irc = exports;
+
+function bind(fn, scope) {
+  var bindArgs = Array.prototype.slice.call(arguments);
+  bindArgs.shift();
+  bindArgs.shift();
+
+  return function() {
+    var args = Array.prototype.slice.call(arguments);
+    fn.apply(scope, bindArgs.concat(args));
+  };
+}
+
+function each(set, iterator) {
+  for (var i = 0; i < set.length; i++) {
+    var r = iterator(set[i], i);
+    if (r === false) {
+      return;
+    }
+  }
+}
+
+var Client = irc.Client = function(host, port) {
+  this.host = host || 'localhost';
+  this.port = port || 6667;
+
+  this.connection = null;
+  this.buffer = '';
+  this.encoding = 'utf8';
+  this.timeout = 10 * 60 * 60 * 1000;
+
+  this.nick = null;
+  this.user = null;
+  this.real = null;
+}
+sys.inherits(Client, process.EventEmitter);
+
+Client.prototype.connect = function(nick, user, real) {
+  var connection = tcp.createConnection(this.port, this.host);
+  connection.setEncoding(this.encoding);
+  connection.setTimeout(this.timeout);
+  connection.addListener('connect', bind(this.onConnect, this));
+  connection.addListener('data', bind(this.onReceive, this));
+  connection.addListener('end', bind(this.onEof, this));
+  connection.addListener('timeout', bind(this.onTimeout, this));
+  connection.addListener('close', bind(this.onClose, this));
+
+  this.nick = nick;
+  this.user = user || 'guest';
+  this.real = real || 'Guest';
+
+  this.connection = connection;
+};
+
+Client.prototype.disconnect = function(why) {
+  if (this.connection.readyState !== 'closed') {
+    this.connection.close();
+    sys.puts('disconnected (reason: '+why+')');
+    this.emit('DISCONNECT', why);
+  }
+};
+
+Client.prototype.send = function(arg1) {
+  if (this.connection.readyState !== 'open') {
+    return this.disconnect('cannot send with readyState: '+this.connection.readyState);
+  }
+
+  var message = [];
+  for (var i = 0; i< arguments.length; i++) {
+    if (arguments[i]) {
+      message.push(arguments[i]);
+    }
+  }
+  message = message.join(' ');
+
+  sys.puts('> '+message);
+  message = message + "\r\n";
+  this.connection.write(message, this.encoding);
+};
+
+Client.prototype.parse = function(message) {
+  var match = message.match(/(?:(:[^\s]+) )?([^\s]+) (.+)/);
+  var parsed = {
+    prefix: match[1],
+    command: match[2]
+  };
+
+  var params = match[3].match(/(.*?) ?:(.*)/);
+  if (params) {
+    // Params before :
+    params[1] = (params[1])
+      ? params[1].split(' ')
+      : [];
+    // Rest after :
+    params[2] = params[2]
+      ? [params[2]]
+      : [];
+
+    params = params[1].concat(params[2]);
+  } else {
+    params = match[3].split(' ');
+  }
+
+  parsed.params = params;
+  return parsed;
+};
+
+Client.prototype.onConnect = function() {
+  this.send('NICK', this.nick);
+  this.send('USER', this.user, '0', '*', ':'+this.real);
+};
+
+Client.prototype.onReceive = function(chunk) {
+  this.buffer = this.buffer + chunk;
+  
+  while (this.buffer) {
+    var offset = this.buffer.indexOf("\r\n");
+    if (offset < 0) {
+      return;
+    }
+  
+    var message = this.buffer.substr(0, offset);
+    this.buffer = this.buffer.substr(offset + 2);
+    sys.puts('< '+message);
+
+    message = this.parse(message);
+
+    this.emit.apply(this, [message.command, message.prefix].concat(message.params));
+
+    if (message !== false) {
+      this.onMessage(message);
+    }
+  }
+}; 
+
+Client.prototype.onMessage = function(message) {
+  switch (message.command) {
+    case 'PING':
+      this.send('PONG', ':'+message.params[0]);
+      break;
+  }
+};
+
+Client.prototype.onEof = function() {
+  this.disconnect('eof');
+};
+
+Client.prototype.onTimeout = function() {
+  this.disconnect('timeout');
+};
+
+Client.prototype.onClose = function() {
+  this.disconnect('close');
+};
+
+exports.user = function(prefix) {
+  return prefix.match(/:([^!]+)!/)[1]
+};
similarity index 72%
rename from node/node_modules/socket.io/new-old/package.json
rename to node/node_modules/socket.io/examples/irc-output/package.json
index c51985e2300f5b0514fb762c5cd959fd6a6d47aa..88bf42f75e6e92237de4043ecff6aea4028bb8d6 100644 (file)
@@ -1,9 +1,10 @@
 {
-    "name": "socket.io-website"
+    "name": "socket.io-irc"
   , "version": "0.0.1"
   , "dependencies": {
         "express": "2.3.11"
       , "jade": "0.12.1"
       , "stylus": "0.13.3"
+      , "nib": "0.0.8"
     }
 }
diff --git a/node/node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl b/node/node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl
new file mode 100644 (file)
index 0000000..2713512
--- /dev/null
@@ -0,0 +1,69 @@
+@import 'nib'
+
+h2
+  font bold 18px Helvetica Neue, Arial
+
+#irc, #messages
+  width 600px
+
+#irc
+  position relative
+  border 1px solid #ccc
+
+#connecting
+  position absolute
+  height 410px
+  z-index 100
+  left 0
+  top 0
+  background #fff
+  text-align center
+  width 600px
+  font 15px Georgia
+  color #666
+  display block
+  .wrap
+    padding-top 150px
+
+.connected
+  #connecting
+    display none
+
+#messages
+  height 380px
+  background #eee
+  overflow auto
+  overflow-x hidden
+  overflow-y auto
+  &::-webkit-scrollbar
+    width 6px
+    height 6px
+  &::-webkit-scrollbar-button:start:decrement, ::-webkit-scrollbar-button:end:increment
+    display block
+    height 10px
+  &::-webkit-scrollbar-button:vertical:increment
+    background-color #fff
+  &::-webkit-scrollbar-track-piece
+    background-color #fff
+    -webkit-border-radius 3px
+  &::-webkit-scrollbar-thumb:vertical
+    height 50px
+    background-color #ccc
+    -webkit-border-radius 3px
+  &::-webkit-scrollbar-thumb:horizontal
+    width 50px
+    background-color #fff
+    -webkit-border-radius 3px
+  em
+    text-shadow 0 1px 0 #fff
+    color #999
+  p
+    padding 0
+    margin 0
+    font 12px Helvetica, Arial
+    padding 5px 10px
+    b
+      display inline-block
+      padding-right 10px
+  p:nth-child(even)
+    background #fafafa
index 8c030912cd37296331d818042206ae7bae1484a1..d974afc4c87d2c35ad08939d8b398fdd4bd56805 100644 (file)
@@ -1,4 +1,3 @@
-
 /*!
  * socket.io-node
  * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
@@ -9,9 +8,7 @@
  * Module dependencies.
  */
 
-var http = require('http')
-  , https = require('https')
-  , fs = require('fs')
+var fs = require('fs')
   , url = require('url')
   , util = require('./util')
   , store = require('./store')
@@ -55,7 +52,7 @@ var parent = module.parent.exports
  * @api public
  */
 
-function Manager (server) {
+function Manager (server, options) {
   this.server = server;
   this.namespaces = {};
   this.sockets = this.of('');
@@ -74,7 +71,7 @@ function Manager (server) {
     , 'heartbeat interval': 20
     , 'polling duration': 20
     , 'flash policy server': true
-    , 'flash policy port': 843
+    , 'flash policy port': 10843
     , 'destroy upgrade': true
     , 'browser client': true
     , 'browser client minification': false
@@ -83,6 +80,10 @@ function Manager (server) {
     , 'client store expiration': 15
   };
 
+  for (var i in options) {
+    this.settings[i] = options[i];
+  }
+
   this.initStore();
 
   // reset listeners
@@ -99,6 +100,14 @@ function Manager (server) {
     self.handleUpgrade(req, socket, head);
   });
 
+  server.on('close', function () {
+    clearInterval(self.gc);
+  });
+
+  server.once('listening', function () {
+    self.gc = setInterval(self.garbageCollection.bind(self), 10000);
+  });
+
   for (var i in transports) {
     if (transports[i].init) {
       transports[i].init(this);
@@ -132,7 +141,7 @@ Manager.prototype.__defineGetter__('log', function () {
   if (this.disabled('log')) return;
 
   var logger = this.get('logger');
-  logger.level = this.get('log level');
+  logger.level = this.get('log level') || -1;
 
   return logger;
 });
@@ -347,15 +356,17 @@ Manager.prototype.onDispatch = function (room, packet, volatile, exceptions) {
 
 Manager.prototype.onJoin = function (id, name) {
   if (!this.roomClients[id]) {
-    this.roomClients[id] = [];
+    this.roomClients[id] = {};
   }
 
   if (!this.rooms[name]) {
     this.rooms[name] = [];
   }
 
-  this.rooms[name].push(id);
-  this.roomClients[id][name] = true;
+  if (!~this.rooms[name].indexOf(id)) {
+    this.rooms[name].push(id);
+    this.roomClients[id][name] = true;
+  }
 };
 
 /**
@@ -366,7 +377,15 @@ Manager.prototype.onJoin = function (id, name) {
 
 Manager.prototype.onLeave = function (id, room) {
   if (this.rooms[room]) {
-    this.rooms[room].splice(this.rooms[room].indexOf(id), 1);
+    var index = this.rooms[room].indexOf(id);
+
+    if (index >= 0) {
+      this.rooms[room].splice(index, 1);
+    }
+
+    if (!this.rooms[room].length) {
+      delete this.rooms[room];
+    }
     delete this.roomClients[id][room];
   }
 };
@@ -425,13 +444,13 @@ Manager.prototype.onClientMessage = function (id, packet) {
  */
 
 Manager.prototype.onClientDisconnect = function (id, reason) {
-  this.onDisconnect(id);
-
   for (var name in this.namespaces) {
     if (this.roomClients[id][name]) {
       this.namespaces[name].handleDisconnect(id, reason);
     }
   }
+
+  this.onDisconnect(id);
 };
 
 /**
@@ -463,8 +482,9 @@ Manager.prototype.onDisconnect = function (id, local) {
 
   if (this.roomClients[id]) {
     for (var room in this.roomClients[id]) {
-      this.rooms[room].splice(this.rooms[room].indexOf(id), 1);
+      this.onLeave(id, room);
     }
+    delete this.roomClients[id]
   }
 
   this.store.destroyClient(id, this.get('client store expiration'));
@@ -581,9 +601,10 @@ Manager.prototype.handleClient = function (data, req) {
     return;
   }
 
-  var transport = new transports[data.transport](this, data, req);
+  var transport = new transports[data.transport](this, data, req)
+    , handshaken = this.handshaken[data.id];
 
-  if (this.handshaken[data.id]) {
+  if (handshaken) {
     if (transport.open) {
       if (this.closed[data.id] && this.closed[data.id].length) {
         transport.payload(this.closed[data.id]);
@@ -599,6 +620,11 @@ Manager.prototype.handleClient = function (data, req) {
       this.onConnect(data.id);
       this.store.publish('connect', data.id);
 
+      // flag as used
+      delete handshaken.issued;
+      this.onHandshake(data.id, handshaken);
+      this.store.publish('handshake', data.id, handshaken);
+
       // initialize the socket for all namespaces
       for (var i in this.namespaces) {
         var socket = this.namespaces[i].socket(data.id, true);
@@ -749,7 +775,7 @@ Manager.prototype.handleHandshake = function (data, req, res) {
       res.writeHead(200, { 'Content-Type': 'application/javascript' });
       res.end('io.j[' + data.query.jsonp + '](new Error("' + message + '"));');
     } else {
-      res.writeHead(status);
+      res.writeHead(status, { 'Content-Type': 'text/plain' });
       res.end(message);
     }
   };
@@ -773,7 +799,7 @@ Manager.prototype.handleHandshake = function (data, req, res) {
       var id = self.generateId()
         , hs = [
               id
-            , self.get('heartbeat timeout') || ''
+            , self.enabled('heartbeats') ? self.get('heartbeat timeout') || '' : ''
             , self.get('close timeout') || ''
             , self.transports(data).join(',')
           ].join(':');
@@ -782,7 +808,7 @@ Manager.prototype.handleHandshake = function (data, req, res) {
         hs = 'io.j[' + data.query.jsonp + '](' + JSON.stringify(hs) + ');';
         res.writeHead(200, { 'Content-Type': 'application/javascript' });
       } else {
-        res.writeHead(200);
+        res.writeHead(200, { 'Content-Type': 'text/plain' });
       }
 
       res.end(hs);
@@ -806,7 +832,8 @@ Manager.prototype.handleHandshake = function (data, req, res) {
 
 Manager.prototype.handshakeData = function (data) {
   var connection = data.request.connection
-    , connectionAddress;
+    , connectionAddress
+    , date = new Date;
 
   if (connection.remoteAddress) {
     connectionAddress = {
@@ -823,9 +850,12 @@ Manager.prototype.handshakeData = function (data) {
   return {
       headers: data.headers
     , address: connectionAddress
-    , time: (new Date).toString()
+    , time: date.toString()
+    , query: data.query
+    , url: data.request.url
     , xdomain: !!data.request.headers.origin
     , secure: data.request.connection.secure
+    , issued: +date
   };
 };
 
@@ -836,7 +866,7 @@ Manager.prototype.handshakeData = function (data) {
  */
 
 Manager.prototype.verifyOrigin = function (request) {
-  var origin = request.headers.origin
+  var origin = request.headers.origin || request.headers.referer
     , origins = this.get('origins');
 
   if (origin === 'null') origin = '*';
@@ -848,14 +878,19 @@ Manager.prototype.verifyOrigin = function (request) {
   if (origin) {
     try {
       var parts = url.parse(origin);
-
-      return
-        ~origins.indexOf(parts.host + ':' + parts.port) ||
-        ~origins.indexOf(parts.host + ':*') ||
+      var ok =
+        ~origins.indexOf(parts.hostname + ':' + parts.port) ||
+        ~origins.indexOf(parts.hostname + ':*') ||
         ~origins.indexOf('*:' + parts.port);
-    } catch (ex) {}
+      if (!ok) this.log.warn('illegal origin: ' + origin);
+      return ok;
+    } catch (ex) {
+      this.log.warn('error parsing origin');
+    }
+  }
+  else {
+    this.log.warn('origin missing from handshake, yet required by config');        
   }
-
   return false;
 };
 
@@ -955,6 +990,8 @@ Manager.prototype.checkRequest = function (req) {
 
 /**
  * Declares a socket namespace
+ *
+ * @api public
  */
 
 Manager.prototype.of = function (nsp) {
@@ -964,3 +1001,26 @@ Manager.prototype.of = function (nsp) {
 
   return this.namespaces[nsp] = new SocketNamespace(this, nsp);
 };
+
+/**
+ * Perform garbage collection on long living objects and properties that cannot
+ * be removed automatically.
+ *
+ * @api private
+ */
+
+Manager.prototype.garbageCollection = function () {
+  // clean up unused handshakes
+  var ids = Object.keys(this.handshaken)
+    , i = ids.length
+    , now = Date.now()
+    , handshake;
+
+  while (i--) {
+    handshake = this.handshaken[ids[i]];
+
+    if ('issued' in handshake && (now - handshake.issued) >= 3E4) {
+      this.onDisconnect(ids[i]);
+    }
+  }
+};
index 471caf32679249097988c5cc56777ea1eb395aa2..b5b26ff41e449d504b6dda0b45617b17daf8a4c7 100644 (file)
@@ -108,7 +108,7 @@ SocketNamespace.prototype.__defineGetter__('volatile', function () {
  * @api public
  */
 
-SocketNamespace.prototype.in = function (room) {
+SocketNamespace.prototype.in = SocketNamespace.prototype.to = function (room) {
   this.flags.endpoint = this.name + (room ? '/' + room : '');
   return this;
 };
@@ -227,6 +227,7 @@ SocketNamespace.prototype.authorization = function (fn) {
 SocketNamespace.prototype.handleDisconnect = function (sid, reason) {
   if (this.sockets[sid] && this.sockets[sid].readable) {
     this.sockets[sid].onDisconnect(reason);
+    delete this.sockets[sid];
   }
 };
 
@@ -323,8 +324,9 @@ SocketNamespace.prototype.handlePacket = function (sessid, packet) {
     case 'event':
       var params = [packet.name].concat(packet.args);
 
-      if (dataAck)
+      if (dataAck) {
         params.push(ack);
+      }
 
       socket.$emit.apply(socket, params);
       break;
index bdb27b22d92c61392708a027308b0fb7790a8291..707c637f6173e00383ea221b634e07028778388e 100644 (file)
@@ -138,7 +138,7 @@ exports.encodePayload = function (packets) {
  * @api private
  */
 
-var regexp = /^([^:]+):([0-9]+)?(\+)?:([^:]+)?:?(.*)?$/;
+var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/;
 
 exports.decodePacket = function (data) {
   var pieces = data.match(regexp);
index ce07dca5eb9804e3b8780a6cab242f806e5ef07c..4c0bae5041b14d36f4ab0adbfdf6358d91c39c7e 100644 (file)
@@ -15,7 +15,7 @@ var client = require('socket.io-client');
  * Version.
  */
 
-exports.version = '0.7.7';
+exports.version = '0.8.4';
 
 /**
  * Supported protocol version.
@@ -32,6 +32,9 @@ exports.clientVersion = client.version;
 /**
  * Attaches a manager
  *
+ * @param {HTTPServer/Number} a HTTP/S server or a port number to listen on.
+ * @param {Object} opts to be passed to Manager and/or http server
+ * @param {Function} callback if a port is supplied
  * @api public
  */
 
@@ -65,7 +68,7 @@ exports.listen = function (server, options, fn) {
   }
 
   // otherwise assume a http/s server
-  return new exports.Manager(server);
+  return new exports.Manager(server, options);
 };
 
 /**
index 7831b399cc289434ec77df2f060f7718ed4c034a..c0d7b50f9bab68d0a80b9a71ef7a49849bdc00fd 100644 (file)
@@ -11,7 +11,7 @@
 
 var parser = require('./parser')
   , util = require('./util')
-  , EventEmitter = process.EventEmitter;
+  , EventEmitter = process.EventEmitter
 
 /**
  * Export the constructor.
@@ -19,6 +19,12 @@ var parser = require('./parser')
 
 exports = module.exports = Socket;
 
+/**
+ * Default error event listener to prevent uncaught exceptions.
+ */
+
+var defaultError = function () {};
+
 /**
  * Socket constructor.
  *
@@ -39,6 +45,7 @@ function Socket (manager, id, nsp, readable) {
   this.setFlags();
   this.readable = readable;
   this.store = this.manager.store.client(this.id);
+  this.on('error', defaultError);
 };
 
 /**
@@ -106,7 +113,7 @@ Socket.prototype.__defineGetter__('broadcast', function () {
  * @api public
  */
 
-Socket.prototype.to = function (room) {
+Socket.prototype.to = Socket.prototype.in = function (room) {
   this.flags.room = room;
   return this;
 };
@@ -160,7 +167,7 @@ Socket.prototype.join = function (name, fn) {
 };
 
 /**
- * Joins a user to a room.
+ * Un-joins a user from a room.
  *
  * @api public
  */
index 689ec8b0f1a93fde559c4b97cea79a30b678633a..26f7a9207b9d75ba6119afa153ae1c3901b44983 100644 (file)
@@ -11,8 +11,7 @@
 
 var crypto = require('crypto')
   , Store = require('../store')
-  , assert = require('assert')
-  , redis = require('redis');
+  , assert = require('assert');
 
 /**
  * Exports the constructor.
@@ -25,6 +24,7 @@ Redis.Client = Client;
  * Redis store.
  * Options:
  *     - nodeId (fn) gets an id that uniquely identifies this node
+ *     - redis (fn) redis constructor, defaults to redis
  *     - redisPub (object) options to pass to the pub redis client
  *     - redisSub (object) options to pass to the sub redis client
  *     - redisClient (object) options to pass to the general redis client
@@ -60,6 +60,8 @@ function Redis (opts) {
     }
   }
 
+  var redis = opts.redis || require('redis');
+
   // initialize a pubsub client and a regular client
   this.pub = redis.createClient(opts.redisPub);
   this.sub = redis.createClient(opts.redisSub);
index 7efe1497e0722c97bd1268c33642a1c9033fdaee..61f456fce9e937a2063f9f619d958a4226c4c79f 100644 (file)
@@ -259,7 +259,7 @@ Transport.prototype.clearCloseTimeout = function () {
  */
 
 Transport.prototype.setHeartbeatTimeout = function () {
-  if (!this.heartbeatTimeout) {
+  if (!this.heartbeatTimeout && this.manager.enabled('heartbeats')) {
     var self = this;
 
     this.heartbeatTimeout = setTimeout(function () {
@@ -279,7 +279,7 @@ Transport.prototype.setHeartbeatTimeout = function () {
  */
 
 Transport.prototype.clearHeartbeatTimeout = function () {
-  if (this.heartbeatTimeout) {
+  if (this.heartbeatTimeout && this.manager.enabled('heartbeats')) {
     clearTimeout(this.heartbeatTimeout);
     this.heartbeatTimeout = null;
     this.log.debug('cleared heartbeat timeout for client', this.id);
@@ -294,7 +294,7 @@ Transport.prototype.clearHeartbeatTimeout = function () {
  */
 
 Transport.prototype.setHeartbeatInterval = function () {
-  if (!this.heartbeatInterval) {
+  if (!this.heartbeatInterval && this.manager.enabled('heartbeats')) {
     var self = this;
 
     this.heartbeatInterval = setTimeout(function () {
@@ -398,7 +398,7 @@ Transport.prototype.onMessage = function (packet) {
  */
 
 Transport.prototype.clearHeartbeatInterval = function () {
-  if (this.heartbeatInterval) {
+  if (this.heartbeatInterval && this.manager.enabled('heartbeats')) {
     clearTimeout(this.heartbeatInterval);
     this.heartbeatInterval = null;
     this.log.debug('cleared heartbeat interval for client', this.id);
index 48b3d95906c343896caae755d269cce51378a73e..16768196acc998f5670aac8ea0cdc800910c2004 100644 (file)
@@ -24,7 +24,7 @@ exports = module.exports = FlashSocket;
  */
  
 function FlashSocket (mng, data, req) {
-  WebSocket.call(this, mng, data, req);
+  return WebSocket.call(this, mng, data, req);
 }
 
 /**
index b2cf2705c1c7b4de059da3a87a2f0ce11e8035ab..d5be006ea3ca55631ee4c1aba47e9613ce859da3 100644 (file)
@@ -54,6 +54,9 @@ HTTPTransport.prototype.handleRequest = function (req) {
     });
 
     req.on('end', function () {
+      res.writeHead(200, headers);
+      res.end('1');
+
       self.onData(self.postEncoded ? qs.parse(buffer).d : buffer);
     });
 
@@ -65,9 +68,6 @@ HTTPTransport.prototype.handleRequest = function (req) {
         headers['Access-Control-Allow-Credentials'] = 'true';
       }
     }
-
-    res.writeHead(200, headers);
-    res.end('1');
   } else {
     this.response = req.res;
 
@@ -83,9 +83,9 @@ HTTPTransport.prototype.handleRequest = function (req) {
 
 HTTPTransport.prototype.onData = function (data) {
   var messages = parser.decodePayload(data);
+  this.log.debug(this.name + ' received data packet', data);
 
   for (var i = 0, l = messages.length; i < l; i++) {
-    this.log.debug(this.name + ' received data packet', data);
     this.onMessage(messages[i]);
   }
 };
index 87456875c65a9f2220ef4f1f265dc0221fbbaf54..86a23f07fe48189b26e52e69f674c91df2e3d375 100644 (file)
@@ -70,6 +70,7 @@ JSONPPolling.prototype.doWrite = function (data) {
       'Content-Type': 'text/javascript; charset=UTF-8'
     , 'Content-Length': Buffer.byteLength(data)
     , 'Connection': 'Keep-Alive'
+    , 'X-XSS-Protection': '0'
   });
 
   this.response.write(data);
index 41f90dc15d259a92757206ff8445e1c69e6a5b5f..84db53119e54485fde0f8e93333a526119ec844d 100644 (file)
@@ -9,10 +9,7 @@
  * Module requirements.
  */
 
-var Transport = require('../transport')
-  , EventEmitter = process.EventEmitter
-  , crypto = require('crypto')
-  , parser = require('../parser');
+var protocolVersions = require('./websocket/');
 
 /**
  * Export the constructor.
@@ -28,323 +25,9 @@ exports = module.exports = WebSocket;
  */
 
 function WebSocket (mng, data, req) {
-  // parser
-  var self = this;
-
-  this.parser = new Parser();
-  this.parser.on('data', function (packet) {
-    self.log.debug(self.name + ' received data packet', packet);
-    self.onMessage(parser.decodePacket(packet));
-  });
-  this.parser.on('close', function () {
-    self.end();
-  });
-  this.parser.on('error', function () {
-    self.end();
-  });
-
-  Transport.call(this, mng, data, req);
-};
-
-/**
- * Inherits from Transport.
- */
-
-WebSocket.prototype.__proto__ = Transport.prototype;
-
-/**
- * Transport name
- *
- * @api public
- */
-
-WebSocket.prototype.name = 'websocket';
-
-/**
- * Called when the socket connects.
- *
- * @api private
- */
-
-WebSocket.prototype.onSocketConnect = function () {
-  var self = this;
-
-  this.socket.setNoDelay(true);
-
-  this.buffer = true;
-  this.buffered = [];
-
-  if (this.req.headers.upgrade !== 'WebSocket') {
-    this.log.warn(this.name + ' connection invalid');
-    this.end();
-    return;
+  var version = req.headers['sec-websocket-version'];
+  if (typeof version !== 'undefined' && typeof protocolVersions[version] !== 'undefined') {
+    return new protocolVersions[version](mng, data, req);
   }
-
-  var origin = this.req.headers.origin
-    , location = (this.socket.encrypted ? 'wss' : 'ws')
-               + '://' + this.req.headers.host + this.req.url
-    , waitingForNonce = false;
-
-  if (this.req.headers['sec-websocket-key1']) {
-    // If we don't have the nonce yet, wait for it (HAProxy compatibility).
-    if (! (this.req.head && this.req.head.length >= 8)) {
-      waitingForNonce = true;
-    }
-
-    var headers = [
-        'HTTP/1.1 101 WebSocket Protocol Handshake'
-      , 'Upgrade: WebSocket'
-      , 'Connection: Upgrade'
-      , 'Sec-WebSocket-Origin: ' + origin
-      , 'Sec-WebSocket-Location: ' + location
-    ];
-
-    if (this.req.headers['sec-websocket-protocol']){
-      headers.push('Sec-WebSocket-Protocol: '
-          + this.req.headers['sec-websocket-protocol']);
-    }
-  } else {
-    var headers = [
-        'HTTP/1.1 101 Web Socket Protocol Handshake'
-      , 'Upgrade: WebSocket'
-      , 'Connection: Upgrade'
-      , 'WebSocket-Origin: ' + origin
-      , 'WebSocket-Location: ' + location
-    ];
-  }
-
-  try {
-    this.socket.write(headers.concat('', '').join('\r\n'));
-    this.socket.setTimeout(0);
-    this.socket.setNoDelay(true);
-    this.socket.setEncoding('utf8');
-  } catch (e) {
-    this.end();
-    return;
-  }
-
-  if (waitingForNonce) {
-    this.socket.setEncoding('binary');
-  } else if (this.proveReception(headers)) {
-    self.flush();
-  }
-
-  var headBuffer = '';
-
-  this.socket.on('data', function (data) {
-    if (waitingForNonce) {
-      headBuffer += data;
-
-      if (headBuffer.length < 8) {
-        return;
-      }
-
-      // Restore the connection to utf8 encoding after receiving the nonce
-      self.socket.setEncoding('utf8');
-      waitingForNonce = false;
-
-      // Stuff the nonce into the location where it's expected to be
-      self.req.head = headBuffer.substr(0, 8);
-      headBuffer = '';
-
-      if (self.proveReception(headers)) {
-        self.flush();
-      }
-
-      return;
-    }
-
-    self.parser.add(data);
-  });
-};
-
-/**
- * Writes to the socket.
- *
- * @api private
- */
-
-WebSocket.prototype.write = function (data) {
-  if (this.open) {
-    this.drained = false;
-
-    if (this.buffer) {
-      this.buffered.push(data);
-      return this;
-    }
-
-    var length = Buffer.byteLength(data)
-      , buffer = new Buffer(2 + length);
-
-    buffer.write('\u0000', 'binary');
-    buffer.write(data, 1, 'utf8');
-    buffer.write('\uffff', 1 + length, 'binary');
-
-    try {
-      if (this.socket.write(buffer)) {
-        this.drained = true;
-      }
-    } catch (e) {
-      this.end();
-    }
-
-    this.log.debug(this.name + ' writing', data);
-  }
-};
-
-/**
- * Flushes the internal buffer
- *
- * @api private
- */
-
-WebSocket.prototype.flush = function () {
-  this.buffer = false;
-
-  for (var i = 0, l = this.buffered.length; i < l; i++) {
-    this.write(this.buffered.splice(0, 1)[0]);
-  }
-};
-
-/**
- * Finishes the handshake.
- *
- * @api private
- */
-
-WebSocket.prototype.proveReception = function (headers) {
-  var self = this
-    , k1 = this.req.headers['sec-websocket-key1']
-    , k2 = this.req.headers['sec-websocket-key2'];
-
-  if (k1 && k2){
-    var md5 = crypto.createHash('md5');
-
-    [k1, k2].forEach(function (k) {
-      var n = parseInt(k.replace(/[^\d]/g, ''))
-        , spaces = k.replace(/[^ ]/g, '').length;
-
-      if (spaces === 0 || n % spaces !== 0){
-        self.log.warn('Invalid ' + self.name + ' key: "' + k + '".');
-        self.end();
-        return false;
-      }
-
-      n /= spaces;
-
-      md5.update(String.fromCharCode(
-        n >> 24 & 0xFF,
-        n >> 16 & 0xFF,
-        n >> 8  & 0xFF,
-        n       & 0xFF));
-    });
-
-    md5.update(this.req.head.toString('binary'));
-
-    try {
-      this.socket.write(md5.digest('binary'), 'binary');
-    } catch (e) {
-      this.end();
-    }
-  }
-
-  return true;
-};
-
-/**
- * Writes a payload.
- *
- * @api private
- */
-
-WebSocket.prototype.payload = function (msgs) {
-  for (var i = 0, l = msgs.length; i < l; i++) {
-    this.write(msgs[i]);
-  }
-
-  return this;
-};
-
-/**
- * Closes the connection.
- *
- * @api private
- */
-
-WebSocket.prototype.doClose = function () {
-  this.socket.end();
-};
-
-/**
- * WebSocket parser
- *
- * @api public
- */
-
-function Parser () {
-  this.buffer = '';
-  this.i = 0;
-};
-
-/**
- * Inherits from EventEmitter.
- */
-
-Parser.prototype.__proto__ = EventEmitter.prototype;
-
-/**
- * Adds data to the buffer.
- *
- * @api public
- */
-
-Parser.prototype.add = function (data) {
-  this.buffer += data;
-  this.parse();
-};
-
-/**
- * Parses the buffer.
- *
- * @api private
- */
-
-Parser.prototype.parse = function () {
-  for (var i = this.i, chr, l = this.buffer.length; i < l; i++){
-    chr = this.buffer[i];
-
-    if (this.buffer.length == 2 && this.buffer[1] == '\u0000') {
-      this.emit('close');
-      this.buffer = '';
-      this.i = 0;
-      return;
-    }
-
-    if (i === 0){
-      if (chr != '\u0000')
-        this.error('Bad framing. Expected null byte as first frame');
-      else
-        continue;
-    }
-
-    if (chr == '\ufffd'){
-      this.emit('data', this.buffer.substr(1, i - 1));
-      this.buffer = this.buffer.substr(i + 1);
-      this.i = 0;
-      return this.parse();
-    }
-  }
-};
-
-/**
- * Handles an error
- *
- * @api private
- */
-
-Parser.prototype.error = function (reason) {
-  this.buffer = '';
-  this.i = 0;
-  this.emit('error', reason);
-  return this;
+  return new protocolVersions['default'](mng, data, req);
 };
diff --git a/node/node_modules/socket.io/lib/transports/websocket/default.js b/node/node_modules/socket.io/lib/transports/websocket/default.js
new file mode 100644 (file)
index 0000000..a05c920
--- /dev/null
@@ -0,0 +1,350 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var Transport = require('../../transport')
+  , EventEmitter = process.EventEmitter
+  , crypto = require('crypto')
+  , parser = require('../../parser');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = WebSocket;
+
+/**
+ * HTTP interface constructor. Interface compatible with all transports that
+ * depend on request-response cycles.
+ *
+ * @api public
+ */
+
+function WebSocket (mng, data, req) {
+  // parser
+  var self = this;
+
+  this.parser = new Parser();
+  this.parser.on('data', function (packet) {
+    self.log.debug(self.name + ' received data packet', packet);
+    self.onMessage(parser.decodePacket(packet));
+  });
+  this.parser.on('close', function () {
+    self.end();
+  });
+  this.parser.on('error', function () {
+    self.end();
+  });
+
+  Transport.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+WebSocket.prototype.__proto__ = Transport.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+WebSocket.prototype.name = 'websocket';
+
+/**
+ * Called when the socket connects.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.onSocketConnect = function () {
+  var self = this;
+
+  this.socket.setNoDelay(true);
+
+  this.buffer = true;
+  this.buffered = [];
+
+  if (this.req.headers.upgrade !== 'WebSocket') {
+    this.log.warn(this.name + ' connection invalid');
+    this.end();
+    return;
+  }
+
+  var origin = this.req.headers.origin
+    , location = (this.socket.encrypted ? 'wss' : 'ws')
+               + '://' + this.req.headers.host + this.req.url
+    , waitingForNonce = false;
+
+  if (this.req.headers['sec-websocket-key1']) {
+    // If we don't have the nonce yet, wait for it (HAProxy compatibility).
+    if (! (this.req.head && this.req.head.length >= 8)) {
+      waitingForNonce = true;
+    }
+
+    var headers = [
+        'HTTP/1.1 101 WebSocket Protocol Handshake'
+      , 'Upgrade: WebSocket'
+      , 'Connection: Upgrade'
+      , 'Sec-WebSocket-Origin: ' + origin
+      , 'Sec-WebSocket-Location: ' + location
+    ];
+
+    if (this.req.headers['sec-websocket-protocol']){
+      headers.push('Sec-WebSocket-Protocol: '
+          + this.req.headers['sec-websocket-protocol']);
+    }
+  } else {
+    var headers = [
+        'HTTP/1.1 101 Web Socket Protocol Handshake'
+      , 'Upgrade: WebSocket'
+      , 'Connection: Upgrade'
+      , 'WebSocket-Origin: ' + origin
+      , 'WebSocket-Location: ' + location
+    ];
+  }
+
+  try {
+    this.socket.write(headers.concat('', '').join('\r\n'));
+    this.socket.setTimeout(0);
+    this.socket.setNoDelay(true);
+    this.socket.setEncoding('utf8');
+  } catch (e) {
+    this.end();
+    return;
+  }
+
+  if (waitingForNonce) {
+    this.socket.setEncoding('binary');
+  } else if (this.proveReception(headers)) {
+    self.flush();
+  }
+
+  var headBuffer = '';
+
+  this.socket.on('data', function (data) {
+    if (waitingForNonce) {
+      headBuffer += data;
+
+      if (headBuffer.length < 8) {
+        return;
+      }
+
+      // Restore the connection to utf8 encoding after receiving the nonce
+      self.socket.setEncoding('utf8');
+      waitingForNonce = false;
+
+      // Stuff the nonce into the location where it's expected to be
+      self.req.head = headBuffer.substr(0, 8);
+      headBuffer = '';
+
+      if (self.proveReception(headers)) {
+        self.flush();
+      }
+
+      return;
+    }
+
+    self.parser.add(data);
+  });
+};
+
+/**
+ * Writes to the socket.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.write = function (data) {
+  if (this.open) {
+    this.drained = false;
+
+    if (this.buffer) {
+      this.buffered.push(data);
+      return this;
+    }
+
+    var length = Buffer.byteLength(data)
+      , buffer = new Buffer(2 + length);
+
+    buffer.write('\x00', 'binary');
+    buffer.write(data, 1, 'utf8');
+    buffer.write('\xff', 1 + length, 'binary');
+
+    try {
+      if (this.socket.write(buffer)) {
+        this.drained = true;
+      }
+    } catch (e) {
+      this.end();
+    }
+
+    this.log.debug(this.name + ' writing', data);
+  }
+};
+
+/**
+ * Flushes the internal buffer
+ *
+ * @api private
+ */
+
+WebSocket.prototype.flush = function () {
+  this.buffer = false;
+
+  for (var i = 0, l = this.buffered.length; i < l; i++) {
+    this.write(this.buffered.splice(0, 1)[0]);
+  }
+};
+
+/**
+ * Finishes the handshake.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.proveReception = function (headers) {
+  var self = this
+    , k1 = this.req.headers['sec-websocket-key1']
+    , k2 = this.req.headers['sec-websocket-key2'];
+
+  if (k1 && k2){
+    var md5 = crypto.createHash('md5');
+
+    [k1, k2].forEach(function (k) {
+      var n = parseInt(k.replace(/[^\d]/g, ''))
+        , spaces = k.replace(/[^ ]/g, '').length;
+
+      if (spaces === 0 || n % spaces !== 0){
+        self.log.warn('Invalid ' + self.name + ' key: "' + k + '".');
+        self.end();
+        return false;
+      }
+
+      n /= spaces;
+
+      md5.update(String.fromCharCode(
+        n >> 24 & 0xFF,
+        n >> 16 & 0xFF,
+        n >> 8  & 0xFF,
+        n       & 0xFF));
+    });
+
+    md5.update(this.req.head.toString('binary'));
+
+    try {
+      this.socket.write(md5.digest('binary'), 'binary');
+    } catch (e) {
+      this.end();
+    }
+  }
+
+  return true;
+};
+
+/**
+ * Writes a payload.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.payload = function (msgs) {
+  for (var i = 0, l = msgs.length; i < l; i++) {
+    this.write(msgs[i]);
+  }
+
+  return this;
+};
+
+/**
+ * Closes the connection.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.doClose = function () {
+  this.socket.end();
+};
+
+/**
+ * WebSocket parser
+ *
+ * @api public
+ */
+
+function Parser () {
+  this.buffer = '';
+  this.i = 0;
+};
+
+/**
+ * Inherits from EventEmitter.
+ */
+
+Parser.prototype.__proto__ = EventEmitter.prototype;
+
+/**
+ * Adds data to the buffer.
+ *
+ * @api public
+ */
+
+Parser.prototype.add = function (data) {
+  this.buffer += data;
+  this.parse();
+};
+
+/**
+ * Parses the buffer.
+ *
+ * @api private
+ */
+
+Parser.prototype.parse = function () {
+  for (var i = this.i, chr, l = this.buffer.length; i < l; i++){
+    chr = this.buffer[i];
+
+    if (this.buffer.length == 2 && this.buffer[1] == '\u0000') {
+      this.emit('close');
+      this.buffer = '';
+      this.i = 0;
+      return;
+    }
+
+    if (i === 0){
+      if (chr != '\u0000')
+        this.error('Bad framing. Expected null byte as first frame');
+      else
+        continue;
+    }
+
+    if (chr == '\ufffd'){
+      this.emit('data', this.buffer.substr(1, i - 1));
+      this.buffer = this.buffer.substr(i + 1);
+      this.i = 0;
+      return this.parse();
+    }
+  }
+};
+
+/**
+ * Handles an error
+ *
+ * @api private
+ */
+
+Parser.prototype.error = function (reason) {
+  this.buffer = '';
+  this.i = 0;
+  this.emit('error', reason);
+  return this;
+};
diff --git a/node/node_modules/socket.io/lib/transports/websocket/hybi-07-12.js b/node/node_modules/socket.io/lib/transports/websocket/hybi-07-12.js
new file mode 100644 (file)
index 0000000..8760a9e
--- /dev/null
@@ -0,0 +1,465 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+/**
+ * Module requirements.
+ */
+
+var Transport = require('../../transport')
+  , EventEmitter = process.EventEmitter
+  , crypto = require('crypto')
+  , parser = require('../../parser')
+  , util = require('../../util');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = WebSocket;
+exports.Parser = Parser;
+
+/**
+ * HTTP interface constructor. Interface compatible with all transports that
+ * depend on request-response cycles.
+ *
+ * @api public
+ */
+
+function WebSocket (mng, data, req) {
+  // parser
+  var self = this;
+
+  this.parser = new Parser();
+  this.parser.on('data', function (packet) {
+    self.onMessage(parser.decodePacket(packet));
+  });
+  this.parser.on('ping', function () {
+    // version 8 ping => pong
+    self.socket.write('\u008a\u0000');
+  });
+  this.parser.on('close', function () {
+    self.end();
+  });
+  this.parser.on('error', function (reason) {
+    self.log.warn(self.name + ' parser error: ' + reason);
+    self.end();
+  });
+
+  Transport.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+WebSocket.prototype.__proto__ = Transport.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+WebSocket.prototype.name = 'websocket';
+
+/**
+ * Called when the socket connects.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.onSocketConnect = function () {
+  var self = this;
+
+  if (this.req.headers.upgrade !== 'websocket') {
+    this.log.warn(this.name + ' connection invalid');
+    this.end();
+    return;
+  }
+
+  var origin = this.req.headers.origin
+    , location = (this.socket.encrypted ? 'wss' : 'ws')
+               + '://' + this.req.headers.host + this.req.url;
+
+  if (!this.req.headers['sec-websocket-key']) {
+    this.log.warn(this.name + ' connection invalid: received no key');
+    this.end();
+    return;
+  }
+    
+  // calc key
+  var key = this.req.headers['sec-websocket-key'];  
+  var shasum = crypto.createHash('sha1');  
+  shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");  
+  key = shasum.digest('base64');
+
+  var headers = [
+      'HTTP/1.1 101 Switching Protocols'
+    , 'Upgrade: websocket'
+    , 'Connection: Upgrade'
+    , 'Sec-WebSocket-Accept: ' + key
+  ];
+
+  try {
+    this.socket.write(headers.concat('', '').join('\r\n'));
+    this.socket.setTimeout(0);
+    this.socket.setNoDelay(true);
+  } catch (e) {
+    this.end();
+    return;
+  }
+
+  this.socket.on('data', function (data) {
+    self.parser.add(data);
+  });
+};
+
+/**
+ * Writes to the socket.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.write = function (data) {
+  if (this.open) {
+    var buf = this.frame(0x81, data);
+    this.socket.write(buf, 'binary');
+    this.log.debug(this.name + ' writing', data);
+  }
+};
+
+/**
+ * Frame server-to-client output as a text packet.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.frame = function (opcode, str) {
+  var dataBuffer = new Buffer(str)
+    , dataLength = dataBuffer.length
+    , startOffset = 2
+    , secondByte = dataLength;
+  if (dataLength > 65536) {
+    startOffset = 10;
+    secondByte = 127;
+  }
+  else if (dataLength > 125) {
+    startOffset = 4;
+    secondByte = 126;
+  }
+  var outputBuffer = new Buffer(dataLength + startOffset);
+  outputBuffer[0] = opcode;
+  outputBuffer[1] = secondByte;
+  dataBuffer.copy(outputBuffer, startOffset);
+  switch (secondByte) {
+  case 126:
+    outputBuffer[2] = dataLength >>> 8;
+    outputBuffer[3] = dataLength % 256;
+    break;
+  case 127:
+    var l = dataLength;
+    for (var i = 1; i <= 8; ++i) {
+      outputBuffer[startOffset - i] = l & 0xff;
+      l >>>= 8;
+    }
+  }
+  return outputBuffer;
+};
+
+/**
+ * Closes the connection.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.doClose = function () {
+  this.socket.end();
+};
+
+/**
+ * WebSocket parser
+ *
+ * @api public
+ */
+function Parser () {
+  this.state = {
+    activeFragmentedOperation: null,
+    lastFragment: false,
+    masked: false,
+    opcode: 0
+  };
+  this.overflow = null;
+  this.expectOffset = 0;
+  this.expectBuffer = null;
+  this.expectHandler = null;
+  this.currentMessage = '';
+
+  var self = this;  
+  this.opcodeHandlers = {
+    // text
+    '1': function(data) {
+      var finish = function(mask, data) {
+        self.currentMessage += self.unmask(mask, data);
+        if (self.state.lastFragment) {
+          self.emit('data', self.currentMessage);
+          self.currentMessage = '';
+        }
+        self.endPacket();
+      }
+
+      var expectData = function(length) {
+        if (self.state.masked) {
+          self.expect('Mask', 4, function(data) {
+            var mask = data;
+            self.expect('Data', length, function(data) {
+              finish(mask, data);
+            });
+          });
+        }
+        else {
+          self.expect('Data', length, function(data) { 
+            finish(null, data);
+          });
+        } 
+      }
+
+      // decode length
+      var firstLength = data[1] & 0x7f;
+      if (firstLength < 126) {
+        expectData(firstLength);
+      }
+      else if (firstLength == 126) {
+        self.expect('Length', 2, function(data) {
+          expectData(util.unpack(data));
+        });
+      }
+      else if (firstLength == 127) {
+        self.expect('Length', 8, function(data) {
+          if (util.unpack(data.slice(0, 4)) != 0) {
+            self.error('packets with length spanning more than 32 bit is currently not supported');
+            return;
+          }
+          var lengthBytes = data.slice(4); // note: cap to 32 bit length
+          expectData(util.unpack(data));
+        });
+      }      
+    },
+    // close
+    '8': function(data) {
+      self.emit('close');
+      self.reset();
+    },
+    // ping
+    '9': function(data) {
+      if (self.state.lastFragment == false) {
+        self.error('fragmented ping is not supported');
+        return;
+      }
+      
+      var finish = function(mask, data) {
+        self.emit('ping', self.unmask(mask, data));
+        self.endPacket();
+      }
+
+      var expectData = function(length) {
+        if (self.state.masked) {
+          self.expect('Mask', 4, function(data) {
+            var mask = data;
+            self.expect('Data', length, function(data) {
+              finish(mask, data);
+            });
+          });
+        }
+        else {
+          self.expect('Data', length, function(data) { 
+            finish(null, data);
+          });
+        } 
+      }
+
+      // decode length
+      var firstLength = data[1] & 0x7f;
+      if (firstLength == 0) {
+        finish(null, null);        
+      }
+      else if (firstLength < 126) {
+        expectData(firstLength);
+      }
+      else if (firstLength == 126) {
+        self.expect('Length', 2, function(data) {
+          expectData(util.unpack(data));
+        });
+      }
+      else if (firstLength == 127) {
+        self.expect('Length', 8, function(data) {
+          expectData(util.unpack(data));
+        });
+      }      
+    }
+  }
+
+  this.expect('Opcode', 2, this.processPacket);  
+};
+
+/**
+ * Inherits from EventEmitter.
+ */
+
+Parser.prototype.__proto__ = EventEmitter.prototype;
+
+/**
+ * Add new data to the parser.
+ *
+ * @api public
+ */
+
+Parser.prototype.add = function(data) {
+  if (this.expectBuffer == null) {
+    this.addToOverflow(data);
+    return;
+  }
+  var toRead = Math.min(data.length, this.expectBuffer.length - this.expectOffset);
+  data.copy(this.expectBuffer, this.expectOffset, 0, toRead);
+  this.expectOffset += toRead;
+  if (toRead < data.length) {
+    // at this point the overflow buffer shouldn't at all exist
+    this.overflow = new Buffer(data.length - toRead);
+    data.copy(this.overflow, 0, toRead, toRead + this.overflow.length);
+  }
+  if (this.expectOffset == this.expectBuffer.length) {
+    var bufferForHandler = this.expectBuffer;
+    this.expectBuffer = null;
+    this.expectOffset = 0;
+    this.expectHandler.call(this, bufferForHandler);
+  }
+}
+
+/**
+ * Adds a piece of data to the overflow.
+ *
+ * @api private
+ */
+
+Parser.prototype.addToOverflow = function(data) {
+  if (this.overflow == null) this.overflow = data;
+  else {
+    var prevOverflow = this.overflow;
+    this.overflow = new Buffer(this.overflow.length + data.length);
+    prevOverflow.copy(this.overflow, 0);
+    data.copy(this.overflow, prevOverflow.length);
+  }  
+}
+
+/**
+ * Waits for a certain amount of bytes to be available, then fires a callback.
+ *
+ * @api private
+ */
+
+Parser.prototype.expect = function(what, length, handler) {
+  this.expectBuffer = new Buffer(length);
+  this.expectOffset = 0;
+  this.expectHandler = handler;
+  if (this.overflow != null) {
+    var toOverflow = this.overflow;
+    this.overflow = null;
+    this.add(toOverflow);
+  }
+}
+
+/**
+ * Start processing a new packet.
+ *
+ * @api private
+ */
+
+Parser.prototype.processPacket = function (data) {
+  if ((data[0] & 0x70) != 0) this.error('reserved fields not empty');
+  this.state.lastFragment = (data[0] & 0x80) == 0x80; 
+  this.state.masked = (data[1] & 0x80) == 0x80;
+  var opcode = data[0] & 0xf;
+  if (opcode == 0) {
+    // continuation frame
+    if (this.state.opcode != 1 || this.state.opcode != 2) {
+      this.error('continuation frame cannot follow current opcode')
+      return;
+    }
+  }
+  else this.state.opcode = opcode;
+  this.state.opcode = data[0] & 0xf;
+  var handler = this.opcodeHandlers[this.state.opcode];
+  if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode);
+  else handler(data);
+}
+
+/**
+ * Endprocessing a packet.
+ *
+ * @api private
+ */
+
+Parser.prototype.endPacket = function() {
+  this.expectOffset = 0;
+  this.expectBuffer = null;
+  this.expectHandler = null;
+  if (this.state.lastFragment && this.state.opcode == this.state.activeFragmentedOperation) {
+    // end current fragmented operation
+    this.state.activeFragmentedOperation = null;
+  }
+  this.state.lastFragment = false;
+  this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0;
+  this.state.masked = false;
+  this.expect('Opcode', 2, this.processPacket);  
+}
+
+/**
+ * Reset the parser state.
+ *
+ * @api private
+ */
+
+Parser.prototype.reset = function() {
+  this.state = {
+    activeFragmentedOperation: null,
+    lastFragment: false,
+    masked: false,
+    opcode: 0
+  };
+  this.expectOffset = 0;
+  this.expectBuffer = null;
+  this.expectHandler = null;
+  this.overflow = null;
+  this.currentMessage = '';
+}
+
+/**
+ * Unmask received data.
+ *
+ * @api private
+ */
+
+Parser.prototype.unmask = function (mask, buf) {
+  if (mask != null) {
+    for (var i = 0, ll = buf.length; i < ll; i++) {
+      buf[i] ^= mask[i % 4];
+    }    
+  }
+  return buf != null ? buf.toString('utf8') : '';
+}
+
+/**
+ * Handles an error
+ *
+ * @api private
+ */
+
+Parser.prototype.error = function (reason) {
+  this.reset();
+  this.emit('error', reason);
+  return this;
+};
diff --git a/node/node_modules/socket.io/lib/transports/websocket/index.js b/node/node_modules/socket.io/lib/transports/websocket/index.js
new file mode 100644 (file)
index 0000000..5c615b2
--- /dev/null
@@ -0,0 +1,10 @@
+
+/**
+ * Export websocket versions.
+ */
+
+module.exports = {
+  7: require('./hybi-07-12'),
+  8: require('./hybi-07-12'),
+  default: require('./default')
+};
index 25f31f2bd8e02e1f16b122c5f011b12b75dbc2a4..f7d9f2b4b4b81f80d553f5a515a47b22d346daae 100644 (file)
@@ -23,3 +23,28 @@ exports.toArray = function (enu) {
 
   return arr;
 };
+
+/**
+ * Unpacks a buffer to a number.
+ *
+ * @api public
+ */
+
+exports.unpack = function (buffer) {
+  var n = 0;
+  for (var i = 0; i < buffer.length; ++i) {
+    n = (i == 0) ? buffer[i] : (n * 256) + buffer[i];
+  }
+  return n;
+}
+
+/**
+ * Left pads a string.
+ *
+ * @api public
+ */
+
+exports.padl = function (s,n,c) { 
+  return new Array(1 + n - s.length).join(c) + s;
+}
+
diff --git a/node/node_modules/socket.io/new-old/app.js b/node/node_modules/socket.io/new-old/app.js
deleted file mode 100644 (file)
index a9d1144..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-
-var express = require('express')
-  , stylus = require('stylus');
-
-var app = express.createServer();
-
-app.configure(function () {
-  app.use(stylus.middleware({ src: __dirname + '/public/css' }));
-  app.use(express.static(__dirname + '/public'));
-  app.set('views', __dirname);
-  app.set('view engine', 'jade');
-});
-
-app.get('/', function (req, res) {
-  res.render('index');
-});
-
-app.get('/new', function (req, res) {
-  res.render('new');
-});
-
-app.listen(3000);
diff --git a/node/node_modules/socket.io/new-old/index.jade b/node/node_modules/socket.io/new-old/index.jade
deleted file mode 100644 (file)
index 5d21c76..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-e inde  doctype 5
-html
-  head
-    title Socket.IO: realtime cross-browser web apps toolkit.
-    link(href='css/main.css', rel='stylesheet', media='all')
-
-    script(src='js/main.js')
-    script
-      var _gaq = _gaq || [];
-      _gaq.push(['_setAccount', 'UA-18488944-1']);
-      _gaq.push(['_trackPageview']);
-
-      (function() {
-        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-      })();
-  body
-    #wrap
-      #header
-        .subtext Introducing
-        a(href='/', class='logo') Socket.IO
-        a(href='http://github.com/learnboost/socket.io-node', class='download')
-          span.version v
-          span.version .7
-      #content
-        .section
-          form(action='http://groups.google.com/group/socket_io/boxsubscribe')
-            a#google-subscribe-link(href='http://groups.google.com/group/socket_io')
-              img(src='images/groups.png', border='0')
-            #google-subscribe-input
-              | Email:
-              input#google-subscribe-email(type='text', name='email')
-              input(type='submit', name='go', value='Subscribe')
diff --git a/node/node_modules/socket.io/new-old/layout.jade b/node/node_modules/socket.io/new-old/layout.jade
deleted file mode 100644 (file)
index 64a3770..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-doctype 5
-html
-  head
-    title Socket.IO: realtime cross-browser web apps toolkit.
-    link(href='css/main.css', rel='stylesheet', media='all')
-
-    script(src='js/main.js')
-    script
-      var _gaq = _gaq || [];
-      _gaq.push(['_setAccount', 'UA-18488944-1']);
-      _gaq.push(['_trackPageview']);
-
-      (function() {
-        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-      })();
-  body
-    #wrap
-      #header
-        .subtext Introducing
-        a(href='/', class='logo') Socket.IO
-        a(href='http://github.com/learnboost/socket.io-node', class='download')
-          span.version v
-          span.version .6
-      #content
-        .section
-          form(action='http://groups.google.com/group/socket_io/boxsubscribe')
-            a#google-subscribe-link(href='http://groups.google.com/group/socket_io')
-              img(src='images/groups.png', border='0')
-            #google-subscribe-input
-              | Email:
-              input#google-subscribe-email(type='text', name='email')
-              input(type='submit', name='go', value='Subscribe')
-        .section#menu
-          ul
-            li.current: a(href='#') Home
-            li.current: a(href='#') Projects
-            li.current: a(href='#') Docs
-            li.current: a(href='#') FAQ
-        .section
-          a(href='/new') Socket.IO 0.7 is out! Click here to see what's new and what's changed.
diff --git a/node/node_modules/socket.io/new-old/public/js/main.js b/node/node_modules/socket.io/new-old/public/js/main.js
deleted file mode 100644 (file)
index 2019da2..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-function getMembers(data){
-  if (!(data && data.query && data.query.results && data.query.results.p)) return;
-  var members = document.createElement('span');
-  members.id = 'google-members-count';
-  members.innerHTML = '('+ data.query.results.p +' members)';
-  document.getElementsByTagName('FORM')[0].insertBefore(members, document.getElementById('google-subscribe-input'));
-};
-
-window.onload = function(){
-  document.getElementById('google-subscribe-email').onfocus = function(){
-    document.getElementById('google-subscribe-input').className = 'focus';
-  };
-  document.getElementById('google-subscribe-email').onblur = function(){
-    document.getElementById('google-subscribe-input').className = '';
-  };
-
-  // lame jsonp
-  var script = document.createElement('script');
-  // yql: select * from html where url="http://groups.google.com/group/socket_io/about" and xpath='//div[@class=\'maincontbox\']/table/tr[1]/td/p[1]
-  script.src = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22http%3A%2F%2Fgroups.google.com%2Fgroup%2Fsocket_io%2Fabout%22%20and%20xpath%3D'%2F%2Fdiv%5B%40class%3D%5C'maincontbox%5C'%5D%2Ftable%2Ftr%5B1%5D%2Ftd%2Fp%5B1%5D'%0A&format=json&callback=getMembers";
-  document.head.appendChild(script);
-};
index 1af8ff5839d09f0a8c75b509cbeb723ce2d12ce1..75116eec4f971608be506041065696b71cfa43d9 100644 (file)
@@ -1,6 +1,6 @@
 {
     "name": "socket.io"
-  , "version": "0.7.7"
+  , "version": "0.8.4"
   , "description": "Real-time apps made cross-browser & easy with a WebSocket-like API"
   , "homepage": "http://socket.io"
   , "keywords": ["websocket", "socket", "realtime", "socket.io", "comet", "ajax"]
@@ -9,19 +9,21 @@
         { "name": "Guillermo Rauch", "email": "rauchg@gmail.com" }
       , { "name": "Arnout Kazemier", "email": "info@3rd-eden.com" }
       , { "name": "Vladimir Dronnikov", "email": "dronnikov@gmail.com" }
+      , { "name": "Einar Otto Stangvik", "email": "einaros@gmail.com" }
     ]
   , "repository":{
         "type": "git"
-      , "url": "https://github.com/LearnBoost/Socket.IO-node.git"
+      , "url": "https://github.com/LearnBoost/socket.io.git"
     }
   , "dependencies": {
-        "socket.io-client": "0.7.4"
-      , "policyfile": "0.0.3"
-      , "redis": "0.6.0"
+        "socket.io-client": "0.8.4"
+      , "policyfile": "0.0.4"
+      , "redis": "0.6.6"
     }
   , "devDependencies": {
         "expresso": "0.7.7"
       , "should": "0.0.4"
+      , "assertvanish": "0.0.3-1"
     }
   , "main": "index"
   , "engines": { "node": ">= 0.4.0" }
diff --git a/node/node_modules/socket.io/support/node-websocket-client/LICENSE b/node/node_modules/socket.io/support/node-websocket-client/LICENSE
new file mode 100644 (file)
index 0000000..f3c2eae
--- /dev/null
@@ -0,0 +1,27 @@
+Copyright (c) 2010, Peter Griess <pg@std.in>
+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 node-websocket-client 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 HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/node/node_modules/socket.io/support/node-websocket-client/Makefile b/node/node_modules/socket.io/support/node-websocket-client/Makefile
new file mode 100644 (file)
index 0000000..e7c849a
--- /dev/null
@@ -0,0 +1,22 @@
+# This makefile exists to help run tests.
+#
+# If TEST_UNIX is a non-empty value, runs tests for UNIX sockets. This
+# functionality is not in node-websocket-server at the moment.
+
+.PHONY: test
+
+all: test test-unix
+
+test:
+       for f in `ls -1 test/test-*.js | grep -v unix` ; do \
+               echo $$f ; \
+               node $$f ; \
+       done
+
+test-unix:
+       if [[ -n "$$TEST_UNIX" ]] ; then \
+               for f in `ls -1 test/test-*.js | grep unix` ; do \
+                       echo $$f ; \
+                       node $$f ; \
+               done \
+       fi
diff --git a/node/node_modules/socket.io/support/node-websocket-client/README.md b/node/node_modules/socket.io/support/node-websocket-client/README.md
new file mode 100644 (file)
index 0000000..8823a5c
--- /dev/null
@@ -0,0 +1,41 @@
+A prototype [Web Socket](http://www.whatwg.org/specs/web-socket-protocol/)
+client implementation for [node.js](http://nodejs.org).
+
+Tested with
+[miksago/node-websocket-server](http://github.com/miksago/node-websocket-server)
+v1.2.00.
+
+Requires [nodejs](http://nodejs.org) 0.1.98 or later.
+
+## Installation
+
+Install this using `npm` as follows
+
+    npm install websocket-client
+
+... or just dump `lib/websocket.js` in your `$NODE_PATH`.
+
+## Usage
+
+    var sys = require('sys');
+    var WebSocket = require('websocket').WebSocket;
+
+    var ws = new WebSocket('ws://localhost:8000/biff', 'borf');
+    ws.addListener('data', function(buf) {
+        sys.debug('Got data: ' + sys.inspect(buf));
+    });
+    ws.onmessage = function(m) {
+        sys.debug('Got message: ' + m);
+    }
+
+## API
+
+This supports the `send()` and `onmessage()` APIs. The `WebSocket` object will
+also emit `data` events that are node `Buffer` objects, in case you want to
+work with something lower-level than strings.
+
+## Transports
+
+Multiple transports are supported, indicated by the scheme provided to the
+`WebSocket` constructor. `ws://` is a standard TCP-based Web Socket;
+`ws+unix://` allows connection to a UNIX socket at the given path.
diff --git a/node/node_modules/socket.io/support/node-websocket-client/examples/client-unix.js b/node/node_modules/socket.io/support/node-websocket-client/examples/client-unix.js
new file mode 100644 (file)
index 0000000..3bb23ba
--- /dev/null
@@ -0,0 +1,12 @@
+var sys = require('sys');
+var WebSocket = require('../lib/websocket').WebSocket;
+
+var ws = new WebSocket('ws+unix://' + process.argv[2], 'boffo');
+
+ws.addListener('message', function(d) {
+    sys.debug('Received message: ' + d.toString('utf8'));
+});
+
+ws.addListener('open', function() {
+    ws.send('This is a message', 1);
+});
diff --git a/node/node_modules/socket.io/support/node-websocket-client/examples/client.js b/node/node_modules/socket.io/support/node-websocket-client/examples/client.js
new file mode 100644 (file)
index 0000000..259bf6e
--- /dev/null
@@ -0,0 +1,10 @@
+var sys = require('sys');
+var WebSocket = require('../lib/websocket').WebSocket;
+
+var ws = new WebSocket('ws://localhost:8000/biff', 'borf');
+ws.addListener('data', function(buf) {
+    sys.debug('Got data: ' + sys.inspect(buf));
+});
+ws.onmessage = function(m) {
+    sys.debug('Got message: ' + m);
+}
diff --git a/node/node_modules/socket.io/support/node-websocket-client/examples/server-unix.js b/node/node_modules/socket.io/support/node-websocket-client/examples/server-unix.js
new file mode 100644 (file)
index 0000000..912be0e
--- /dev/null
@@ -0,0 +1,13 @@
+var sys = require('sys');
+var ws = require('websocket-server/ws');
+
+var srv = ws.createServer({ debug : true});
+srv.addListener('connection', function(s) {
+    sys.debug('Got a connection!');
+
+    s._req.socket.addListener('fd', function(fd) {
+        sys.debug('Got an fd: ' + fd);
+    });
+});
+
+srv.listen(process.argv[2]);
diff --git a/node/node_modules/socket.io/support/node-websocket-client/lib/websocket.js b/node/node_modules/socket.io/support/node-websocket-client/lib/websocket.js
new file mode 100644 (file)
index 0000000..32dd79b
--- /dev/null
@@ -0,0 +1,599 @@
+var assert = require('assert');
+var buffer = require('buffer');
+var crypto = require('crypto');
+var events = require('events');
+var http = require('http');
+var net = require('net');
+var urllib = require('url');
+var sys = require('sys');
+
+var FRAME_NO = 0;
+var FRAME_LO = 1;
+var FRAME_HI = 2;
+
+// Values for readyState as per the W3C spec
+var CONNECTING = 0;
+var OPEN = 1;
+var CLOSING = 2;
+var CLOSED = 3;
+
+var debugLevel = parseInt(process.env.NODE_DEBUG, 16);
+var debug = (debugLevel & 0x4) ?
+    function() { sys.error.apply(this, arguments); } :
+    function() { };
+
+// Generate a Sec-WebSocket-* value
+var createSecretKey = function() {
+    // How many spaces will we be inserting?
+    var numSpaces = 1 + Math.floor(Math.random() * 12);
+    assert.ok(1 <= numSpaces && numSpaces <= 12);
+
+    // What is the numerical value of our key?
+    var keyVal = (Math.floor(
+        Math.random() * (4294967295 / numSpaces)
+    ) * numSpaces);
+
+    // Our string starts with a string representation of our key
+    var s = keyVal.toString();
+
+    // Insert 'numChars' worth of noise in the character ranges
+    // [0x21, 0x2f] (14 characters) and [0x3a, 0x7e] (68 characters)
+    var numChars = 1 + Math.floor(Math.random() * 12);
+    assert.ok(1 <= numChars && numChars <= 12);
+    
+    for (var i = 0; i < numChars; i++) {
+        var pos = Math.floor(Math.random() * s.length + 1);
+
+        var c = Math.floor(Math.random() * (14 + 68));
+        c = (c <= 14) ?
+            String.fromCharCode(c + 0x21) :
+            String.fromCharCode((c - 14) + 0x3a);
+
+        s = s.substring(0, pos) + c + s.substring(pos, s.length);
+    }
+
+    // We shoudln't have any spaces in our value until we insert them
+    assert.equal(s.indexOf(' '), -1);
+
+    // Insert 'numSpaces' worth of spaces
+    for (var i = 0; i < numSpaces; i++) {
+        var pos = Math.floor(Math.random() * (s.length - 1)) + 1;
+        s = s.substring(0, pos) + ' ' + s.substring(pos, s.length);
+    }
+
+    assert.notEqual(s.charAt(0), ' ');
+    assert.notEqual(s.charAt(s.length), ' ');
+
+    return s;
+};
+
+// Generate a challenge sequence
+var createChallenge = function() {
+    var c = ''; 
+    for (var i = 0; i < 8; i++) {
+        c += String.fromCharCode(Math.floor(Math.random() * 255));
+    }
+
+    return c;
+};
+
+// Get the value of a secret key string
+//
+// This strips non-digit values and divides the result by the number of
+// spaces found.
+var secretKeyValue = function(sk) {
+    var ns = 0;
+    var v = 0;
+
+    for (var i = 0; i < sk.length; i++) {
+        var cc = sk.charCodeAt(i);
+        
+        if (cc == 0x20) {
+            ns++;
+        } else if (0x30 <= cc && cc <= 0x39) {
+            v = v * 10 + cc - 0x30;
+        }
+    }
+
+    return Math.floor(v / ns);
+}
+
+// Get the to-be-hashed value of a secret key string
+//
+// This takes the result of secretKeyValue() and encodes it in a big-endian
+// byte string
+var secretKeyHashValue = function(sk) {
+    var skv = secretKeyValue(sk);
+   
+    var hv = '';
+    hv += String.fromCharCode((skv >> 24) & 0xff);
+    hv += String.fromCharCode((skv >> 16) & 0xff);
+    hv += String.fromCharCode((skv >> 8) & 0xff);
+    hv += String.fromCharCode((skv >> 0) & 0xff);
+
+    return hv;
+};
+
+// Compute the secret key signature based on two secret key strings and some
+// handshaking data.
+var computeSecretKeySignature = function(s1, s2, hs) { 
+    assert.equal(hs.length, 8);
+
+    var hash = crypto.createHash('md5');
+
+    hash.update(secretKeyHashValue(s1));
+    hash.update(secretKeyHashValue(s2));
+    hash.update(hs);
+
+    return hash.digest('binary');
+};
+
+// Return a hex representation of the given binary string; used for debugging
+var str2hex = function(str) {
+    var hexChars = [
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
+        'a', 'b', 'c', 'd', 'e', 'f'
+    ];
+
+    var out = '';
+    for (var i = 0; i < str.length; i++) {
+        var c = str.charCodeAt(i);
+        out += hexChars[(c & 0xf0) >>> 4];
+        out += hexChars[c & 0x0f];
+        out += ' ';
+    }
+
+    return out.trim();
+};
+
+// Get the scheme for a URL, undefined if none is found
+var getUrlScheme = function(url) {
+    var i = url.indexOf(':');
+    if (i == -1) {
+        return undefined;
+    }
+
+    return url.substring(0, i);
+};
+
+// Set a constant on the given object
+var setConstant = function(obj, name, value) {
+    Object.defineProperty(obj, name, {
+        get : function() {
+            return value;
+        }
+    });
+};
+
+// WebSocket object
+//
+// This is intended to conform (mostly) to http://dev.w3.org/html5/websockets/
+//
+// N.B. Arguments are parsed in the anonymous function at the bottom of the
+//      constructor.
+var WebSocket = function(url, proto, opts) {
+    events.EventEmitter.call(this);
+
+    // Retain a reference to our object
+    var self = this;
+
+    // State of our end of the connection
+    var readyState = CONNECTING;
+
+    // Whether or not the server has sent a close handshake
+    var serverClosed = false;
+
+    // Our underlying net.Stream instance
+    var stream = undefined;
+
+    opts = opts || {
+        origin : 'http://www.example.com'
+    };
+
+    // Frame parsing functions
+    //
+    // These read data from the given buffer starting at the given offset,
+    // looking for the end of the current frame. If found, the current frame is
+    // emitted and the function returns. Only a single frame is processed at a
+    // time.
+    //
+    // The number of bytes read to complete a frame is returned, which the
+    // caller is to use to advance along its buffer. If 0 is returned, no
+    // completed frame bytes were found, and the caller should probably enqueue
+    // the buffer as a continuation of the current message. If a complete frame
+    // is read, the function is responsible for resting 'frameType'.
+
+    // Framing data
+    var frameType = FRAME_NO;
+    var bufs = [];
+    var bufsBytes = 0;
+
+    // Frame-parsing functions
+    var frameFuncs = [
+        // FRAME_NO
+        function(buf, off) {
+            if (buf[off] & 0x80) {
+                frameType = FRAME_HI;
+            } else {
+                frameType = FRAME_LO;
+            }
+
+            return 1;
+        },
+
+        // FRAME_LO
+        function(buf, off) {
+            debug('frame_lo(' + sys.inspect(buf) + ', ' + off + ')');
+
+            // Find the first instance of 0xff, our terminating byte
+            for (var i = off; i < buf.length && buf[i] != 0xff; i++)
+                ;
+
+            // We didn't find a terminating byte
+            if (i >= buf.length) {
+                return 0;
+            }
+
+            // We found a terminating byte; collect all bytes into a single buffer
+            // and emit it
+            var mb = null;
+            if (bufs.length == 0) {
+                mb = buf.slice(off, i);
+            } else {
+                mb = new buffer.Buffer(bufsBytes + i);
+
+                var mbOff = 0;
+                bufs.forEach(function(b) {
+                    b.copy(mb, mbOff, 0, b.length);
+                    mbOff += b.length;
+                });
+
+                assert.equal(mbOff, bufsBytes);
+
+                // Don't call Buffer.copy() if we're coping 0 bytes. Rather
+                // than being a no-op, this will trigger a range violation on
+                // the destination.
+                if (i > 0) {
+                    buf.copy(mb, mbOff, off, i);
+                }
+
+                // We consumed all of the buffers that we'd been saving; clear
+                // things out
+                bufs = [];
+                bufsBytes = 0;
+            }
+
+            process.nextTick(function() {
+                var b = mb;
+                return function() {
+                    var m = b.toString('utf8');
+
+                    self.emit('data', b);
+                    self.emit('message', m);        // wss compat
+
+                    if (self.onmessage) {
+                        self.onmessage({data: m});
+                    }
+                };
+            }());
+
+            frameType = FRAME_NO;
+            return i - off + 1;
+        },
+
+        // FRAME_HI
+        function(buf, off) {
+            debug('frame_hi(' + sys.inspect(buf) + ', ' + off + ')');
+
+            if (buf[off] !== 0) {
+                throw new Error('High-byte framing not supported.');
+            }
+
+            serverClosed = true;
+            return 1;
+        }
+    ];
+
+    // Handle data coming from our socket
+    var dataListener = function(buf) {
+        if (buf.length <= 0 || serverClosed) {
+            return;
+        }
+
+        debug('dataListener(' + sys.inspect(buf) + ')');
+
+        var off = 0;
+        var consumed = 0;
+
+        do {
+            if (frameType < 0 || frameFuncs.length <= frameType) {
+                throw new Error('Unexpected frame type: ' + frameType);
+            }
+
+            assert.equal(bufs.length === 0, bufsBytes === 0);
+            assert.ok(off < buf.length);
+
+            consumed = frameFuncs[frameType](buf, off);
+            off += consumed;
+        } while (!serverClosed && consumed > 0 && off < buf.length);
+
+        if (serverClosed) {
+            serverCloseHandler();
+        }
+        
+        if (consumed == 0) {
+            bufs.push(buf.slice(off, buf.length));
+            bufsBytes += buf.length - off;
+        }
+    };
+
+    // Handle incoming file descriptors
+    var fdListener = function(fd) {
+        self.emit('fd', fd);
+    };
+
+    // Handle errors from any source (HTTP client, stream, etc)
+    var errorListener = function(e) {
+        process.nextTick(function() {
+            self.emit('wserror', e);
+
+            if (self.onerror) {
+                self.onerror(e);
+            }
+        });
+    };
+
+    // Finish the closing process; destroy the socket and tell the application
+    // that we've closed.
+    var finishClose = self.finishClose = function() {
+        readyState = CLOSED;
+
+        if (stream) {
+            stream.end();
+            stream.destroy();
+            stream = undefined;
+        }
+
+        process.nextTick(function() {
+            self.emit('close');
+            if (self.onclose) {
+                self.onclose();
+            }
+        });
+    };
+
+    // Send a close frame to the server
+    var sendClose = function() {
+        assert.equal(OPEN, readyState);
+
+        readyState = CLOSING;
+        stream.write('\xff\x00', 'binary');
+    };
+
+    // Handle a close packet sent from the server
+    var serverCloseHandler = function() {
+        assert.ok(serverClosed);
+        assert.ok(readyState === OPEN || readyState === CLOSING);
+
+        bufs = [];
+        bufsBytes = 0;
+
+        // Handle state transitions asynchronously so that we don't change
+        // readyState before the application has had a chance to process data
+        // events which are already in the delivery pipeline. For example, a
+        // 'data' event could be delivered with a readyState of CLOSING if we
+        // received both frames in the same packet.
+        process.nextTick(function() {
+            if (readyState === OPEN) {
+                sendClose();
+            }
+
+            finishClose();
+        });
+    };
+
+    // External API
+    self.close = function(timeout) {
+        if (readyState === CONNECTING) {
+            // If we're still in the process of connecting, the server is not
+            // in a position to understand our close frame. Just nuke the
+            // connection and call it a day.
+            finishClose();
+        } else if (readyState === OPEN) {
+            sendClose();
+
+            if (timeout) {
+                setTimeout(finishClose, timeout * 1000);
+            }
+        }
+    };
+
+    self.send = function(str, fd) {
+        if (readyState != OPEN) {
+            return;
+        }
+
+        stream.write('\x00', 'binary');
+        stream.write(str, 'utf8', fd);
+        stream.write('\xff', 'binary');
+    };
+
+    // wss compat
+    self.write = self.send;
+
+    setConstant(self, 'url', url);
+
+    Object.defineProperty(self, 'readyState',  {
+        get : function() {
+            return readyState;
+        }
+    });
+
+    // Connect and perform handshaking with the server
+    (function() {
+        // Parse constructor arguments 
+        if (!url) {
+            throw new Error('Url and must be specified.');
+        }
+
+        // Secrets used for handshaking
+        var key1 = createSecretKey();
+        var key2 = createSecretKey();
+        var challenge = createChallenge();
+
+        debug(
+            'key1=\'' + str2hex(key1) + '\'; ' +
+            'key2=\'' + str2hex(key2) + '\'; ' +
+            'challenge=\'' + str2hex(challenge) + '\''
+        );
+
+        var httpHeaders = {
+            'Connection' : 'Upgrade',
+            'Upgrade' : 'WebSocket',
+            'Sec-WebSocket-Key1' : key1,
+            'Sec-WebSocket-Key2' : key2
+        };
+        if (opts.origin) {
+            httpHeaders['Origin'] = opts.origin;
+        }
+        if (proto) {
+            httpHeaders['Sec-WebSocket-Protocol'] = proto;
+        }
+
+        var httpPath = '/';
+
+        // Create the HTTP client that we'll use for handshaking. We'll cannabalize
+        // its socket via the 'upgrade' event and leave it to rot.
+        //
+        // N.B. The ws+unix:// scheme makes use of the implementation detail
+        //      that http.Client passes its constructor arguments through,
+        //      un-inspected to net.Stream.connect(). The latter accepts a
+        //      string as its first argument to connect to a UNIX socket.
+        var httpClient = undefined;
+        switch (getUrlScheme(url)) {
+        case 'ws':
+            var u = urllib.parse(url);
+            httpClient = http.createClient(u.port || 80, u.hostname);
+            httpPath = (u.pathname || '/') + (u.search || '');
+            httpHeaders.Host = u.hostname + (u.port ? (":" + u.port) : "");
+            break;
+
+        case 'ws+unix':
+            var sockPath = url.substring('ws+unix://'.length, url.length);
+            httpClient = http.createClient(sockPath);
+            httpHeaders.Host = 'localhost';
+            break;
+
+        default:
+            throw new Error('Invalid URL scheme \'' + urlScheme + '\' specified.');
+        }
+
+        httpClient.on('upgrade', (function() {
+            var data = undefined;
+
+            return function(req, s, head) {
+                stream = s;
+
+                stream.on('data', function(d) {
+                    if (d.length <= 0) {
+                        return;
+                    }
+
+                    if (!data) {
+                        data = d;
+                    } else {
+                        var data2 = new buffer.Buffer(data.length + d.length);
+
+                        data.copy(data2, 0, 0, data.length);
+                        d.copy(data2, data.length, 0, d.length);
+
+                        data = data2;
+                    }
+
+                    if (data.length >= 16) {
+                        var expected = computeSecretKeySignature(key1, key2, challenge);
+                        var actual = data.slice(0, 16).toString('binary');
+
+                        // Handshaking fails; we're donezo
+                        if (actual != expected) {
+                            debug(
+                                'expected=\'' + str2hex(expected) + '\'; ' +
+                                'actual=\'' + str2hex(actual) + '\''
+                            );
+
+                            process.nextTick(function() {
+                                // N.B. Emit 'wserror' here, as 'error' is a reserved word in the
+                                //      EventEmitter world, and gets thrown.
+                                self.emit(
+                                    'wserror',
+                                    new Error('Invalid handshake from server:' +
+                                        'expected \'' + str2hex(expected) + '\', ' +
+                                        'actual \'' + str2hex(actual) + '\''
+                                    )
+                                );
+
+                                if (self.onerror) {
+                                    self.onerror();
+                                }
+
+                                finishClose();
+                            });
+                        }
+
+                        // Un-register our data handler and add the one to be used
+                        // for the normal, non-handshaking case. If we have extra
+                        // data left over, manually fire off the handler on
+                        // whatever remains.
+                        //
+                        // XXX: This is lame. We should only remove the listeners
+                        //      that we added.
+                        httpClient.removeAllListeners('upgrade');
+                        stream.removeAllListeners('data');
+                        stream.on('data', dataListener);
+
+                        readyState = OPEN;
+
+                        process.nextTick(function() {
+                            self.emit('open');
+
+                            if (self.onopen) {
+                                self.onopen();
+                            }
+                        });
+
+                        // Consume any leftover data
+                        if (data.length > 16) {
+                            stream.emit('data', data.slice(16, data.length));
+                        }
+                    }
+                });
+                stream.on('fd', fdListener);
+                stream.on('error', errorListener);
+                stream.on('close', function() {
+                    errorListener(new Error('Stream closed unexpectedly.'));
+                });
+
+                stream.emit('data', head);
+            };
+        })());
+        httpClient.on('error', function(e) {
+            httpClient.end();
+            errorListener(e);
+        });
+
+        var httpReq = httpClient.request(httpPath, httpHeaders);
+
+        httpReq.write(challenge, 'binary');
+        httpReq.end();
+    })();
+};
+sys.inherits(WebSocket, events.EventEmitter);
+exports.WebSocket = WebSocket;
+
+// Add some constants to the WebSocket object
+setConstant(WebSocket.prototype, 'CONNECTING', CONNECTING);
+setConstant(WebSocket.prototype, 'OPEN', OPEN);
+setConstant(WebSocket.prototype, 'CLOSING', CLOSING);
+setConstant(WebSocket.prototype, 'CLOSED', CLOSED);
+
+// vim:ts=4 sw=4 et
diff --git a/node/node_modules/socket.io/support/node-websocket-client/package.json b/node/node_modules/socket.io/support/node-websocket-client/package.json
new file mode 100644 (file)
index 0000000..c6e221f
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "name" : "websocket-client",
+    "version" : "1.0.0",
+    "description" : "An HTML5 Web Sockets client",
+    "author" : "Peter Griess <pg@std.in>",
+    "engines" : {
+        "node" : ">=0.1.98"
+    },
+    "repositories" : [
+        {
+            "type" : "git",
+            "url" : "http://github.com/pgriess/node-websocket-client.git"
+        }
+    ],
+    "licenses" : [
+        {
+            "type" : "BSD",
+            "url" : "http://github.com/pgriess/node-websocket-client/blob/master/LICENSE"
+        }
+    ],
+    "main" : "./lib/websocket"
+}
diff --git a/node/node_modules/socket.io/support/node-websocket-client/test/test-basic.js b/node/node_modules/socket.io/support/node-websocket-client/test/test-basic.js
new file mode 100644 (file)
index 0000000..f010424
--- /dev/null
@@ -0,0 +1,68 @@
+// Verify that we can connect to a WebSocket server, exchange messages, and
+// shut down cleanly.
+
+var assert = require('assert');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PORT = 1024 + Math.floor(Math.random() * 4096);
+var C_MSG = 'Client test: ' + (Math.random() * 100);
+var S_MSG = 'Server test: ' + (Math.random() * 100);
+
+var serverGotConnection = false;
+var clientGotOpen = false;
+var clientGotData = false;
+var clientGotMessage = false;
+var serverGotMessage = false;
+var serverGotClose = false;
+var clientGotClose = false;
+
+var wss = new WebSocketServer();
+wss.listen(PORT, 'localhost');
+wss.on('connection', function(c) {
+    serverGotConnection = true;
+
+    c.on('message', function(m) {
+        assert.equal(m, C_MSG);
+        serverGotMessage = true;
+
+        c.close();
+    });
+
+    c.on('close', function() {
+        serverGotClose = true;
+        wss.close();
+    });
+
+    c.write(S_MSG);
+});
+
+var ws = new WebSocket('ws://localhost:' + PORT + '/', 'biff');
+ws.on('open', function() {
+    clientGotOpen = true;
+});
+ws.on('data', function(buf) {
+    assert.equal(typeof buf, 'object');
+    assert.equal(buf.toString('utf8'), S_MSG);
+
+    clientGotData = true;
+
+    ws.send(C_MSG);
+});
+ws.onmessage = function(m) {
+    assert.deepEqual(m, {data : S_MSG});
+    clientGotMessage = true;
+};
+ws.onclose = function() {
+    clientGotClose = true;
+};
+
+process.on('exit', function() {
+    assert.ok(serverGotConnection);
+    assert.ok(clientGotOpen);
+    assert.ok(clientGotData);
+    assert.ok(clientGotMessage);
+    assert.ok(serverGotMessage);
+    assert.ok(serverGotClose);
+    assert.ok(clientGotClose);
+});
diff --git a/node/node_modules/socket.io/support/node-websocket-client/test/test-client-close.js b/node/node_modules/socket.io/support/node-websocket-client/test/test-client-close.js
new file mode 100644 (file)
index 0000000..76fb81f
--- /dev/null
@@ -0,0 +1,43 @@
+// Verify that a connection can be closed gracefully from the client.
+
+var assert = require('assert');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PORT = 1024 + Math.floor(Math.random() * 4096);
+var C_MSG = 'Client test: ' + (Math.random() * 100);
+
+var serverGotClientMessage = false;
+var clientGotServerClose = false;
+var serverGotClientClose = false;
+
+var wss = new WebSocketServer();
+wss.listen(PORT, 'localhost');
+wss.on('connection', function(c) {
+    c.on('message', function(m) {
+        assert.equal(m, C_MSG);
+        serverGotClientMessage = true;
+    });
+    c.on('close', function() {
+        serverGotClientClose = true;
+        wss.close();
+    });
+});
+
+var ws = new WebSocket('ws://localhost:' + PORT);
+ws.onopen = function() {
+    ws.send(C_MSG);
+
+    // XXX: Add a timeout here 
+    ws.close(5);
+};
+ws.onclose = function() {
+    assert.equal(ws.CLOSED, ws.readyState);
+    clientGotServerClose = true;
+};
+
+process.on('exit', function() {
+    assert.ok(serverGotClientMessage);
+    assert.ok(clientGotServerClose);
+    assert.ok(serverGotClientClose);
+});
diff --git a/node/node_modules/socket.io/support/node-websocket-client/test/test-readonly-attrs.js b/node/node_modules/socket.io/support/node-websocket-client/test/test-readonly-attrs.js
new file mode 100644 (file)
index 0000000..de896b3
--- /dev/null
@@ -0,0 +1,43 @@
+// Verify that some attributes of a WebSocket object are read-only.
+
+var assert = require('assert');
+var sys = require('sys');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PORT = 1024 + Math.floor(Math.random() * 4096);
+
+var wss = new WebSocketServer();
+wss.listen(PORT, 'localhost');
+wss.on('connection', function(c) {
+    c.close();
+    wss.close();
+});
+var ws = new WebSocket('ws://localhost:' + PORT + '/', 'biff');
+ws.on('open', function() {
+    assert.equal(ws.CONNECTING, 0);
+    try {
+        ws.CONNECTING = 13;
+        assert.equal(
+            ws.CONNECTING, 0,
+            'Should not have been able to set read-only CONNECTING attribute'
+        );
+    } catch (e) {
+        assert.equal(e.type, 'no_setter_in_callback');
+    }
+
+    assert.equal(ws.OPEN, 1);
+    assert.equal(ws.CLOSING, 2);
+    assert.equal(ws.CLOSED, 3);
+
+    assert.equal(ws.url, 'ws://localhost:' + PORT + '/');
+    try {
+        ws.url = 'foobar';
+        assert.equal(
+            ws.url, 'ws://localhost:' + PORT + '/',
+            'Should not have been able to set read-only url attribute'
+        );
+    } catch (e) {
+        assert.equal(e.type, 'no_setter_in_callback');
+    }
+});
diff --git a/node/node_modules/socket.io/support/node-websocket-client/test/test-ready-state.js b/node/node_modules/socket.io/support/node-websocket-client/test/test-ready-state.js
new file mode 100644 (file)
index 0000000..8fcbd4c
--- /dev/null
@@ -0,0 +1,26 @@
+// Verify that readyState transitions are implemented correctly
+
+var assert = require('assert');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PORT = 1024 + Math.floor(Math.random() * 4096);
+
+var wss = new WebSocketServer();
+wss.listen(PORT, 'localhost');
+wss.on('connection', function(c) {
+    c.close();
+});
+
+var ws = new WebSocket('ws://localhost:' + PORT);
+assert.equal(ws.readyState, ws.CONNECTING);
+ws.onopen = function() {
+    assert.equal(ws.readyState, ws.OPEN);
+
+    ws.close();
+    assert.ok(ws.readyState == ws.CLOSING);
+};
+ws.onclose = function() {
+    assert.equal(ws.readyState, ws.CLOSED);
+    wss.close();
+};
diff --git a/node/node_modules/socket.io/support/node-websocket-client/test/test-server-close.js b/node/node_modules/socket.io/support/node-websocket-client/test/test-server-close.js
new file mode 100644 (file)
index 0000000..a286429
--- /dev/null
@@ -0,0 +1,41 @@
+// Verify that a connection can be closed gracefully from the server.
+
+var assert = require('assert');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PORT = 1024 + Math.floor(Math.random() * 4096);
+var S_MSG = 'Server test: ' + (Math.random() * 100);
+
+var clientGotServerMessage = false;
+var clientGotServerClose = false;
+var serverGotClientClose = false;
+
+var wss = new WebSocketServer();
+wss.listen(PORT, 'localhost');
+wss.on('connection', function(c) {
+    c.on('close', function() {
+        serverGotClientClose = true;
+        wss.close();
+    });
+
+    c.write(S_MSG);
+    c.close();
+});
+
+var ws = new WebSocket('ws://localhost:' + PORT);
+ws.onmessage = function(m) {
+    assert.deepEqual(m, {data: S_MSG});
+
+    clientGotServerMessage = true;
+};
+ws.onclose = function() {
+    assert.equal(ws.CLOSED, ws.readyState);
+    clientGotServerClose = true;
+};
+
+process.on('exit', function() {
+    assert.ok(clientGotServerMessage);
+    assert.ok(clientGotServerClose);
+    assert.ok(serverGotClientClose);
+});
diff --git a/node/node_modules/socket.io/support/node-websocket-client/test/test-unix-send-fd.js b/node/node_modules/socket.io/support/node-websocket-client/test/test-unix-send-fd.js
new file mode 100644 (file)
index 0000000..8f1c28d
--- /dev/null
@@ -0,0 +1,63 @@
+// Verify that both sides of the WS connection can both send and receive file
+// descriptors.
+
+var assert = require('assert');
+var fs = require('fs');
+var path = require('path');
+var sys = require('sys');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PATH = path.join(__dirname, 'sock.' + process.pid);
+var C_MSG = 'Client test: ' + (Math.random() * 100);
+var S_MSG = 'Server test: ' + (Math.random() * 100);
+
+var clientReceivedData = false;
+var clientReceivedFD = false;
+var serverReceivedData = false;
+var serverReceivedFD = false;
+
+var wss = new WebSocketServer();
+wss.on('listening', function() {
+    var ws = new WebSocket('ws+unix://' + PATH);
+    ws.on('data', function(d) {
+        assert.equal(d.toString('utf8'), S_MSG);
+
+        clientReceivedData = true;
+
+        ws.send(C_MSG, 1);
+        ws.close();
+    });
+    ws.on('fd', function(fd) {
+        assert.ok(fd >= 0);
+
+        clientReceivedFD = true;
+    });
+});
+wss.on('connection', function(c) {
+    c.write(S_MSG, 0);
+    c._req.socket.on('fd', function(fd) {
+        assert.ok(fd >= 0);
+
+        serverReceivedFD = true;
+    });
+    c.on('message', function(d) {
+        assert.equal(d, C_MSG);
+
+        serverReceivedData = true;
+
+        wss.close();
+    });
+});
+wss.listen(PATH);
+
+process.on('exit', function() {
+    assert.ok(clientReceivedFD);
+    assert.ok(clientReceivedData);
+    assert.ok(serverReceivedFD);
+    assert.ok(serverReceivedData);
+
+    try {
+        fs.unlinkSync(PATH);
+    } catch (e) { }
+});
diff --git a/node/node_modules/socket.io/support/node-websocket-client/test/test-unix-sockets.js b/node/node_modules/socket.io/support/node-websocket-client/test/test-unix-sockets.js
new file mode 100644 (file)
index 0000000..5cbf094
--- /dev/null
@@ -0,0 +1,46 @@
+// Verify that we can connect to a server over UNIX domain sockets.
+
+var assert = require('assert');
+var fs = require('fs');
+var path = require('path');
+var sys = require('sys');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PATH = path.join(__dirname, 'sock.' + process.pid);
+var S_MSG = 'Server test: ' + (Math.random() * 100);
+
+var serverGotConnection = false;
+var clientGotOpen = false;
+var clientGotData = false;
+
+var wss = new WebSocketServer();
+wss.on('listening', function() {
+    var ws = new WebSocket('ws+unix://' + PATH);
+    ws.on('open', function() {
+        clientGotOpen = true;
+
+        ws.close();
+    });
+    ws.on('data', function(d) {
+        assert.equal(d.toString('utf8'), S_MSG);
+        clientGotData = true;
+    });
+});
+wss.on('connection', function(c) {
+    serverGotConnection = true;
+
+    c.write(S_MSG);
+    wss.close();
+});
+wss.listen(PATH);
+
+process.on('exit', function() {
+    assert.ok(serverGotConnection);
+    assert.ok(clientGotOpen);
+    assert.ok(clientGotData);
+
+    try {
+        fs.unlinkSync(PATH);
+    } catch(e) { }
+});
diff --git a/node/node_modules/socket.io/test/common.js b/node/node_modules/socket.io/test/common.js
new file mode 100644 (file)
index 0000000..e658f72
--- /dev/null
@@ -0,0 +1,244 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Test dependencies.
+ */
+
+var io = require('socket.io')
+  , parser = io.parser
+  , http = require('http')
+  , https = require('https')
+  , WebSocket = require('../support/node-websocket-client/lib/websocket').WebSocket;
+
+/**
+ * Exports.
+ */
+
+var should = module.exports = require('should');
+
+should.HTTPClient = HTTPClient;
+
+/**
+ * Client utility.
+ *
+ * @api publiC
+ */
+
+function HTTPClient (port) {
+  this.port = port;
+  this.agent = new http.Agent({
+      host: 'localhost'
+    , port: port
+  });
+};
+
+/**
+ * Issue a request
+ *
+ * @api private
+ */
+
+HTTPClient.prototype.request = function (path, opts, fn) {
+  if ('function' == typeof opts) {
+    fn = opts;
+    opts = {};
+  }
+
+  opts = opts || {};
+  opts.agent = this.agent;
+  opts.host = 'localhost';
+  opts.port = this.port;
+  opts.path = path.replace(/{protocol}/g, io.protocol);
+
+  opts.headers = opts.headers || {};
+  opts.headers.Host = 'localhost';
+  opts.headers.Connection = 'keep-alive';
+
+  var req = http.request(opts, function (res) {
+    if (false === opts.buffer)
+      return fn && fn(res);
+
+    var buf = '';
+
+    res.on('data', function (chunk) {
+      buf += chunk;
+    });
+
+    res.on('end', function () {
+      fn && fn(res, opts.parse ? opts.parse(buf) : buf);
+    });
+  });
+
+  req.on('error', function (err) { });
+
+  if (undefined !== opts.data)
+    req.write(opts.data);
+
+  req.end();
+
+  return req;
+};
+
+/**
+ * Terminates the client and associated connections.
+ *
+ * @api public
+ */
+
+HTTPClient.prototype.end = function () {
+  this.agent.sockets.forEach(function (socket) {
+    socket.end();
+  });
+};
+
+/**
+ * Issue a GET request
+ *
+ * @api public
+ */
+
+HTTPClient.prototype.get = function (path, opts, fn) {
+  if ('function' == typeof opts) {
+    fn = opts;
+    opts = {};
+  }
+
+  opts = opts || {};
+  opts.method = 'GET';
+
+  // override the parser for transport requests
+  if (/\/(xhr-polling|htmlfile|jsonp-polling)\//.test(path)) {
+    // parser that might be necessary for transport-specific framing
+    var transportParse = opts.parse;
+    opts.parse = function (data) {
+      if (data === '') return data;
+
+      data = transportParse ? transportParse(data) : data;
+      return parser.decodePayload(data);
+    };
+  } else {
+    opts.parse = undefined;
+  }
+
+  return this.request(path, opts, fn);
+};
+
+/**
+ * Issue a POST request
+ *
+ * @api private
+ */
+
+HTTPClient.prototype.post = function (path, data, opts, fn) {
+  if ('function' == typeof opts) {
+    fn = opts;
+    opts = {};
+  }
+
+  opts = opts || {};
+  opts.method = 'POST';
+  opts.data = data;
+
+  return this.request(path, opts, fn);
+};
+
+/**
+ * Performs a handshake (GET) request
+ *
+ * @api private
+ */
+
+HTTPClient.prototype.handshake = function (opts, fn) {
+  if ('function' == typeof opts) {
+    fn = opts;
+    opts = {};
+  }
+
+  return this.get('/socket.io/{protocol}', opts, function (res, data) {
+    fn && fn.apply(null, data.split(':'));
+  });
+};
+
+/**
+ * Generates a new client for the given port.
+ *
+ * @api private
+ */
+
+client = function (port) {
+  return new HTTPClient(port);
+};
+
+/**
+ * Create a socket.io server.
+ */
+
+create = function (cl) {
+  console.log('');
+  var manager = io.listen(cl.port);
+  manager.set('client store expiration', 0);
+  return manager;
+};
+
+/**
+ * WebSocket socket.io client.
+ *
+ * @api private
+ */
+
+function WSClient (port, sid) {
+  this.sid = sid;
+  this.port = port;
+
+  WebSocket.call(
+      this
+    , 'ws://localhost:' + port + '/socket.io/' 
+        + io.protocol + '/websocket/' + sid
+  );
+};
+
+/**
+ * Inherits from WebSocket.
+ */
+
+WSClient.prototype.__proto__ = WebSocket.prototype;
+
+/**
+ * Overrides message event emission.
+ *
+ * @api private
+ */
+
+WSClient.prototype.emit = function (name) {
+  var args = arguments;
+
+  if (name == 'message' || name == 'data') {
+    args[1] = parser.decodePacket(args[1].toString());
+  }
+
+  return WebSocket.prototype.emit.apply(this, arguments);
+};
+
+/**
+ * Writes a packet
+ */
+
+WSClient.prototype.packet = function (pack) {
+  this.write(parser.encodePacket(pack));
+  return this;
+};
+
+/**
+ * Creates a websocket client.
+ *
+ * @api public
+ */
+
+websocket = function (cl, sid) {
+  return new WSClient(cl.port, sid);
+};
diff --git a/node/node_modules/socket.io/test/fixtures/cert.crt b/node/node_modules/socket.io/test/fixtures/cert.crt
new file mode 100644 (file)
index 0000000..5883cd4
--- /dev/null
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDXTCCAkWgAwIBAgIJAMUSOvlaeyQHMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTAxMTE2MDkzMjQ5WhcNMTMxMTE1MDkzMjQ5WjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAz+LXZOjcQCJq3+ZKUFabj71oo/ex/XsBcFqtBThjjTw9CVEVwfPQQp4X
+wtPiB204vnYXwQ1/R2NdTQqCZu47l79LssL/u2a5Y9+0NEU3nQA5qdt+1FAE0c5o
+exPimXOrR3GWfKz7PmZ2O0117IeCUUXPG5U8umhDe/4mDF4ZNJiKc404WthquTqg
+S7rLQZHhZ6D0EnGnOkzlmxJMYPNHSOY1/6ivdNUUcC87awNEA3lgfhy25IyBK3QJ
+c+aYKNTbt70Lery3bu2wWLFGtmNiGlQTS4JsxImRsECTI727ObS7/FWAQsqW+COL
+0Sa5BuMFrFIpjPrEe0ih7vRRbdmXRwIDAQABo1AwTjAdBgNVHQ4EFgQUDnV4d6mD
+tOnluLoCjkUHTX/n4agwHwYDVR0jBBgwFoAUDnV4d6mDtOnluLoCjkUHTX/n4agw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAFwV4MQfTo+qMv9JMiyno
+IEiqfOz4RgtmBqRnXUffcjS2dhc7/z+FPZnM79Kej8eLHoVfxCyWRHFlzm93vEdv
+wxOCrD13EDOi08OOZfxWyIlCa6Bg8cMAKqQzd2OvQOWqlRWBTThBJIhWflU33izX
+Qn5GdmYqhfpc+9ZHHGhvXNydtRQkdxVK2dZNzLBvBlLlRmtoClU7xm3A+/5dddeP
+AQHEPtyFlUw49VYtZ3ru6KqPms7MKvcRhYLsy9rwSfuuniMlx4d0bDR7TOkw0QQS
+A0N8MGQRQpzl4mw4jLzyM5d5QtuGBh2P6hPGa0YQxtI3RPT/p6ENzzBiAKXiSfzo
+xw==
+-----END CERTIFICATE-----
diff --git a/node/node_modules/socket.io/test/fixtures/key.key b/node/node_modules/socket.io/test/fixtures/key.key
new file mode 100644 (file)
index 0000000..f31ff3d
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAz+LXZOjcQCJq3+ZKUFabj71oo/ex/XsBcFqtBThjjTw9CVEV
+wfPQQp4XwtPiB204vnYXwQ1/R2NdTQqCZu47l79LssL/u2a5Y9+0NEU3nQA5qdt+
+1FAE0c5oexPimXOrR3GWfKz7PmZ2O0117IeCUUXPG5U8umhDe/4mDF4ZNJiKc404
+WthquTqgS7rLQZHhZ6D0EnGnOkzlmxJMYPNHSOY1/6ivdNUUcC87awNEA3lgfhy2
+5IyBK3QJc+aYKNTbt70Lery3bu2wWLFGtmNiGlQTS4JsxImRsECTI727ObS7/FWA
+QsqW+COL0Sa5BuMFrFIpjPrEe0ih7vRRbdmXRwIDAQABAoIBAGe4+9VqZfJN+dsq
+8Osyuz01uQ8OmC0sAWTIqUlQgENIyf9rCJsUBlYmwR5BT6Z69XP6QhHdpSK+TiAR
+XUz0EqG9HYzcxHIBaACP7j6iRoQ8R4kbbiWKo0z3WqQGIOqFjvD/mKEuQdE5mEYw
+eOUCG6BnX1WY2Yr8WKd2AA/tp0/Y4d8z04u9eodMpSTbHTzYMJb5SbBN1vo6FY7q
+8zSuO0BMzXlAxUsCwHsk1GQHFr8Oh3zIR7bQGtMBouI+6Lhh7sjFYsfxJboqMTBV
+IKaA216M6ggHG7MU1/jeKcMGDmEfqQLQoyWp29rMK6TklUgipME2L3UD7vTyAVzz
+xbVOpZkCgYEA8CXW4sZBBrSSrLR5SB+Ubu9qNTggLowOsC/kVKB2WJ4+xooc5HQo
+mFhq1v/WxPQoWIxdYsfg2odlL+JclK5Qcy6vXmRSdAQ5lK9gBDKxZSYc3NwAw2HA
+zyHCTK+I0n8PBYQ+yGcrxu0WqTGnlLW+Otk4CejO34WlgHwbH9bbY5UCgYEA3ZvT
+C4+OoMHXlmICSt29zUrYiL33IWsR3/MaONxTEDuvgkOSXXQOl/8Ebd6Nu+3WbsSN
+bjiPC/JyL1YCVmijdvFpl4gjtgvfJifs4G+QHvO6YfsYoVANk4u6g6rUuBIOwNK4
+RwYxwDc0oysp+g7tPxoSgDHReEVKJNzGBe9NGGsCgYEA4O4QP4gCEA3B9BF2J5+s
+n9uPVxmiyvZUK6Iv8zP4pThTBBMIzNIf09G9AHPQ7djikU2nioY8jXKTzC3xGTHM
+GJZ5m6fLsu7iH+nDvSreDSeNkTBfZqGAvoGYQ8uGE+L+ZuRfCcXYsxIOT5s6o4c3
+Dle2rVFpsuKzCY00urW796ECgYBn3go75+xEwrYGQSer6WR1nTgCV29GVYXKPooy
+zmmMOT1Yw80NSkEw0pFD4cTyqVYREsTrPU0mn1sPfrOXxnGfZSVFpcR/Je9QVfQ7
+eW7GYxwfom335aqHVj10SxRqteP+UoWWnHujCPz94VRKZMakBddYCIGSan+G6YdS
+7sdmwwKBgBc2qj0wvGXDF2kCLwSGfWoMf8CS1+5fIiUIdT1e/+7MfDdbmLMIFVjF
+QKS3zVViXCbrG5SY6wS9hxoc57f6E2A8vcaX6zy2xkZlGHQCpWRtEM5R01OWJQaH
+HsHMmQZGUQVoDm1oRkDhrTFK4K3ukc3rAxzeTZ96utOQN8/KJsTv
+-----END RSA PRIVATE KEY-----
diff --git a/node/node_modules/socket.io/test/io.test.js b/node/node_modules/socket.io/test/io.test.js
new file mode 100644 (file)
index 0000000..adc316e
--- /dev/null
@@ -0,0 +1,125 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Test dependencies.
+ */
+
+var sio = require('socket.io')
+  , fs = require('fs')
+  , http = require('http')
+  , https = require('https')
+  , should = require('./common')
+  , ports = 15000;
+
+/**
+ * Test.
+ */
+
+module.exports = {
+
+  'test that protocol version is present': function (done) {
+    sio.protocol.should.be.a('number');
+    done();
+  },
+
+  'test that default transports are present': function (done) {
+    sio.Manager.defaultTransports.should.be.an.instanceof(Array);
+    done();
+  },
+
+  'test that version is present': function (done) {
+    sio.version.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/);
+    done();
+  },
+
+  'test listening with a port': function (done) {
+    var cl = client(++ports)
+      , io = create(cl);
+
+    io.server.should.be.an.instanceof(http.Server);
+
+    cl.get('/', function (res, data) {
+      res.statusCode.should.eql(200);
+      data.should.eql('Welcome to socket.io.');
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test listening with a server': function (done) {
+    var server = http.createServer()
+      , io = sio.listen(server)
+      , port = ++ports
+      , cl = client(port);
+
+    server.listen(port);
+
+    cl.get('/socket.io', function (res, data) {
+      res.statusCode.should.eql(200);
+      data.should.eql('Welcome to socket.io.');
+
+      cl.end();
+      server.close();
+      done();
+    });
+  },
+
+  'test listening with a https server': function (done) {
+    var server = https.createServer({
+            key: fs.readFileSync(__dirname + '/fixtures/key.key')
+          , cert: fs.readFileSync(__dirname + '/fixtures/cert.crt')
+        }, function () { })
+      , io = sio.listen(server)
+      , port = ++ports;
+
+    server.listen(port);
+
+    var req = require('https').get({
+        host: 'localhost'
+      , port: port
+      , path: '/socket.io'
+    }, function (res) {
+      res.statusCode.should.eql(200);
+
+      var buf = '';
+
+      res.on('data', function (data) {
+        buf += data;
+      });
+
+      res.on('end', function () {
+        buf.should.eql('Welcome to socket.io.');
+
+        res.socket.end();
+        server.close();
+        done();
+      });
+    });
+  },
+
+  'test listening with no arguments listens on 80': function (done) {
+    try {
+      var io = sio.listen()
+        , cl = client(80);
+
+      cl.get('/socket.io', function (res) {
+        res.statusCode.should.eql(200);
+
+        cl.end();
+        io.server.close();
+        done();
+      });
+    } catch (e) {
+      e.should.match(/EACCES/);
+      done();
+    }
+  }
+
+};
diff --git a/node/node_modules/socket.io/test/leaks/socket.leaktest.js b/node/node_modules/socket.io/test/leaks/socket.leaktest.js
new file mode 100644 (file)
index 0000000..8613b3c
--- /dev/null
@@ -0,0 +1,54 @@
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Test dependencies.
+ */
+
+require.paths.unshift(__dirname + '/../../lib');
+
+var assertvanish = require('assertvanish')
+  , common = require('../common')
+  , ports = 15800;
+
+function resultCallback (leaks, leakedSocket) {
+  if (leaks) {
+    console.error('Leak detected');
+    process.exit(1);
+  } else {
+    console.error('No leaks');
+    process.exit(0);
+  }
+};
+
+/**
+ * Test.
+ */
+
+var cl = client(++ports);
+var io = create(cl);
+
+io.sockets.on('connection', function (socket) {
+  console.log('connected');
+  
+  socket.on('disconnect', function() {
+    console.log("client gone");
+    setTimeout(gc, 1000);
+    assertvanish(socket, 2000, {silent: true, callback: resultCallback});
+  });
+});
+
+setTimeout(function() {
+  cl.handshake(function (sid) {
+    var ws = websocket(cl, sid);
+    ws.on('open', function () {
+      console.log('open!');
+      setTimeout(function() {
+        ws.close();
+      }, 500);
+    });
+  });
+}, 100);
diff --git a/node/node_modules/socket.io/test/manager.test.js b/node/node_modules/socket.io/test/manager.test.js
new file mode 100644 (file)
index 0000000..93922d3
--- /dev/null
@@ -0,0 +1,731 @@
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Test dependencies.
+ */
+
+var sio = require('socket.io')
+  , http = require('http')
+  , should = require('./common')
+  , ports = 15100;
+
+/**
+ * Test.
+ */
+
+module.exports = {
+
+  'test setting and getting a configuration flag': function (done) {
+    var port = ++ports
+      , io = sio.listen(http.createServer());
+
+    io.set('a', 'b');
+    io.get('a').should.eql('b');
+
+    var port = ++ports
+      , io = sio.listen(http.createServer());
+
+    io.configure(function () {
+      io.set('a', 'b');
+      io.enable('tobi');
+    });
+
+    io.get('a').should.eql('b');
+
+    done();
+  },
+
+  'test enabling and disabling a configuration flag': function (done) {
+    var port = ++ports
+      , io = sio.listen(http.createServer());
+
+    io.enable('flag');
+    io.enabled('flag').should.be.true;
+    io.disabled('flag').should.be.false;
+
+    io.disable('flag');
+    var port = ++ports
+      , io = sio.listen(http.createServer());
+
+    io.configure(function () {
+      io.enable('tobi');
+    });
+
+    io.enabled('tobi').should.be.true;
+
+    done();
+  },
+
+  'test configuration callbacks with envs': function (done) {
+    var port = ++ports
+      , io = sio.listen(http.createServer());
+
+    process.env.NODE_ENV = 'development';
+
+    io.configure('production', function () {
+      io.set('ferret', 'tobi');
+    });
+
+    io.configure('development', function () {
+      io.set('ferret', 'jane');
+    });
+
+    io.get('ferret').should.eql('jane');
+    done();
+  },
+
+  'test configuration callbacks conserve scope': function (done) {
+    var port = ++ports
+      , io = sio.listen(http.createServer())
+      , calls = 0;
+
+    process.env.NODE_ENV = 'development';
+
+    io.configure(function () {
+      this.should.eql(io);
+      calls++;
+    });
+
+    io.configure('development', function () {
+      this.should.eql(io);
+      calls++;
+    });
+
+    calls.should.eql(2);
+    done();
+  },
+
+  'test configuration update notifications': function (done) {
+    var port = ++ports
+      , io = sio.listen(http.createServer())
+      , calls = 0;
+
+    io.on('set:foo', function () {
+      calls++;
+    });
+
+    io.set('foo', 'bar');
+    io.set('baz', 'bar');
+
+    calls.should.eql(1);
+
+    io.enable('foo');
+    io.disable('foo');
+
+    calls.should.eql(3);
+    done();
+  },
+
+  'test that normal requests are still served': function (done) {
+    var server = http.createServer(function (req, res) {
+      res.writeHead(200);
+      res.end('woot');
+    });
+
+    var io = sio.listen(server)
+      , port = ++ports
+      , cl = client(port);
+
+    server.listen(ports);
+
+    cl.get('/socket.io', function (res, data) {
+      res.statusCode.should.eql(200);
+      data.should.eql('Welcome to socket.io.');
+
+      cl.get('/woot', function (res, data) {
+        res.statusCode.should.eql(200);
+        data.should.eql('woot');
+
+        cl.end();
+        server.close();
+        done();
+      });
+    });
+  },
+
+  'test that the client is served': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    cl.get('/socket.io/socket.io.js', function (res, data) {
+      res.headers['content-type'].should.eql('application/javascript');
+      res.headers['content-length'].should.match(/([0-9]+)/);
+      should.strictEqual(res.headers.etag, undefined);
+
+      data.should.match(/XMLHttpRequest/);
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test that the client etag is served': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      io.enable('browser client etag');
+    });
+
+    cl.get('/socket.io/socket.io.js', function (res, data) {
+      res.headers['content-type'].should.eql('application/javascript');
+      res.headers['content-length'].should.match(/([0-9]+)/);
+      res.headers.etag.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/);
+
+      data.should.match(/XMLHttpRequest/);
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test that the cached client is served': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    cl.get('/socket.io/socket.io.js', function (res, data) {
+      res.headers['content-type'].should.eql('application/javascript');
+      res.headers['content-length'].should.match(/([0-9]+)/);
+      should.strictEqual(res.headers.etag, undefined);
+
+      data.should.match(/XMLHttpRequest/);
+      var static = sio.Manager.static;
+      static.cache['/socket.io.js'].content.should.match(/XMLHttpRequest/);
+
+      cl.get('/socket.io/socket.io.js', function (res, data) {
+        res.headers['content-type'].should.eql('application/javascript');
+        res.headers['content-length'].should.match(/([0-9]+)/);
+        should.strictEqual(res.headers.etag, undefined);
+
+        data.should.match(/XMLHttpRequest/);
+
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+  },
+
+  'test that the cached client etag is served': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      io.enable('browser client etag');
+    });
+
+    cl.get('/socket.io/socket.io.js', function (res, data) {
+      res.headers['content-type'].should.eql('application/javascript');
+      res.headers['content-length'].should.match(/([0-9]+)/);
+      res.headers.etag.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/);
+
+      data.should.match(/XMLHttpRequest/);
+      var static = sio.Manager.static
+        , cache = static.cache['/socket.io.js'];
+
+      cache.content.toString().should.match(/XMLHttpRequest/);
+      Buffer.isBuffer(cache.content).should.be.true;
+
+      cl.get('/socket.io/socket.io.js', function (res, data) {
+        res.headers['content-type'].should.eql('application/javascript');
+        res.headers['content-length'].should.match(/([0-9]+)/);
+        res.headers.etag.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/);
+
+        data.should.match(/XMLHttpRequest/);
+
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+  },
+
+  'test that the cached client sends a 304 header': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+     io.configure(function () {
+      io.enable('browser client etag');
+    });
+
+    cl.get('/socket.io/socket.io.js', function (res, data) {
+      cl.get('/socket.io/socket.io.js', {headers:{'if-none-match':res.headers.etag}}, function (res, data) {
+        res.statusCode.should.eql(304);
+
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+  },
+
+  'test that client minification works': function (done) {
+    // server 1
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    // server 2
+    var port = ++ports
+      , io2 = sio.listen(port)
+      , cl2 = client(port);
+
+    io.configure(function () {
+      io.enable('browser client minification');
+    });
+
+    cl.get('/socket.io/socket.io.js', function (res, data) {
+      var length = data.length;
+
+      cl.end();
+      io.server.close();
+
+      cl2.get('/socket.io/socket.io.js', function (res, data) {
+        res.headers['content-type'].should.eql('application/javascript');
+        res.headers['content-length'].should.match(/([0-9]+)/);
+        should.strictEqual(res.headers.etag, undefined);
+
+        data.should.match(/XMLHttpRequest/);
+        data.length.should.be.greaterThan(length);
+
+        cl2.end();
+        io2.server.close();
+        done();
+      });
+    });
+  },
+
+  'test that the WebSocketMain.swf is served': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    cl.get('/socket.io/static/flashsocket/WebSocketMain.swf', function (res, data) {
+      res.headers['content-type'].should.eql('application/x-shockwave-flash');
+      res.headers['content-length'].should.match(/([0-9]+)/);
+      should.strictEqual(res.headers.etag, undefined);
+
+      var static = sio.Manager.static
+        , cache = static.cache['/static/flashsocket/WebSocketMain.swf'];
+
+      Buffer.isBuffer(cache.content).should.be.true;
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test that the WebSocketMainInsecure.swf is served': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    cl.get('/socket.io/static/flashsocket/WebSocketMainInsecure.swf', function (res, data) {
+      res.headers['content-type'].should.eql('application/x-shockwave-flash');
+      res.headers['content-length'].should.match(/([0-9]+)/);
+      should.strictEqual(res.headers.etag, undefined);
+
+      var static = sio.Manager.static
+        , cache = static.cache['/static/flashsocket/WebSocketMain.swf'];
+
+      Buffer.isBuffer(cache.content).should.be.true;
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test that you can serve custom clients': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      io.set('browser client handler', function (req, res) {
+        res.writeHead(200, {
+            'Content-Type': 'application/javascript'
+          , 'Content-Length': 13
+          , 'ETag': '1.0'
+        });
+        res.end('custom_client');
+      });
+    });
+
+    cl.get('/socket.io/socket.io.js', function (res, data) {
+      res.headers['content-type'].should.eql('application/javascript');
+      res.headers['content-length'].should.eql(13);
+      res.headers.etag.should.eql('1.0');
+
+      data.should.eql('custom_client');
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test that you can disable clients': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      io.disable('browser client');
+    });
+
+    cl.get('/socket.io/socket.io.js', function (res, data) {
+      res.statusCode.should.eql(200);
+      data.should.eql('Welcome to socket.io.');
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test handshake': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    cl.get('/socket.io/{protocol}/', function (res, data) {
+      res.statusCode.should.eql(200);
+      data.should.match(/([^:]+):([0-9]+)?:([0-9]+)?:(.+)/);
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test handshake with unsupported protocol version': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    cl.get('/socket.io/-1/', function (res, data) {
+      res.statusCode.should.eql(500);
+      data.should.match(/Protocol version not supported/);
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test authorization failure in handshake': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      function auth (data, fn) {
+        fn(null, false);
+      };
+
+      io.set('authorization', auth);
+    });
+
+    cl.get('/socket.io/{protocol}/', function (res, data) {
+      res.statusCode.should.eql(403);
+      data.should.match(/handshake unauthorized/);
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test a handshake error': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      function auth (data, fn) {
+        fn(new Error);
+      };
+
+      io.set('authorization', auth);
+    });
+
+    cl.get('/socket.io/{protocol}/', function (res, data) {
+      res.statusCode.should.eql(500);
+      data.should.match(/handshake error/);
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test that a referer is accepted for *:* origin': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      io.set('origins', '*:*');
+    });
+
+    cl.get('/socket.io/{protocol}', { headers: { referer: 'http://foo.bar.com:82/something' } }, function (res, data) {
+      res.statusCode.should.eql(200);
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test that valid referer is accepted for addr:* origin': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      io.set('origins', 'foo.bar.com:*');
+    });
+
+    cl.get('/socket.io/{protocol}', { headers: { referer: 'http://foo.bar.com/something' } }, function (res, data) {
+      res.statusCode.should.eql(200);
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test that erroneous referer is denied for addr:* origin': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      io.set('origins', 'foo.bar.com:*');
+    });
+
+    cl.get('/socket.io/{protocol}', { headers: { referer: 'http://baz.bar.com/something' } }, function (res, data) {
+      res.statusCode.should.eql(403);
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test that valid referer port is accepted for addr:port origin': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      io.set('origins', 'foo.bar.com:81');
+    });
+
+    cl.get('/socket.io/{protocol}', { headers: { referer: 'http://foo.bar.com:81/something' } }, function (res, data) {
+      res.statusCode.should.eql(200);
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test that erroneous referer port is denied for addr:port origin': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      io.set('origins', 'foo.bar.com:81');
+    });
+
+    cl.get('/socket.io/{protocol}', { headers: { referer: 'http://foo.bar.com/something' } }, function (res, data) {
+      res.statusCode.should.eql(403);
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test limiting the supported transports for a manager': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      io.set('transports', ['tobi', 'jane']);
+    });
+
+    cl.get('/socket.io/{protocol}/', function (res, data) {
+      res.statusCode.should.eql(200);
+      data.should.match(/([^:]+):([0-9]+)?:([0-9]+)?:tobi,jane/);
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test setting a custom close timeout': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      io.set('close timeout', 66);
+    });
+
+    cl.get('/socket.io/{protocol}/', function (res, data) {
+      res.statusCode.should.eql(200);
+      data.should.match(/([^:]+):([0-9]+)?:66?:(.*)/);
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test setting a custom heartbeat timeout': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      io.set('heartbeat timeout', 33);
+    });
+
+    cl.get('/socket.io/{protocol}/', function (res, data) {
+      res.statusCode.should.eql(200);
+      data.should.match(/([^:]+):33:([0-9]+)?:(.*)/);
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test disabling timeouts': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port);
+
+    io.configure(function () {
+      io.set('heartbeat timeout', null);
+      io.set('close timeout', '');
+    });
+
+    cl.get('/socket.io/{protocol}/', function (res, data) {
+      res.statusCode.should.eql(200);
+      data.should.match(/([^:]+)::?:(.*)/);
+
+      cl.end();
+      io.server.close();
+      done();
+    });
+  },
+
+  'test disabling heartbeats': function (done) {
+    var port = ++ports
+      , io = sio.listen(port)
+      , cl = client(port)
+      , messages = 0
+      , beat = false
+      , ws;
+
+    io.configure(function () {
+      io.disable('heartbeats');
+      io.set('heartbeat interval', .05);
+      io.set('heartbeat timeout', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      setTimeout(function () {
+        socket.disconnect();
+      }, io.get('heartbeat timeout') * 1000 + 100);
+
+      socket.on('disconnect', function (reason) {
+        beat.should.be.false;
+
+        cl.end();
+        ws.finishClose();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.get('/socket.io/{protocol}/', function (res, data) {
+      res.statusCode.should.eql(200);
+      data.should.match(/([^:]+)::[\.0-9]+:(.*)/);
+
+      cl.handshake(function (sid) {
+        ws = websocket(cl, sid);
+        ws.on('message', function (packet) {
+          if (++messages == 1) {
+            packet.type.should.eql('connect');
+          } else if (packet.type == 'heartbeat'){
+            beat = true;
+          }
+        });
+      });
+    });
+  },
+
+  'no duplicate room members': function (done) {
+    var port = ++ports
+      , io = sio.listen(port);
+
+    Object.keys(io.rooms).length.should.equal(0);
+
+    io.onJoin(123, 'foo');
+    io.rooms.foo.length.should.equal(1);
+
+    io.onJoin(123, 'foo');
+    io.rooms.foo.length.should.equal(1);
+
+    io.onJoin(124, 'foo');
+    io.rooms.foo.length.should.equal(2);
+
+    io.onJoin(124, 'foo');
+    io.rooms.foo.length.should.equal(2);
+
+    io.onJoin(123, 'bar');
+    io.rooms.foo.length.should.equal(2);
+    io.rooms.bar.length.should.equal(1);
+
+    io.onJoin(123, 'bar');
+    io.rooms.foo.length.should.equal(2);
+    io.rooms.bar.length.should.equal(1);
+
+    io.onJoin(124, 'bar');
+    io.rooms.foo.length.should.equal(2);
+    io.rooms.bar.length.should.equal(2);
+
+    io.onJoin(124, 'bar');
+    io.rooms.foo.length.should.equal(2);
+    io.rooms.bar.length.should.equal(2);
+
+    io.server.close();
+    done();
+  },
+
+  'test passing options directly to the Manager through listen': function (done) {
+    var port = ++ports
+      , io = sio.listen(port, { resource: '/my resource', custom: 'opt' });
+
+    io.get('resource').should.equal('/my resource');
+    io.get('custom').should.equal('opt');
+    io.server.close();
+    done();
+  }
+};
diff --git a/node/node_modules/socket.io/test/namespace.test.js b/node/node_modules/socket.io/test/namespace.test.js
new file mode 100644 (file)
index 0000000..5acb9d4
--- /dev/null
@@ -0,0 +1,247 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Test dependencies.
+ */
+
+var sio = require('socket.io')
+  , should = require('./common')
+  , ports = 15700;
+
+/**
+ * Test.
+ */
+
+module.exports = {
+  'namespace pass no authentication': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , ws;
+
+    io.of('/a')
+      .on('connection', function (socket) {
+        cl.end();
+        ws.finishClose();
+        io.server.close()
+        done();
+      });
+
+    cl.handshake(function (sid) {
+      ws = websocket(cl, sid);
+      ws.on('open', function () {
+        ws.packet({
+            type: 'connect'
+          , endpoint: '/a'
+        });
+      })
+    });
+  },
+
+  'namespace pass authentication': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , ws;
+
+    io.of('/a')
+      .authorization(function (data, fn) {
+        fn(null, true);
+      })
+      .on('connection', function (socket) {
+        cl.end();
+        ws.finishClose();
+        io.server.close()
+        done();
+      });
+
+    cl.handshake(function (sid) {
+      ws = websocket(cl, sid);
+      ws.on('open', function () {
+        ws.packet({
+            type: 'connect'
+          , endpoint: '/a'
+        });
+      })
+    });
+  },
+
+  'namespace authentication handshake data': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , ws;
+
+    io.of('/a')
+      .authorization(function (data, fn) {
+        data.foo = 'bar';
+        fn(null, true);
+      })
+      .on('connection', function (socket) {
+        (!!socket.handshake.address.address).should.be.true;
+        (!!socket.handshake.address.port).should.be.true;
+        socket.handshake.headers.host.should.equal('localhost');
+        socket.handshake.headers.connection.should.equal('keep-alive');
+        socket.handshake.time.should.match(/GMT/);
+        socket.handshake.foo.should.equal('bar');
+
+        cl.end();
+        ws.finishClose();
+        io.server.close()
+        done();
+      });
+
+    cl.handshake(function (sid) {
+      ws = websocket(cl, sid);
+      ws.on('open', function () {
+        ws.packet({
+            type: 'connect'
+          , endpoint: '/a'
+        });
+      })
+    });
+  },
+
+  'namespace fail authentication': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , calls = 0
+      , ws;
+
+    io.of('/a')
+      .authorization(function (data, fn) {
+        fn(null, false);
+      })
+      .on('connection', function (socket) {
+        throw new Error('Should not be called');
+      });
+
+    cl.handshake(function (sid) {
+      ws = websocket(cl, sid);
+      ws.on('open', function () {
+        ws.packet({
+            type: 'connect'
+          , endpoint: '/a'
+        });
+      });
+
+      ws.on('message', function (data) {
+        if (data.endpoint == '/a') {
+          data.type.should.eql('error');
+          data.reason.should.eql('unauthorized')
+          
+          cl.end();
+          ws.finishClose();
+          io.server.close()
+          done();
+        }
+      })
+    });
+  },
+
+  'broadcasting sends and emits on a namespace': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , calls = 0
+      , connect = 0
+      , message = 0
+      , events = 0
+      , expected = 5
+      , ws1
+      , ws2;
+
+    io.of('a')
+      .on('connection', function (socket){
+        socket.broadcast.emit('b', 'test');
+        socket.broadcast.json.emit('json', {foo:'bar'});
+        socket.broadcast.send('foo');
+      });
+
+    function finish () {
+      connect.should.equal(2);
+      message.should.equal(1);
+      events.should.equal(2);
+
+      cl.end();
+      ws1.finishClose();
+      ws2.finishClose();
+      io.server.close();
+      done();
+    }
+
+    cl.handshake(function (sid) {
+     ws1 = websocket(cl, sid);
+
+      ws1.on('open', function() {
+        ws1.packet({
+            type: 'connect'
+          , endpoint: 'a'
+        });
+      });
+
+      ws1.on('message', function (data) {
+        if (data.type === 'connect') {
+          ++connect;
+          if (++calls === expected) finish();
+        }
+
+        if (data.type === 'message') {
+          ++message;
+          if (++calls === expected) finish();
+        }
+
+        if (data.type === 'event') {
+          if (data.name === 'b' || data.name === 'json') ++events;
+          if (++calls === expected) finish();
+        }
+      });
+
+      cl.handshake(function (sid) {
+        ws2 = websocket(cl, sid);
+
+        ws2.on('open', function () {
+          ws2.packet({
+              type: 'connect'
+            , endpoint: 'a'
+          });
+        });
+      })
+    })
+  },
+
+  'joining rooms inside a namespace': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , calls = 0
+      , ws;
+
+    io.of('/foo').on('connection', function (socket) {
+      socket.join('foo.bar');
+      this.in('foo.bar').emit('baz', 'pewpew');
+    });
+
+    cl.handshake(function (sid) {
+      ws = websocket(cl, sid);
+
+      ws.on('open', function (){
+         ws.packet({
+            type: 'connect'
+          , endpoint: '/foo'
+        });
+      });
+
+      ws.on('message', function (data) {
+        if (data.type === 'event') {
+          data.name.should.equal('baz');
+
+          cl.end();
+          ws.finishClose();
+          io.server.close();
+          done();
+        }
+      });
+    })
+  }
+};
diff --git a/node/node_modules/socket.io/test/parser.test.js b/node/node_modules/socket.io/test/parser.test.js
new file mode 100644 (file)
index 0000000..ee51033
--- /dev/null
@@ -0,0 +1,356 @@
+
+/**
+ * Test dependencies.
+ */
+
+var parser = require('socket.io').parser
+  , decode = parser.decode
+  , should = require('./common');
+
+/**
+ * Test.
+ */
+
+module.exports = {
+
+  'decoding error packet': function () {
+    parser.decodePacket('7:::').should.eql({
+        type: 'error'
+      , reason: ''
+      , advice: ''
+      , endpoint: ''
+    });
+  },
+
+  'decoding error packet with reason': function () {
+    parser.decodePacket('7:::0').should.eql({
+        type: 'error'
+      , reason: 'transport not supported'
+      , advice: ''
+      , endpoint: ''
+    });
+  },
+
+  'decoding error packet with reason and advice': function () {
+    parser.decodePacket('7:::2+0').should.eql({
+        type: 'error'
+      , reason: 'unauthorized'
+      , advice: 'reconnect'
+      , endpoint: ''
+    });
+  },
+
+  'decoding error packet with endpoint': function () {
+    parser.decodePacket('7::/woot').should.eql({
+        type: 'error'
+      , reason: ''
+      , advice: ''
+      , endpoint: '/woot'
+    });
+  },
+
+  'decoding ack packet': function () {
+    parser.decodePacket('6:::140').should.eql({
+        type: 'ack'
+      , ackId: '140'
+      , endpoint: ''
+      , args: []
+    });
+  },
+
+  'decoding ack packet with args': function () {
+    parser.decodePacket('6:::12+["woot","wa"]').should.eql({
+        type: 'ack'
+      , ackId: '12'
+      , endpoint: ''
+      , args: ['woot', 'wa']
+    });
+  },
+
+  'decoding ack packet with bad json': function () {
+    var thrown = false;
+
+    try {
+      parser.decodePacket('6:::1+{"++]').should.eql({
+          type: 'ack'
+        , ackId: '1'
+        , endpoint: ''
+        , args: []
+      });
+    } catch (e) {
+      thrown = true;
+    }
+
+    thrown.should.be.false;
+  },
+
+  'decoding json packet': function () {
+    parser.decodePacket('4:::"2"').should.eql({
+        type: 'json'
+      , endpoint: ''
+      , data: '2'
+    });
+  },
+
+  'decoding json packet with message id and ack data': function () {
+    parser.decodePacket('4:1+::{"a":"b"}').should.eql({
+        type: 'json'
+      , id: 1
+      , ack: 'data'
+      , endpoint: ''
+      , data: { a: 'b' }
+    });
+  },
+
+  'decoding an event packet': function () {
+    parser.decodePacket('5:::{"name":"woot"}').should.eql({
+        type: 'event'
+      , name: 'woot'
+      , endpoint: ''
+      , args: []
+    });
+  },
+
+  'decoding an event packet with message id and ack': function () {
+    parser.decodePacket('5:1+::{"name":"tobi"}').should.eql({
+        type: 'event'
+      , id: 1
+      , ack: 'data'
+      , endpoint: ''
+      , name: 'tobi'
+      , args: []
+    });
+  },
+
+  'decoding an event packet with data': function () {
+    parser.decodePacket('5:::{"name":"edwald","args":[{"a": "b"},2,"3"]}')
+    .should.eql({
+        type: 'event'
+      , name: 'edwald'
+      , endpoint: ''
+      , args: [{a: 'b'}, 2, '3']
+    });
+  },
+
+  'decoding a message packet': function () {
+    parser.decodePacket('3:::woot').should.eql({
+        type: 'message'
+      , endpoint: ''
+      , data: 'woot'
+    });
+  },
+
+  'decoding a message packet with id and endpoint': function () {
+    parser.decodePacket('3:5:/tobi').should.eql({
+        type: 'message'
+      , id: 5
+      , ack: true
+      , endpoint: '/tobi'
+      , data: ''
+    });
+  },
+
+  'decoding a heartbeat packet': function () {
+    parser.decodePacket('2:::').should.eql({
+        type: 'heartbeat'
+      , endpoint: ''
+    });
+  },
+
+  'decoding a connection packet': function () {
+    parser.decodePacket('1::/tobi').should.eql({
+        type: 'connect'
+      , endpoint: '/tobi'
+      , qs: ''
+    });
+  },
+
+  'decoding a connection packet with query string': function () {
+    parser.decodePacket('1::/test:?test=1').should.eql({
+        type: 'connect'
+      , endpoint: '/test'
+      , qs: '?test=1'
+    });
+  },
+
+  'decoding a disconnection packet': function () {
+    parser.decodePacket('0::/woot').should.eql({
+        type: 'disconnect'
+      , endpoint: '/woot'
+    });
+  },
+
+  'encoding error packet': function () {
+    parser.encodePacket({
+        type: 'error'
+      , reason: ''
+      , advice: ''
+      , endpoint: ''
+    }).should.eql('7::');
+  },
+
+  'encoding error packet with reason': function () {
+    parser.encodePacket({
+        type: 'error'
+      , reason: 'transport not supported'
+      , advice: ''
+      , endpoint: ''
+    }).should.eql('7:::0');
+  },
+
+  'encoding error packet with reason and advice': function () {
+    parser.encodePacket({
+        type: 'error'
+      , reason: 'unauthorized'
+      , advice: 'reconnect'
+      , endpoint: ''
+    }).should.eql('7:::2+0');
+  },
+
+  'encoding error packet with endpoint': function () {
+    parser.encodePacket({
+        type: 'error'
+      , reason: ''
+      , advice: ''
+      , endpoint: '/woot'
+    }).should.eql('7::/woot');
+  },
+
+  'encoding ack packet': function () {
+    parser.encodePacket({
+        type: 'ack'
+      , ackId: '140'
+      , endpoint: ''
+      , args: []
+    }).should.eql('6:::140');
+  },
+
+  'encoding ack packet with args': function () {
+    parser.encodePacket({
+        type: 'ack'
+      , ackId: '12'
+      , endpoint: ''
+      , args: ['woot', 'wa']
+    }).should.eql('6:::12+["woot","wa"]');
+  },
+
+  'encoding json packet': function () {
+    parser.encodePacket({
+        type: 'json'
+      , endpoint: ''
+      , data: '2'
+    }).should.eql('4:::"2"');
+  },
+
+  'encoding json packet with message id and ack data': function () {
+    parser.encodePacket({
+        type: 'json'
+      , id: 1
+      , ack: 'data'
+      , endpoint: ''
+      , data: { a: 'b' }
+    }).should.eql('4:1+::{"a":"b"}');
+  },
+
+  'encoding an event packet': function () {
+    parser.encodePacket({
+        type: 'event'
+      , name: 'woot'
+      , endpoint: ''
+      , args: []
+    }).should.eql('5:::{"name":"woot"}');
+  },
+
+  'encoding an event packet with message id and ack': function () {
+    parser.encodePacket({
+        type: 'event'
+      , id: 1
+      , ack: 'data'
+      , endpoint: ''
+      , name: 'tobi'
+      , args: []
+    }).should.eql('5:1+::{"name":"tobi"}');
+  },
+
+  'encoding an event packet with data': function () {
+    parser.encodePacket({
+        type: 'event'
+      , name: 'edwald'
+      , endpoint: ''
+      , args: [{a: 'b'}, 2, '3']
+    }).should.eql('5:::{"name":"edwald","args":[{"a":"b"},2,"3"]}');
+  },
+
+  'encoding a message packet': function () {
+    parser.encodePacket({
+        type: 'message'
+      , endpoint: ''
+      , data: 'woot'
+    }).should.eql('3:::woot');
+  },
+
+  'encoding a message packet with id and endpoint': function () {
+    parser.encodePacket({
+        type: 'message'
+      , id: 5
+      , ack: true
+      , endpoint: '/tobi'
+      , data: ''
+    }).should.eql('3:5:/tobi');
+  },
+
+  'encoding a heartbeat packet': function () {
+    parser.encodePacket({
+        type: 'heartbeat'
+      , endpoint: ''
+    }).should.eql('2::');
+  },
+
+  'encoding a connection packet': function () {
+    parser.encodePacket({
+        type: 'connect'
+      , endpoint: '/tobi'
+      , qs: ''
+    }).should.eql('1::/tobi');
+  },
+
+  'encoding a connection packet with query string': function () {
+    parser.encodePacket({
+        type: 'connect'
+      , endpoint: '/test'
+      , qs: '?test=1'
+    }).should.eql('1::/test:?test=1');
+  },
+
+  'encoding a disconnection packet': function () {
+    parser.encodePacket({
+        type: 'disconnect'
+      , endpoint: '/woot'
+    }).should.eql('0::/woot');
+  },
+
+  'test decoding a payload': function () {
+    parser.decodePayload('\ufffd5\ufffd3:::5\ufffd7\ufffd3:::53d'
+      + '\ufffd3\ufffd0::').should.eql([
+        { type: 'message', data: '5', endpoint: '' }
+      , { type: 'message', data: '53d', endpoint: '' }
+      , { type: 'disconnect', endpoint: '' }
+    ]);
+  },
+
+  'test encoding a payload': function () {
+    parser.encodePayload([
+        parser.encodePacket({ type: 'message', data: '5', endpoint: '' })
+      , parser.encodePacket({ type: 'message', data: '53d', endpoint: '' })
+    ]).should.eql('\ufffd5\ufffd3:::5\ufffd7\ufffd3:::53d')
+  },
+
+  'test decoding newline': function () {
+    parser.decodePacket('3:::\n').should.eql({
+        type: 'message'
+      , endpoint: ''
+      , data: '\n'
+    });
+  }
+
+};
diff --git a/node/node_modules/socket.io/test/socket.js b/node/node_modules/socket.io/test/socket.js
new file mode 100644 (file)
index 0000000..a700cb5
--- /dev/null
@@ -0,0 +1,15 @@
+
+/**
+ * Test dependencies.
+ */
+
+var sio = require('socket.io')
+  , should = require('./common');
+
+/**
+ * Test.
+ */
+
+module.exports = {
+
+};
diff --git a/node/node_modules/socket.io/test/stores.memory.test.js b/node/node_modules/socket.io/test/stores.memory.test.js
new file mode 100644 (file)
index 0000000..ecf9c96
--- /dev/null
@@ -0,0 +1,190 @@
+
+/**
+ * Test dependencies
+ *
+ * @api private
+ */
+
+var sio = require('socket.io')
+  , should = require('should')
+  , MemoryStore = sio.MemoryStore;
+
+/**
+ * Test.
+ */
+
+module.exports = {
+
+  'test storing data for a client': function (done) {
+    var store = new MemoryStore
+      , client = store.client('test');
+
+    client.id.should.equal('test');
+
+    client.set('a', 'b', function (err) {
+      should.strictEqual(err, null);
+
+      client.get('a', function (err, val) {
+        should.strictEqual(err, null);
+        val.should.eql('b');
+
+        client.has('a', function (err, has) {
+          should.strictEqual(err, null);
+          has.should.be.true;
+
+          client.has('b', function (err, has) {
+            should.strictEqual(err, null);
+            has.should.be.false;
+
+            client.del('a', function (err) {
+              should.strictEqual(err, null);
+
+              client.has('a', function (err, has) {
+                should.strictEqual(err, null);
+                has.should.be.false;
+
+                client.set('b', 'c', function (err) {
+                  should.strictEqual(err, null);
+                  
+                  client.set('c', 'd', function (err) {
+                    should.strictEqual(err, null);
+
+                    client.get('b', function (err, val) {
+                      should.strictEqual(err, null);
+                      val.should.equal('c');
+
+                      client.get('c', function (err, val) {
+                        should.strictEqual(err, null);
+                        val.should.equal('d');
+
+                        store.destroy();
+                        done();
+                      });
+                    });
+                  });
+                });
+              });
+            });
+          });
+        });
+      });
+    });
+  },
+
+  'test cleaning up clients data': function (done) {
+    var rand1 = Math.abs(Math.random() * Date.now() | 0)
+      , rand2 = Math.abs(Math.random() * Date.now() | 0);
+
+    var store = new MemoryStore()
+      , client1 = store.client(rand1)
+      , client2 = store.client(rand2);
+
+    client1.set('a', 'b', function (err) {
+      should.strictEqual(err, null);
+
+      client2.set('c', 'd', function (err) {
+        should.strictEqual(err, null);
+
+        client1.has('a', function (err, val) {
+          should.strictEqual(err, null);
+          val.should.be.true;
+
+          client2.has('c', function (err, val) {
+            should.strictEqual(err, null);
+            val.should.be.true;
+
+            store.destroy();
+
+            var newstore = new MemoryStore()
+              , newclient1 = newstore.client(rand1)
+              , newclient2 = newstore.client(rand2);
+
+            newclient1.has('a', function (err, val) {
+              should.strictEqual(err, null);
+              val.should.be.false;
+
+              newclient2.has('c', function (err, val) {
+                should.strictEqual(err, null);
+                val.should.be.false;
+
+                newstore.destroy();
+                done();
+              });
+            });
+          });
+        });
+      });
+    });
+  },
+
+  'test cleaning up a particular client': function (done) {
+    var rand1 = Math.abs(Math.random() * Date.now() | 0)
+      , rand2 = Math.abs(Math.random() * Date.now() | 0);
+
+    var store = new MemoryStore()
+      , client1 = store.client(rand1)
+      , client2 = store.client(rand2);
+
+    client1.set('a', 'b', function (err) {
+      should.strictEqual(err, null);
+
+      client2.set('c', 'd', function (err) {
+        should.strictEqual(err, null);
+
+        client1.has('a', function (err, val) {
+          should.strictEqual(err, null);
+          val.should.be.true;
+
+          client2.has('c', function (err, val) {
+            should.strictEqual(err, null);
+            val.should.be.true;
+
+            store.clients.should.have.property(rand1);
+            store.clients.should.have.property(rand2);
+            store.destroyClient(rand1);
+
+            store.clients.should.not.have.property(rand1);
+            store.clients.should.have.property(rand2);
+
+            client1.has('a', function (err, val) {
+              should.strictEqual(err, null);
+              val.should.equal(false);
+
+              store.destroy();
+              done();
+            });
+          });
+        });
+      });
+    });
+  },
+
+  'test destroy expiration': function (done) {
+    var store = new MemoryStore()
+      , id = Math.abs(Math.random() * Date.now() | 0)
+      , client = store.client(id);
+
+    client.set('a', 'b', function (err) {
+      should.strictEqual(err, null);
+      store.destroyClient(id, 1);
+
+      setTimeout(function () {
+        client.get('a', function (err, val) {
+          should.strictEqual(err, null);
+          val.should.equal('b');
+        });
+      }, 500);
+
+      setTimeout(function () {
+        client.get('a', function (err, val) {
+          should.strictEqual(err, null);
+          should.strictEqual(val, null);
+
+          store.destroy();
+          done();
+        });
+      }, 1900);
+    });
+  }
+
+};
diff --git a/node/node_modules/socket.io/test/stores.redis.test.js b/node/node_modules/socket.io/test/stores.redis.test.js
new file mode 100644 (file)
index 0000000..69848f3
--- /dev/null
@@ -0,0 +1,240 @@
+
+/**
+ * Test dependencies
+ *
+ * @api private
+ */
+
+var sio = require('socket.io')
+  , redis = require('redis')
+  , should = require('should')
+  , RedisStore = sio.RedisStore;
+
+/**
+ * Test.
+ */
+
+module.exports = {
+
+  'test publishing doesnt get caught by the own store subscriber': function (done) {
+    var a = new RedisStore
+      , b = new RedisStore;
+
+    a.subscribe('woot', function (arg) {
+      arg.should.equal('bb');
+      a.destroy();
+      b.destroy();
+      done();
+    }, function () {
+      a.publish('woot', 'aa');
+      b.publish('woot', 'bb');
+    });
+  },
+
+  'test publishing to multiple subscribers': function (done) {
+    var a = new RedisStore
+      , b = new RedisStore
+      , c = new RedisStore
+      , subscriptions = 3
+      , messages = 2;
+
+    a.subscribe('tobi', function () {
+      throw new Error('Shouldnt publish to itself');
+    }, publish);
+
+    function subscription (arg1, arg2, arg3) {
+      arg1.should.equal(1);
+      arg2.should.equal(2);
+      arg3.should.equal(3);
+      --messages || finish();
+    }
+
+    b.subscribe('tobi', subscription, publish);
+    c.subscribe('tobi', subscription, publish);
+
+    function publish () {
+      --subscriptions || a.publish('tobi', 1, 2, 3);
+    }
+
+    function finish () {
+      a.destroy();
+      b.destroy();
+      c.destroy();
+      done();
+    }
+  },
+
+  'test storing data for a client': function (done) {
+    var store = new RedisStore
+      , rand = 'test-' + Date.now()
+      , client = store.client(rand);
+
+    client.id.should.equal(rand);
+
+    client.set('a', 'b', function (err) {
+      should.strictEqual(err, null);
+
+      client.get('a', function (err, val) {
+        should.strictEqual(err, null);
+        val.should.equal('b');
+
+        client.has('a', function (err, has) {
+          should.strictEqual(err, null);
+          has.should.be.true;
+
+          client.has('b', function (err, has) {
+            should.strictEqual(err, null);
+            has.should.be.false;
+
+            client.del('a', function (err) {
+              should.strictEqual(err, null);
+
+              client.has('a', function (err, has) {
+                should.strictEqual(err, null);
+                has.should.be.false;
+
+                client.set('b', 'c', function (err) {
+                  should.strictEqual(err, null);
+                  
+                  client.set('c', 'd', function (err) {
+                    should.strictEqual(err, null);
+
+                    client.get('b', function (err, val) {
+                      should.strictEqual(err, null);
+                      val.should.equal('c');
+
+                      client.get('c', function (err, val) {
+                        should.strictEqual(err, null);
+                        val.should.equal('d');
+
+                        store.destroy();
+                        done();
+                      });
+                    });
+                  });
+                });
+              });
+            });
+          });
+        });
+      });
+    });
+  },
+
+  'test cleaning up clients data': function (done) {
+    var rand1 = Math.abs(Math.random() * Date.now() | 0)
+      , rand2 = Math.abs(Math.random() * Date.now() | 0);
+
+    var store = new RedisStore()
+      , client1 = store.client(rand1)
+      , client2 = store.client(rand2);
+
+    client1.set('a', 'b', function (err) {
+      should.strictEqual(err, null);
+
+      client2.set('c', 'd', function (err) {
+        should.strictEqual(err, null);
+
+        client1.has('a', function (err, val) {
+          should.strictEqual(err, null);
+          val.should.be.true;
+
+          client2.has('c', function (err, val) {
+            should.strictEqual(err, null);
+            val.should.be.true;
+
+            store.destroy();
+
+            var newstore = new RedisStore()
+              , newclient1 = newstore.client(rand1)
+              , newclient2 = newstore.client(rand2);
+
+            newclient1.has('a', function (err, val) {
+              should.strictEqual(err, null);
+              val.should.be.false;
+
+              newclient2.has('c', function (err, val) {
+                should.strictEqual(err, null);
+                val.should.be.false;
+
+                newstore.destroy();
+                done();
+              });
+            });
+          });
+        });
+      });
+    });
+  },
+
+  'test cleaning up a particular client': function (done) {
+    var rand1 = Math.abs(Math.random() * Date.now() | 0)
+      , rand2 = Math.abs(Math.random() * Date.now() | 0);
+
+    var store = new RedisStore()
+      , client1 = store.client(rand1)
+      , client2 = store.client(rand2);
+
+    client1.set('a', 'b', function (err) {
+      should.strictEqual(err, null);
+
+      client2.set('c', 'd', function (err) {
+        should.strictEqual(err, null);
+
+        client1.has('a', function (err, val) {
+          should.strictEqual(err, null);
+          val.should.be.true;
+
+          client2.has('c', function (err, val) {
+            should.strictEqual(err, null);
+            val.should.be.true;
+
+            store.clients.should.have.property(rand1);
+            store.clients.should.have.property(rand2);
+            store.destroyClient(rand1);
+
+            store.clients.should.not.have.property(rand1);
+            store.clients.should.have.property(rand2);
+
+            client1.has('a', function (err, val) {
+              should.strictEqual(err, null);
+              val.should.equal(false);
+
+              store.destroy();
+              done();
+            });
+          });
+        });
+      });
+    });
+  },
+
+  'test destroy expiration': function (done) {
+    var store = new RedisStore()
+      , id = Math.abs(Math.random() * Date.now() | 0)
+      , client = store.client(id);
+
+    client.set('a', 'b', function (err) {
+      should.strictEqual(err, null);
+      store.destroyClient(id, 1);
+
+      setTimeout(function () {
+        client.get('a', function (err, val) {
+          should.strictEqual(err, null);
+          val.should.equal('b');
+        });
+      }, 500);
+
+      setTimeout(function () {
+        client.get('a', function (err, val) {
+          should.strictEqual(err, null);
+          should.strictEqual(val, null);
+
+          store.destroy();
+          done();
+        });
+      }, 2000);
+    });
+  }
+
+};
diff --git a/node/node_modules/socket.io/test/transports.flashsocket.test.js b/node/node_modules/socket.io/test/transports.flashsocket.test.js
new file mode 100644 (file)
index 0000000..7ba79d3
--- /dev/null
@@ -0,0 +1,168 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Test dependencies.
+ */
+
+var sio = require('socket.io')
+  , net = require('net')
+  , http = require('http')
+  , should = require('./common')
+  , WebSocket = require('../support/node-websocket-client/lib/websocket').WebSocket
+  , WSClient = require('./transports.websocket.test')
+  , parser = sio.parser
+  , ports = 15600;
+
+/**
+ * FlashSocket client constructor.
+ *
+ * @api private
+ */
+
+function FlashSocket (port, sid) {
+  this.sid = sid;
+  this.port = port;
+
+  WebSocket.call(
+      this
+    , 'ws://localhost:' + port + '/socket.io/' 
+        + sio.protocol + '/flashsocket/' + sid
+  );
+};
+
+/**
+ * Inherits from WSClient.
+ */
+
+FlashSocket.prototype.__proto__ = WebSocket.prototype;
+
+/**
+ * Creates a TCP connection to a port.
+ *
+ * @api public
+ */
+
+function netConnection (port, callback){
+  var nclient = net.createConnection(port);
+
+  nclient.on('data', function (data) {
+    callback.call(nclient, null, data);
+  });
+
+  nclient.on('error', function (e){
+    callback.call(nclient, e);
+  });
+
+  nclient.write('<policy-file-request/>\0');
+}
+
+/**
+ * Tests.
+ */
+
+module.exports = {
+
+  'flashsocket disabled by default': function (done) {
+    var io = sio.listen(http.createServer());
+    io.get('transports').should.not.contain('flashsocket');
+    done();
+  },
+
+  'flash policy port': function (done) {
+    var io = sio.listen(http.createServer())
+      , port = ++ports;
+
+    io.get('flash policy port').should.eql(10843);
+    io.set('flash policy port', port);
+    io.get('flash policy port').should.eql(port);
+
+    should.strictEqual(io.flashPolicyServer, undefined);
+
+    netConnection(port, function (err, data){
+      err.should.be.an.instanceof(Error);
+      err.code.should.eql('ECONNREFUSED');
+
+      this.destroy();
+      done();
+    })
+  },
+
+  'start flash policy': function (done) {
+    var io = sio.listen(http.createServer())
+      , port = ++ports;
+
+    io.set('flash policy port', port);
+    io.set('transports', ['flashsocket']);
+
+    io.flashPolicyServer.should.be.a('object');
+
+    netConnection(port, function (err, data){
+      should.strictEqual(err, null);
+
+      data.toString().should.include.string('<cross-domain-policy>');
+
+      this.destroy();
+      io.flashPolicyServer.close();
+      done();
+    })
+
+  },
+
+  'change running flash server port': function (done) {
+    var io = sio.listen(http.createServer())
+      , port = ++ports
+      , next = ++ports;
+
+    io.set('flash policy port', port);
+    io.set('transports', ['flashsocket']);
+    io.set('flash policy port', next);
+    io.flashPolicyServer.port.should.eql(next);
+
+    netConnection(port, function (err, data){
+      err.should.be.an.instanceof(Error);
+      err.code.should.eql('ECONNREFUSED');
+
+      this.destroy();
+
+      // should work
+      netConnection(next, function (err, data){
+        should.strictEqual(err, null);
+
+        data.toString().should.include.string('<cross-domain-policy>');
+
+        this.destroy();
+        io.flashPolicyServer.close();
+        done();
+      });
+    });
+  },
+
+  'different origins': function(done) {
+    var io = sio.listen(http.createServer())
+      , port = ++ports;
+
+    io.set('flash policy port', port);
+    io.set('transports', ['flashsocket']);
+    io.set('origins', 'google.com:80');
+
+    var server = io.flashPolicyServer;
+
+    server.origins.should.contain('google.com:80');
+    server.origins.should.not.contain('*.*');
+
+    io.set('origins', ['foo.bar:80', 'socket.io:1337']);
+    server.origins.should.not.contain('google.com:80');
+    server.origins.should.contain('foo.bar:80');
+    server.origins.should.contain('socket.io:1337');
+    server.buffer.toString('utf8').should.include.string('socket.io');
+
+    io.flashPolicyServer.close();
+    done();
+  }
+
+};
diff --git a/node/node_modules/socket.io/test/transports.htmlfile.test.js b/node/node_modules/socket.io/test/transports.htmlfile.test.js
new file mode 100644 (file)
index 0000000..a9429ab
--- /dev/null
@@ -0,0 +1,458 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Test dependencies.
+ */
+
+var sio = require('socket.io')
+  , should = require('./common')
+  , HTTPClient = should.HTTPClient
+  , parser = sio.parser
+  , ports = 15300;
+
+/**
+ * HTTPClient for htmlfile transport.
+ */
+
+function HTMLFile (port) {
+  HTTPClient.call(this, port);
+};
+
+/**
+ * Inhertis from HTTPClient.
+ */
+
+HTMLFile.prototype.__proto__ = HTTPClient.prototype;
+
+/**
+ * Override GET request with streaming parser.
+ *
+ * @api public
+ */
+
+var head = '<script>_('
+  , foot = ');</script>'
+  , initial = '<html><body>'
+      + '<script>var _ = function (msg) { parent.s._(msg, document); };</script>'
+      + new Array(174).join(' ')
+
+HTMLFile.prototype.data = function (path, opts, fn) {
+  if ('function' == typeof opts) {
+    fn = opts;
+    opts = {};
+  }
+
+  opts.buffer = false;
+
+  return this.request(path, opts, function (res) {
+    var buf = ''
+      , messages = 0
+      , state = 0;
+
+    res.on('data', function (chunk) {
+      buf += chunk;
+
+      function parse () {
+        switch (state) {
+          case 0:
+            if (buf.indexOf(initial) === 0) {
+              buf = buf.substr(initial.length);
+              state = 1;
+            } else {
+              break;
+            }
+
+          case 1:
+            if (buf.indexOf(head) === 0) {
+              buf = buf.substr(head.length);
+              state = 2;
+            } else {
+              break;
+            }
+
+          case 2:
+            if (buf.indexOf(foot) != -1) {
+              var data = buf.slice(0, buf.indexOf(foot))
+                , obj = JSON.parse(data);
+
+              fn(obj === '' ? obj : parser.decodePayload(obj), ++messages);
+
+              buf = buf.substr(data.length + foot.length);
+              state = 1;
+
+              parse();
+            }
+        };
+      };
+
+      parse();
+    });
+  });
+};
+
+/**
+ * Create client for this transport.
+ *
+ * @api public
+ */
+
+function client (port) {
+  return new HTMLFile(port);
+};
+
+/**
+ * Tests.
+ */
+
+module.exports = {
+
+  'test that not responding to a heartbeat drops client': function (done) {
+    var port = ++ports
+      , cl = client(port)
+      , io = create(cl)
+      , beat = false;
+
+    io.configure(function () {
+      io.set('heartbeat interval', .05);
+      io.set('heartbeat timeout', .05);
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function (reason) {
+        beat.should.be.true;
+        reason.should.eql('heartbeat timeout');
+
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs, i) {
+        switch (i) {
+          case 1:
+            msgs.should.have.length(1);
+            msgs[0].type.should.eql('connect');
+            msgs[0].endpoint.should.eql('');
+            break;
+
+          case 2:
+            msgs.should.have.length(1);
+            msgs[0].type.should.eql('heartbeat');
+            beat = true;
+        };
+      });
+    });
+  },
+
+  'test that responding to a heartbeat maintains session': function (done) {
+    var port = ++ports
+      , cl = client(port)
+      , io = create(cl)
+      , heartbeats = 0;
+
+    io.configure(function () {
+      io.set('heartbeat interval', .05);
+      io.set('heartbeat timeout', .05);
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function (reason) {
+        heartbeats.should.eql(2);
+        reason.should.eql('heartbeat timeout');
+
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs, i) {
+        switch (i) {
+          case 1:
+            msgs.should.have.length(1);
+            msgs[0].type.should.eql('connect');
+            msgs[0].endpoint.should.eql('');
+            break;
+
+          default:
+            msgs.should.have.length(1);
+            msgs[0].type.should.eql('heartbeat');
+
+            heartbeats++;
+
+            if (heartbeats == 1) {
+              cl.post('/socket.io/{protocol}/htmlfile/' + sid, parser.encodePacket({
+                type: 'heartbeat'
+              }));
+            }
+        }
+      });
+    });
+  },
+
+  'test sending undeliverable volatile messages': function (done) {
+    var port = ++ports
+      , cl = client(port)
+      , io = create(cl)
+      , messaged = false
+      , s;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        messaged.should.be.false;
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.data('/socket.io/{protocol}/htmlfile/' + sid, function () { });
+
+      setTimeout(function () {
+        cl.end();
+
+        setTimeout(function () {
+          s.volatile.send('wooooot');
+          cl = client(port);
+          cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs) {
+            if (msgs && msgs.length)
+              messaged = true;
+          });
+
+          setTimeout(function () {
+            cl.end();
+          }, 20);
+        }, 20);
+      }, 20);
+    });
+  },
+
+  'test sending undeliverable volatile json': function (done) {
+    var port = ++ports
+      , cl = client(port)
+      , io = create(cl)
+      , messaged = false
+      , s;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        messaged.should.be.false;
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.data('/socket.io/{protocol}/htmlfile/' + sid, function () { });
+
+      setTimeout(function () {
+        cl.end();
+
+        setTimeout(function () {
+          s.volatile.json.send(123);
+
+          cl = client(port);
+          cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs) {
+            if (msgs && msgs.length)
+              messaged = true;
+          });
+
+          setTimeout(function () {
+            cl.end();
+          }, 20);
+        }, 20);
+      }, 20);
+    });
+  },
+
+  'test sending undeliverable volatile events': function (done) {
+    var port = ++ports
+      , cl = client(port)
+      , io = create(cl)
+      , messaged = false
+      , s;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        messaged.should.be.false;
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.data('/socket.io/{protocol}/htmlfile/' + sid, function () { });
+
+      setTimeout(function () {
+        cl.end();
+
+        setTimeout(function () {
+          s.volatile.emit('tobi');
+
+          cl = client(port);
+          cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs) {
+            if (msgs && msgs.length)
+              messaged = true;
+          });
+
+          setTimeout(function () {
+            cl.end();
+          }, 20);
+        }, 20);
+      }, 20);
+    });
+  },
+
+  'test sending deliverable volatile messages': function (done) {
+    var port = ++ports
+      , cl = client(port)
+      , io = create(cl)
+      , messaged = false;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.volatile.send('woot');
+
+      socket.on('disconnect', function () {
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs, i) {
+        switch (i) {
+          case 1:
+            msgs.should.have.length(1);
+            msgs[0].type.should.eql('connect');
+            msgs[0].endpoint.should.eql('');
+            break;
+
+          case 2:
+            msgs.should.have.length(1);
+            msgs[0].should.eql({
+                type: 'message'
+              , data: 'woot'
+              , endpoint: ''
+            });
+            cl.end();
+        }
+      });
+    });
+  },
+
+  'test sending deliverable volatile json': function (done) {
+    var port = ++ports
+      , cl = client(port)
+      , io = create(cl)
+      , messaged = false;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.volatile.json.send(['woot']);
+
+      socket.on('disconnect', function () {
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs, i) {
+        switch (i) {
+          case 1:
+            msgs.should.have.length(1);
+            msgs[0].type.should.eql('connect');
+            msgs[0].endpoint.should.eql('');
+            break;
+
+          case 2:
+            msgs.should.have.length(1);
+            msgs[0].should.eql({
+                type: 'json'
+              , data: ['woot']
+              , endpoint: ''
+            });
+            cl.end();
+        }
+      });
+    });
+  },
+
+  'test sending deliverable volatile events': function (done) {
+    var port = ++ports
+      , cl = client(port)
+      , io = create(cl)
+      , messaged = false;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.volatile.emit('aaa');
+
+      socket.on('disconnect', function () {
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs, i) {
+        switch (i) {
+          case 1:
+            msgs.should.have.length(1);
+            msgs[0].type.should.eql('connect');
+            msgs[0].endpoint.should.eql('');
+            break;
+
+          case 2:
+            msgs.should.have.length(1);
+            msgs[0].should.eql({
+                type: 'event'
+              , name: 'aaa'
+              , endpoint: ''
+              , args: []
+            });
+            cl.end();
+        }
+      });
+    });
+  }
+
+};
diff --git a/node/node_modules/socket.io/test/transports.jsonp-polling.test.js b/node/node_modules/socket.io/test/transports.jsonp-polling.test.js
new file mode 100644 (file)
index 0000000..c087d33
--- /dev/null
@@ -0,0 +1,770 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Test dependencies.
+ */
+
+var sio = require('socket.io')
+  , should = require('./common')
+  , qs = require('querystring')
+  , HTTPClient = should.HTTPClient
+  , parser = sio.parser
+  , ports = 15500;
+
+/**
+ * HTTPClient for jsonp-polling transport.
+ */
+
+function JSONPPolling (port) {
+  HTTPClient.call(this, port);
+};
+
+/**
+ * Inhertis from HTTPClient.
+ */
+
+JSONPPolling.prototype.__proto__ = HTTPClient.prototype;
+
+/**
+ * Performs a json-p (cross domain) handshake
+ *
+ * @api public
+ */
+
+JSONPPolling.prototype.handshake = function (opts, fn) {
+  if ('function' == typeof opts) {
+    fn = opts;
+    opts = {};
+  }
+
+  var self = this;
+
+  return this.get(
+      '/socket.io/{protocol}?jsonp=0'
+    , opts
+    , function (res, data) {
+        var head = 'io.j[0]('
+          , foot = ');';
+
+        data.substr(0, head.length).should.eql(head);
+        data.substr(-foot.length).should.eql(foot);
+        data = data.slice(head.length, data.length - foot.length);
+
+        var parts = JSON.parse(data).split(':');
+
+        if (opts.ignoreConnect) {
+          return fn && fn.apply(null, parts);
+        }
+
+        // expect connect packet right after handshake
+        self.get(
+            '/socket.io/{protocol}/jsonp-polling/' + parts[0]
+          , function (res, msgs) {
+              res.statusCode.should.eql(200);
+
+              msgs.should.have.length(1);
+              msgs[0].should.eql({ type: 'connect', endpoint: '', qs: '' });
+
+              fn && fn.apply(null, parts);
+            }
+        );
+      }
+  );
+};
+
+/**
+ * Override GET requests.
+ *
+ * @api public
+ */
+
+JSONPPolling.prototype.get = function (path, opts, fn) {
+  if ('function' == typeof opts) {
+    fn = opts;
+    opts = {};
+  }
+
+  opts = opts || {};
+
+  opts.parse = function (data) {
+    var head = 'io.j[0]('
+      , foot = ');';
+
+    if (~path.indexOf('?i=1')) {
+      head = 'io.j[1](';
+    }
+
+    data.substr(0, head.length).should.eql(head);
+    data.substr(-foot.length).should.eql(foot);
+
+    data = data.substr(head.length, data.length - head.length - foot.length);
+
+    return JSON.parse(data);
+  };
+
+  return HTTPClient.prototype.get.call(this, path, opts, fn);
+};
+
+/**
+ * Issue an encoded POST request
+ *
+ * @api private
+ */
+
+JSONPPolling.prototype.post = function (path, data, opts, fn) {
+  if ('function' == typeof opts) {
+    fn = opts;
+    opts = {};
+  }
+
+  opts = opts || {};
+  opts.method = 'POST';
+  opts.data = qs.stringify({ d: data });
+
+  return this.request(path, opts, fn);
+};
+
+/**
+ * Create client for this transport.
+ *
+ * @api public
+ */
+
+function client (port) {
+  return new JSONPPolling(port);
+};
+
+/**
+ * Test.
+ */
+
+module.exports = {
+
+  'test jsonp handshake': function (done) {
+    var cl = client(++ports)
+      , io = create(cl);
+
+    io.configure(function () {
+      io.set('close timeout', .05);
+      io.set('polling duration', 0);
+    });
+
+    function finish () {
+      cl.end();
+      io.server.close();
+      done();
+    };
+
+    cl.handshake(function (sid) {
+      var total = 2;
+
+      cl.get('/socket.io/{protocol}/jsonp-polling/tobi', function (res, msgs) {
+        res.statusCode.should.eql(200);
+
+        msgs.should.have.length(1);
+        msgs[0].should.eql({
+            type: 'error'
+          , reason: 'client not handshaken'
+          , endpoint: ''
+          , advice: 'reconnect'
+        });
+
+        --total || finish();
+      });
+
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+        --total || finish();
+      });
+    });
+  },
+
+  'test the connection event': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , sid;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.id.should.eql(sid);
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake({ ignoreConnect: true }, function (sessid) {
+      sid = sessid;
+
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].type.should.eql('connect');
+      });
+    });
+  },
+
+  'test the disconnection event after a close timeout': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , sid;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.id.should.eql(sid);
+
+      socket.on('disconnect', function () {
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake({ ignoreConnect: true }, function (sessid) {
+      sid = sessid;
+
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].type.should.eql('connect');
+
+        setTimeout(function () {
+          cl.end();
+        }, 10);
+      });
+    });
+  },
+
+  'test the disconnection event when the client sends ?disconnect req':
+  function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , disconnected = false
+      , sid;
+
+    io.configure(function () {
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function () {
+        disconnected = true;
+      });
+    });
+
+    cl.handshake({ ignoreConnect: true }, function (sessid) {
+      sid = sessid;
+
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].type.should.eql('connect');
+
+        cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
+          msgs.should.have.length(1);
+          msgs[0].should.eql({ type: 'disconnect', endpoint: '' });
+          disconnected.should.be.true;
+          cl.end();
+          io.server.close();
+          done();
+        });
+
+        cl.get('/socket.io/{protocol}/jsonp-polling/' + sid + '/?disconnect');
+      });
+    });
+  },
+
+  'test the disconnection event booting a client': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , forced = false;
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function () {
+        io.server.close();
+        done();
+      });
+
+      cl.end();
+      socket.disconnect();
+      forced = true;
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'disconnect', endpoint: '' });
+
+        forced.should.be.true;
+      });
+    });
+  },
+
+  'test the disconnection event with client disconnect packet': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , sid;
+
+    io.sockets.on('connection', function (client) {
+      cl.post(
+          '/socket.io/{protocol}/jsonp-polling/' + sid
+        , parser.encodePacket({ type: 'disconnect' })
+        , function (res, data) {
+            res.statusCode.should.eql(200);
+            data.should.eql('1');
+          }
+      );
+
+      client.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake({ ignoreConnect: true }, function (sessid) {
+      sid = sessid;
+
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].type.should.eql('connect');
+      });
+    });
+  },
+
+  'test sending back data': function (done) {
+    var cl = client(++ports)
+      , io = create(cl);
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.send('woot');
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, packs) {
+        packs.should.have.length(1);
+        packs[0].type.should.eql('message');
+        packs[0].data.should.eql('woot');
+      });
+    });
+  },
+
+  'test sending a batch of messages': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , sid;
+
+    io.configure(function () {
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      var messages = 0;
+
+      cl.post(
+          '/socket.io/{protocol}/jsonp-polling/' + sid
+        , parser.encodePayload([
+              parser.encodePacket({ type: 'message', data: 'a' })
+            , parser.encodePacket({ type: 'message', data: 'b' })
+            , parser.encodePacket({ type: 'disconnect' })
+          ])
+        , function (res, data) {
+            res.statusCode.should.eql(200);
+            data.should.eql('1');
+          }
+      );
+
+      socket.on('message', function (data) {
+        messages++;
+
+        if (messages == 1)
+          data.should.eql('a');
+
+        if (messages == 2)
+          data.should.eql('b');
+      });
+
+      socket.on('disconnect', function () {
+        messages.should.eql(2);
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake({ ignoreConnect: true }, function (sessid) {
+      sid = sessid;
+
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].type.should.eql('connect');
+      });
+    });
+  },
+
+  'test message buffering between a response and a request': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messages = false
+      , tobi;
+
+    io.configure(function () {
+      io.set('polling duration', .1);
+      io.set('close timeout', .2);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      tobi = function () {
+        socket.send('a');
+        socket.send('b');
+        socket.send('c');
+      };
+
+      socket.on('disconnect', function () {
+        messages.should.be.true;
+
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        tobi();
+
+        cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
+          msgs.should.have.length(3);
+          msgs[0].should.eql({ type: 'message', endpoint: '', data: 'a' });
+          msgs[1].should.eql({ type: 'message', endpoint: '', data: 'b' });
+          msgs[2].should.eql({ type: 'message', endpoint: '', data: 'c' });
+          messages = true;
+        });
+      })
+    });
+  },
+
+  'test connecting to a specific endpoint': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , connectMessage = false
+      , sid;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.of('/woot').on('connection', function (socket) {
+      connectMessage.should.be.true;
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, data) {
+        cl.get('/socket.io/{protocol}/jsonp-polling/' + sid);
+
+        connectMessage = true;
+
+        cl.post(
+            '/socket.io/{protocol}/jsonp-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/woot' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+            }
+        );
+      });
+    });
+  },
+
+  'test that connecting doesnt connect to defined endpoints': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , tobiConnected = false
+      , mainConnected = false
+      , sid;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      mainConnected = true;
+
+      socket.on('disconnect', function () {
+        tobiConnected.should.be.false;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    io.of('/tobi').on('connection', function () {
+      tobiConnected = true;
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid);
+    });
+  },
+
+  'test disconnecting a specific endpoint': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , wootDisconnected = false
+      , mainDisconnected = false
+      , checked = false;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (data) {
+        data.should.eql('ferret');
+        mainDisconnected.should.be.false;
+        wootDisconnected.should.be.true;
+        checked = true;
+      });
+
+      socket.on('disconnect', function () {
+        mainDisconnected = true;
+        checked.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    io.of('/woot').on('connection', function (socket) {
+      socket.on('disconnect', function () {
+        wootDisconnected = true;
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function () {
+        cl.post(
+            '/socket.io/{protocol}/jsonp-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/woot' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.post(
+                  '/socket.io/{protocol}/jsonp-polling/' + sid
+                , parser.encodePacket({ type: 'disconnect', endpoint: '/woot' })
+                , function (res, data) {
+                    res.statusCode.should.eql(200);
+                    data.should.eql('1');
+
+                    cl.post(
+                        '/socket.io/{protocol}/jsonp-polling/' + sid
+                      , parser.encodePacket({ type: 'message', data: 'ferret' })
+                      , function (res, data) {
+                          res.statusCode.should.eql(200);
+                          data.should.eql('1');
+                        }
+                    );
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test that disconnecting disconnects all endpoints': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , aDisconnected = false
+      , bDisconnected = false;
+
+    io.configure(function () {
+      io.set('polling duration', .2);
+      io.set('close timeout', .2);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function () {
+        setTimeout(function () {
+          aDisconnected.should.be.true;
+          bDisconnected.should.be.true;
+          cl.end();
+          io.server.close();
+          done();
+        }, 50);
+      });
+    });
+
+    io.of('/a').on('connection', function (socket) {
+      socket.on('disconnect', function (msg) {
+        aDisconnected = true;
+      });
+    });
+
+    io.of('/b').on('connection', function (socket) {
+      socket.on('disconnect', function (msg) {
+        bDisconnected = true;
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        cl.post(
+            '/socket.io/{protocol}/jsonp-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/a' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+            }
+        );
+
+        cl.post(
+            '/socket.io/{protocol}/jsonp-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/b' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+            }
+        );
+      });
+    });
+  },
+
+  'test messaging a specific endpoint': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = true
+      , aMessaged = false
+      , bMessaged = false;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        msg.should.eql('');
+        messaged = true;
+      });
+
+      socket.on('disconnect', function () {
+        messaged.should.be.true;
+        aMessaged.should.be.true;
+        bMessaged.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    io.of('/a').on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        msg.should.eql('a');
+        aMessaged = true;
+      });
+    });
+
+    io.of('/b').on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        msg.should.eql('b');
+        bMessaged = true;
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/jsonp-polling/' + sid
+          , parser.encodePacket({ type: 'message', data: '' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+            }
+        );
+
+        cl.post(
+            '/socket.io/{protocol}/jsonp-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/a' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.post(
+                  '/socket.io/{protocol}/jsonp-polling/' + sid
+                , parser.encodePacket({ type: 'message', endpoint: '/a', data: 'a' })
+                , function (res, data) {
+                    res.statusCode.should.eql(200);
+                    data.should.eql('1');
+                  }
+              );
+            }
+        );
+
+        cl.post(
+            '/socket.io/{protocol}/jsonp-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/b' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.post(
+                  '/socket.io/{protocol}/jsonp-polling/' + sid
+                , parser.encodePacket({ type: 'message', endpoint: '/b', data: 'b' })
+                , function (res, data) {
+                    res.statusCode.should.eql(200);
+                    data.should.eql('1');
+                  }
+              );
+            }
+        );
+      });
+    });
+  }
+
+};
diff --git a/node/node_modules/socket.io/test/transports.websocket.hybi07-12.parser.test.js b/node/node_modules/socket.io/test/transports.websocket.hybi07-12.parser.test.js
new file mode 100644 (file)
index 0000000..94efaa6
--- /dev/null
@@ -0,0 +1,271 @@
+/**
+ * Test dependencies.
+ */
+
+var assert = require('assert'); 
+var Parser = require('../lib/transports/websocket/hybi-07-12.js').Parser;
+
+/**
+ * Returns a Buffer from a "ff 00 ff"-type hex string.
+ */
+
+function makeBufferFromHexString(byteStr) {
+  var bytes = byteStr.split(' ');
+  var buf = new Buffer(bytes.length);
+  for (var i = 0; i < bytes.length; ++i) {
+    buf[i] = parseInt(bytes[i], 16);
+  }
+  return buf;
+}
+
+/**
+ * Splits a buffer in two parts.
+ */
+
+function splitBuffer(buffer) {
+  var b1 = new Buffer(Math.ceil(buffer.length / 2));
+  buffer.copy(b1, 0, 0, b1.length);
+  var b2 = new Buffer(Math.floor(buffer.length / 2));
+  buffer.copy(b2, 0, b1.length, b1.length + b2.length);
+  return [b1, b2];
+}
+
+/**
+ * Performs hybi07+ type masking on a hex string.
+ */
+
+function mask(str, maskString) {
+  var buf = new Buffer(str);
+  var mask = makeBufferFromHexString(maskString || '34 83 a8 68');
+  for (var i = 0; i < buf.length; ++i) {
+    buf[i] ^= mask[i % 4];    
+  }
+  return buf;
+}
+
+/**
+ * Unpacks a Buffer into a number.
+ */
+
+function unpack(buffer) {
+  var n = 0;
+  for (var i = 0; i < buffer.length; ++i) {
+    n = (i == 0) ? buffer[i] : (n * 256) + buffer[i];
+  }
+  return n;
+}
+
+/**
+ * Returns a hex string, representing a specific byte count 'length', from a number.
+ */
+
+function pack(length, number) {
+  return padl(number.toString(16), length, '0').replace(/(\d\d)/g, '$1 ').trim();
+}
+
+/**
+ * Left pads the string 's' to a total length of 'n' with char 'c'.
+ */
+
+function padl(s, n, c) { 
+  return new Array(1 + n - s.length).join(c) + s;
+}
+
+/**
+ * Returns a hex string from a Buffer.
+ */
+
+function dump(data) {
+  var s = '';
+  for (var i = 0; i < data.length; ++i) {
+    s += padl(data[i].toString(16), 2, '0') + ' ';
+  }
+  return s.trim();
+}
+
+/**
+ * Tests.
+ */
+
+module.exports = {
+  'can parse unmasked text message': function() {
+    var p = new Parser();
+    var packet = '81 05 48 65 6c 6c 6f';
+  
+    var gotData = false;
+    p.on('data', function(data) {
+      gotData = true;
+      assert.equal('Hello', data);
+    });
+  
+    p.add(makeBufferFromHexString(packet));
+    assert.ok(gotData);
+  },
+  'can parse close message': function() {
+    var p = new Parser();
+    var packet = '88 00';
+  
+    var gotClose = false;
+    p.on('close', function(data) {
+      gotClose = true;
+    });
+  
+    p.add(makeBufferFromHexString(packet));
+    assert.ok(gotClose);
+  },
+  'can parse masked text message': function() {
+    var p = new Parser();
+    var packet = '81 93 34 83 a8 68 01 b9 92 52 4f a1 c6 09 59 e6 8a 52 16 e6 cb 00 5b a1 d5';
+  
+    var gotData = false;
+    p.on('data', function(data) {
+      gotData = true;
+      assert.equal('5:::{"name":"echo"}', data);
+    });
+  
+    p.add(makeBufferFromHexString(packet));
+    assert.ok(gotData);
+  },
+  'can parse a masked text message longer than 125 bytes': function() {
+    var p = new Parser();
+    var message = 'A';
+    for (var i = 0; i < 300; ++i) message += (i % 5).toString();
+    var packet = '81 FE ' + pack(4, message.length) + ' 34 83 a8 68 ' + dump(mask(message, '34 83 a8 68'));
+    
+    var gotData = false;
+    p.on('data', function(data) {
+      gotData = true;
+      assert.equal(message, data);
+    });
+  
+    p.add(makeBufferFromHexString(packet));
+    assert.ok(gotData);
+  },
+  'can parse a really long masked text message': function() {
+    var p = new Parser();
+    var message = 'A';
+    for (var i = 0; i < 64*1024; ++i) message += (i % 5).toString();
+    var packet = '81 FF ' + pack(16, message.length) + ' 34 83 a8 68 ' + dump(mask(message, '34 83 a8 68'));
+
+    var gotData = false;
+    p.on('data', function(data) {
+      gotData = true;
+      assert.equal(message, data);
+    });
+  
+    p.add(makeBufferFromHexString(packet));
+    assert.ok(gotData);
+  },
+  'can parse a fragmented masked text message of 300 bytes': function() {
+    var p = new Parser();
+    var message = 'A';
+    for (var i = 0; i < 300; ++i) message += (i % 5).toString();
+    var msgpiece1 = message.substr(0, 150);
+    var msgpiece2 = message.substr(150);
+    var packet1 = '01 FE ' + pack(4, msgpiece1.length) + ' 34 83 a8 68 ' + dump(mask(msgpiece1, '34 83 a8 68'));
+    var packet2 = '81 FE ' + pack(4, msgpiece2.length) + ' 34 83 a8 68 ' + dump(mask(msgpiece2, '34 83 a8 68'));
+  
+    var gotData = false;
+    p.on('data', function(data) {
+      gotData = true;      
+      assert.equal(message, data);
+    });
+  
+    p.add(makeBufferFromHexString(packet1));
+    p.add(makeBufferFromHexString(packet2));
+    assert.ok(gotData);
+  },
+  'can parse a ping message': function() {
+    var p = new Parser();
+    var message = 'Hello';
+    var packet = '89 FE ' + pack(4, message.length) + ' 34 83 a8 68 ' + dump(mask(message, '34 83 a8 68'));
+    
+    var gotPing = false;
+    p.on('ping', function(data) {
+      gotPing = true;
+      assert.equal(message, data);
+    });
+    
+    p.add(makeBufferFromHexString(packet));
+    assert.ok(gotPing);
+  },
+  'can parse a ping with no data': function() {
+    var p = new Parser();
+    var packet = '89 00';
+    
+    var gotPing = false;
+    p.on('ping', function(data) {
+      gotPing = true;
+    });
+    
+    p.add(makeBufferFromHexString(packet));
+    assert.ok(gotPing);
+  },
+  'can parse a fragmented masked text message of 300 bytes with a ping in the middle': function() {
+    var p = new Parser();
+    var message = 'A';
+    for (var i = 0; i < 300; ++i) message += (i % 5).toString();
+  
+    var msgpiece1 = message.substr(0, 150);
+    var packet1 = '01 FE ' + pack(4, msgpiece1.length) + ' 34 83 a8 68 ' + dump(mask(msgpiece1, '34 83 a8 68'));
+  
+    var pingMessage = 'Hello';
+    var pingPacket = '89 FE ' + pack(4, pingMessage.length) + ' 34 83 a8 68 ' + dump(mask(pingMessage, '34 83 a8 68'));
+  
+    var msgpiece2 = message.substr(150);
+    var packet2 = '81 FE ' + pack(4, msgpiece2.length) + ' 34 83 a8 68 ' + dump(mask(msgpiece2, '34 83 a8 68'));
+  
+    var gotData = false;
+    p.on('data', function(data) {
+      gotData = true;
+      assert.equal(message, data);
+    });
+    var gotPing = false;
+    p.on('ping', function(data) {
+      gotPing = true;
+      assert.equal(pingMessage, data);
+    });
+    
+    p.add(makeBufferFromHexString(packet1));
+    p.add(makeBufferFromHexString(pingPacket));
+    p.add(makeBufferFromHexString(packet2));
+    assert.ok(gotData);
+    assert.ok(gotPing);
+  },
+  'can parse a fragmented masked text message of 300 bytes with a ping in the middle, which is delievered over sevaral tcp packets': function() {
+    var p = new Parser();
+    var message = 'A';
+    for (var i = 0; i < 300; ++i) message += (i % 5).toString();
+  
+    var msgpiece1 = message.substr(0, 150);
+    var packet1 = '01 FE ' + pack(4, msgpiece1.length) + ' 34 83 a8 68 ' + dump(mask(msgpiece1, '34 83 a8 68'));
+  
+    var pingMessage = 'Hello';
+    var pingPacket = '89 FE ' + pack(4, pingMessage.length) + ' 34 83 a8 68 ' + dump(mask(pingMessage, '34 83 a8 68'));
+  
+    var msgpiece2 = message.substr(150);
+    var packet2 = '81 FE ' + pack(4, msgpiece2.length) + ' 34 83 a8 68 ' + dump(mask(msgpiece2, '34 83 a8 68'));
+  
+    var gotData = false;
+    p.on('data', function(data) {
+      gotData = true;
+      assert.equal(message, data);
+    });
+    var gotPing = false;
+    p.on('ping', function(data) {
+      gotPing = true;
+      assert.equal(pingMessage, data);
+    });
+    
+    var buffers = [];
+    buffers = buffers.concat(splitBuffer(makeBufferFromHexString(packet1)));
+    buffers = buffers.concat(splitBuffer(makeBufferFromHexString(pingPacket)));
+    buffers = buffers.concat(splitBuffer(makeBufferFromHexString(packet2)));
+    for (var i = 0; i < buffers.length; ++i) {
+      p.add(buffers[i]);
+    }
+    assert.ok(gotData);
+    assert.ok(gotPing);
+  },
+};
+
diff --git a/node/node_modules/socket.io/test/transports.websocket.test.js b/node/node_modules/socket.io/test/transports.websocket.test.js
new file mode 100644 (file)
index 0000000..4b9ff61
--- /dev/null
@@ -0,0 +1,1771 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Test dependencies.
+ */
+
+var sio = require('socket.io')
+  , should = require('./common')
+  , parser = sio.parser
+  , ports = 15800;
+
+/**
+ * Tests.
+ */
+
+module.exports = {
+
+  'test that not responding to a heartbeat drops client': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messages = 0
+      , ws;
+
+    io.configure(function () {
+      io.set('heartbeat interval', .05);
+      io.set('heartbeat timeout', .05);
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function (reason) {
+        beat.should.be.true;
+        reason.should.eql('heartbeat timeout');
+
+        cl.end();
+        ws.finishClose();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      ws = websocket(cl, sid);
+      ws.on('message', function (packet) {
+        if (++messages == 1) {
+          packet.type.should.eql('connect');
+        } else {
+          packet.type.should.eql('heartbeat');
+          beat = true;
+        }
+      });
+    });
+  },
+
+  'test that responding to a heartbeat maintains session': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messages = 0
+      , heartbeats = 0
+      , ws;
+
+    io.configure(function () {
+      io.set('heartbeat interval', .05);
+      io.set('heartbeat timeout', .05);
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function (reason) {
+        heartbeats.should.eql(2);
+        reason.should.eql('heartbeat timeout');
+
+        cl.end();
+        ws.finishClose();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      ws = websocket(cl, sid);
+      ws.on('message', function (packet) {
+        if (++messages == 1) {
+          packet.type.should.eql('connect');
+        } else {
+          packet.type.should.eql('heartbeat');
+          heartbeats++;
+
+          if (heartbeats == 1) {
+            ws.packet({ type: 'heartbeat' });
+          }
+        }
+      });
+    });
+  },
+
+  'test sending undeliverable volatile messages': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messages = 0
+      , messaged = false
+      , s;
+
+    io.configure(function () {
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        messaged.should.be.false;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      var ws = websocket(cl, sid);
+      ws.on('message', function (msg) {
+        msg.type.should.eql('connect');
+        ws.finishClose();
+
+        setTimeout(function () {
+          s.volatile.send('ah wha wha');
+
+          ws = websocket(cl, sid);
+          ws.on('message', function () {
+            messaged = true;
+          });
+
+          setTimeout(function () {
+            ws.finishClose();
+          }, 10);
+        }, 10);
+      });
+    });
+  },
+
+  'test sending undeliverable volatile json': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = false
+      , s;
+
+    io.configure(function () {
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        messaged.should.be.false;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      var ws = websocket(cl, sid);
+      ws.on('message', function () {
+        ws.finishClose();
+
+        setTimeout(function () {
+          s.volatile.json.send({ a: 'b' });
+
+          ws = websocket(cl, sid);
+          ws.on('message', function () {
+            messaged = true;
+          });
+
+          setTimeout(function () {
+            ws.finishClose();
+          }, 10);
+        }, 10);
+      });
+    });
+  },
+
+  'test sending undeliverable volatile events': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = false
+      , s;
+
+    io.configure(function () {
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        messaged.should.be.false;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      var ws = websocket(cl, sid);
+      ws.on('message', function () {
+        ws.finishClose();
+
+        setTimeout(function () {
+          s.volatile.emit({ a: 'b' });
+
+          ws = websocket(cl, sid);
+          ws.on('message', function () {
+            messaged = true;
+          });
+
+          setTimeout(function () {
+            ws.finishClose();
+          }, 10);
+        }, 10);
+      });
+    });
+  },
+
+  'test sending deliverable volatile messages': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messages = 0
+      , messaged = false;
+
+    io.configure(function () {
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.volatile.send('tobi');
+
+      socket.on('disconnect', function () {
+        messaged.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      var ws = websocket(cl, sid);
+      ws.on('message', function (msg) {
+        if (++messages == 1) {
+          msg.type.should.eql('connect');
+        } else {
+          msg.should.eql({
+              type: 'message'
+            , data: 'tobi'
+            , endpoint: ''
+          });
+          messaged = true;
+          ws.finishClose();
+        }
+      });
+    });
+  },
+
+  'test sending deliverable volatile json': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = false;
+
+    io.configure(function () {
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.volatile.json.send([1, 2, 3]);
+
+      socket.on('disconnect', function () {
+        messaged.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      var ws = websocket(cl, sid);
+      ws.on('message', function (msg) {
+        if (!ws.connected) {
+          msg.type.should.eql('connect');
+          ws.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'json'
+            , data: [1, 2, 3]
+            , endpoint: ''
+          });
+          messaged = true;
+          ws.finishClose();
+        }
+      });
+    });
+  },
+
+  'test sending deliverable volatile events': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = false;
+
+    io.configure(function () {
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.volatile.emit('tobi');
+
+      socket.on('disconnect', function () {
+        messaged.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      var ws = websocket(cl, sid);
+      ws.on('message', function (msg) {
+        if (!ws.connected) {
+          msg.type.should.eql('connect');
+          ws.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'event'
+            , name: 'tobi'
+            , endpoint: ''
+            , args: []
+          });
+          messaged = true;
+          ws.finishClose();
+        }
+      });
+    });
+  },
+
+  'test sending to all clients in a namespace': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , io = create(cl1)
+      , messages = 0
+      , connections = 0
+      , disconnections = 0;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      connections++;
+
+      if (connections == 2) {
+        io.sockets.send('yup');
+      }
+
+      socket.on('disconnect', function () {
+        disconnections++;
+
+        if (disconnections == 2) {
+          messages.should.eql(2);
+          cl1.end();
+          cl2.end();
+          io.server.close();
+          done();
+        }
+      });
+    });
+
+    cl1.handshake(function (sid) {
+      var ws1 = websocket(cl1, sid);
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'message'
+            , data: 'yup'
+            , endpoint: ''
+          });
+
+          messages++;
+          ws1.finishClose();
+        }
+      });
+    });
+
+    cl2.handshake(function (sid) {
+      var ws2 = websocket(cl2, sid);
+      ws2.on('message', function (msg) {
+        if (!ws2.connected) {
+          msg.type.should.eql('connect');
+          ws2.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'message'
+            , data: 'yup'
+            , endpoint: ''
+          });
+
+          messages++;
+          ws2.finishClose();
+        }
+      });
+    });
+  },
+
+  'test sending json to all clients in a namespace': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , io = create(cl1)
+      , messages = 0
+      , connections = 0
+      , disconnections = 0;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      connections++;
+
+      if (connections == 2) {
+        io.sockets.json.send({ a: 'b' });
+      }
+
+      socket.on('disconnect', function () {
+        disconnections++;
+
+        if (disconnections == 2) {
+          messages.should.eql(2);
+          cl1.end();
+          cl2.end();
+          io.server.close();
+          done();
+        }
+      });
+    });
+
+    cl1.handshake(function (sid) {
+      var ws1 = websocket(cl1, sid);
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'json'
+            , data: { a: 'b' }
+            , endpoint: ''
+          });
+
+          messages++;
+          ws1.finishClose();
+        }
+      });
+    });
+
+    cl2.handshake(function (sid) {
+      var ws2 = websocket(cl2, sid);
+      ws2.on('message', function (msg) {
+        if (!ws2.connected) {
+          msg.type.should.eql('connect');
+          ws2.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'json'
+            , data: { a: 'b' }
+            , endpoint: ''
+          });
+
+          messages++;
+          ws2.finishClose();
+        }
+      });
+    });
+  },
+
+  'test emitting to all clients in a namespace': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , io = create(cl1)
+      , messages = 0
+      , connections = 0
+      , disconnections = 0;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      connections++;
+
+      if (connections == 2) {
+        io.sockets.emit('tobi', 'rapture');
+      }
+
+      socket.on('disconnect', function () {
+        disconnections++;
+
+        if (disconnections == 2) {
+          messages.should.eql(2);
+          cl1.end();
+          cl2.end();
+          io.server.close();
+          done();
+        }
+      });
+    });
+
+    cl1.handshake(function (sid) {
+      var ws1 = websocket(cl1, sid);
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'event'
+            , name: 'tobi'
+            , args: ['rapture']
+            , endpoint: ''
+          });
+
+          messages++;
+          ws1.finishClose();
+        }
+      });
+    });
+
+    cl2.handshake(function (sid) {
+      var ws2 = websocket(cl2, sid);
+      ws2.on('message', function (msg) {
+        if (!ws2.connected) {
+          msg.type.should.eql('connect');
+          ws2.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'event'
+            , name: 'tobi'
+            , args: ['rapture']
+            , endpoint: ''
+          });
+
+          messages++;
+          ws2.finishClose();
+        }
+      });
+    });
+  },
+
+  'test sending to all clients in a room': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , cl3 = client(port)
+      , io = create(cl1)
+      , messages = 0
+      , joins = 0
+      , connections = 0
+      , disconnections = 0;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      connections++;
+
+      if (connections != 3) {
+        socket.join('woot');
+        joins++;
+
+        if (joins == 2) {
+          setTimeout(function () {
+            connections.should.eql(3);
+            io.sockets.in('woot').send('hahaha');
+          }, 20);
+        }
+      }
+
+      socket.on('disconnect', function () {
+        disconnections++;
+
+        if (disconnections == 3) {
+          messages.should.eql(2);
+          cl1.end();
+          cl2.end();
+          cl3.end();
+          io.server.close();
+          done();
+        }
+      });
+    });
+
+    cl1.handshake(function (sid) {
+      var ws1 = websocket(cl1, sid);
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'message'
+            , data: 'hahaha'
+            , endpoint: ''
+          });
+
+          messages++;
+        }
+      });
+
+      setTimeout(function () {
+        ws1.finishClose();
+      }, 50);
+    });
+
+    cl2.handshake(function (sid) {
+      var ws2 = websocket(cl2, sid);
+      ws2.on('message', function (msg) {
+        if (!ws2.connected) {
+          msg.type.should.eql('connect');
+          ws2.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'message'
+            , data: 'hahaha'
+            , endpoint: ''
+          });
+
+          messages++;
+        }
+      });
+
+      setTimeout(function () {
+        ws2.finishClose();
+      }, 50);
+    });
+
+    cl3.handshake(function (sid) {
+      var ws3 = websocket(cl3, sid);
+      ws3.on('message', function (msg) {
+        if (!ws3.connected) {
+          msg.type.should.eql('connect');
+          ws3.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'message'
+            , data: 'hahaha'
+            , endpoint: ''
+          });
+
+          messages++;
+        }
+      });
+
+      setTimeout(function () {
+        ws3.finishClose();
+      }, 50);
+    });
+  },
+
+  'test sending json to all clients in a room': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , cl3 = client(port)
+      , io = create(cl1)
+      , messages = 0
+      , joins = 0
+      , connections = 0
+      , disconnections = 0;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      connections++;
+
+      if (connections != 3) {
+        socket.join('woot');
+        joins++;
+
+        if (joins == 2) {
+          setTimeout(function () {
+            connections.should.eql(3);
+            io.sockets.in('woot').json.send(123);
+          }, 20);
+        }
+      }
+
+      socket.on('disconnect', function () {
+        disconnections++;
+
+        if (disconnections == 3) {
+          messages.should.eql(2);
+          cl1.end();
+          cl2.end();
+          cl3.end();
+          io.server.close();
+          done();
+        }
+      });
+    });
+
+    cl1.handshake(function (sid) {
+      var ws1 = websocket(cl1, sid);
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'json'
+            , data: 123
+            , endpoint: ''
+          });
+
+          messages++;
+        }
+      });
+
+      setTimeout(function () {
+        ws1.finishClose();
+      }, 50);
+    });
+
+    cl2.handshake(function (sid) {
+      var ws2 = websocket(cl2, sid);
+      ws2.on('message', function (msg) {
+        if (!ws2.connected) {
+          msg.type.should.eql('connect');
+          ws2.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'json'
+            , data: 123
+            , endpoint: ''
+          });
+
+          messages++;
+        }
+      });
+
+      setTimeout(function () {
+        ws2.finishClose();
+      }, 50);
+    });
+
+    cl3.handshake(function (sid) {
+      var ws3 = websocket(cl3, sid);
+      ws3.on('message', function (msg) {
+        if (!ws3.connected) {
+          msg.type.should.eql('connect');
+          ws3.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'json'
+            , data: 123
+            , endpoint: ''
+          });
+
+          messages++;
+        }
+      });
+
+      setTimeout(function () {
+        ws3.finishClose();
+      }, 50);
+    });
+  },
+
+  'test emitting to all clients in a room': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , cl3 = client(port)
+      , io = create(cl1)
+      , messages = 0
+      , joins = 0
+      , connections = 0
+      , disconnections = 0;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      connections++;
+
+      if (connections != 3) {
+        socket.join('woot');
+        joins++;
+
+        if (joins == 2) {
+          setTimeout(function () {
+            connections.should.eql(3);
+            io.sockets.in('woot').emit('locki');
+          }, 20);
+        }
+      }
+
+      socket.on('disconnect', function () {
+        disconnections++;
+
+        if (disconnections == 3) {
+          messages.should.eql(2);
+          cl1.end();
+          cl2.end();
+          cl3.end();
+          io.server.close();
+          done();
+        }
+      });
+    });
+
+    cl1.handshake(function (sid) {
+      var ws1 = websocket(cl1, sid);
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'event'
+            , name: 'locki'
+            , args: []
+            , endpoint: ''
+          });
+
+          messages++;
+        }
+      });
+
+      setTimeout(function () {
+        ws1.finishClose();
+      }, 50);
+    });
+
+    cl2.handshake(function (sid) {
+      var ws2 = websocket(cl2, sid);
+      ws2.on('message', function (msg) {
+        if (!ws2.connected) {
+          msg.type.should.eql('connect');
+          ws2.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'event'
+            , name: 'locki'
+            , args: []
+            , endpoint: ''
+          });
+
+          messages++;
+        }
+      });
+
+      setTimeout(function () {
+        ws2.finishClose();
+      }, 50);
+    });
+
+    cl3.handshake(function (sid) {
+      var ws3 = websocket(cl3, sid);
+      ws3.on('message', function (msg) {
+        if (!ws3.connected) {
+          msg.type.should.eql('connect');
+          ws3.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'event'
+            , name: 'locki'
+            , args: []
+            , endpoint: ''
+          });
+
+          messages++;
+        }
+      });
+
+      setTimeout(function () {
+        ws3.finishClose();
+      }, 50);
+    });
+  },
+
+  'test leaving a room': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , io = create(cl1)
+      , joins = 0
+      , disconnects = 0;
+
+    io.set('close timeout', 0);
+
+    io.sockets.on('connection', function (socket) {
+      socket.join('foo');
+      io.sockets.clients('foo').should.have.length(++joins);
+
+      socket.on('disconnect', function () {
+        socket.leave('foo');
+        socket.leave('foo');
+        socket.leave('foo');
+
+        io.sockets.clients('foo').should.have.length(--joins);
+
+        if (++disconnects == 2) {
+          io.server.close();
+          cl1.end();
+          cl2.end();
+          done();
+        }
+      })
+    });
+
+    cl1.handshake(function (sid) {
+      var ws1 = websocket(cl1, sid);
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+           ws1.finishClose();
+        }
+      });
+    });
+
+    cl2.handshake(function (sid) {
+      var ws2 = websocket(cl2, sid);
+      ws2.on('message', function (msg) {
+        if (!ws2.connected) {
+          msg.type.should.eql('connect');
+          ws2.connected = true;
+          ws2.finishClose();
+        }
+      });
+    });
+  },
+
+  'test message with broadcast flag': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , cl3 = client(port)
+      , io = create(cl1)
+      , messages = 0
+      , disconnections = 0;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('trigger broadcast', function () {
+        socket.broadcast.send('boom');
+      });
+
+      socket.on('disconnect', function () {
+        disconnections++;
+
+        if (disconnections == 3) {
+          messages.should.eql(2);
+          cl1.end();
+          cl2.end();
+          cl3.end();
+          io.server.close();
+          done();
+        }
+      });
+    });
+
+    cl1.handshake(function (sid) {
+      var ws1 = websocket(cl1, sid);
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'message'
+            , data: 'boom'
+            , endpoint: ''
+          });
+
+          messages++;
+          ws1.finishClose();
+        }
+      });
+    });
+
+    cl2.handshake(function (sid) {
+      var ws2 = websocket(cl2, sid);
+      ws2.on('message', function (msg) {
+        if (!ws2.connected) {
+          msg.type.should.eql('connect');
+          ws2.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'message'
+            , data: 'boom'
+            , endpoint: ''
+          });
+
+          messages++;
+          ws2.finishClose();
+        }
+      });
+    });
+
+    cl3.handshake(function (sid) {
+      var ws3 = websocket(cl3, sid);
+      ws3.on('open', function () {
+        ws3.packet({
+            type: 'event'
+          , name: 'trigger broadcast'
+          , endpoint: ''
+        });
+
+        setTimeout(function () {
+          ws3.finishClose();
+        }, 50);
+      });
+
+      ws3.on('message', function (msg) {
+        if (!ws3.connected) {
+          msg.type.should.eql('connect');
+          ws3.connected = true;
+        } else {
+          throw new Error('we shouldnt get a message here');
+        }
+      });
+    });
+  },
+
+  'test json with broadcast flag': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , cl3 = client(port)
+      , io = create(cl1)
+      , messages = 0
+      , disconnections = 0;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('trigger broadcast', function () {
+        socket.broadcast.json.send([1, 2, 3]);
+      });
+
+      socket.on('disconnect', function () {
+        disconnections++;
+
+        if (disconnections == 3) {
+          messages.should.eql(2);
+          cl1.end();
+          cl2.end();
+          cl3.end();
+          io.server.close();
+          done();
+        }
+      });
+    });
+
+    cl1.handshake(function (sid) {
+      var ws1 = websocket(cl1, sid);
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'json'
+            , data: [1, 2, 3]
+            , endpoint: ''
+          });
+
+          messages++;
+          ws1.finishClose();
+        }
+      });
+    });
+
+    cl2.handshake(function (sid) {
+      var ws2 = websocket(cl2, sid);
+      ws2.on('message', function (msg) {
+        if (!ws2.connected) {
+          msg.type.should.eql('connect');
+          ws2.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'json'
+            , data: [1, 2, 3]
+            , endpoint: ''
+          });
+
+          messages++;
+          ws2.finishClose();
+        }
+      });
+    });
+
+    cl3.handshake(function (sid) {
+      var ws3 = websocket(cl3, sid);
+      ws3.on('open', function () {
+        ws3.packet({
+            type: 'event'
+          , name: 'trigger broadcast'
+          , endpoint: ''
+        });
+
+        setTimeout(function () {
+          ws3.finishClose();
+        }, 50);
+      });
+
+      ws3.on('message', function (msg) {
+        if (!ws3.connected) {
+          msg.type.should.eql('connect');
+          ws3.connected = true;
+        } else {
+          throw new Error('we shouldnt get a message here');
+        }
+      });
+    });
+  },
+
+  'test event with broadcast flag': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , cl3 = client(port)
+      , io = create(cl1)
+      , messages = 0
+      , disconnections = 0;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('trigger broadcast', function () {
+        socket.broadcast.emit('hey', 'arnold');
+      });
+
+      socket.on('disconnect', function () {
+        disconnections++;
+
+        if (disconnections == 3) {
+          messages.should.eql(2);
+          cl1.end();
+          cl2.end();
+          cl3.end();
+          io.server.close();
+          done();
+        }
+      });
+    });
+
+    cl1.handshake(function (sid) {
+      var ws1 = websocket(cl1, sid);
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'event'
+            , name: 'hey'
+            , args: ['arnold']
+            , endpoint: ''
+          });
+
+          messages++;
+          ws1.finishClose();
+        }
+      });
+    });
+
+    cl2.handshake(function (sid) {
+      var ws2 = websocket(cl2, sid);
+      ws2.on('message', function (msg) {
+        if (!ws2.connected) {
+          msg.type.should.eql('connect');
+          ws2.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'event'
+            , name: 'hey'
+            , args: ['arnold']
+            , endpoint: ''
+          });
+
+          messages++;
+          ws2.finishClose();
+        }
+      });
+    });
+
+    cl3.handshake(function (sid) {
+      var ws3 = websocket(cl3, sid);
+      ws3.on('open', function () {
+        ws3.packet({
+            type: 'event'
+          , name: 'trigger broadcast'
+          , endpoint: ''
+        });
+
+        setTimeout(function () {
+          ws3.finishClose();
+        }, 50);
+      });
+
+      ws3.on('message', function (msg) {
+        if (!ws3.connected) {
+          msg.type.should.eql('connect');
+          ws3.connected = true;
+        } else {
+          throw new Error('we shouldnt get a message here');
+        }
+      });
+    });
+  },
+
+  'test message with broadcast flag and to()': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , cl3 = client(port)
+      , io = create(cl1)
+      , messages = 0
+      , connections = 0
+      , disconnections = 0;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      connections++;
+
+      if (connections == 1) {
+        socket.join('losers');
+      }
+
+      socket.on('trigger broadcast', function () {
+        socket.broadcast.to('losers').send('boom');
+      });
+
+      socket.on('disconnect', function () {
+        disconnections++;
+
+        if (disconnections == 3) {
+          messages.should.eql(1);
+          cl1.end();
+          cl2.end();
+          cl3.end();
+          io.server.close();
+          done();
+        }
+      });
+    });
+
+    cl1.handshake(function (sid) {
+      var ws1 = websocket(cl1, sid);
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'message'
+            , data: 'boom'
+            , endpoint: ''
+          });
+
+          messages++;
+        }
+      });
+
+      ws1.on('open', function () {
+        cl2.handshake(function (sid) {
+          var ws2 = websocket(cl2, sid);
+          ws2.on('message', function (msg) {
+            if (!ws2.connected) {
+              msg.type.should.eql('connect');
+              ws2.connected = true;
+            } else {
+              throw new Error('This socket shouldnt get a message');
+            }
+          });
+
+          ws2.on('open', function () {
+            cl3.handshake(function (sid) {
+              var ws3 = websocket(cl3, sid);
+              ws3.on('open', function () {
+                ws3.packet({
+                    type: 'event'
+                  , name: 'trigger broadcast'
+                  , endpoint: ''
+                });
+
+                setTimeout(function () {
+                  ws1.finishClose();
+                  ws2.finishClose();
+                  ws3.finishClose();
+                }, 50);
+              });
+
+              ws3.on('message', function (msg) {
+                if (!ws3.connected) {
+                  msg.type.should.eql('connect');
+                  ws3.connected = true;
+                } else {
+                  throw new Error('we shouldnt get a message here');
+                }
+              });
+            });
+          });
+        });
+      });
+    });
+  },
+
+  'test json with broadcast flag and to()': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , cl3 = client(port)
+      , io = create(cl1)
+      , messages = 0
+      , connections = 0
+      , disconnections = 0;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      connections++;
+
+      if (connections == 1) {
+        socket.join('losers');
+      }
+
+      socket.on('trigger broadcast', function () {
+        socket.broadcast.json.to('losers').send({ hello: 'world' });
+      });
+
+      socket.on('disconnect', function () {
+        disconnections++;
+
+        if (disconnections == 3) {
+          messages.should.eql(1);
+          cl1.end();
+          cl2.end();
+          cl3.end();
+          io.server.close();
+          done();
+        }
+      });
+    });
+
+    cl1.handshake(function (sid) {
+      var ws1 = websocket(cl1, sid);
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'json'
+            , data: { hello: 'world' }
+            , endpoint: ''
+          });
+
+          messages++;
+        }
+      });
+
+      ws1.on('open', function () {
+        cl2.handshake(function (sid) {
+          var ws2 = websocket(cl2, sid);
+          ws2.on('message', function (msg) {
+            if (!ws2.connected) {
+              msg.type.should.eql('connect');
+              ws2.connected = true;
+            } else {
+              throw new Error('This socket shouldnt get a message');
+            }
+          });
+
+          ws2.on('open', function () {
+            cl3.handshake(function (sid) {
+              var ws3 = websocket(cl3, sid);
+              ws3.on('open', function () {
+                ws3.packet({
+                    type: 'event'
+                  , name: 'trigger broadcast'
+                  , endpoint: ''
+                });
+
+                setTimeout(function () {
+                  ws1.finishClose();
+                  ws2.finishClose();
+                  ws3.finishClose();
+                }, 50);
+              });
+
+              ws3.on('message', function (msg) {
+                if (!ws3.connected) {
+                  msg.type.should.eql('connect');
+                  ws3.connected = true;
+                } else {
+                  throw new Error('we shouldnt get a message here');
+                }
+              });
+            });
+          });
+        });
+      });
+    });
+  },
+
+  'test event with broadcast flag and to()': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , cl3 = client(port)
+      , io = create(cl1)
+      , messages = 0
+      , connections = 0
+      , disconnections = 0;
+
+    io.configure(function () {
+      io.set('close timeout', 0);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      connections++;
+
+      if (connections == 1) {
+        socket.join('losers');
+      }
+
+      socket.on('trigger broadcast', function () {
+        socket.broadcast.to('losers').emit('victory');
+      });
+
+      socket.on('disconnect', function () {
+        disconnections++;
+
+        if (disconnections == 3) {
+          messages.should.eql(1);
+          cl1.end();
+          cl2.end();
+          cl3.end();
+          io.server.close();
+          done();
+        }
+      });
+    });
+
+    cl1.handshake(function (sid) {
+      var ws1 = websocket(cl1, sid);
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+        } else {
+          msg.should.eql({
+              type: 'event'
+            , name: 'victory'
+            , args: []
+            , endpoint: ''
+          });
+
+          messages++;
+        }
+      });
+
+      ws1.on('open', function () {
+        cl2.handshake(function (sid) {
+          var ws2 = websocket(cl2, sid);
+          ws2.on('message', function (msg) {
+            if (!ws2.connected) {
+              msg.type.should.eql('connect');
+              ws2.connected = true;
+            } else {
+              throw new Error('This socket shouldnt get a message');
+            };
+          });
+
+          ws2.on('open', function () {
+            cl3.handshake(function (sid) {
+              var ws3 = websocket(cl3, sid);
+              ws3.on('open', function () {
+                ws3.packet({
+                    type: 'event'
+                  , name: 'trigger broadcast'
+                  , endpoint: ''
+                });
+
+                setTimeout(function () {
+                  ws1.finishClose();
+                  ws2.finishClose();
+                  ws3.finishClose();
+                }, 50);
+              });
+
+              ws3.on('message', function (msg) {
+                if (!ws3.connected) {
+                  msg.type.should.eql('connect');
+                  ws3.connected = true;
+                } else {
+                  throw new Error('we shouldnt get a message here');
+                }
+              });
+            });
+          });
+        });
+      });
+    });
+  },
+
+  'test accessing handshake data from sockets': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , ws;
+
+    io.sockets.on('connection', function (socket) {
+      (!!socket.handshake.address.address).should.be.true;
+      (!!socket.handshake.address.port).should.be.true;
+      socket.handshake.headers.host.should.equal('localhost');
+      socket.handshake.headers.connection.should.equal('keep-alive');
+      socket.handshake.time.should.match(/GMT/);
+
+      socket.on('disconnect', function () {
+        setTimeout(function () {
+          ws.finishClose();
+          cl.end();
+          io.server.close();
+          done();
+        }, 10);
+      });
+
+      socket.disconnect();
+    });
+
+    cl.handshake(function (sid) {
+      ws = websocket(cl, sid);
+      ws.on('message', function (msg) {
+        if (!ws.connected) {
+          msg.type.should.eql('connect');
+          ws.connected = true;
+        }
+      });
+    });
+  },
+
+  'test accessing the array of clients': function (done) {
+    var port = ++ports
+      , cl1 = client(port)
+      , cl2 = client(port)
+      , io = create(cl1)
+      , total = 2
+      , ws1, ws2;
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('join ferrets', function () {
+        socket.join('ferrets');
+        socket.send('done');
+      });
+    });
+
+    function check() {
+      io.sockets.clients('ferrets').should.have.length(1);
+      io.sockets.clients('ferrets')[0].should.be.an.instanceof(sio.Socket);
+      io.sockets.clients('ferrets')[0].id.should.equal(ws1.sid);
+      io.sockets.clients().should.have.length(2);
+      io.sockets.clients()[0].should.be.an.instanceof(sio.Socket);
+      io.sockets.clients()[0].id.should.equal(ws1.sid);
+      io.sockets.clients()[1].should.be.an.instanceof(sio.Socket);
+      io.sockets.clients()[1].id.should.equal(ws2.sid);
+
+      ws1.finishClose();
+      ws2.finishClose();
+      cl1.end();
+      cl2.end();
+      io.server.close();
+      done();
+    };
+
+    cl1.handshake(function (sid) {
+      ws1 = websocket(cl1, sid);
+      ws1.sid = sid;
+      ws1.on('message', function (msg) {
+        if (!ws1.connected) {
+          msg.type.should.eql('connect');
+          ws1.connected = true;
+          ws1.packet({
+              type: 'event'
+            , name: 'join ferrets'
+            , endpoint: ''
+          });
+        } else {
+          cl2.handshake(function (sid) {
+            ws2 = websocket(cl2, sid);
+            ws2.sid = sid;
+            ws2.on('message', function (msg) {
+              if (!ws2.connected) {
+                msg.type.should.eql('connect');
+                ws2.connected = true;
+                check();
+              }
+            });
+          });
+        }
+      });
+    });
+  },
+
+  'test accessing handshake data from sockets on disconnect': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , ws;
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function () {
+
+      (!!socket.handshake.address.address).should.be.true;
+      (!!socket.handshake.address.port).should.be.true;
+      socket.handshake.headers.host.should.equal('localhost');
+      socket.handshake.headers.connection.should.equal('keep-alive');
+      socket.handshake.time.should.match(/GMT/);
+
+        setTimeout(function () {
+          ws.finishClose();
+          cl.end();
+          io.server.close();
+          done();
+        }, 10);
+      });
+
+      socket.disconnect();
+    });
+
+    cl.handshake(function (sid) {
+      ws = websocket(cl, sid);
+      ws.on('message', function (msg) {
+        if (!ws.connected) {
+          msg.type.should.eql('connect');
+          ws.connected = true;
+        }
+      });
+    });
+  },
+
+  'test for intentional and unintentional disconnects': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , calls = 0
+      , ws;
+
+    function close () {
+      cl.end();
+      io.server.close();
+      ws.finishClose();
+      done();
+    }
+
+    io.configure(function () {
+      io.set('heartbeat interval', .05);
+      io.set('heartbeat timeout', .05);
+      io.set('close timeout', 0);
+    });
+
+    io.of('/foo').on('connection', function (socket) {
+      socket.on('disconnect', function (reason) {
+       reason.should.equal('packet');
+
+       if (++calls == 2) close();
+      });
+    });
+
+    io.of('/bar').on('connection', function (socket) {
+      socket.on('disconnect', function (reason) {
+        reason.should.equal('socket end');
+
+        if (++calls == 2) close();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      var messages = 0;
+      ws = websocket(cl, sid);
+      ws.on('open', function () {
+        ws.packet({
+            type: 'connect'
+          , endpoint: '/foo'
+        });
+        ws.packet({
+            type: 'connect'
+          , endpoint: '/bar'
+        });
+      });
+
+      ws.on('message', function (packet) {
+        if (packet.type == 'connect') {
+          if (++messages === 3) {
+            ws.packet({ type: 'disconnect', endpoint:'/foo' });
+            ws.finishClose();
+          }
+        }
+      });
+    });
+  },
+
+  'test socket clean up': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , ws;
+
+    io.sockets.on('connection', function (socket) {
+      var self = this
+        , id = socket.id;
+
+      socket.on('disconnect', function () {
+        setTimeout(function () {
+          var available = !!self.sockets[id];
+
+          available.should.be.false;
+          ws.finishClose();
+          cl.end();
+          io.server.close();
+          done();
+        }, 10);
+      });
+
+      socket.disconnect();
+    });
+
+    cl.handshake(function (sid) {
+      ws = websocket(cl, sid);
+      ws.on('message', function (msg) {
+        if (!ws.connected) {
+          msg.type.should.eql('connect');
+          ws.connected = true;
+        }
+      });
+    });
+  },
+
+};
diff --git a/node/node_modules/socket.io/test/transports.xhr-polling.test.js b/node/node_modules/socket.io/test/transports.xhr-polling.test.js
new file mode 100644 (file)
index 0000000..fb039ab
--- /dev/null
@@ -0,0 +1,2754 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Test dependencies.
+ */
+
+var sio = require('socket.io')
+  , should = require('./common')
+  , HTTPClient = should.HTTPClient
+  , parser = sio.parser
+  , ports = 15200;
+
+/**
+ * HTTPClient for xhr-polling transport.
+ */
+
+function XHRPolling (port) {
+  HTTPClient.call(this, port);
+};
+
+/**
+ * Inhertis from HTTPClient.
+ */
+
+XHRPolling.prototype.__proto__ = HTTPClient.prototype;
+
+/**
+ * Performs the handshake and expects the connect echo packet.
+ *
+ * @api public
+ */
+
+XHRPolling.prototype.handshake = function (opts, fn) {
+  if ('function' == typeof opts) {
+    fn = opts;
+    opts = {};
+  }
+
+  var self = this;
+
+  return this.get('/socket.io/{protocol}', opts, function (res, data) {
+    var parts = data.split(':');
+
+    if (opts.ignoreConnect) {
+      return fn && fn.apply(null, parts);
+    }
+
+    // expect connect packet right after handshake
+    self.get(
+        '/socket.io/{protocol}/xhr-polling/' + parts[0]
+      , function (res, msgs) {
+          res.statusCode.should.eql(200);
+
+          msgs.should.have.length(1);
+          msgs[0].should.eql({ type: 'connect', endpoint: '', qs: '' });
+
+          fn && fn.apply(null, parts);
+        }
+    );
+  });
+};
+
+/**
+ * Create client for this transport.
+ *
+ * @api public
+ */
+
+function client (port) {
+  return new XHRPolling(port);
+};
+
+/**
+ * Test.
+ */
+
+module.exports = {
+
+  'test handshake': function (done) {
+    var cl = client(++ports)
+      , io = create(cl);
+
+    io.configure(function () {
+      io.set('close timeout', .05);
+      io.set('polling duration', 0);
+    });
+
+    function finish () {
+      cl.end();
+      io.server.close();
+      done();
+    };
+
+    cl.handshake(function (sid) {
+      var total = 2;
+
+      cl.get('/socket.io/{protocol}/xhr-polling/tobi', function (res, msgs) {
+        res.statusCode.should.eql(200);
+
+        msgs.should.have.length(1);
+        msgs[0].should.eql({
+            type: 'error'
+          , reason: 'client not handshaken'
+          , endpoint: ''
+          , advice: 'reconnect'
+        });
+
+        --total || finish();
+      });
+
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+        --total || finish();
+      });
+    });
+  },
+
+  'test the connection event': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , sid;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.id.should.eql(sid);
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake({ ignoreConnect: true }, function (sessid) {
+      sid = sessid;
+
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].type.should.eql('connect');
+      });
+    });
+  },
+
+  'test the disconnection event after a close timeout': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , sid;
+
+    io.configure(function () {
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.id.should.eql(sid);
+
+      socket.on('disconnect', function () {
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake({ ignoreConnect: true }, function (sessid) {
+      sid = sessid;
+
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].type.should.eql('connect');
+
+        setTimeout(function () {
+          cl.end();
+        }, 10);
+      });
+    });
+  },
+
+  'test the disconnection event when the client sends ?disconnect req':
+  function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , disconnected = false
+      , sid;
+
+    io.configure(function () {
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function () {
+        disconnected = true;
+      });
+    });
+
+    cl.handshake({ ignoreConnect: true }, function (sessid) {
+      sid = sessid;
+
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].type.should.eql('connect');
+
+        cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+          msgs.should.have.length(1);
+          msgs[0].should.eql({ type: 'disconnect', endpoint: '' });
+          disconnected.should.be.true;
+          cl.end();
+          io.server.close();
+          done();
+        });
+
+        cl.get('/socket.io/{protocol}/xhr-polling/' + sid + '/?disconnect');
+      });
+    });
+  },
+
+  'test the disconnection event booting a client': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , forced = false;
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function () {
+        io.server.close();
+        done();
+      });
+
+      cl.end();
+      socket.disconnect();
+      forced = true;
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'disconnect', endpoint: '' });
+
+        forced.should.be.true;
+      });
+    });
+  },
+
+  'test the disconnection event with client disconnect packet': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , sid;
+
+    io.sockets.on('connection', function (client) {
+      cl.post(
+          '/socket.io/{protocol}/xhr-polling/' + sid
+        , parser.encodePacket({ type: 'disconnect' })
+        , function (res, data) {
+            res.statusCode.should.eql(200);
+            data.should.eql('1');
+          }
+      );
+
+      client.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake({ ignoreConnect: true }, function (sessid) {
+      sid = sessid;
+
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].type.should.eql('connect');
+      });
+    });
+  },
+
+  'test sending back data': function (done) {
+    var cl = client(++ports)
+      , io = create(cl);
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.send('woot');
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, packs) {
+        packs.should.have.length(1);
+        packs[0].type.should.eql('message');
+        packs[0].data.should.eql('woot');
+      });
+    });
+  },
+
+  'test sending a batch of messages': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , sid;
+
+    io.configure(function () {
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      var messages = 0;
+
+      cl.post(
+          '/socket.io/{protocol}/xhr-polling/' + sid
+        , parser.encodePayload([
+              parser.encodePacket({ type: 'message', data: 'a' })
+            , parser.encodePacket({ type: 'message', data: 'b' })
+            , parser.encodePacket({ type: 'disconnect' })
+          ])
+        , function (res, data) {
+            res.statusCode.should.eql(200);
+            data.should.eql('1');
+          }
+      );
+
+      socket.on('message', function (data) {
+        messages++;
+
+        if (messages == 1)
+          data.should.eql('a');
+
+        if (messages == 2)
+          data.should.eql('b');
+      });
+
+      socket.on('disconnect', function () {
+        messages.should.eql(2);
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake({ ignoreConnect: true }, function (sessid) {
+      sid = sessid;
+
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].type.should.eql('connect');
+      });
+    });
+  },
+
+  'test message buffering between a response and a request': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messages = false
+      , tobi;
+
+    io.configure(function () {
+      io.set('polling duration', .1);
+      io.set('close timeout', .2);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      tobi = function () {
+        socket.send('a');
+        socket.send('b');
+        socket.send('c');
+      };
+
+      socket.on('disconnect', function () {
+        messages.should.be.true;
+
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        tobi();
+
+        cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+          msgs.should.have.length(3);
+          msgs[0].should.eql({ type: 'message', endpoint: '', data: 'a' });
+          msgs[1].should.eql({ type: 'message', endpoint: '', data: 'b' });
+          msgs[2].should.eql({ type: 'message', endpoint: '', data: 'c' });
+          messages = true;
+        });
+      })
+    });
+  },
+
+  'test connecting to a specific endpoint': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , connectMessage = false
+      , sid;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.of('/woot').on('connection', function (socket) {
+      connectMessage.should.be.true;
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.get('/socket.io/{protocol}/xhr-polling/' + sid);
+
+        connectMessage = true;
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/woot' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+            }
+        );
+      });
+    });
+  },
+
+  'test that connecting doesnt connect to defined endpoints': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , tobiConnected = false
+      , mainConnected = false
+      , sid;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      mainConnected = true;
+
+      socket.on('disconnect', function () {
+        tobiConnected.should.be.false;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    io.of('/tobi').on('connection', function () {
+      tobiConnected = true;
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid);
+    });
+  },
+
+  'test disconnecting a specific endpoint': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , wootDisconnected = false
+      , mainDisconnected = false
+      , checked = false;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (data) {
+        data.should.eql('ferret');
+        mainDisconnected.should.be.false;
+        wootDisconnected.should.be.true;
+        checked = true;
+      });
+
+      socket.on('disconnect', function () {
+        mainDisconnected = true;
+        checked.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    io.of('/woot').on('connection', function (socket) {
+      socket.on('disconnect', function () {
+        wootDisconnected = true;
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function () {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/woot' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.post(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , parser.encodePacket({ type: 'disconnect', endpoint: '/woot' })
+                , function (res, data) {
+                    res.statusCode.should.eql(200);
+                    data.should.eql('1');
+
+                    cl.post(
+                        '/socket.io/{protocol}/xhr-polling/' + sid
+                      , parser.encodePacket({ type: 'message', data: 'ferret' })
+                      , function (res, data) {
+                          res.statusCode.should.eql(200);
+                          data.should.eql('1');
+                        }
+                    );
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test that disconnecting disconnects all endpoints': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , aDisconnected = false
+      , bDisconnected = false;
+
+    io.configure(function () {
+      io.set('polling duration', .2);
+      io.set('close timeout', .2);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function () {
+        setTimeout(function () {
+          aDisconnected.should.be.true;
+          bDisconnected.should.be.true;
+          cl.end();
+          io.server.close();
+          done();
+        }, 50);
+      });
+    });
+
+    io.of('/a').on('connection', function (socket) {
+      socket.on('disconnect', function (msg) {
+        aDisconnected = true;
+      });
+    });
+
+    io.of('/b').on('connection', function (socket) {
+      socket.on('disconnect', function (msg) {
+        bDisconnected = true;
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/a' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+            }
+        );
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/b' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+            }
+        );
+      });
+    });
+  },
+
+  'test messaging a specific endpoint': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = true
+      , aMessaged = false
+      , bMessaged = false;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        msg.should.eql('');
+        messaged = true;
+      });
+
+      socket.on('disconnect', function () {
+        messaged.should.be.true;
+        aMessaged.should.be.true;
+        bMessaged.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    io.of('/a').on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        msg.should.eql('a');
+        aMessaged = true;
+      });
+    });
+
+    io.of('/b').on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        msg.should.eql('b');
+        bMessaged = true;
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'message', data: '' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+            }
+        );
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/a' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.post(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , parser.encodePacket({ type: 'message', endpoint: '/a', data: 'a' })
+                , function (res, data) {
+                    res.statusCode.should.eql(200);
+                    data.should.eql('1');
+                  }
+              );
+            }
+        );
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/b' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.post(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , parser.encodePacket({ type: 'message', endpoint: '/b', data: 'b' })
+                , function (res, data) {
+                    res.statusCode.should.eql(200);
+                    data.should.eql('1');
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test sending json from the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messages = 0
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        s.json.send(['a', 'b', 'c']);
+        s.json.send({
+            a: 'b'
+          , c: 'd'
+        });
+
+        cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+          res.statusCode.should.eql(200);
+
+          msgs.should.have.length(2);
+          msgs[0].should.eql({
+              type: 'json'
+            , data: ['a', 'b', 'c']
+            , endpoint: ''
+          });
+          msgs[1].should.eql({
+              type: 'json'
+            , data: {
+                  a: 'b'
+                , c: 'd'
+              }
+            , endpoint: ''
+          });
+        });
+      })
+    });
+  },
+
+  'test sending json to the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messages = 0;
+    
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .1);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        messages++;
+
+        if (messages == 1) {
+          msg.should.eql({ tobi: 'rocks' });
+        } else if (messages == 2) {
+          msg.should.eql(5000);
+        }
+      });
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({
+                type: 'json'
+              , data: { tobi: 'rocks' }
+            })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.equal('1');
+
+              cl.post(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , parser.encodePacket({
+                      type: 'json'
+                    , data: 5000
+                  })
+                , function (res, data) {
+                    res.statusCode.should.eql(200);
+                    data.should.equal('1');
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test emitting an event from the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        s.emit('tobi is playing');
+
+        cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+          res.statusCode.should.eql(200);
+
+          msgs.should.have.length(1);
+          msgs[0].should.eql({
+              type: 'event'
+            , name: 'tobi is playing'
+            , endpoint: ''
+            , args: []
+          });
+        });
+      });
+    });
+  },
+
+  'test emitting an event with data from the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        s.emit('edwald', { woot: 'woot' }, [1, 2, 3]);
+
+        cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+          res.statusCode.should.eql(200);
+
+          msgs.should.have.length(1);
+          msgs[0].should.eql({
+              type: 'event'
+            , name: 'edwald'
+            , endpoint: ''
+            , args: [{ woot: 'woot' }, [1, 2, 3]]
+          });
+        });
+      });
+    });
+  },
+
+  'test emitting an event to the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = false;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('jane', function (a, b, c) {
+        messaged = true;
+      });
+
+      socket.on('disconnect', function () {
+        messaged.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({
+                type: 'event'
+              , name: 'jane'
+            })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.equal('1');
+            }
+        );
+      });
+    });
+  },
+
+  'test that emitting an error event doesnt throw': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({
+                type: 'event'
+              , name: 'error'
+            })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.equal('1');
+            }
+        );
+      });
+    });
+  },
+
+  'test emitting an event to the server with data': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = false;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('woot', function (a, b, c) {
+        a.should.eql('a');
+        b.should.eql(2);
+        c.should.eql([1, 2]);
+
+        messaged = true;
+      });
+
+      socket.on('disconnect', function () {
+        messaged.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({
+                type: 'event'
+              , name: 'woot'
+              , args: ['a', 2, [1, 2]]
+            })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.equal('1');
+            }
+        );
+      });
+    });
+  },
+
+  'test sending undeliverable volatile messages': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        s.volatile.send('woooot');
+
+        cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+          res.statusCode.should.equal(200);
+          msgs.should.have.length(1);
+          msgs[0].should.eql({ type: 'noop', endpoint: '' });
+        });
+      });
+    });
+  },
+
+  'test sending undeliverable volatile json': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        s.volatile.json.send('woooot');
+
+        cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+          res.statusCode.should.equal(200);
+          msgs.should.have.length(1);
+          msgs[0].should.eql({ type: 'noop', endpoint: '' });
+        });
+      });
+    });
+  },
+
+  'test sending undeliverable volatile events': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        s.volatile.emit('woooot');
+
+        cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+          res.statusCode.should.equal(200);
+          msgs.should.have.length(1);
+          msgs[0].should.eql({ type: 'noop', endpoint: '' });
+        });
+      });
+    });
+  },
+
+  'test sending deliverable volatile messages': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+
+        msgs.should.have.length(1);
+        msgs[0].should.eql({
+            type: 'message'
+          , data: 'woooot'
+          , endpoint: ''
+        });
+      });
+
+      setTimeout(function () {
+        s.volatile.send('woooot');
+      }, 10);
+    });
+  },
+
+  'test sending deliverable volatile json': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+
+        msgs.should.have.length(1);
+        msgs[0].should.eql({
+            type: 'json'
+          , data: 5
+          , endpoint: ''
+        });
+      });
+
+      setTimeout(function () {
+        s.volatile.json.send(5);
+      }, 10);
+    });
+  },
+
+  'test sending deliverable volatile events': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+
+        msgs.should.have.length(1);
+        msgs[0].should.eql({
+            type: 'event'
+          , name: 'tobi'
+          , args: []
+          , endpoint: ''
+        });
+      });
+
+      setTimeout(function () {
+        s.volatile.json.emit('tobi');
+      }, 10);
+    });
+  },
+
+  'test automatic acknowledgements sent from the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , received = false;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        msg.should.eql('woot');
+        received = true;
+      });
+
+      socket.on('disconnect', function () {
+        received.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({
+                type: 'message'
+              , data: 'woot'
+              , id: 1
+              , endpoint: ''
+            })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.get(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , function (res, msgs) {
+                    res.statusCode.should.eql(200);
+                    msgs.should.have.length(1);
+                    msgs[0].should.eql({
+                        type: 'ack'
+                      , ackId: 1
+                      , endpoint: ''
+                      , args: []
+                    });
+                  }
+              );
+            }
+        );
+      });
+
+    });
+  },
+
+  'test manual data acknowledgement sent from the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , acknowledged = false;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (data, fn) {
+        data.should.eql('tobi');
+        fn('woot');
+        acknowledged = true;
+      });
+
+      socket.on('disconnect', function () {
+        acknowledged.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({
+            type: 'ack'
+          , args: ['woot']
+          , endpoint: ''
+          , ackId: '3'
+        });
+      });
+
+      cl.post(
+          '/socket.io/{protocol}/xhr-polling/' + sid
+        , parser.encodePacket({
+              type: 'message'
+            , data: 'tobi'
+            , ack: 'data'
+            , id: '3'
+          })
+        , function (res, data) {
+            res.statusCode.should.eql(200);
+            data.should.eql('1');
+          }
+      );
+    });
+  },
+
+  'test automatic acknowledgements sent from the client': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , acknowledged = false;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.send('aaaa', function () {
+        acknowledged = true;
+      });
+
+      socket.on('disconnect', function () {
+        acknowledged.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({
+            type: 'message'
+          , id: '1'
+          , data: 'aaaa'
+          , ack: true
+          , endpoint: ''
+        });
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({
+                type: 'ack'
+              , ackId: '1'
+            })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+            }
+        );
+      });
+    });
+  },
+
+  'test automatic ack with event sent from the client': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , acked = false;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.emit('woot', 1, 2, '3', function () {
+        acked = true;
+      });
+
+      socket.on('disconnect', function () {
+        acked.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({
+            type: 'event'
+          , name: 'woot'
+          , args: [1, 2, '3']
+          , id: '1'
+          , ack: true
+          , endpoint: ''
+        });
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({
+                type: 'ack'
+              , ackId: '1'
+              , args: []
+              , endpoint: ''
+            })
+        );
+      });
+    });
+  },
+
+  'test manual data ack with event sent from the client': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , acked = false;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.emit('woot', 1, 2, '3', function (a) {
+        a.should.eql('1');
+        acked = true;
+      });
+
+      socket.on('disconnect', function () {
+        acked.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({
+            type: 'event'
+          , name: 'woot'
+          , args: [1, 2, '3']
+          , id: '1'
+          , ack: 'data'
+          , endpoint: ''
+        });
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({
+                type: 'ack'
+              , ackId: '1'
+              , args: ['1']
+              , endpoint: ''
+            })
+        );
+      });
+    });
+  },
+
+  'test endpoint sending json from the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , received = false;;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function () {
+        received.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    io.of('/chrislee').on('connection', function (socket) {
+      socket.json.send([1, 2, { 3: 4 }]);
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.get(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , function (res, msgs) {
+                    res.statusCode.should.eql(200);
+                    msgs.should.have.length(2);
+                    msgs[0].should.eql({
+                        type: 'connect'
+                      , endpoint: '/chrislee'
+                      , qs: ''
+                    });
+                    msgs[1].should.eql({
+                        type: 'json'
+                      , data: [1, 2, { 3: 4 }]
+                      , endpoint: '/chrislee'
+                    });
+
+                    received = true;
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint sending json to the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = false
+      , subMessaged = false;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        messaged = true;
+      });
+
+      socket.on('disconnect', function () {
+        messaged.should.be.false;
+        subMessaged.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    io.of('/a').on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        msg.should.eql(['a', 'b', { c: 'd' }]);
+        subMessaged = true;
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/a' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.post(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , parser.encodePacket({
+                      type: 'json'
+                    , endpoint: '/a'
+                    , data: ['a', 'b', { c: 'd' }]
+                  })
+                , function (res, data) {
+                    res.statusCode.should.eql(200);
+                    data.should.eql('1');
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint emitting an event from the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , received = false;;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function () {
+        received.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    io.of('/chrislee').on('connection', function (socket) {
+      socket.emit('tj');
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.get(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , function (res, msgs) {
+                    res.statusCode.should.eql(200);
+                    msgs.should.have.length(2);
+                    msgs[0].should.eql({
+                        type: 'connect'
+                      , endpoint: '/chrislee'
+                      , qs: ''
+                    });
+                    msgs[1].should.eql({
+                        type: 'event'
+                      , name: 'tj'
+                      , args: []
+                      , endpoint: '/chrislee'
+                    });
+
+                    received = true;
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint emitting an event with data from the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , received = false;;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('disconnect', function () {
+        received.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    io.of('/chrislee').on('connection', function (socket) {
+      socket.emit('tj', 1, 2, 3, 4);
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.get(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , function (res, msgs) {
+                    res.statusCode.should.eql(200);
+                    msgs.should.have.length(2);
+                    msgs[0].should.eql({
+                        type: 'connect'
+                      , endpoint: '/chrislee'
+                      , qs: ''
+                    });
+                    msgs[1].should.eql({
+                        type: 'event'
+                      , name: 'tj'
+                      , args: [1, 2, 3, 4]
+                      , endpoint: '/chrislee'
+                    });
+
+                    received = true;
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint emitting an event to the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = false
+      , subMessaged = false;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        messaged = true;
+      });
+
+      socket.on('disconnect', function () {
+        messaged.should.be.false;
+        subMessaged.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    io.of('/a').on('connection', function (socket) {
+      socket.on('tj', function () {
+        subMessaged = true;
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/a' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.post(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , parser.encodePacket({
+                      type: 'event'
+                    , name: 'tj'
+                    , endpoint: '/a'
+                  })
+                , function (res, data) {
+                    res.statusCode.should.eql(200);
+                    data.should.eql('1');
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint emitting an event to the server with data': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = false
+      , subMessaged = false;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        messaged = true;
+      });
+
+      socket.on('disconnect', function () {
+        messaged.should.be.false;
+        subMessaged.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    io.of('/a').on('connection', function (socket) {
+      socket.on('tj', function (ferret, age) {
+        ferret.should.eql('tobi');
+        age.should.eql(23);
+        subMessaged = true;
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/a' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.post(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , parser.encodePacket({
+                      type: 'event'
+                    , name: 'tj'
+                    , endpoint: '/a'
+                    , args: ['tobi', 23]
+                  })
+                , function (res, data) {
+                    res.statusCode.should.eql(200);
+                    data.should.eql('1');
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint sending undeliverable volatile messages': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , empty = false
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.of('/chrislee').on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        empty.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              s.volatile.send('woot');
+
+              cl.get(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , function (res, msgs) {
+                    res.statusCode.should.eql(200);
+                    msgs.length.should.eql(1);
+                    msgs[0].should.eql({
+                        type: 'connect'
+                      , endpoint: '/chrislee'
+                      , qs: ''
+                    });
+                    empty = true;
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint sending undeliverable volatile json': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , empty = false
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.of('/chrislee').on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        empty.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              s.volatile.json.send(15);
+
+              cl.get(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , function (res, msgs) {
+                    res.statusCode.should.eql(200);
+                    msgs.length.should.eql(1);
+                    msgs[0].should.eql({
+                        type: 'connect'
+                      , endpoint: '/chrislee'
+                      , qs: ''
+                    });
+                    empty = true;
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint sending undeliverable volatile events': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , empty = false
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.of('/chrislee').on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        empty.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              s.volatile.json.emit('woot');
+
+              cl.get(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , function (res, msgs) {
+                    res.statusCode.should.eql(200);
+                    msgs.length.should.eql(1);
+                    msgs[0].should.eql({
+                        type: 'connect'
+                      , endpoint: '/chrislee'
+                      , qs: ''
+                    });
+                    empty = true;
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint sending deliverable volatile messages': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , received = false
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.of('/chrislee').on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        received.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.get(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , function (res, msgs) {
+                    res.statusCode.should.eql(200);
+                    msgs.should.have.length(1);
+                    msgs[0].should.eql({
+                        type: 'connect'
+                      , endpoint: '/chrislee'
+                      , qs: ''
+                    });
+
+                    cl.get(
+                        '/socket.io/{protocol}/xhr-polling/' + sid
+                      , function (res, msgs) {
+                          msgs.should.have.length(1);
+                          msgs[0].should.eql({
+                              type: 'message'
+                            , data: 'edwald'
+                            , endpoint: '/chrislee'
+                          });
+
+                          received = true;
+                        }
+                    );
+
+                    setTimeout(function () {
+                      s.volatile.send('edwald');
+                    }, 20);
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint sending deliverable volatile json': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , received = false
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.of('/chrislee').on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        received.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.get(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , function (res, msgs) {
+                    res.statusCode.should.eql(200);
+                    msgs.should.have.length(1);
+                    msgs[0].should.eql({
+                        type: 'connect'
+                      , endpoint: '/chrislee'
+                      , qs: ''
+                    });
+
+                    cl.get(
+                        '/socket.io/{protocol}/xhr-polling/' + sid
+                      , function (res, msgs) {
+                          msgs.should.have.length(1);
+                          msgs[0].should.eql({
+                              type: 'json'
+                            , data: 152
+                            , endpoint: '/chrislee'
+                          });
+
+                          received = true;
+                        }
+                    );
+
+                    setTimeout(function () {
+                      s.volatile.json.send(152);
+                    }, 20);
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint sending deliverable volatile events': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , received = false
+      , s;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.of('/chrislee').on('connection', function (socket) {
+      s = socket;
+
+      socket.on('disconnect', function () {
+        received.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.get(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , function (res, msgs) {
+                    res.statusCode.should.eql(200);
+                    msgs.should.have.length(1);
+                    msgs[0].should.eql({
+                        type: 'connect'
+                      , endpoint: '/chrislee'
+                      , qs: ''
+                    });
+
+                    cl.get(
+                        '/socket.io/{protocol}/xhr-polling/' + sid
+                      , function (res, msgs) {
+                          msgs.should.have.length(1);
+                          msgs[0].should.eql({
+                              type: 'event'
+                            , name: 'woooo'
+                            , args: [[1, 2]]
+                            , endpoint: '/chrislee'
+                          });
+
+                          received = true;
+                        }
+                    );
+
+                    setTimeout(function () {
+                      s.volatile.emit('woooo', [1, 2]);
+                    }, 20);
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint automatic acks sent from the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = false
+      , acked = false;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.of('/tobi').on('connection', function (socket) {
+      socket.on('message', function (msg) {
+        msg.should.eql('woot');
+        messaged = true;
+      });
+
+      socket.on('disconnect', function () {
+        acked.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/tobi' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.post(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , parser.encodePacket({
+                      type: 'message'
+                    , id: '3'
+                    , data: 'woot'
+                    , endpoint: '/tobi'
+                  })
+                , function (res, data) {
+                    res.statusCode.should.eql(200);
+                    data.should.eql('1');
+
+                    cl.get(
+                        '/socket.io/{protocol}/xhr-polling/' + sid
+                      , function (res, msgs) {
+                          res.statusCode.should.eql(200);
+                          msgs.should.have.length(2);
+                          msgs[0].should.eql({
+                              type: 'connect'
+                            , endpoint: '/tobi'
+                            , qs: ''
+                          });
+                          msgs[1].should.eql({
+                              type: 'ack'
+                            , ackId: '3'
+                            , endpoint: '/tobi'
+                            , args: []
+                          });
+
+                          acked = true;
+                        }
+                    );
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint manual data ack sent from the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = false
+      , acked = false;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.of('/tobi').on('connection', function (socket) {
+      socket.on('message', function (msg, fn) {
+        msg.should.eql('woot');
+        fn();
+        messaged = true;
+      });
+
+      socket.on('disconnect', function () {
+        acked.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/tobi' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.post(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , parser.encodePacket({
+                      type: 'message'
+                    , id: '3'
+                    , data: 'woot'
+                    , ack: 'data'
+                    , endpoint: '/tobi'
+                  })
+                , function (res, data) {
+                    res.statusCode.should.eql(200);
+                    data.should.eql('1');
+
+                    cl.get(
+                        '/socket.io/{protocol}/xhr-polling/' + sid
+                      , function (res, msgs) {
+                          res.statusCode.should.eql(200);
+                          msgs.should.have.length(2);
+                          msgs[0].should.eql({
+                              type: 'connect'
+                            , endpoint: '/tobi'
+                            , qs: ''
+                          });
+                          msgs[1].should.eql({
+                              type: 'ack'
+                            , ackId: '3'
+                            , args: []
+                            , endpoint: '/tobi'
+                          });
+
+                          acked = true;
+                        }
+                    );
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint manual data event ack sent from the server': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = false
+      , acked = false;
+
+    io.configure(function () {
+      io.set('polling duration', 0);
+      io.set('close timeout', .05);
+    });
+
+    io.of('/tobi').on('connection', function (socket) {
+      socket.on('woot', function (msg, fn) {
+        msg.should.eql(1);
+        fn('aaaa');
+        messaged = true;
+      });
+
+      socket.on('disconnect', function () {
+        acked.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) {
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/tobi' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.post(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , parser.encodePacket({
+                      type: 'event'
+                    , id: '3'
+                    , name: 'woot'
+                    , ack: 'data'
+                    , args: [1]
+                    , endpoint: '/tobi'
+                  })
+                , function (res, data) {
+                    res.statusCode.should.eql(200);
+                    data.should.eql('1');
+
+                    cl.get(
+                        '/socket.io/{protocol}/xhr-polling/' + sid
+                      , function (res, msgs) {
+                          res.statusCode.should.eql(200);
+                          msgs.should.have.length(2);
+                          msgs[0].should.eql({
+                              type: 'connect'
+                            , endpoint: '/tobi'
+                            , qs: ''
+                          });
+                          msgs[1].should.eql({
+                              type: 'ack'
+                            , ackId: '3'
+                            , args: ['aaaa']
+                            , endpoint: '/tobi'
+                          });
+
+                          acked = true;
+                        }
+                    );
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint acknowledgements sent from the client': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , acked = false;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.of('/woot').on('connection', function (socket) {
+      socket.send('aaa', function () {
+        acked = true;
+      });
+
+      socket.on('disconnect', function () {
+        acked.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.eql(200);
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/woot' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.get(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , function (res, msgs) {
+                    msgs.should.have.length(2);
+                    msgs[0].should.eql({
+                        type: 'connect'
+                      , endpoint: '/woot'
+                      , qs: ''
+                    });
+                    msgs[1].should.eql({
+                        type: 'message'
+                      , data: 'aaa'
+                      , endpoint: '/woot'
+                      , id: '1'
+                      , ack: true
+                    });
+
+                    cl.post(
+                        '/socket.io/{protocol}/xhr-polling/' + sid
+                      , parser.encodePacket({
+                            type: 'ack'
+                          , ackId: '1'
+                          , endpoint: '/woot'
+                        })
+                      , function (res, data) {
+                          res.statusCode.should.eql(200);
+                          data.should.eql('1');
+                        }
+                    );
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test endpoint manual data event acks sent from the client': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , acked = false;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.of('/rapture').on('connection', function (socket) {
+      socket.emit('woot', 'a', function (a, b, c) {
+        a.should.eql(5);
+        b.should.eql('hello');
+        c.should.eql([1, 2, 3]);
+
+        acked = true;
+      });
+
+      socket.on('disconnect', function () {
+        acked.should.be.true;
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) {
+        res.statusCode.should.equal(200);
+        msgs.should.have.length(1);
+        msgs[0].should.eql({ type: 'noop', endpoint: '' });
+
+        cl.post(
+            '/socket.io/{protocol}/xhr-polling/' + sid
+          , parser.encodePacket({ type: 'connect', endpoint: '/rapture' })
+          , function (res, data) {
+              res.statusCode.should.eql(200);
+              data.should.eql('1');
+
+              cl.get(
+                  '/socket.io/{protocol}/xhr-polling/' + sid
+                , function (res, msgs) {
+                    res.statusCode.should.eql(200);
+                    msgs.should.have.length(2);
+                    msgs[0].should.eql({
+                        type: 'connect'
+                      , endpoint: '/rapture'
+                      , qs: ''
+                    });
+                    msgs[1].should.eql({
+                        type: 'event'
+                      , id: '1'
+                      , name: 'woot'
+                      , args: ['a']
+                      , ack: 'data'
+                      , endpoint: '/rapture'
+                    });
+
+                    cl.post(
+                        '/socket.io/{protocol}/xhr-polling/' + sid
+                      , parser.encodePacket({
+                            type: 'ack'
+                          , ackId: '1'
+                          , args: [5, 'hello', [1, 2, 3]]
+                          , endpoint: '/rapture'
+                        })
+                      , function (res, data) {
+                          res.statusCode.should.eql(200);
+                          data.should.eql('1');
+                        }
+                    );
+                  }
+              );
+            }
+        );
+      });
+    });
+  },
+
+  'test CORS': function (done) {
+    var cl = client(++ports)
+      , io = create(cl)
+      , messaged = false;
+
+    io.configure(function () {
+      io.set('polling duration', .05);
+      io.set('close timeout', .05);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.send('woot');
+
+      socket.on('message', function (msg) {
+        msg.should.equal('woot');
+        messaged = true;
+      });
+
+      socket.on('disconnect', function () {
+        cl.end();
+        io.server.close();
+        done();
+      });
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, {
+        headers: {
+          Origin: 'http://localhost:3500'
+        }
+      }, function (res, packs) {
+        var headers = res.headers;
+
+        headers['access-control-allow-origin'].should.equal('*');
+        should.strictEqual(headers['access-control-allow-credentials'], undefined);
+
+        packs.should.have.length(1);
+        packs[0].type.should.eql('message');
+        packs[0].data.should.eql('woot');
+
+        cl.post('/socket.io/{protocol}/xhr-polling/' + sid, parser.encodePacket({
+            type: 'message'
+          , data: 'woot'
+        }), {
+          headers: {
+              Origin: 'http://localhost:3500'
+            , Cookie: 'woot=woot'
+          }
+        }, function (res, data) {
+          var headers = res.headers;
+          headers['access-control-allow-origin'].should.equal('*');
+          headers['access-control-allow-credentials'].should.equal('true');
+
+          data.should.equal('1');
+        });
+      });
+    });
+  },
+
+  'test emitting to closed clients': function (done) {
+    var cl = client(++ports)
+      , cl2 = client(ports)
+      , io = create(cl)
+      , connections = 0;
+
+    io.configure(function () {
+      io.set('close timeout', .1);
+    });
+
+    io.sockets.on('connection', function (socket) {
+      socket.send('a');
+    });
+
+    cl.handshake(function (sid) {
+      cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, packs) {
+        res.statusCode.should.equal(200);
+        packs.should.have.length(1);
+        packs[0].should.eql({ type: 'message', endpoint: '', data: 'a' });
+
+        cl2.handshake(function (sid2) {
+          cl2.get(
+              '/socket.io/{protocol}/xhr-polling/' + sid2
+            , function (res, packs) {
+                res.statusCode.should.equal(200);
+                packs.should.have.length(1);
+                packs[0].should.eql({ type: 'message', endpoint: '', data: 'a' });
+
+                io.sockets.emit('woot', 'b');
+
+                var total = 2;
+
+                cl.get(
+                    '/socket.io/{protocol}/xhr-polling/' + sid
+                  , function (res, packs) {
+                      res.statusCode.should.equal(200);
+                      packs.should.have.length(1);
+                      packs[0].should.eql({
+                          type: 'event'
+                        , endpoint: ''
+                        , name: 'woot'
+                        , args: ['b']
+                      });
+
+                      --total || finish();
+                    }
+                );
+
+                cl2.get(
+                    '/socket.io/{protocol}/xhr-polling/' + sid2
+                  , function (res, packs) {
+                      res.statusCode.should.equal(200);
+                      packs.should.have.length(1);
+                      packs[0].should.eql({
+                          type: 'event'
+                        , endpoint: ''
+                        , name: 'woot'
+                        , args: ['b']
+                      });
+
+                      --total || finish();
+                    }
+                );
+
+                function finish () {
+                  cl.end();
+                  cl2.end();
+                  io.server.close();
+                  done();
+                };
+              }
+          );
+        });
+        
+      });
+    });
+  }
+
+};
index 8bc5da6c582490bc99a10ab615d94440350c3c10..bd69e63e6b930b9124cb51575b5131f318255584 100644 (file)
@@ -7,7 +7,7 @@ lang="en" xml:lang="en">
 <title>UglifyJS -- a JavaScript parser/compressor/beautifier</title>
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
 <meta name="generator" content="Org-mode"/>
-<meta name="generated" content="2011-07-14 12:50:31 EEST"/>
+<meta name="generated" content="2011-08-20 10:08:28 EEST"/>
 <meta name="author" content="Mihai Bazon"/>
 <meta name="description" content="a JavaScript parser/compressor/beautifier in JavaScript"/>
 <meta name="keywords" content="javascript, js, parser, compiler, compressor, mangle, minify, minifier"/>
@@ -85,6 +85,7 @@ lang="en" xml:lang="en">
 <li><a href="#sec-1_1">1.1 Unsafe transformations </a>
 <ul>
 <li><a href="#sec-1_1_1">1.1.1 Calls involving the global Array constructor </a></li>
+<li><a href="#sec-1_1_2">1.1.2 <code>obj.toString()</code> ==&gt; <code>obj+“”</code> </a></li>
 </ul>
 </li>
 <li><a href="#sec-1_2">1.2 Install (NPM) </a></li>
@@ -224,16 +225,9 @@ function/variable declarations).
 
 
 <p>
-UglifyJS tries its best to achieve great compression while leaving the
-semantics of the code intact.  In general, if your code logic is broken by
-UglifyJS then it's a bug in UglifyJS and you should report it and I should
-fix it. :-)
-</p>
-<p>
-However, I opted to include the following potentially unsafe transformations
-as default behavior.  Discussion is welcome, if you have ideas of how to
-handle this better, or any objections to these optimizations, please let me
-know.
+The following transformations can in theory break code, although they're
+probably safe in most practical cases.  To enable them you need to pass the
+<code>--unsafe</code> flag.
 </p>
 
 </div>
@@ -249,10 +243,10 @@ The following transformations occur:
 
 
 
-<pre class="src src-js"><span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(1, 2, 3, 4)  =&gt; [1,2,3,4]
+<pre class="src src-js"><span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(1, 2, 3, 4)  =&gt; [1,2,3,4]
 Array(a, b, c)         =&gt; [a,b,c]
-<span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(5)           =&gt; Array(5)
-<span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(a)           =&gt; Array(a)
+<span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(5)           =&gt; Array(5)
+<span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(a)           =&gt; Array(a)
 </pre>
 
 
@@ -270,42 +264,51 @@ following cases UglifyJS <b>doesn't touch</b> calls or instantiations of Array:
 
 
 
-<pre class="src src-js"><span style="color: #00008b;">// </span><span style="color: #00008b;">case 1.  globally declared variable
-</span>  <span style="color: #8b0000;">var</span> <span style="color: #8b008b;">Array</span>;
-  <span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(1, 2, 3);
+<pre class="src src-js"><span style="color: #b22222;">// </span><span style="color: #b22222;">case 1.  globally declared variable
+</span>  <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">Array</span>;
+  <span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(1, 2, 3);
   Array(a, b);
 
-  <span style="color: #00008b;">// </span><span style="color: #00008b;">or (can be declared later)
-</span>  <span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(1, 2, 3);
-  <span style="color: #8b0000;">var</span> <span style="color: #8b008b;">Array</span>;
+  <span style="color: #b22222;">// </span><span style="color: #b22222;">or (can be declared later)
+</span>  <span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(1, 2, 3);
+  <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">Array</span>;
 
-  <span style="color: #00008b;">// </span><span style="color: #00008b;">or (can be a function)
-</span>  <span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(1, 2, 3);
-  <span style="color: #8b0000;">function</span> <span style="color: #8b2323;">Array</span>() { ... }
+  <span style="color: #b22222;">// </span><span style="color: #b22222;">or (can be a function)
+</span>  <span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(1, 2, 3);
+  <span style="color: #a020f0;">function</span> <span style="color: #0000ff;">Array</span>() { ... }
 
-<span style="color: #00008b;">// </span><span style="color: #00008b;">case 2.  declared in a function
-</span>  (<span style="color: #8b0000;">function</span>(){
-    a = <span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(1, 2, 3);
+<span style="color: #b22222;">// </span><span style="color: #b22222;">case 2.  declared in a function
+</span>  (<span style="color: #a020f0;">function</span>(){
+    a = <span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(1, 2, 3);
     b = Array(5, 6);
-    <span style="color: #8b0000;">var</span> <span style="color: #8b008b;">Array</span>;
+    <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">Array</span>;
   })();
 
-  <span style="color: #00008b;">// </span><span style="color: #00008b;">or
-</span>  (<span style="color: #8b0000;">function</span>(<span style="color: #8b008b;">Array</span>){
-    <span style="color: #8b0000;">return</span> Array(5, 6, 7);
+  <span style="color: #b22222;">// </span><span style="color: #b22222;">or
+</span>  (<span style="color: #a020f0;">function</span>(<span style="color: #b8860b;">Array</span>){
+    <span style="color: #a020f0;">return</span> Array(5, 6, 7);
   })();
 
-  <span style="color: #00008b;">// </span><span style="color: #00008b;">or
-</span>  (<span style="color: #8b0000;">function</span>(){
-    <span style="color: #8b0000;">return</span> <span style="color: #8b0000;">new</span> <span style="color: #4682b4;">Array</span>(1, 2, 3, 4);
-    <span style="color: #8b0000;">function</span> <span style="color: #8b2323;">Array</span>() { ... }
+  <span style="color: #b22222;">// </span><span style="color: #b22222;">or
+</span>  (<span style="color: #a020f0;">function</span>(){
+    <span style="color: #a020f0;">return</span> <span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(1, 2, 3, 4);
+    <span style="color: #a020f0;">function</span> <span style="color: #0000ff;">Array</span>() { ... }
   })();
 
-  <span style="color: #00008b;">// </span><span style="color: #00008b;">etc.
+  <span style="color: #b22222;">// </span><span style="color: #b22222;">etc.
 </span></pre>
 
 
 
+</div>
+
+</div>
+
+<div id="outline-container-1_1_2" class="outline-4">
+<h4 id="sec-1_1_2"><span class="section-number-4">1.1.2</span> <code>obj.toString()</code> ==&gt; <code>obj+“”</code> </h4>
+<div class="outline-text-4" id="text-1_1_2">
+
+
 </div>
 </div>
 
@@ -332,21 +335,21 @@ the job.
 
 
 
-<pre class="src src-sh"><span style="color: #00008b;">## </span><span style="color: #00008b;">clone the repository
+<pre class="src src-sh"><span style="color: #b22222;">## </span><span style="color: #b22222;">clone the repository
 </span>mkdir -p /where/you/wanna/put/it
-<span style="color: #cd0000;">cd</span> /where/you/wanna/put/it
+<span style="color: #da70d6;">cd</span> /where/you/wanna/put/it
 git clone git://github.com/mishoo/UglifyJS.git
 
-<span style="color: #00008b;">## </span><span style="color: #00008b;">make the module available to Node
+<span style="color: #b22222;">## </span><span style="color: #b22222;">make the module available to Node
 </span>mkdir -p ~/.node_libraries/
-<span style="color: #cd0000;">cd</span> ~/.node_libraries/
+<span style="color: #da70d6;">cd</span> ~/.node_libraries/
 ln -s /where/you/wanna/put/it/UglifyJS/uglify-js.js
 
-<span style="color: #00008b;">## </span><span style="color: #00008b;">and if you want the CLI script too:
+<span style="color: #b22222;">## </span><span style="color: #b22222;">and if you want the CLI script too:
 </span>mkdir -p ~/bin
-<span style="color: #cd0000;">cd</span> ~/bin
+<span style="color: #da70d6;">cd</span> ~/bin
 ln -s /where/you/wanna/put/it/UglifyJS/bin/uglifyjs
-  <span style="color: #00008b;"># </span><span style="color: #00008b;">(then add ~/bin to your $PATH if it's not there already)
+  <span style="color: #b22222;"># </span><span style="color: #b22222;">(then add ~/bin to your $PATH if it's not there already)
 </span></pre>
 
 
@@ -461,12 +464,6 @@ internals.
 <code>-v</code> or <code>--verbose</code> &mdash; output some notes on STDERR (for now just how long
 each operation takes).
 
-</li>
-<li>
-<code>--extra</code> &mdash; enable additional optimizations that have not yet been
-extensively tested.  These might, or might not, break your code.  If you
-find a bug using this option, please report a test case.
-
 </li>
 <li>
 <code>--unsafe</code> &mdash; enable other additional optimizations that are known to be
@@ -498,6 +495,30 @@ intact you'd specify &ndash;reserved-names "require,$super".
 <code>--inline-script</code> &ndash; when you want to include the output literally in an
 HTML <code>&lt;script&gt;</code> tag you can use this option to prevent <code>&lt;/script</code> from
 showing up in the output.
+
+</li>
+<li>
+<code>--lift-vars</code> &ndash; when you pass this, UglifyJS will apply the following
+transformations (see the notes in API, <code>ast_lift_variables</code>):
+
+<ul>
+<li>
+put all <code>var</code> declarations at the start of the scope
+</li>
+<li>
+make sure a variable is declared only once
+</li>
+<li>
+discard unused function arguments
+</li>
+<li>
+discard unused inner (named) functions
+</li>
+<li>
+finally, try to merge assignments into that one <code>var</code> declaration, if
+possible.
+</li>
+</ul>
 </li>
 </ul>
 
@@ -517,14 +538,14 @@ NodeJS):
 
 
 
-<pre class="src src-js"><span style="color: #8b0000;">var</span> <span style="color: #8b008b;">jsp</span> = require(<span style="color: #008b00;">"uglify-js"</span>).parser;
-<span style="color: #8b0000;">var</span> <span style="color: #8b008b;">pro</span> = require(<span style="color: #008b00;">"uglify-js"</span>).uglify;
+<pre class="src src-js"><span style="color: #a020f0;">var</span> <span style="color: #b8860b;">jsp</span> = require(<span style="color: #bc8f8f;">"uglify-js"</span>).parser;
+<span style="color: #a020f0;">var</span> <span style="color: #b8860b;">pro</span> = require(<span style="color: #bc8f8f;">"uglify-js"</span>).uglify;
 
-<span style="color: #8b0000;">var</span> <span style="color: #8b008b;">orig_code</span> = <span style="color: #008b00;">"... JS code here"</span>;
-<span style="color: #8b0000;">var</span> <span style="color: #8b008b;">ast</span> = jsp.parse(orig_code); <span style="color: #00008b;">// </span><span style="color: #00008b;">parse code and get the initial AST
-</span>ast = pro.ast_mangle(ast); <span style="color: #00008b;">// </span><span style="color: #00008b;">get a new AST with mangled names
-</span>ast = pro.ast_squeeze(ast); <span style="color: #00008b;">// </span><span style="color: #00008b;">get an AST with compression optimizations
-</span><span style="color: #8b0000;">var</span> <span style="color: #8b008b;">final_code</span> = pro.gen_code(ast); <span style="color: #00008b;">// </span><span style="color: #00008b;">compressed code here
+<span style="color: #a020f0;">var</span> <span style="color: #b8860b;">orig_code</span> = <span style="color: #bc8f8f;">"... JS code here"</span>;
+<span style="color: #a020f0;">var</span> <span style="color: #b8860b;">ast</span> = jsp.parse(orig_code); <span style="color: #b22222;">// </span><span style="color: #b22222;">parse code and get the initial AST
+</span>ast = pro.ast_mangle(ast); <span style="color: #b22222;">// </span><span style="color: #b22222;">get a new AST with mangled names
+</span>ast = pro.ast_squeeze(ast); <span style="color: #b22222;">// </span><span style="color: #b22222;">get an AST with compression optimizations
+</span><span style="color: #a020f0;">var</span> <span style="color: #b8860b;">final_code</span> = pro.gen_code(ast); <span style="color: #b22222;">// </span><span style="color: #b22222;">compressed code here
 </span></pre>
 
 
@@ -549,6 +570,68 @@ if you want to strictly sanitize your code.
 
 </li>
 <li>
+<code>pro.ast_lift_variables(ast)</code> &ndash; merge and move <code>var</code> declarations to the
+scop of the scope; discard unused function arguments or variables; discard
+unused (named) inner functions.  It also tries to merge assignments
+following the <code>var</code> declaration into it.
+
+<p>
+If your code is very hand-optimized concerning <code>var</code> declarations, this
+lifting variable declarations might actually increase size.  For me it
+helps out.  On jQuery it adds 865 bytes (243 after gzip).  YMMV.  Also
+note that (since it's not enabled by default) this operation isn't yet
+heavily tested (please report if you find issues!).
+</p>
+<p>
+Note that although it might increase the image size (on jQuery it gains
+865 bytes, 243 after gzip) it's technically more correct: in certain
+situations, dead code removal might drop variable declarations, which
+would not happen if the variables are lifted in advance.
+</p>
+<p>
+Here's an example of what it does:
+</p>
+</li>
+</ul>
+
+
+
+
+<pre class="src src-js"><span style="color: #a020f0;">function</span> <span style="color: #0000ff;">f</span>(<span style="color: #b8860b;">a</span>, <span style="color: #b8860b;">b</span>, <span style="color: #b8860b;">c</span>, <span style="color: #b8860b;">d</span>, <span style="color: #b8860b;">e</span>) {
+    <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">q</span>;
+    <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">w</span>;
+    w = 10;
+    q = 20;
+    <span style="color: #a020f0;">for</span> (<span style="color: #a020f0;">var</span> <span style="color: #b8860b;">i</span> = 1; i &lt; 10; ++i) {
+        <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">boo</span> = foo(a);
+    }
+    <span style="color: #a020f0;">for</span> (<span style="color: #a020f0;">var</span> <span style="color: #b8860b;">i</span> = 0; i &lt; 1; ++i) {
+        <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">boo</span> = bar(c);
+    }
+    <span style="color: #a020f0;">function</span> <span style="color: #0000ff;">foo</span>(){ ... }
+    <span style="color: #a020f0;">function</span> <span style="color: #0000ff;">bar</span>(){ ... }
+    <span style="color: #a020f0;">function</span> <span style="color: #0000ff;">baz</span>(){ ... }
+}
+
+<span style="color: #b22222;">// </span><span style="color: #b22222;">transforms into ==&gt;
+</span>
+<span style="color: #a020f0;">function</span> <span style="color: #0000ff;">f</span>(<span style="color: #b8860b;">a</span>, <span style="color: #b8860b;">b</span>, <span style="color: #b8860b;">c</span>) {
+    <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">i</span>, <span style="color: #b8860b;">boo</span>, <span style="color: #b8860b;">w</span> = 10, <span style="color: #b8860b;">q</span> = 20;
+    <span style="color: #a020f0;">for</span> (i = 1; i &lt; 10; ++i) {
+        boo = foo(a);
+    }
+    <span style="color: #a020f0;">for</span> (i = 0; i &lt; 1; ++i) {
+        boo = bar(c);
+    }
+    <span style="color: #a020f0;">function</span> <span style="color: #0000ff;">foo</span>() { ... }
+    <span style="color: #a020f0;">function</span> <span style="color: #0000ff;">bar</span>() { ... }
+}
+</pre>
+
+
+
+<ul>
+<li>
 <code>pro.ast_mangle(ast, options)</code> &ndash; generates a new AST containing mangled
 (compressed) variable and function names.  It supports the following
 options:
@@ -654,63 +737,30 @@ the processing stages.
 
 
 <p>
-(XXX: this is somewhat outdated.  On the jQuery source code we beat Closure
-by 168 bytes (560 after gzip) and by many seconds.)
-</p>
-<p>
-There are a few popular JS minifiers nowadays &ndash; the two most well known
-being the GoogleClosure (GCL) compiler and the YUI compressor.  For some
-reason they are both written in Java.  I didn't really hope to beat any of
-them, but finally I did &ndash; UglifyJS compresses better than the YUI
-compressor, and safer than GoogleClosure.
-</p>
-<p>
-I tested it on two big libraries.  <a href="http://www.dynarchlib.com/">DynarchLIB</a> is my own, and it's big enough
-to contain probably all the JavaScript tricks known to mankind.  <a href="http://jquery.com/">jQuery</a> is
-definitely the most popular JavaScript library (to some people, it's a
-synonym to JavaScript itself).
-</p>
-<p>
-I cannot swear that there are no bugs in the generated codes, but they
-appear to work fine.
+Here are updated statistics.  (I also updated my Google Closure and YUI
+installations).
 </p>
 <p>
-Compression results:
+We're still a lot better than YUI in terms of compression, though slightly
+slower.  We're still a lot faster than Closure, and compression after gzip
+is comparable.
 </p>
 <table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
 <caption></caption>
-<colgroup><col align="left" /><col align="right" /><col align="right" /><col align="left" /><col align="left" />
+<colgroup><col align="left" /><col align="left" /><col align="right" /><col align="left" /><col align="right" /><col align="left" /><col align="right" />
 </colgroup>
 <thead>
-<tr><th scope="col">Library</th><th scope="col">Orig. size</th><th scope="col">UglifyJS</th><th scope="col">YUI</th><th scope="col">GCL</th></tr>
+<tr><th scope="col">File</th><th scope="col">UglifyJS</th><th scope="col">UglifyJS+gzip</th><th scope="col">Closure</th><th scope="col">Closure+gzip</th><th scope="col">YUI</th><th scope="col">YUI+gzip</th></tr>
 </thead>
 <tbody>
-<tr><td>DynarchLIB</td><td>636896</td><td>241441</td><td>246452 (+5011)</td><td>240439 (-1002) (buggy)</td></tr>
-<tr><td>jQuery</td><td>163855</td><td>72006</td><td>79702  (+7696)</td><td>71858   (-148)</td></tr>
+<tr><td>jquery-1.6.2.js</td><td>91001 (0:01.59)</td><td>31896</td><td>90678 (0:07.40)</td><td>31979</td><td>101527 (0:01.82)</td><td>34646</td></tr>
+<tr><td>paper.js</td><td>142023 (0:01.65)</td><td>43334</td><td>134301 (0:07.42)</td><td>42495</td><td>173383 (0:01.58)</td><td>48785</td></tr>
+<tr><td>prototype.js</td><td>88544 (0:01.09)</td><td>26680</td><td>86955 (0:06.97)</td><td>26326</td><td>92130 (0:00.79)</td><td>28624</td></tr>
+<tr><td>thelib-full.js (DynarchLIB)</td><td>251939 (0:02.55)</td><td>72535</td><td>249911 (0:09.05)</td><td>72696</td><td>258869 (0:01.94)</td><td>76584</td></tr>
 </tbody>
 </table>
 
 
-<p>
-UglifyJS is the fastest to run.  On my laptop UglifyJS takes 1.35s for
-DynarchLIB, while YUI takes 2.7s and GCL takes 6.5s.
-</p>
-<p>
-GoogleClosure does a lot of smart ass optimizations.  I had to strive really
-hard to get close to it.  It should be possible to even beat it, but then
-again, GCL has a gazillion lines of code and runs terribly slow, so I'm not
-sure it worths spending the effort to save a few bytes.  Also, GCL doesn't
-cope with <code>eval()</code> or <code>with{}</code> &ndash; it just dumps a warning and proceeds to
-mangle names anyway; my DynarchLIB compiled with it is buggy because of
-this.
-</p>
-<p>
-UglifyJS consists of ~1100 lines of code for the tokenizer/parser, and ~1100
-lines for the compressor and code generator.  That should make it very
-maintainable and easily extensible, so I would say it has a good place in
-this field and it's bound to become the de-facto standard JS minifier.  And
-I shall rule the world. :-) Use it, and <b>spread the word</b>!
-</p>
 </div>
 
 </div>
@@ -748,6 +798,9 @@ I'd love to hear about them (<a href="http://groups.google.com/group/uglifyjs">u
 
 <ul>
 <li>
+Twitter: <a href="http://twitter.com/UglifyJS">@UglifyJS</a>
+</li>
+<li>
 Project at GitHub: <a href="http://github.com/mishoo/UglifyJS">http://github.com/mishoo/UglifyJS</a>
 </li>
 <li>
@@ -827,7 +880,7 @@ SUCH DAMAGE.
 <div id="postamble">
 <p class="author"> Author: Mihai Bazon
 </p>
-<p class="date"> Date: 2011-07-14 12:50:31 EEST</p>
+<p class="date"> Date: 2011-08-20 10:08:28 EEST</p>
 <p class="creator">HTML generated by org-mode 7.01trans in emacs 23</p>
 </div>
 </div>
index f0ae354c70498963ec83cc97c69632777c98a43f..93b119514e7506450c035944f30b21d56239ebd8 100644 (file)
@@ -72,15 +72,9 @@ manipulates the AST generated by the parser to provide the following:
 
 ** <<Unsafe transformations>>
 
-UglifyJS tries its best to achieve great compression while leaving the
-semantics of the code intact.  In general, if your code logic is broken by
-UglifyJS then it's a bug in UglifyJS and you should report it and I should
-fix it. :-)
-
-However, I opted to include the following potentially unsafe transformations
-as default behavior.  Discussion is welcome, if you have ideas of how to
-handle this better, or any objections to these optimizations, please let me
-know.
+The following transformations can in theory break code, although they're
+probably safe in most practical cases.  To enable them you need to pass the
+=--unsafe= flag.
 
 *** Calls involving the global Array constructor
 
@@ -136,6 +130,8 @@ following cases UglifyJS *doesn't touch* calls or instantiations of Array:
   // etc.
 #+END_SRC
 
+*** =obj.toString()= ==> =obj+“”=
+
 ** Install (NPM)
 
 UglifyJS is now available through NPM --- =npm install uglify-js= should do
@@ -227,10 +223,6 @@ Supported options:
 - =-v= or =--verbose= --- output some notes on STDERR (for now just how long
   each operation takes).
 
-- =--extra= --- enable additional optimizations that have not yet been
-  extensively tested.  These might, or might not, break your code.  If you
-  find a bug using this option, please report a test case.
-
 - =--unsafe= --- enable other additional optimizations that are known to be
   unsafe in some contrived situations, but could still be generally useful.
   For now only this:
@@ -251,6 +243,16 @@ Supported options:
   HTML =<script>= tag you can use this option to prevent =</script= from
   showing up in the output.
 
+- =--lift-vars= -- when you pass this, UglifyJS will apply the following
+  transformations (see the notes in API, =ast_lift_variables=):
+
+  - put all =var= declarations at the start of the scope
+  - make sure a variable is declared only once
+  - discard unused function arguments
+  - discard unused inner (named) functions
+  - finally, try to merge assignments into that one =var= declaration, if
+    possible.
+
 *** API
 
 To use the library from JavaScript, you'd do the following (example for
@@ -281,6 +283,56 @@ Some of these functions take optional arguments.  Here's a description:
   it doesn't find it.  For most JS code you don't want that, but it's useful
   if you want to strictly sanitize your code.
 
+- =pro.ast_lift_variables(ast)= -- merge and move =var= declarations to the
+  scop of the scope; discard unused function arguments or variables; discard
+  unused (named) inner functions.  It also tries to merge assignments
+  following the =var= declaration into it.
+
+  If your code is very hand-optimized concerning =var= declarations, this
+  lifting variable declarations might actually increase size.  For me it
+  helps out.  On jQuery it adds 865 bytes (243 after gzip).  YMMV.  Also
+  note that (since it's not enabled by default) this operation isn't yet
+  heavily tested (please report if you find issues!).
+
+  Note that although it might increase the image size (on jQuery it gains
+  865 bytes, 243 after gzip) it's technically more correct: in certain
+  situations, dead code removal might drop variable declarations, which
+  would not happen if the variables are lifted in advance.
+
+  Here's an example of what it does:
+
+#+BEGIN_SRC js
+function f(a, b, c, d, e) {
+    var q;
+    var w;
+    w = 10;
+    q = 20;
+    for (var i = 1; i < 10; ++i) {
+        var boo = foo(a);
+    }
+    for (var i = 0; i < 1; ++i) {
+        var boo = bar(c);
+    }
+    function foo(){ ... }
+    function bar(){ ... }
+    function baz(){ ... }
+}
+
+// transforms into ==>
+
+function f(a, b, c) {
+    var i, boo, w = 10, q = 20;
+    for (i = 1; i < 10; ++i) {
+        boo = foo(a);
+    }
+    for (i = 0; i < 1; ++i) {
+        boo = bar(c);
+    }
+    function foo() { ... }
+    function bar() { ... }
+}
+#+END_SRC
+
 - =pro.ast_mangle(ast, options)= -- generates a new AST containing mangled
   (compressed) variable and function names.  It supports the following
   options:
@@ -333,46 +385,19 @@ the processing stages.
 
 ** Compression -- how good is it?
 
-(XXX: this is somewhat outdated.  On the jQuery source code we beat Closure
-by 168 bytes (560 after gzip) and by many seconds.)
-
-There are a few popular JS minifiers nowadays -- the two most well known
-being the GoogleClosure (GCL) compiler and the YUI compressor.  For some
-reason they are both written in Java.  I didn't really hope to beat any of
-them, but finally I did -- UglifyJS compresses better than the YUI
-compressor, and safer than GoogleClosure.
-
-I tested it on two big libraries.  [[http://www.dynarchlib.com/][DynarchLIB]] is my own, and it's big enough
-to contain probably all the JavaScript tricks known to mankind.  [[http://jquery.com/][jQuery]] is
-definitely the most popular JavaScript library (to some people, it's a
-synonym to JavaScript itself).
-
-I cannot swear that there are no bugs in the generated codes, but they
-appear to work fine.
-
-Compression results:
-
-| Library    | Orig. size | UglifyJS | YUI            | GCL                    |
-|------------+------------+----------+----------------+------------------------|
-| DynarchLIB |     636896 |   241441 | 246452 (+5011) | 240439 (-1002) (buggy) |
-| jQuery     |     163855 |    72006 | 79702  (+7696) | 71858   (-148)         |
-
-UglifyJS is the fastest to run.  On my laptop UglifyJS takes 1.35s for
-DynarchLIB, while YUI takes 2.7s and GCL takes 6.5s.
+Here are updated statistics.  (I also updated my Google Closure and YUI
+installations).
 
-GoogleClosure does a lot of smart ass optimizations.  I had to strive really
-hard to get close to it.  It should be possible to even beat it, but then
-again, GCL has a gazillion lines of code and runs terribly slow, so I'm not
-sure it worths spending the effort to save a few bytes.  Also, GCL doesn't
-cope with =eval()= or =with{}= -- it just dumps a warning and proceeds to
-mangle names anyway; my DynarchLIB compiled with it is buggy because of
-this.
+We're still a lot better than YUI in terms of compression, though slightly
+slower.  We're still a lot faster than Closure, and compression after gzip
+is comparable.
 
-UglifyJS consists of ~1100 lines of code for the tokenizer/parser, and ~1100
-lines for the compressor and code generator.  That should make it very
-maintainable and easily extensible, so I would say it has a good place in
-this field and it's bound to become the de-facto standard JS minifier.  And
-I shall rule the world. :-) Use it, and *spread the word*!
+| File                        | UglifyJS         | UglifyJS+gzip | Closure          | Closure+gzip | YUI              | YUI+gzip |
+|-----------------------------+------------------+---------------+------------------+--------------+------------------+----------|
+| jquery-1.6.2.js             | 91001 (0:01.59)  |         31896 | 90678 (0:07.40)  |        31979 | 101527 (0:01.82) |    34646 |
+| paper.js                    | 142023 (0:01.65) |         43334 | 134301 (0:07.42) |        42495 | 173383 (0:01.58) |    48785 |
+| prototype.js                | 88544 (0:01.09)  |         26680 | 86955 (0:06.97)  |        26326 | 92130 (0:00.79)  |    28624 |
+| thelib-full.js (DynarchLIB) | 251939 (0:02.55) |         72535 | 249911 (0:09.05) |        72696 | 258869 (0:01.94) |    76584 |
 
 ** Bugs?
 
@@ -395,6 +420,7 @@ I'd love to hear about them ([[http://groups.google.com/group/uglifyjs][use the
 
 ** Links
 
+- Twitter: [[http://twitter.com/UglifyJS][@UglifyJS]]
 - Project at GitHub: [[http://github.com/mishoo/UglifyJS][http://github.com/mishoo/UglifyJS]]
 - Google Group: [[http://groups.google.com/group/uglifyjs][http://groups.google.com/group/uglifyjs]]
 - Common Lisp JS parser: [[http://marijn.haverbeke.nl/parse-js/][http://marijn.haverbeke.nl/parse-js/]]
old mode 100644 (file)
new mode 100755 (executable)
index 3a23be8..9779e16
@@ -21,6 +21,7 @@ var options = {
         unsafe: false,
         reserved_names: null,
         defines: { },
+        lift_vars: false,
         codegen_options: {
                 ascii_only: false,
                 beautify: false,
@@ -97,6 +98,9 @@ out: while (args.length > 0) {
             case "--reserved-names":
                 options.reserved_names = args.shift().split(",");
                 break;
+            case "--lift-vars":
+                options.lift_vars = true;
+                break;
             case "-d":
             case "--define":
                  var defarg = args.shift();
@@ -269,6 +273,9 @@ function squeeze_it(code) {
         }
         try {
                 var ast = time_it("parse", function(){ return jsp.parse(code); });
+                if (options.lift_vars) {
+                        ast = time_it("lift", function(){ return pro.ast_lift_variables(ast); });
+                }
                 if (options.mangle) ast = time_it("mangle", function(){
                         return pro.ast_mangle(ast, {
                                 toplevel: options.mangle_toplevel,
@@ -297,6 +304,7 @@ function squeeze_it(code) {
                 sys.debug(ex.stack);
                 sys.debug(sys.inspect(ex));
                 sys.debug(JSON.stringify(ex));
+                process.exit(1);
         }
 };
 
diff --git a/node/node_modules/uglify-js/lib/object-ast.js b/node/node_modules/uglify-js/lib/object-ast.js
new file mode 100644 (file)
index 0000000..afdb69f
--- /dev/null
@@ -0,0 +1,75 @@
+var jsp = require("./parse-js"),
+    pro = require("./process");
+
+var BY_TYPE = {};
+
+function HOP(obj, prop) {
+        return Object.prototype.hasOwnProperty.call(obj, prop);
+};
+
+function AST_Node(parent) {
+        this.parent = parent;
+};
+
+AST_Node.prototype.init = function(){};
+
+function DEFINE_NODE_CLASS(type, props, methods) {
+        var base = methods && methods.BASE || AST_Node;
+        if (!base) base = AST_Node;
+        function D(parent, data) {
+                base.apply(this, arguments);
+                if (props) props.forEach(function(name, i){
+                        this["_" + name] = data[i];
+                });
+                this.init();
+        };
+        var P = D.prototype = new AST_Node;
+        P.node_type = function(){ return type };
+        if (props) props.forEach(function(name){
+                var propname = "_" + name;
+                P["set_" + name] = function(val) {
+                        this[propname] = val;
+                        return this;
+                };
+                P["get_" + name] = function() {
+                        return this[propname];
+                };
+        });
+        if (type != null) BY_TYPE[type] = D;
+        if (methods) for (var i in methods) if (HOP(methods, i)) {
+                P[i] = methods[i];
+        }
+        return D;
+};
+
+var AST_String_Node = DEFINE_NODE_CLASS("string", ["value"]);
+var AST_Number_Node = DEFINE_NODE_CLASS("num", ["value"]);
+var AST_Name_Node = DEFINE_NODE_CLASS("name", ["value"]);
+
+var AST_Statlist_Node = DEFINE_NODE_CLASS(null, ["body"]);
+var AST_Root_Node = DEFINE_NODE_CLASS("toplevel", null, { BASE: AST_Statlist_Node });
+var AST_Block_Node = DEFINE_NODE_CLASS("block", null, { BASE: AST_Statlist_Node });
+var AST_Splice_Node = DEFINE_NODE_CLASS("splice", null, { BASE: AST_Statlist_Node });
+
+var AST_Var_Node = DEFINE_NODE_CLASS("var", ["definitions"]);
+var AST_Const_Node = DEFINE_NODE_CLASS("const", ["definitions"]);
+
+var AST_Try_Node = DEFINE_NODE_CLASS("try", ["body", "catch", "finally"]);
+var AST_Throw_Node = DEFINE_NODE_CLASS("throw", ["exception"]);
+
+var AST_New_Node = DEFINE_NODE_CLASS("new", ["constructor", "arguments"]);
+
+var AST_Switch_Node = DEFINE_NODE_CLASS("switch", ["expression", "branches"]);
+var AST_Switch_Branch_Node = DEFINE_NODE_CLASS(null, ["expression", "body"]);
+
+var AST_Break_Node = DEFINE_NODE_CLASS("break", ["label"]);
+var AST_Continue_Node = DEFINE_NODE_CLASS("continue", ["label"]);
+var AST_Assign_Node = DEFINE_NODE_CLASS("assign", ["operator", "lvalue", "rvalue"]);
+var AST_Dot_Node = DEFINE_NODE_CLASS("dot", ["expression", "name"]);
+var AST_Call_Node = DEFINE_NODE_CLASS("call", ["function", "arguments"]);
+
+var AST_Lambda_Node = DEFINE_NODE_CLASS(null, ["name", "arguments", "body"])
+var AST_Function_Node = DEFINE_NODE_CLASS("function", null, AST_Lambda_Node);
+var AST_Defun_Node = DEFINE_NODE_CLASS("defun", null, AST_Lambda_Node);
+
+var AST_If_Node = DEFINE_NODE_CLASS("if", ["condition", "then", "else"]);
index 70bf999f5679ee15f659fec921e362caf0802efe..69abf6c6cafc341e3b8caf9a490b8d6f83eee066 100644 (file)
@@ -189,7 +189,7 @@ var OPERATORS = array_to_hash([
         "||"
 ]);
 
-var WHITESPACE_CHARS = array_to_hash(characters(" \u00a0\n\r\t\f\v\u200b"));
+var WHITESPACE_CHARS = array_to_hash(characters(" \u00a0\n\r\t\f\u000b\u200b"));
 
 var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:"));
 
@@ -404,11 +404,12 @@ function tokenizer($TEXT) {
                     case "r" : return "\r";
                     case "t" : return "\t";
                     case "b" : return "\b";
-                    case "v" : return "\v";
+                    case "v" : return "\u000b";
                     case "f" : return "\f";
                     case "0" : return "\0";
                     case "x" : return String.fromCharCode(hex_bytes(2));
                     case "u" : return String.fromCharCode(hex_bytes(4));
+                    case "\n": return "";
                     default  : return ch;
                 }
         };
@@ -1300,7 +1301,7 @@ function array_to_hash(a) {
 };
 
 function slice(a, start) {
-        return Array.prototype.slice.call(a, start == null ? 0 : start);
+        return Array.prototype.slice.call(a, start || 0);
 };
 
 function characters(str) {
index 775e305109cf113cb8ac5336411e9424707a99a2..d34e23949450be6ad5aeab74077cbf79571d849e 100644 (file)
@@ -66,7 +66,7 @@ var jsp = require("./parse-js"),
 
 /* -----[ helper for AST traversal ]----- */
 
-function ast_walker(ast) {
+function ast_walker() {
         function _vardefs(defs) {
                 return [ this[0], MAP(defs, function(def){
                         var a = [ def[0] ];
@@ -351,9 +351,15 @@ Scope.prototype = {
                 if (!newMangle) return name;                      // not found and no mangling requested
                 return s.set_mangle(name, s.next_mangled());
         },
-        define: function(name) {
-                if (name != null)
-                        return this.names[name] = name;
+        references: function(name) {
+                return name && !this.parent || this.uses_with || this.uses_eval || this.refs[name];
+        },
+        define: function(name, type) {
+                if (name != null) {
+                        if (type == "var" || !HOP(this.names, name))
+                                this.names[name] = type || "var";
+                        return name;
+                }
         }
 };
 
@@ -371,8 +377,8 @@ function ast_add_scope(ast) {
                 return ret;
         };
 
-        function define(name) {
-                return current_scope.define(name);
+        function define(name, type) {
+                return current_scope.define(name, type);
         };
 
         function reference(name) {
@@ -381,33 +387,41 @@ function ast_add_scope(ast) {
 
         function _lambda(name, args, body) {
                 var is_defun = this[0] == "defun";
-                return [ this[0], is_defun ? define(name) : name, args, with_new_scope(function(){
-                        if (!is_defun) define(name);
-                        MAP(args, define);
+                return [ this[0], is_defun ? define(name, "defun") : name, args, with_new_scope(function(){
+                        if (!is_defun) define(name, "lambda");
+                        MAP(args, function(name){ define(name, "arg") });
                         return MAP(body, walk);
                 })];
         };
 
+        function _vardefs(type) {
+                return function(defs) {
+                        MAP(defs, function(d){
+                                define(d[0], type);
+                                if (d[1]) reference(d[0]);
+                        });
+                };
+        };
+
         return with_new_scope(function(){
                 // process AST
                 var ret = w.with_walkers({
                         "function": _lambda,
                         "defun": _lambda,
+                        "label": function(name, stat) { define(name, "label") },
+                        "break": function(label) { if (label) reference(label) },
+                        "continue": function(label) { if (label) reference(label) },
                         "with": function(expr, block) {
                                 for (var s = current_scope; s; s = s.parent)
                                         s.uses_with = true;
                         },
-                        "var": function(defs) {
-                                MAP(defs, function(d){ define(d[0]) });
-                        },
-                        "const": function(defs) {
-                                MAP(defs, function(d){ define(d[0]) });
-                        },
+                        "var": _vardefs("var"),
+                        "const": _vardefs("const"),
                         "try": function(t, c, f) {
                                 if (c != null) return [
                                         this[0],
                                         MAP(t, walk),
-                                        [ define(c[0]), MAP(c[1], walk) ],
+                                        [ define(c[0], "catch"), MAP(c[1], walk) ],
                                         f != null ? MAP(f, walk) : null
                                 ];
                         },
@@ -535,6 +549,9 @@ function ast_mangle(ast, options) {
                         }
                         return ast;
                 },
+                "label": function(label, stat) { return [ this[0], get_mangled(label), walk(stat) ] },
+                "break": function(label) { if (label) return [ this[0], get_mangled(label) ] },
+                "continue": function(label) { if (label) return [ this[0], get_mangled(label) ] },
                 "var": _vardefs,
                 "const": _vardefs,
                 "name": function(name) {
@@ -581,10 +598,12 @@ function last_stat(b) {
 }
 
 function aborts(t) {
-        if (t) {
-                t = last_stat(t);
-                if (t[0] == "return" || t[0] == "break" || t[0] == "continue" || t[0] == "throw")
-                        return true;
+        if (t) switch (last_stat(t)[0]) {
+            case "return":
+            case "break":
+            case "continue":
+            case "throw":
+                return true;
         }
 };
 
@@ -773,9 +792,7 @@ function prepare_ifs(ast) {
                         var conditional = walk(fi[1]);
 
                         var e_body = statements.slice(i + 1);
-                        var e;
-                        if (e_body.length == 1) e = e_body[0];
-                        else e = [ "block", e_body ];
+                        var e = e_body.length == 1 ? e_body[0] : [ "block", e_body ];
 
                         var ret = statements.slice(0, i).concat([ [
                                 fi[0],          // "if"
@@ -792,14 +809,11 @@ function prepare_ifs(ast) {
 
         function redo_if_lambda(name, args, body) {
                 body = redo_if(body);
-                return [ this[0], name, args.slice(), body ];
+                return [ this[0], name, args, body ];
         };
 
         function redo_if_block(statements) {
-                var out = [ this[0] ];
-                if (statements != null)
-                        out.push(redo_if(statements));
-                return out;
+                return [ this[0], statements != null ? redo_if(statements) : null ];
         };
 
         return w.with_walkers({
@@ -823,6 +837,139 @@ function prepare_ifs(ast) {
         });
 };
 
+function for_side_effects(ast, handler) {
+        var w = ast_walker(), walk = w.walk;
+        var $stop = {}, $restart = {};
+        function stop() { throw $stop };
+        function restart() { throw $restart };
+        function found(){ return handler.call(this, this, w, stop, restart) };
+        function unary(op) {
+                if (op == "++" || op == "--")
+                        return found.apply(this, arguments);
+        };
+        return w.with_walkers({
+                "try": found,
+                "throw": found,
+                "return": found,
+                "new": found,
+                "switch": found,
+                "break": found,
+                "continue": found,
+                "assign": found,
+                "call": found,
+                "if": found,
+                "for": found,
+                "for-in": found,
+                "while": found,
+                "do": found,
+                "return": found,
+                "unary-prefix": unary,
+                "unary-postfix": unary,
+                "defun": found
+        }, function(){
+                while (true) try {
+                        walk(ast);
+                        break;
+                } catch(ex) {
+                        if (ex === $stop) break;
+                        if (ex === $restart) continue;
+                        throw ex;
+                }
+        });
+};
+
+function ast_lift_variables(ast) {
+        var w = ast_walker(), walk = w.walk, scope;
+        function do_body(body, env) {
+                var _scope = scope;
+                scope = env;
+                body = MAP(body, walk);
+                var hash = {}, names = MAP(env.names, function(type, name){
+                        if (type != "var") return MAP.skip;
+                        if (!env.references(name)) return MAP.skip;
+                        hash[name] = true;
+                        return [ name ];
+                });
+                if (names.length > 0) {
+                        // looking for assignments to any of these variables.
+                        // we can save considerable space by moving the definitions
+                        // in the var declaration.
+                        for_side_effects([ "block", body ], function(ast, walker, stop, restart) {
+                                if (ast[0] == "assign"
+                                    && ast[1] === true
+                                    && ast[2][0] == "name"
+                                    && HOP(hash, ast[2][1])) {
+                                        // insert the definition into the var declaration
+                                        for (var i = names.length; --i >= 0;) {
+                                                if (names[i][0] == ast[2][1]) {
+                                                        if (names[i][1]) // this name already defined, we must stop
+                                                                stop();
+                                                        names[i][1] = ast[3]; // definition
+                                                        names.push(names.splice(i, 1)[0]);
+                                                        break;
+                                                }
+                                        }
+                                        // remove this assignment from the AST.
+                                        var p = walker.parent();
+                                        if (p[0] == "seq") {
+                                                var a = p[2];
+                                                a.unshift(0, p.length);
+                                                p.splice.apply(p, a);
+                                        }
+                                        else if (p[0] == "stat") {
+                                                p.splice(0, p.length, "block"); // empty statement
+                                        }
+                                        else {
+                                                stop();
+                                        }
+                                        restart();
+                                }
+                                stop();
+                        });
+                        body.unshift([ "var", names ]);
+                }
+                scope = _scope;
+                return body;
+        };
+        function _vardefs(defs) {
+                var ret = null;
+                for (var i = defs.length; --i >= 0;) {
+                        var d = defs[i];
+                        if (!d[1]) continue;
+                        d = [ "assign", true, [ "name", d[0] ], d[1] ];
+                        if (ret == null) ret = d;
+                        else ret = [ "seq", d, ret ];
+                }
+                if (ret == null) {
+                        if (w.parent()[0] == "for-in")
+                                return [ "name", defs[0][0] ];
+                        return MAP.skip;
+                }
+                return [ "stat", ret ];
+        };
+        function _toplevel(body) {
+                return [ this[0], do_body(body, this.scope) ];
+        };
+        return w.with_walkers({
+                "function": function(name, args, body){
+                        for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);)
+                                args.pop();
+                        if (!body.scope.references(name)) name = null;
+                        return [ this[0], name, args, do_body(body, body.scope) ];
+                },
+                "defun": function(name, args, body){
+                        if (!scope.references(name)) return MAP.skip;
+                        for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);)
+                                args.pop();
+                        return [ this[0], name, args, do_body(body, body.scope) ];
+                },
+                "var": _vardefs,
+                "toplevel": _toplevel
+        }, function(){
+                return walk(ast_add_scope(ast));
+        });
+};
+
 function ast_squeeze(ast, options) {
         options = defaults(options, {
                 make_seqs   : true,
@@ -887,15 +1034,14 @@ function ast_squeeze(ast, options) {
         function _lambda(name, args, body) {
                 var is_defun = this[0] == "defun";
                 body = with_scope(body.scope, function(){
-                        var ret = tighten(MAP(body, walk), "lambda");
-                        if (!is_defun && name && !HOP(scope.refs, name))
+                        var ret = tighten(body, "lambda");
+                        if (!is_defun && name && !scope.references(name))
                                 name = null;
                         return ret;
                 });
                 return [ this[0], name, args, body ];
         };
 
-        // we get here for blocks that have been already transformed.
         // this function does a few things:
         // 1. discard useless blocks
         // 2. join consecutive var declarations
@@ -903,6 +1049,8 @@ function ast_squeeze(ast, options) {
         // 4. transform consecutive statements using the comma operator
         // 5. if block_type == "lambda" and it detects constructs like if(foo) return ... - rewrite like if (!foo) { ... }
         function tighten(statements, block_type) {
+                statements = MAP(statements, walk);
+
                 statements = statements.reduce(function(a, stat){
                         if (stat[0] == "block") {
                                 if (stat[1]) {
@@ -930,7 +1078,17 @@ function ast_squeeze(ast, options) {
                 if (options.dead_code) statements = (function(a, has_quit){
                         statements.forEach(function(st){
                                 if (has_quit) {
-                                        if (member(st[0], [ "function", "defun" , "var", "const" ])) {
+                                        if (st[0] == "function" || st[0] == "defun") {
+                                                a.push(st);
+                                        }
+                                        else if (st[0] == "var" || st[0] == "const") {
+                                                if (!options.no_warnings)
+                                                        warn("Variables declared in unreachable code");
+                                                st[1] = MAP(st[1], function(def){
+                                                        if (def[1] && !options.no_warnings)
+                                                                warn_unreachable([ "assign", true, [ "name", def[0] ], def[1] ]);
+                                                        return [ def[0] ];
+                                                });
                                                 a.push(st);
                                         }
                                         else if (!options.no_warnings)
@@ -954,27 +1112,38 @@ function ast_squeeze(ast, options) {
                                         prev = cur;
                                 }
                         });
+                        if (a.length >= 2
+                            && a[a.length-2][0] == "stat"
+                            && (a[a.length-1][0] == "return" || a[a.length-1][0] == "throw")
+                            && a[a.length-1][1])
+                        {
+                                a.splice(a.length - 2, 2,
+                                         [ a[a.length-1][0],
+                                           [ "seq", a[a.length-2][1], a[a.length-1][1] ]]);
+                        }
                         return a;
                 })([]);
 
-                if (block_type == "lambda") statements = (function(i, a, stat){
-                        while (i < statements.length) {
-                                stat = statements[i++];
-                                if (stat[0] == "if" && !stat[3]) {
-                                        if (stat[2][0] == "return" && stat[2][1] == null) {
-                                                a.push(make_if(negate(stat[1]), [ "block", statements.slice(i) ]));
-                                                break;
-                                        }
-                                        var last = last_stat(stat[2]);
-                                        if (last[0] == "return" && last[1] == null) {
-                                                a.push(make_if(stat[1], [ "block", stat[2][1].slice(0, -1) ], [ "block", statements.slice(i) ]));
-                                                break;
-                                        }
-                                }
-                                a.push(stat);
-                        }
-                        return a;
-                })(0, []);
+                // this increases jQuery by 1K.  Probably not such a good idea after all..
+                // part of this is done in prepare_ifs anyway.
+                // if (block_type == "lambda") statements = (function(i, a, stat){
+                //         while (i < statements.length) {
+                //                 stat = statements[i++];
+                //                 if (stat[0] == "if" && !stat[3]) {
+                //                         if (stat[2][0] == "return" && stat[2][1] == null) {
+                //                                 a.push(make_if(negate(stat[1]), [ "block", statements.slice(i) ]));
+                //                                 break;
+                //                         }
+                //                         var last = last_stat(stat[2]);
+                //                         if (last[0] == "return" && last[1] == null) {
+                //                                 a.push(make_if(stat[1], [ "block", stat[2][1].slice(0, -1) ], [ "block", statements.slice(i) ]));
+                //                                 break;
+                //                         }
+                //                 }
+                //                 a.push(stat);
+                //         }
+                //         return a;
+                // })(0, []);
 
                 return statements;
         };
@@ -1070,9 +1239,6 @@ function ast_squeeze(ast, options) {
                 });
         };
 
-        ast = prepare_ifs(ast);
-        ast = ast_add_scope(ast);
-
         return w.with_walkers({
                 "sub": function(expr, subscript) {
                         if (subscript[0] == "string") {
@@ -1086,13 +1252,13 @@ function ast_squeeze(ast, options) {
                 "if": make_if,
                 "toplevel": function(body) {
                         return [ "toplevel", with_scope(this.scope, function(){
-                                return tighten(MAP(body, walk));
+                                return tighten(body);
                         }) ];
                 },
                 "switch": function(expr, body) {
                         var last = body.length - 1;
                         return [ "switch", walk(expr), MAP(body, function(branch, i){
-                                var block = tighten(MAP(branch[1], walk));
+                                var block = tighten(branch[1]);
                                 if (i == last && block.length > 0) {
                                         var node = block[block.length - 1];
                                         if (node[0] == "break" && !node[1])
@@ -1104,7 +1270,7 @@ function ast_squeeze(ast, options) {
                 "function": _lambda,
                 "defun": _lambda,
                 "block": function(body) {
-                        if (body) return rmblock([ "block", tighten(MAP(body, walk)) ]);
+                        if (body) return rmblock([ "block", tighten(body) ]);
                 },
                 "binary": function(op, left, right) {
                         return when_constant([ "binary", op, walk(left), walk(right) ], function yes(c){
@@ -1119,9 +1285,9 @@ function ast_squeeze(ast, options) {
                 "try": function(t, c, f) {
                         return [
                                 "try",
-                                tighten(MAP(t, walk)),
-                                c != null ? [ c[0], tighten(MAP(c[1], walk)) ] : null,
-                                f != null ? tighten(MAP(f, walk)) : null
+                                tighten(t),
+                                c != null ? [ c[0], tighten(c[1]) ] : null,
+                                f != null ? tighten(f) : null
                         ];
                 },
                 "unary-prefix": function(op, expr) {
@@ -1139,23 +1305,14 @@ function ast_squeeze(ast, options) {
                             case "false": return [ "unary-prefix", "!", [ "num", 1 ]];
                         }
                 },
-                "new": function(ctor, args) {
-                        if (ctor[0] == "name" && ctor[1] == "Array" && !scope.has("Array")) {
-                                if (args.length != 1) {
-                                        return [ "array", args ];
-                                } else {
-                                        return [ "call", [ "name", "Array" ], args ];
-                                }
-                        }
-                },
-                "call": function(expr, args) {
-                        if (expr[0] == "name" && expr[1] == "Array" && args.length != 1 && !scope.has("Array")) {
-                                return [ "array", args ];
-                        }
-                },
                 "while": _do_while
         }, function() {
-                return walk(ast);
+                for (var i = 0; i < 2; ++i) {
+                        ast = prepare_ifs(ast);
+                        ast = ast_add_scope(ast);
+                        ast = walk(ast);
+                }
+                return ast;
         });
 };
 
@@ -1300,7 +1457,7 @@ function gen_code(ast, options) {
                         // we're the first in this "seq" and the
                         // parent is "stat", and so on.  Messy stuff,
                         // but it worths the trouble.
-                        var a = slice($stack), self = a.pop(), p = a.pop();
+                        var a = slice(w.stack()), self = a.pop(), p = a.pop();
                         while (p) {
                                 if (p[0] == "stat") return true;
                                 if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) ||
@@ -1330,7 +1487,9 @@ function gen_code(ast, options) {
                 return best_of(a);
         };
 
-        var generators = {
+        var w = ast_walker();
+        var make = w.walk;
+        return w.with_walkers({
                 "string": encode_string,
                 "num": make_num,
                 "name": make_name,
@@ -1339,7 +1498,7 @@ function gen_code(ast, options) {
                                 .join(newline + newline);
                 },
                 "splice": function(statements) {
-                        var parent = $stack[$stack.length - 2][0];
+                        var parent = w.parent();
                         if (HOP(SPLICE_NEEDS_BRACKETS, parent)) {
                                 // we need block brackets in this case
                                 return make_block.apply(this, arguments);
@@ -1513,7 +1672,7 @@ function gen_code(ast, options) {
                                                 // body in p[1][3] and type ("get" / "set") in p[2].
                                                 return indent(make_function(p[0], p[1][2], p[1][3], p[2]));
                                         }
-                                        var key = p[0], val = make(p[1]);
+                                        var key = p[0], val = parenthesize(p[1], "seq");
                                         if (options.quote_keys) {
                                                 key = encode_string(key);
                                         } else if ((typeof key == "number" || !beautify && +key + "" == key)
@@ -1553,7 +1712,7 @@ function gen_code(ast, options) {
                 "atom": function(name) {
                         return make_name(name);
                 }
-        };
+        }, function(){ return make(ast) });
 
         // The squeezer replaces "block"-s that contain only a single
         // statement with the statement itself; technically, the AST
@@ -1568,7 +1727,7 @@ function gen_code(ast, options) {
                         // IE croaks with "syntax error" on code like this:
                         //     if (foo) do ... while(cond); else ...
                         // we need block brackets around do/while
-                        return make([ "block", [ th ]]);
+                        return make_block([ th ]);
                 }
                 var b = th;
                 while (true) {
@@ -1595,20 +1754,31 @@ function gen_code(ast, options) {
                 return add_spaces([ out, make_block(body) ]);
         };
 
+        function must_has_semicolon(node) {
+                switch (node[0]) {
+                    case "with":
+                    case "while":
+                        return empty(node[2]); // `with' or `while' with empty body?
+                    case "for":
+                    case "for-in":
+                        return empty(node[4]); // `for' with empty body?
+                    case "if":
+                        if (empty(node[2]) && !node[3]) return true; // `if' with empty `then' and no `else'
+                        if (node[3]) {
+                                if (empty(node[3])) return true; // `else' present but empty
+                                return must_has_semicolon(node[3]); // dive into the `else' branch
+                        }
+                        return must_has_semicolon(node[2]); // dive into the `then' branch
+                }
+        };
+
         function make_block_statements(statements, noindent) {
                 for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) {
                         var stat = statements[i];
                         var code = make(stat);
                         if (code != ";") {
-                                if (!beautify && i == last) {
-                                        if ((stat[0] == "while" && empty(stat[2])) ||
-                                            (member(stat[0], [ "for", "for-in"] ) && empty(stat[4])) ||
-                                            (stat[0] == "if" && empty(stat[2]) && !stat[3]) ||
-                                            (stat[0] == "if" && stat[3] && empty(stat[3]))) {
-                                                code = code.replace(/;*\s*$/, ";");
-                                        } else {
-                                                code = code.replace(/;+\s*$/, "");
-                                        }
+                                if (!beautify && i == last && !must_has_semicolon(stat)) {
+                                        code = code.replace(/;+\s*$/, "");
                                 }
                                 a.push(code);
                         }
@@ -1648,20 +1818,6 @@ function gen_code(ast, options) {
                 return name;
         };
 
-        var $stack = [];
-
-        function make(node) {
-                var type = node[0];
-                var gen = generators[type];
-                if (!gen)
-                        throw new Error("Can't find generator for \"" + type + "\"");
-                $stack.push(node);
-                var ret = gen.apply(type, node.slice(1));
-                $stack.pop();
-                return ret;
-        };
-
-        return make(ast);
 };
 
 function split_lines(code, max_line_length) {
@@ -1746,16 +1902,34 @@ var MAP;
 
 (function(){
         MAP = function(a, f, o) {
-                var ret = [];
-                for (var i = 0; i < a.length; ++i) {
+                var ret = [], top = [], i;
+                function doit() {
                         var val = f.call(o, a[i], i);
-                        if (val instanceof AtTop) ret.unshift(val.v);
-                        else ret.push(val);
-                }
-                return ret;
+                        if (val instanceof AtTop) {
+                                val = val.v;
+                                if (val instanceof Splice) {
+                                        top.push.apply(top, val.v);
+                                } else {
+                                        top.push(val);
+                                }
+                        }
+                        else if (val != skip) {
+                                if (val instanceof Splice) {
+                                        ret.push.apply(ret, val.v);
+                                } else {
+                                        ret.push(val);
+                                }
+                        }
+                };
+                if (a instanceof Array) for (i = 0; i < a.length; ++i) doit();
+                else for (i in a) if (HOP(a, i)) doit();
+                return top.concat(ret);
         };
         MAP.at_top = function(val) { return new AtTop(val) };
+        MAP.splice = function(val) { return new Splice(val) };
+        var skip = MAP.skip = {};
         function AtTop(val) { this.v = val };
+        function Splice(val) { this.v = val };
 })();
 
 /* -----[ Exports ]----- */
@@ -1763,6 +1937,7 @@ var MAP;
 exports.ast_walker = ast_walker;
 exports.ast_mangle = ast_mangle;
 exports.ast_squeeze = ast_squeeze;
+exports.ast_lift_variables = ast_lift_variables;
 exports.gen_code = gen_code;
 exports.ast_add_scope = ast_add_scope;
 exports.set_logger = function(logger) { warn = logger };
index 12380af82c6f60e97ebb84253fe8393dc91940a5..0bf14ed67b18c050a9ec6d7a9b284c0367e39b00 100644 (file)
@@ -2,20 +2,49 @@ var jsp = require("./parse-js"),
     pro = require("./process"),
     slice = jsp.slice,
     member = jsp.member,
+    curry = jsp.curry,
+    MAP = pro.MAP,
     PRECEDENCE = jsp.PRECEDENCE,
     OPERATORS = jsp.OPERATORS;
 
 function ast_squeeze_more(ast) {
-        var w = pro.ast_walker(), walk = w.walk;
+        var w = pro.ast_walker(), walk = w.walk, scope;
+        function with_scope(s, cont) {
+                var save = scope, ret;
+                scope = s;
+                ret = cont();
+                scope = save;
+                return ret;
+        };
+        function _lambda(name, args, body) {
+                return [ this[0], name, args, with_scope(body.scope, curry(MAP, body, walk)) ];
+        };
         return w.with_walkers({
+                "toplevel": function(body) {
+                        return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ];
+                },
+                "function": _lambda,
+                "defun": _lambda,
+                "new": function(ctor, args) {
+                        if (ctor[0] == "name" && ctor[1] == "Array" && !scope.has("Array")) {
+                                if (args.length != 1) {
+                                        return [ "array", args ];
+                                } else {
+                                        return walk([ "call", [ "name", "Array" ], args ]);
+                                }
+                        }
+                },
                 "call": function(expr, args) {
                         if (expr[0] == "dot" && expr[2] == "toString" && args.length == 0) {
                                 // foo.toString()  ==>  foo+""
                                 return [ "binary", "+", expr[1], [ "string", "" ]];
                         }
+                        if (expr[0] == "name" && expr[1] == "Array" && args.length != 1 && !scope.has("Array")) {
+                                return [ "array", args ];
+                        }
                 }
         }, function() {
-                return walk(ast);
+                return walk(pro.ast_add_scope(ast));
         });
 };
 
index 49eaddcbec68bb93c69ee306a52ac226c3053430..ab37fdb0667e76345fce05633fde56db60d865e0 100644 (file)
@@ -7,7 +7,7 @@
                 "url"   : "http://mihai.bazon.net/blog"
         },
 
-        "version" : "1.0.6",
+        "version" : "1.0.7",
 
         "main"    : "./uglify-js.js",
 
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index a8e876c4734a8e4b667169f70e87e0bd8d3537f9..c5836bd3101d9b4df1fa182874880a523f80b644 100644 (file)
@@ -1 +1 @@
-function mak(){for(;;);}function foo(){while(bar());}function bar(){return--x}var x=5
+function bar(){return--x}function foo(){while(bar());}function mak(){for(;;);}var x=5
index 92a6ac280a80f73f57e78d4f12314a345b6b387a..d6ea94062a78ab9dba623a72a95a9e98ee357eeb 100644 (file)
@@ -1 +1 @@
-function y(a){return typeof a=="object"?a:null}function x(a){return typeof a=="object"?a:a===42?0:a*2}
+function x(a){return typeof a=="object"?a:a===42?0:a*2}function y(a){return typeof a=="object"?a:null}
index d7f63f728911e881c5d5edefaefbe00f5a2cc3a3..4ec46c8bc846aa1a4aa085e600cff377f2066d10 100644 (file)
@@ -1 +1 @@
-function f(){function b(){}a||b()}
+function f(){function b(){}if(a)return;b()}
index 5d1f526d0afb3e31382851f736e38471a8b139cf..9fdd96c6d995ebc6e3831011ea42f669ba2af8a8 100644 (file)
@@ -12,7 +12,7 @@ var scriptsPath = __dirname;
 function compress(code) {
        var ast = jsp.parse(code);
        ast = pro.ast_mangle(ast);
-       ast = pro.ast_squeeze(ast, {no_warnings: true, extra: true});
+       ast = pro.ast_squeeze(ast, { no_warnings: true });
         ast = pro.ast_squeeze_more(ast);
        return pro.gen_code(ast);
 };
diff --git a/node/node_modules/uglify-js/tmp/hoist.js b/node/node_modules/uglify-js/tmp/hoist.js
new file mode 100644 (file)
index 0000000..4bf2b94
--- /dev/null
@@ -0,0 +1,33 @@
+function foo(arg1, arg2, arg3, arg4, arg5, arg6) {
+        var a = 5;
+        {
+                var d = 10, mak = 20, buz = 30;
+                var q = buz * 2;
+        }
+        if (moo) {
+                var a, b, c;
+        }
+        for (var arg1 = 0, d = 20; arg1 < 10; ++arg1)
+                console.log(arg3);
+        for (var i in mak) {}
+        for (j in d) {}
+        var d;
+
+        function test() {
+                
+        };
+
+        //test();
+
+        (function moo(first, second){
+                console.log(first);
+        })(1);
+
+        (function moo(first, second){
+                console.log(moo());
+        })(1);
+}
+
+
+var foo;
+var bar;
diff --git a/node/node_modules/uglify-js/tmp/test.js b/node/node_modules/uglify-js/tmp/test.js
new file mode 100755 (executable)
index 0000000..46842f6
--- /dev/null
@@ -0,0 +1,16 @@
+#! /usr/bin/env node
+
+global.sys = require(/^v0\.[012]/.test(process.version) ? "sys" : "util");
+var fs = require("fs");
+var uglify = require("uglify-js"), // symlink ~/.node_libraries/uglify-js.js to ../uglify-js.js
+    jsp = uglify.parser,
+    pro = uglify.uglify;
+
+var code = fs.readFileSync("hoist.js", "utf8");
+var ast = jsp.parse(code);
+
+ast = pro.ast_lift_variables(ast);
+
+console.log(pro.gen_code(ast, {
+        beautify: true
+}));
diff --git a/node/npm-debug.log b/node/npm-debug.log
deleted file mode 100644 (file)
index 97c6989..0000000
+++ /dev/null
@@ -1,747 +0,0 @@
-info it worked if it ends with ok
-verbose cli [ 'node',
-verbose cli   '/root/local/node/bin/npm',
-verbose cli   'install',
-verbose cli   'uglify-js' ]
-info using npm@1.0.15
-info using node@v0.4.10-pre
-verbose config file /root/.npmrc
-verbose config file /root/local/node/etc/npmrc
-silly testEngine { name: 'jade',
-silly testEngine   description: 'Jade template engine',
-silly testEngine   version: '0.13.0',
-silly testEngine   author: 
-silly testEngine    { name: 'TJ Holowaychuk',
-silly testEngine      email: 'tj@vision-media.ca' },
-silly testEngine   repository: 
-silly testEngine    { type: 'git',
-silly testEngine      url: 'git://github.com/visionmedia/jade.git' },
-silly testEngine   main: './index.js',
-silly testEngine   bin: { jade: './bin/jade' },
-silly testEngine   devDependencies: 
-silly testEngine    { expresso: '0.6.4',
-silly testEngine      'coffee-script': '>= 0.0.1',
-silly testEngine      sass: '>= 0.0.1',
-silly testEngine      less: '>= 0.0.1',
-silly testEngine      markdown: '>= 0.0.1',
-silly testEngine      stylus: '>= 0.0.1' },
-silly testEngine   scripts: { prepublish: 'npm prune' },
-silly testEngine   engines: { node: '>= 0.1.98' },
-silly testEngine   _npmJsonOpts: 
-silly testEngine    { file: '/var/www/kiwi/KiwiIRC/node/node_modules/jade/package.json',
-silly testEngine      wscript: false,
-silly testEngine      contributors: false,
-silly testEngine      serverjs: false },
-silly testEngine   _id: 'jade@0.13.0',
-silly testEngine   dependencies: {},
-silly testEngine   _engineSupported: true,
-silly testEngine   _npmVersion: '1.0.15',
-silly testEngine   _nodeVersion: 'v0.4.10-pre',
-silly testEngine   _defaultsLoaded: true }
-verbose caching /var/www/kiwi/KiwiIRC/node/node_modules/jade/package.json
-verbose loadDefaults jade@0.13.0
-silly testEngine { name: 'node-static',
-silly testEngine   description: 'simple, compliant file streaming module for node',
-silly testEngine   url: 'http://github.com/cloudhead/node-static',
-silly testEngine   keywords: [ 'http', 'static', 'file', 'server' ],
-silly testEngine   author: 
-silly testEngine    { name: 'Alexis Sellier',
-silly testEngine      email: 'self@cloudhead.net' },
-silly testEngine   contributors: [],
-silly testEngine   licenses: [ 'MIT' ],
-silly testEngine   dependencies: {},
-silly testEngine   lib: 'lib',
-silly testEngine   main: './lib/node-static',
-silly testEngine   version: '0.5.6',
-silly testEngine   directories: { test: './test' },
-silly testEngine   engines: { node: '>= 0.4.1' },
-silly testEngine   _npmJsonOpts: 
-silly testEngine    { file: '/var/www/kiwi/KiwiIRC/node/node_modules/node-static/package.json',
-silly testEngine      wscript: false,
-silly testEngine      contributors: false,
-silly testEngine      serverjs: false },
-silly testEngine   _id: 'node-static@0.5.6',
-silly testEngine   devDependencies: {},
-silly testEngine   _engineSupported: true,
-silly testEngine   _npmVersion: '1.0.15',
-silly testEngine   _nodeVersion: 'v0.4.10-pre',
-silly testEngine   _defaultsLoaded: true }
-verbose caching /var/www/kiwi/KiwiIRC/node/node_modules/node-static/package.json
-verbose loadDefaults node-static@0.5.6
-silly testEngine { name: 'socket.io',
-silly testEngine   version: '0.7.7',
-silly testEngine   description: 'Real-time apps made cross-browser & easy with a WebSocket-like API',
-silly testEngine   homepage: 'http://socket.io',
-silly testEngine   keywords: 
-silly testEngine    [ 'websocket',
-silly testEngine      'socket',
-silly testEngine      'realtime',
-silly testEngine      'socket.io',
-silly testEngine      'comet',
-silly testEngine      'ajax' ],
-silly testEngine   author: 
-silly testEngine    { name: 'Guillermo Rauch',
-silly testEngine      email: 'guillermo@learnboost.com' },
-silly testEngine   contributors: 
-silly testEngine    [ { name: 'Guillermo Rauch', email: 'rauchg@gmail.com' },
-silly testEngine      { name: 'Arnout Kazemier',
-silly testEngine        email: 'info@3rd-eden.com' },
-silly testEngine      { name: 'Vladimir Dronnikov',
-silly testEngine        email: 'dronnikov@gmail.com' } ],
-silly testEngine   repository: 
-silly testEngine    { type: 'git',
-silly testEngine      url: 'git://github.com/LearnBoost/Socket.IO-node.git' },
-silly testEngine   dependencies: 
-silly testEngine    { 'socket.io-client': '0.7.4',
-silly testEngine      policyfile: '0.0.3',
-silly testEngine      redis: '0.6.0' },
-silly testEngine   devDependencies: { expresso: '0.7.7', should: '0.0.4' },
-silly testEngine   main: 'index',
-silly testEngine   engines: { node: '>= 0.4.0' },
-silly testEngine   _npmJsonOpts: 
-silly testEngine    { file: '/var/www/kiwi/KiwiIRC/node/node_modules/socket.io/package.json',
-silly testEngine      wscript: false,
-silly testEngine      contributors: false,
-silly testEngine      serverjs: false },
-silly testEngine   _id: 'socket.io@0.7.7',
-silly testEngine   _engineSupported: true,
-silly testEngine   _npmVersion: '1.0.15',
-silly testEngine   _nodeVersion: 'v0.4.10-pre',
-silly testEngine   _defaultsLoaded: true }
-verbose caching /var/www/kiwi/KiwiIRC/node/node_modules/socket.io/package.json
-verbose loadDefaults socket.io@0.7.7
-silly testEngine { name: 'socket.io-client',
-silly testEngine   description: 'Socket.IO client for the browser and node.js',
-silly testEngine   version: '0.7.4',
-silly testEngine   main: './lib/io.js',
-silly testEngine   browserify: './dist/socket.io.js',
-silly testEngine   homepage: 'http://socket.io',
-silly testEngine   keywords: 
-silly testEngine    [ 'websocket',
-silly testEngine      'socket',
-silly testEngine      'realtime',
-silly testEngine      'socket.io',
-silly testEngine      'comet',
-silly testEngine      'ajax' ],
-silly testEngine   author: 
-silly testEngine    { name: 'Guillermo Rauch',
-silly testEngine      email: 'guillermo@learnboost.com' },
-silly testEngine   contributors: 
-silly testEngine    [ { name: 'Guillermo Rauch', email: 'rauchg@gmail.com' },
-silly testEngine      { name: 'Arnout Kazemier',
-silly testEngine        email: 'info@3rd-eden.com' },
-silly testEngine      { name: 'Vladimir Dronnikov',
-silly testEngine        email: 'dronnikov@gmail.com' } ],
-silly testEngine   repository: 
-silly testEngine    { type: 'git',
-silly testEngine      url: 'git://github.com/LearnBoost/Socket.IO.git' },
-silly testEngine   dependencies: { 'uglify-js': '1.0.3' },
-silly testEngine   devDependencies: 
-silly testEngine    { expresso: '0.7.7',
-silly testEngine      express: '2.3.11',
-silly testEngine      jade: '0.12.1',
-silly testEngine      stylus: '0.13.3',
-silly testEngine      'socket.io': '0.7.7',
-silly testEngine      'socket.io-client': '0.7.4' },
-silly testEngine   engines: { node: '>= 0.4.0' },
-silly testEngine   _npmJsonOpts: 
-silly testEngine    { file: '/var/www/kiwi/KiwiIRC/node/node_modules/socket.io-client/package.json',
-silly testEngine      wscript: false,
-silly testEngine      contributors: false,
-silly testEngine      serverjs: false },
-silly testEngine   _id: 'socket.io-client@0.7.4',
-silly testEngine   _engineSupported: true,
-silly testEngine   _npmVersion: '1.0.15',
-silly testEngine   _nodeVersion: 'v0.4.10-pre',
-silly testEngine   _defaultsLoaded: true }
-verbose caching /var/www/kiwi/KiwiIRC/node/node_modules/socket.io-client/package.json
-verbose loadDefaults socket.io-client@0.7.4
-verbose into /var/www/kiwi/KiwiIRC/node [ 'uglify-js' ]
-verbose cache add [ 'uglify-js', null ]
-info addNamed [ 'uglify-js', '' ]
-verbose addNamed [ null, '' ]
-verbose GET uglify-js
-verbose raw, before any munging uglify-js
-verbose url resolving [ 'http://registry.npmjs.org/', './uglify-js' ]
-verbose url resolved http://registry.npmjs.org/uglify-js
-verbose url parsed { protocol: 'http:',
-verbose url parsed   slashes: true,
-verbose url parsed   host: 'registry.npmjs.org',
-verbose url parsed   hostname: 'registry.npmjs.org',
-verbose url parsed   href: 'http://registry.npmjs.org/uglify-js',
-verbose url parsed   pathname: '/uglify-js' }
-verbose response http://registry.npmjs.org/uglify-js
-silly chunk {"_id":"uglify-js","_rev":"26-8064181b8cb5259cdda963e8c227c8d7","name":"uglify-js","dist-tags":{"latest":"1.0.6"},"versions":{"0.0.1":{"name":"uglify-js","author":{"name":"Mihai Bazon - http://github.com/mishoo"},"version":"0.0.1","main":"index","bin":{"uglifyjs":"./bin/uglifyjs"},"_id":"uglify-js@0.0.1","engines":{"node":"*"},"_nodeSupported":true,"_npmVersion":"0.2.7-2","_nodeVersion":"v0.2.4","dist":{"tarball":"http://registry.npmjs.org/uglify-js/-/uglify-js-0.0.1.tgz"},"directories":{}},"0.0.2":{"name":"uglify-js","author":{"name":"Mihai Bazon - http://github.com/mishoo"},"version":"0.0.2","main":"index","bin":{"uglifyjs":"./bin/uglifyjs"},"_id":"uglify-js@0.0.2","engines":{"node":"*"},"_nodeSupported":true,"_npmVersion":"0.2.12-1","_nodeVersion":"v0.3.5-pre","dist":{"shasum":"baaf5c2223440d31f008bd248aaa728e8c771a8a","tarball":"http://registry.npmjs.org/uglify-js/-/uglify-js-0.0.2.tgz"},"directories":{}},"0.0.3":{"name":"uglify-js","author":{"name":"Mihai Bazon - http://github.com/mishoo"},"version":"0.0.3","main":"index","bin":{"uglifyjs":"./bin/uglifyjs"},"_id":"uglify-js@0.0.3","engines":{"node":"*"},"_nodeSupported":true,"_npmVersion":"0.2.12-1","_nodeVersion":"v0.3.5-pre","dist":{"shasum":"04e48708cb7175fba8b23aba7596e39c849ccfab","tarball":"http://registry.npmjs.org/uglify-js/-/uglify-js-0.0.3.tgz"},"directories":{}},"0.0.4":{"name":"uglify-js",
-silly chunk "author":{"name":"Mihai Bazon - http://github.com/mishoo"},"version":"0.0.4","main":"index","bin":{"uglifyjs":"./bin/uglifyjs"},"_id":"uglify-js@0.0.4","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"0.2.17","_nodeVersion":"v0.3.8-pre","directories":{"lib":"./lib","bin":"./bin"},"files":[""],"_defaultsLoaded":true,"dist":{"shasum":"48b2d19b65c284a82c4d6ccab6ed141b8e313a72","tarball":"http://registry.npmjs.org/uglify-js/-/uglify-js-0.0.4.tgz"}},"0.0.5":{"name":"uglify-js","author":{"name":"Mihai Bazon - http://github.com/mishoo"},"version":"0.0.5","main":"index.js","bin":{"uglifyjs":"./bin/uglifyjs"},"_id":"uglify-js@0.0.5","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"0.3.3","_nodeVersion":"v0.4.1","directories":{"lib":"./lib","bin":"./bin"},"files":[""],"_defaultsLoaded":true,"dist":{"shasum":"c40d18e51784a230477bb0354fa415ec361dba5e","tarball":"http://registry.npmjs.org/uglify-js/-/uglify-js-0.0.5.tgz"}},"1.0.1":{"name":"uglify-js","author":{"name":"Mihai Bazon","email":"mihai.bazon@gmail.com","url":"http://mihai.bazon.net/blog"},"version":"1.0.1","main":"./uglify-js.js","bin":{"uglifyjs":"./bin/uglifyjs"},"repository":{"type":"git","url":"git@github.com:mishoo/UglifyJS.git"},"dependencies":{},"devDependencies":{},"_id":"uglify-js@1.0.1","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.1rc5","_nodeVersion":"
-silly chunk v0.5.0-pre","_defaultsLoaded":true,"dist":{"shasum":"b34b3220e7d634401f388c8bd69e9663cec6ca94","tarball":"http://registry.npmjs.org/uglify-js/-/uglify-js-1.0.1.tgz"},"directories":{}},"1.0.2":{"name":"uglify-js","author":{"name":"Mihai Bazon","email":"mihai.bazon@gmail.com","url":"http://mihai.bazon.net/blog"},"version":"1.0.2","main":"./uglify-js.js","bin":{"uglifyjs":"./bin/uglifyjs"},"repository":{"type":"git","url":"git@github.com:mishoo/UglifyJS.git"},"dependencies":{},"devDependencies":{},"_id":"uglify-js@1.0.2","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.1rc5","_nodeVersion":"v0.5.0-pre","_defaultsLoaded":true,"dist":{"shasum":"28494cc77c26042d4065d73736391d78417d680a","tarball":"http://registry.npmjs.org/uglify-js/-/uglify-js-1.0.2.tgz"},"directories":{}},"1.0.3":{"name":"uglify-js","author":{"name":"Mihai Bazon","email":"mihai.bazon@gmail.com","url":"http://mihai.bazon.net/blog"},"version":"1.0.3","main":"./uglify-js.js","bin":{"uglifyjs":"./bin/uglifyjs"},"repository":{"type":"git","url":"git@github.com:mishoo/UglifyJS.git"},"dependencies":{},"devDependencies":{},"_id":"uglify-js@1.0.3","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.1rc5","_nodeVersion":"v0.5.0-pre","_defaultsLoaded":true,"dist":{"shasum":"73c4f09bcec47ec5e8669cb37c11b95b7014f945","tarball":"http://registry.npmjs.org/uglify-js/-/uglify-js-
-silly chunk 1.0.3.tgz"},"directories":{}},"1.0.4":{"name":"uglify-js","author":{"name":"Mihai Bazon","email":"mihai.bazon@gmail.com","url":"http://mihai.bazon.net/blog"},"version":"1.0.4","main":"./uglify-js.js","bin":{"uglifyjs":"./bin/uglifyjs"},"repository":{"type":"git","url":"git@github.com:mishoo/UglifyJS.git"},"dependencies":{},"devDependencies":{},"_id":"uglify-js@1.0.4","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.1rc5","_nodeVersion":"v0.5.0-pre","_defaultsLoaded":true,"dist":{"shasum":"7512dbbfca85e749683800c65407e55491700778","tarball":"http://registry.npmjs.org/uglify-js/-/uglify-js-1.0.4.tgz"},"directories":{}},"1.0.5":{"name":"uglify-js","author":{"name":"Mihai Bazon","email":"mihai.bazon@gmail.com","url":"http://mihai.bazon.net/blog"},"version":"1.0.5","main":"./uglify-js.js","bin":{"uglifyjs":"./bin/uglifyjs"},"repository":{"type":"git","url":"git@github.com:mishoo/UglifyJS.git"},"dependencies":{},"devDependencies":{},"_id":"uglify-js@1.0.5","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.1rc5","_nodeVersion":"v0.5.0-pre","_defaultsLoaded":true,"dist":{"shasum":"25679bdcff52f9500774a644cef3129b8ddb5cf2","tarball":"http://registry.npmjs.org/uglify-js/-/uglify-js-1.0.5.tgz"},"directories":{}},"1.0.6":{"name":"uglify-js","author":{"name":"Mihai Bazon","email":"mihai.bazon@gmail.com","url":"http://mihai.bazon.net/blo
-silly chunk g"},"version":"1.0.6","main":"./uglify-js.js","bin":{"uglifyjs":"./bin/uglifyjs"},"repository":{"type":"git","url":"git@github.com:mishoo/UglifyJS.git"},"dependencies":{},"devDependencies":{},"_id":"uglify-js@1.0.6","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.1rc5","_nodeVersion":"v0.5.0-pre","_defaultsLoaded":true,"dist":{"shasum":"f0d3aafd463f26a437b9ebc19f4947ab7e8078aa","tarball":"http://registry.npmjs.org/uglify-js/-/uglify-js-1.0.6.tgz"},"directories":{}}},"maintainers":[{"name":"caires","email":"cairesvs@gmail.com"},{"name":"mape","email":"mape@mape.me"},{"name":"mishoo","email":"mihai.bazon@gmail.com"}],"author":{"name":"Mihai Bazon","email":"mihai.bazon@gmail.com","url":"http://mihai.bazon.net/blog"},"time":{"0.0.1":"2011-01-05T17:56:48.593Z","0.0.2":"2011-01-09T13:47:55.729Z","0.0.3":"2011-01-25T05:53:18.848Z","0.0.4":"2011-02-05T13:28:37.926Z","0.0.5":"2011-02-20T16:37:04.786Z","1.0.1":"2011-04-03T22:03:32.396Z","1.0.2":"2011-05-19T16:13:13.281Z","1.0.3":"2011-06-27T16:52:42.404Z","1.0.4":"2011-07-01T10:26:41.824Z","1.0.5":"2011-07-14T09:54:00.537Z","1.0.6":"2011-07-14T20:36:30.484Z"},"repository":{"type":"git","url":"git@github.com:mishoo/UglifyJS.git"}}
-silly get cb [ 200,
-silly get cb   { vary: 'Accept',
-silly get cb     server: 'CouchDB/1.1.0 (Erlang OTP/R14B03)',
-silly get cb     etag: '"2CZS2DKWM45Z3WMB02DQSV95J"',
-silly get cb     date: 'Sat, 23 Jul 2011 12:25:08 GMT',
-silly get cb     'content-type': 'application/json',
-silly get cb     'content-length': '6718' } ]
-verbose GET uglify-js/1.0.6
-verbose raw, before any munging uglify-js/1.0.6
-verbose url resolving [ 'http://registry.npmjs.org/', './uglify-js/1.0.6' ]
-verbose url resolved http://registry.npmjs.org/uglify-js/1.0.6
-verbose url parsed { protocol: 'http:',
-verbose url parsed   slashes: true,
-verbose url parsed   host: 'registry.npmjs.org',
-verbose url parsed   hostname: 'registry.npmjs.org',
-verbose url parsed   href: 'http://registry.npmjs.org/uglify-js/1.0.6',
-verbose url parsed   pathname: '/uglify-js/1.0.6' }
-verbose response http://registry.npmjs.org/uglify-js/1.0.6
-silly chunk {"name":"uglify-js","author":{"name":"Mihai Bazon","email":"mihai.bazon@gmail.com","url":"http://mihai.bazon.net/blog"},"version":"1.0.6","main":"./uglify-js.js","bin":{"uglifyjs":"./bin/uglifyjs"},"repository":{"type":"git","url":"git@github.com:mishoo/UglifyJS.git"},"dependencies":{},"devDependencies":{},"_id":"uglify-js@1.0.6","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.1rc5","_nodeVersion":"v0.5.0-pre","_defaultsLoaded":true,"dist":{"shasum":"f0d3aafd463f26a437b9ebc19f4947ab7e8078aa","tarball":"http://registry.npmjs.org/uglify-js/-/uglify-js-1.0.6.tgz"},"directories":{}}
-silly get cb [ 200,
-silly get cb   { vary: 'Accept',
-silly get cb     server: 'CouchDB/1.1.0 (Erlang OTP/R14B03)',
-silly get cb     etag: '"2CZS2DKWM45Z3WMB02DQSV95J"',
-silly get cb     date: 'Sat, 23 Jul 2011 12:25:09 GMT',
-silly get cb     'content-type': 'application/json',
-silly get cb     'content-length': '603' } ]
-verbose mkdir done: /root/.npm/uglify-js/1.0.6 755
-verbose bin dist [ '0.4-ares1.7.4-ev4.4-openssl0.9.8o-v83.1.8.25-linux-2.6.35-30-generic',
-verbose bin dist   { shasum: 'f0d3aafd463f26a437b9ebc19f4947ab7e8078aa',
-verbose bin dist     tarball: 'http://registry.npmjs.org/uglify-js/-/uglify-js-1.0.6.tgz' } ]
-verbose addRemoteTarball [ 'http://registry.npmjs.org/uglify-js/-/uglify-js-1.0.6.tgz',
-verbose addRemoteTarball   'f0d3aafd463f26a437b9ebc19f4947ab7e8078aa' ]
-verbose mkdir done: /tmp/npm-1311423850738/1311423850738-0.8425169289112091 755
-info fetch http://registry.npmjs.org/uglify-js/-/uglify-js-1.0.6.tgz
-verbose fetch to /tmp/npm-1311423850738/1311423850738-0.8425169289112091/tmp.tgz
-silly updated sha bytes 40960
-silly updated sha bytes 12084
-info shasum f0d3aafd463f26a437b9ebc19f4947ab7e8078aa
-info shasum /tmp/npm-1311423850738/1311423850738-0.8425169289112091/tmp.tgz
-verbose mkdir done: /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm 755
-verbose unpack_ uid, gid [ 1000, 1000 ]
-verbose unpackTarget /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/package
-silly gunzTarPerm modes [ '755', '644' ]
-verbose success gzip "--decompress" "--stdout" "/tmp/npm-1311423850738/1311423850738-0.8425169289112091/tmp.tgz"
-verbose success tar "-mvxpf" "-" "--no-same-owner" "-C" "/tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm"
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/uglify-js.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/docstyle.css
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/package.json
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/README.html
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/README.org
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/.gitignore
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/bin/
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/bin/uglifyjs
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/tmp/
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/tmp/instrument2.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/tmp/instrument.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/lib/
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/lib/parse-js.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/lib/squeeze-more.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/lib/process.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/testparser.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/beautify.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/scripts.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue68.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue10.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue30.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue21.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue13.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue28.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue50.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/array3.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/concatstring.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue17.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue11.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/assignment.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/var.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/if.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/empty-blocks.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue16.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue53.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/with.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/ifreturn2.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue14.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue48.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/mangle.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/array1.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue20.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/array4.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue25.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue54.1.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/const.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/strict-equals.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue27.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue69.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/forstatement.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue29.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/array2.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue9.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/ifreturn.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue34.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/expected/issue4.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue68.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue10.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue30.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue21.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue13.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue28.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue50.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/array3.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/concatstring.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue17.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue11.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/assignment.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/var.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/if.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/empty-blocks.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue16.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue53.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/with.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/ifreturn2.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue14.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue48.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/mangle.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/array1.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue20.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/array4.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue25.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue54.1.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/const.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/strict-equals.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue27.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue69.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/forstatement.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue29.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/array2.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue9.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/ifreturn.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue34.js
-silly asyncMap in gTP /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package/test/unit/compress/test/issue4.js
-verbose gunzed /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package
-verbose rm'ed /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/package
-verbose renamed [ '/tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/___package.npm/package',
-verbose renamed   '/tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/package' ]
-silly testEngine { name: 'uglify-js',
-silly testEngine   author: 
-silly testEngine    { name: 'Mihai Bazon',
-silly testEngine      email: 'mihai.bazon@gmail.com',
-silly testEngine      url: 'http://mihai.bazon.net/blog' },
-silly testEngine   version: '1.0.6',
-silly testEngine   main: './uglify-js.js',
-silly testEngine   bin: { uglifyjs: './bin/uglifyjs' },
-silly testEngine   repository: 
-silly testEngine    { type: 'git',
-silly testEngine      url: 'git@github.com:mishoo/UglifyJS.git' },
-silly testEngine   _npmJsonOpts: 
-silly testEngine    { file: '/tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/package/package.json',
-silly testEngine      wscript: false,
-silly testEngine      contributors: false,
-silly testEngine      serverjs: false },
-silly testEngine   _id: 'uglify-js@1.0.6',
-silly testEngine   dependencies: {},
-silly testEngine   devDependencies: {},
-silly testEngine   engines: { node: '*' },
-silly testEngine   _engineSupported: true,
-silly testEngine   _npmVersion: '1.0.15',
-silly testEngine   _nodeVersion: 'v0.4.10-pre',
-silly testEngine   _defaultsLoaded: true,
-silly testEngine   path: '/tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/package' }
-verbose caching /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/package/package.json
-verbose loadDefaults uglify-js@1.0.6
-verbose tarball contents [ 'package' ]
-verbose from cache /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/package/package.json
-verbose pack /tmp/npm-1311423850738/1311423850738-0.8425169289112091/contents/package /root/.npm/uglify-js/1.0.6/package.tgz
-verbose mkdir'ed /root/.npm/uglify-js/1.0.6
-verbose tar about to write tar and gzip it.
-silly tar args [ '-cvf',
-silly tar args   '-',
-silly tar args   'package/uglify-js.js',
-silly tar args   'package/docstyle.css',
-silly tar args   'package/package.json',
-silly tar args   'package/README.html',
-silly tar args   'package/README.org',
-silly tar args   'package/.gitignore',
-silly tar args   'package/bin/uglifyjs',
-silly tar args   'package/tmp/instrument2.js',
-silly tar args   'package/tmp/instrument.js',
-silly tar args   'package/lib/parse-js.js',
-silly tar args   'package/lib/squeeze-more.js',
-silly tar args   'package/lib/process.js',
-silly tar args   'package/test/testparser.js',
-silly tar args   'package/test/beautify.js',
-silly tar args   'package/test/unit/scripts.js',
-silly tar args   'package/test/unit/compress/expected/issue68.js',
-silly tar args   'package/test/unit/compress/expected/issue10.js',
-silly tar args   'package/test/unit/compress/expected/issue30.js',
-silly tar args   'package/test/unit/compress/expected/issue21.js',
-silly tar args   'package/test/unit/compress/expected/issue13.js',
-silly tar args   'package/test/unit/compress/expected/issue28.js',
-silly tar args   'package/test/unit/compress/expected/issue50.js',
-silly tar args   'package/test/unit/compress/expected/array3.js',
-silly tar args   'package/test/unit/compress/expected/concatstring.js',
-silly tar args   'package/test/unit/compress/expected/issue17.js',
-silly tar args   'package/test/unit/compress/expected/issue11.js',
-silly tar args   'package/test/unit/compress/expected/assignment.js',
-silly tar args   'package/test/unit/compress/expected/var.js',
-silly tar args   'package/test/unit/compress/expected/if.js',
-silly tar args   'package/test/unit/compress/expected/empty-blocks.js',
-silly tar args   'package/test/unit/compress/expected/issue16.js',
-silly tar args   'package/test/unit/compress/expected/issue53.js',
-silly tar args   'package/test/unit/compress/expected/with.js',
-silly tar args   'package/test/unit/compress/expected/ifreturn2.js',
-silly tar args   'package/test/unit/compress/expected/issue14.js',
-silly tar args   'package/test/unit/compress/expected/issue48.js',
-silly tar args   'package/test/unit/compress/expected/mangle.js',
-silly tar args   'package/test/unit/compress/expected/array1.js',
-silly tar args   'package/test/unit/compress/expected/issue20.js',
-silly tar args   'package/test/unit/compress/expected/array4.js',
-silly tar args   'package/test/unit/compress/expected/issue25.js',
-silly tar args   'package/test/unit/compress/expected/issue54.1.js',
-silly tar args   'package/test/unit/compress/expected/const.js',
-silly tar args   'package/test/unit/compress/expected/strict-equals.js',
-silly tar args   'package/test/unit/compress/expected/issue27.js',
-silly tar args   'package/test/unit/compress/expected/issue69.js',
-silly tar args   'package/test/unit/compress/expected/forstatement.js',
-silly tar args   'package/test/unit/compress/expected/issue29.js',
-silly tar args   'package/test/unit/compress/expected/array2.js',
-silly tar args   'package/test/unit/compress/expected/issue9.js',
-silly tar args   'package/test/unit/compress/expected/ifreturn.js',
-silly tar args   'package/test/unit/compress/expected/issue34.js',
-silly tar args   'package/test/unit/compress/expected/issue4.js',
-silly tar args   'package/test/unit/compress/test/issue68.js',
-silly tar args   'package/test/unit/compress/test/issue10.js',
-silly tar args   'package/test/unit/compress/test/issue30.js',
-silly tar args   'package/test/unit/compress/test/issue21.js',
-silly tar args   'package/test/unit/compress/test/issue13.js',
-silly tar args   'package/test/unit/compress/test/issue28.js',
-silly tar args   'package/test/unit/compress/test/issue50.js',
-silly tar args   'package/test/unit/compress/test/array3.js',
-silly tar args   'package/test/unit/compress/test/concatstring.js',
-silly tar args   'package/test/unit/compress/test/issue17.js',
-silly tar args   'package/test/unit/compress/test/issue11.js',
-silly tar args   'package/test/unit/compress/test/assignment.js',
-silly tar args   'package/test/unit/compress/test/var.js',
-silly tar args   'package/test/unit/compress/test/if.js',
-silly tar args   'package/test/unit/compress/test/empty-blocks.js',
-silly tar args   'package/test/unit/compress/test/issue16.js',
-silly tar args   'package/test/unit/compress/test/issue53.js',
-silly tar args   'package/test/unit/compress/test/with.js',
-silly tar args   'package/test/unit/compress/test/ifreturn2.js',
-silly tar args   'package/test/unit/compress/test/issue14.js',
-silly tar args   'package/test/unit/compress/test/issue48.js',
-silly tar args   'package/test/unit/compress/test/mangle.js',
-silly tar args   'package/test/unit/compress/test/array1.js',
-silly tar args   'package/test/unit/compress/test/issue20.js',
-silly tar args   'package/test/unit/compress/test/array4.js',
-silly tar args   'package/test/unit/compress/test/issue25.js',
-silly tar args   'package/test/unit/compress/test/issue54.1.js',
-silly tar args   'package/test/unit/compress/test/const.js',
-silly tar args   'package/test/unit/compress/test/strict-equals.js',
-silly tar args   'package/test/unit/compress/test/issue27.js',
-silly tar args   'package/test/unit/compress/test/issue69.js',
-silly tar args   'package/test/unit/compress/test/forstatement.js',
-silly tar args   'package/test/unit/compress/test/issue29.js',
-silly tar args   'package/test/unit/compress/test/array2.js',
-silly tar args   'package/test/unit/compress/test/issue9.js',
-silly tar args   'package/test/unit/compress/test/ifreturn.js',
-silly tar args   'package/test/unit/compress/test/issue34.js',
-silly tar args   'package/test/unit/compress/test/issue4.js' ]
-verbose success tar -cvf - <file list elided>
-verbose success gzip "--stdout"
-verbose mkdir done: /root/.npm/uglify-js/1.0.6/___package.npm 755
-verbose unpack_ uid, gid [ 1000, 1000 ]
-verbose unpackTarget /root/.npm/uglify-js/1.0.6/package
-silly gunzTarPerm modes [ '755', '644' ]
-verbose success gzip "--decompress" "--stdout" "/root/.npm/uglify-js/1.0.6/package.tgz"
-verbose success tar "-mvxpf" "-" "--no-same-owner" "-C" "/root/.npm/uglify-js/1.0.6/___package.npm"
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/uglify-js.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/docstyle.css
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/package.json
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/README.html
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/README.org
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/.gitignore
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/bin/
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/bin/uglifyjs
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/lib/
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/lib/parse-js.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/lib/squeeze-more.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/lib/process.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/tmp/
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/tmp/instrument2.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/tmp/instrument.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/testparser.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/beautify.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/scripts.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue68.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue10.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue30.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue21.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue13.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue28.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue50.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/array3.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/concatstring.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue17.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue11.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/assignment.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/var.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/if.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/empty-blocks.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue16.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue53.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/with.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/ifreturn2.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue14.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue48.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/mangle.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/array1.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue20.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/array4.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue25.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue54.1.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/const.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/strict-equals.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue27.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue69.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/forstatement.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue29.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/array2.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue9.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/ifreturn.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue34.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/expected/issue4.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue68.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue10.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue30.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue21.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue13.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue28.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue50.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/array3.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/concatstring.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue17.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue11.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/assignment.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/var.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/if.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/empty-blocks.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue16.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue53.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/with.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/ifreturn2.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue14.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue48.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/mangle.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/array1.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue20.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/array4.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue25.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue54.1.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/const.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/strict-equals.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue27.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue69.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/forstatement.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue29.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/array2.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue9.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/ifreturn.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue34.js
-silly asyncMap in gTP /root/.npm/uglify-js/1.0.6/___package.npm/package/test/unit/compress/test/issue4.js
-verbose gunzed /root/.npm/uglify-js/1.0.6/___package.npm/package
-verbose rm'ed /root/.npm/uglify-js/1.0.6/package
-verbose renamed [ '/root/.npm/uglify-js/1.0.6/___package.npm/package',
-verbose renamed   '/root/.npm/uglify-js/1.0.6/package' ]
-silly testEngine { name: 'uglify-js',
-silly testEngine   author: 
-silly testEngine    { name: 'Mihai Bazon',
-silly testEngine      email: 'mihai.bazon@gmail.com',
-silly testEngine      url: 'http://mihai.bazon.net/blog' },
-silly testEngine   version: '1.0.6',
-silly testEngine   main: './uglify-js.js',
-silly testEngine   bin: { uglifyjs: './bin/uglifyjs' },
-silly testEngine   repository: 
-silly testEngine    { type: 'git',
-silly testEngine      url: 'git@github.com:mishoo/UglifyJS.git' },
-silly testEngine   _npmJsonOpts: 
-silly testEngine    { file: '/root/.npm/uglify-js/1.0.6/package/package.json',
-silly testEngine      wscript: false,
-silly testEngine      contributors: false,
-silly testEngine      serverjs: false },
-silly testEngine   _id: 'uglify-js@1.0.6',
-silly testEngine   dependencies: {},
-silly testEngine   devDependencies: {},
-silly testEngine   engines: { node: '*' },
-silly testEngine   _engineSupported: true,
-silly testEngine   _npmVersion: '1.0.15',
-silly testEngine   _nodeVersion: 'v0.4.10-pre',
-silly testEngine   _defaultsLoaded: true,
-silly testEngine   dist: { shasum: 'eabbc5c1ccc65c6cb0f337ae43ecdf2be277cd8e' } }
-verbose caching /root/.npm/uglify-js/1.0.6/package/package.json
-verbose loadDefaults uglify-js@1.0.6
-silly updated sha bytes 40960
-silly updated sha bytes 12384
-info shasum eabbc5c1ccc65c6cb0f337ae43ecdf2be277cd8e
-info shasum /root/.npm/uglify-js/1.0.6/package.tgz
-verbose from cache /root/.npm/uglify-js/1.0.6/package/package.json
-verbose chmod /root/.npm/uglify-js/1.0.6/package.tgz 644
-silly resolved [ { name: 'uglify-js',
-silly resolved     author: 
-silly resolved      { name: 'Mihai Bazon',
-silly resolved        email: 'mihai.bazon@gmail.com',
-silly resolved        url: 'http://mihai.bazon.net/blog' },
-silly resolved     version: '1.0.6',
-silly resolved     main: './uglify-js.js',
-silly resolved     bin: { uglifyjs: './bin/uglifyjs' },
-silly resolved     repository: 
-silly resolved      { type: 'git',
-silly resolved        url: 'git@github.com:mishoo/UglifyJS.git' },
-silly resolved     _npmJsonOpts: 
-silly resolved      { file: '/root/.npm/uglify-js/1.0.6/package/package.json',
-silly resolved        wscript: false,
-silly resolved        contributors: false,
-silly resolved        serverjs: false },
-silly resolved     _id: 'uglify-js@1.0.6',
-silly resolved     dependencies: {},
-silly resolved     devDependencies: {},
-silly resolved     engines: { node: '*' },
-silly resolved     _engineSupported: true,
-silly resolved     _npmVersion: '1.0.15',
-silly resolved     _nodeVersion: 'v0.4.10-pre',
-silly resolved     _defaultsLoaded: true,
-silly resolved     dist: { shasum: 'eabbc5c1ccc65c6cb0f337ae43ecdf2be277cd8e' } } ]
-info into /var/www/kiwi/KiwiIRC/node uglify-js@1.0.6
-info installOne uglify-js@1.0.6
-info unbuild /var/www/kiwi/KiwiIRC/node/node_modules/uglify-js
-verbose from cache /root/.npm/uglify-js/1.0.6/package/package.json
-verbose mkdir done: /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm 755
-verbose unpack_ uid, gid [ 1000, 1000 ]
-verbose unpackTarget /var/www/kiwi/KiwiIRC/node/node_modules/uglify-js
-silly gunzTarPerm modes [ '755', '644' ]
-verbose success gzip "--decompress" "--stdout" "/root/.npm/uglify-js/1.0.6/package.tgz"
-verbose success tar "-mvxpf" "-" "--no-same-owner" "-C" "/var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm"
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/.gitignore
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/docstyle.css
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/package.json
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/README.html
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/README.org
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/uglify-js.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/bin/
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/bin/uglifyjs
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/tmp/
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/tmp/instrument.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/tmp/instrument2.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/lib/
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/lib/parse-js.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/lib/process.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/lib/squeeze-more.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/beautify.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/testparser.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/scripts.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array1.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array2.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array3.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/array4.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/assignment.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/concatstring.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/const.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/empty-blocks.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/forstatement.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/if.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/ifreturn.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/ifreturn2.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue10.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue11.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue13.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue14.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue16.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue17.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue20.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue21.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue25.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue27.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue28.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue29.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue30.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue34.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue4.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue48.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue50.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue53.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue54.1.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue68.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue69.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/issue9.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/mangle.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/strict-equals.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/var.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/test/with.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array1.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array2.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array3.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/array4.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/assignment.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/concatstring.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/const.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/empty-blocks.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/forstatement.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/if.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/ifreturn.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/ifreturn2.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue10.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue11.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue13.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue14.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue16.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue17.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue20.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue21.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue25.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue27.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue28.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue29.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue30.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue34.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue4.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue48.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue50.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue53.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue54.1.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue68.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue69.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/issue9.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/mangle.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/strict-equals.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/var.js
-silly asyncMap in gTP /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package/test/unit/compress/expected/with.js
-verbose gunzed /var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package
-verbose rm'ed /var/www/kiwi/KiwiIRC/node/node_modules/uglify-js
-ERR! error installing uglify-js@1.0.6 Error: EACCES, Permission denied '/var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package'
-info unbuild /var/www/kiwi/KiwiIRC/node/node_modules/uglify-js
-verbose installOne cb uglify-js@1.0.6
-ERR! Error: EACCES, Permission denied '/var/www/kiwi/KiwiIRC/node/node_modules/___uglify-js.npm/package'
-ERR! 
-ERR! Please use 'sudo' or log in as root to run this command.
-ERR!     sudo npm "install" "uglify-js"
-ERR! or set the 'unsafe-perm' config var to true.
-ERR!     npm config set unsafe-perm true
-ERR! 
-ERR! System Linux 2.6.35-30-generic
-ERR! command "node" "/root/local/node/bin/npm" "install" "uglify-js"
-verbose exit [ 13, true ]