From 620f2626a3d9de6c9c7bdbc380b9a58cfe282591 Mon Sep 17 00:00:00 2001 From: logsol Date: Sat, 16 Jun 2012 22:03:03 +0200 Subject: [PATCH] added networking tests --- networking/app.js | 94 + networking/app.js~ | 94 + networking/box2d.js | 10864 ++ networking/client.js | 107 + networking/client.js~ | 107 + networking/common.js | 82 + networking/common.js~ | 82 + networking/index.html | 15 + networking/index.html~ | 15 + networking/node_modules/box2d/README | 58 + networking/node_modules/box2d/box2dnode.js | 11132 ++ networking/node_modules/box2d/package.json | 24 + networking/node_modules/socket.io/.npmignore | 3 + networking/node_modules/socket.io/.travis.yml | 6 + networking/node_modules/socket.io/History.md | 260 + networking/node_modules/socket.io/Makefile | 31 + networking/node_modules/socket.io/Readme.md | 345 + .../socket.io/benchmarks/decode.bench.js | 64 + .../socket.io/benchmarks/encode.bench.js | 90 + .../socket.io/benchmarks/runner.js | 55 + .../socket.io/examples/chat/app.js | 80 + .../socket.io/examples/chat/index.jade | 83 + .../socket.io/examples/chat/package.json | 11 + .../chat/public/stylesheets/mixins.styl | 96 + .../chat/public/stylesheets/style.css | 188 + .../chat/public/stylesheets/style.styl | 118 + .../socket.io/examples/irc-output/app.js | 74 + .../socket.io/examples/irc-output/index.jade | 28 + .../socket.io/examples/irc-output/irc.js | 164 + .../examples/irc-output/package.json | 10 + .../irc-output/public/stylesheets/style.styl | 69 + networking/node_modules/socket.io/index.js | 8 + .../node_modules/socket.io/lib/client.js | 167 + .../node_modules/socket.io/lib/logger.js | 97 + .../node_modules/socket.io/lib/manager.js | 984 + .../node_modules/socket.io/lib/namespace.js | 355 + .../node_modules/socket.io/lib/parser.js | 249 + .../node_modules/socket.io/lib/socket.io.js | 136 + .../node_modules/socket.io/lib/socket.js | 369 + .../node_modules/socket.io/lib/static.js | 395 + .../node_modules/socket.io/lib/store.js | 98 + .../socket.io/lib/stores/memory.js | 143 + .../socket.io/lib/stores/redis.js | 269 + .../node_modules/socket.io/lib/transport.js | 534 + .../socket.io/lib/transports/flashsocket.js | 106 + .../socket.io/lib/transports/htmlfile.js | 82 + .../socket.io/lib/transports/http-polling.js | 147 + .../socket.io/lib/transports/http.js | 119 + .../socket.io/lib/transports/index.js | 12 + .../socket.io/lib/transports/jsonp-polling.js | 97 + .../socket.io/lib/transports/websocket.js | 36 + .../lib/transports/websocket/default.js | 360 + .../lib/transports/websocket/hybi-07-12.js | 622 + .../lib/transports/websocket/hybi-16.js | 622 + .../lib/transports/websocket/index.js | 11 + .../socket.io/lib/transports/xhr-polling.js | 69 + networking/node_modules/socket.io/lib/util.js | 50 + .../node_modules/policyfile/.npmignore | 1 + .../socket.io/node_modules/policyfile/LICENSE | 19 + .../node_modules/policyfile/Makefile | 7 + .../node_modules/policyfile/README.md | 98 + .../node_modules/policyfile/doc/index.html | 375 + .../policyfile/examples/basic.fallback.js | 8 + .../node_modules/policyfile/examples/basic.js | 5 + .../node_modules/policyfile/index.js | 1 + .../node_modules/policyfile/lib/server.js | 289 + .../node_modules/policyfile/package.json | 55 + .../node_modules/policyfile/tests/ssl/ssl.crt | 21 + .../policyfile/tests/ssl/ssl.private.key | 27 + .../policyfile/tests/unit.test.js | 231 + .../socket.io/node_modules/redis/README.md | 567 + .../socket.io/node_modules/redis/changelog.md | 184 + .../socket.io/node_modules/redis/eval_test.js | 9 + .../node_modules/redis/examples/auth.js | 5 + .../redis/examples/backpressure_drain.js | 33 + .../node_modules/redis/examples/extend.js | 24 + .../node_modules/redis/examples/file.js | 32 + .../node_modules/redis/examples/mget.js | 5 + .../node_modules/redis/examples/monitor.js | 10 + .../node_modules/redis/examples/multi.js | 46 + .../node_modules/redis/examples/multi2.js | 29 + .../node_modules/redis/examples/psubscribe.js | 33 + .../node_modules/redis/examples/pub_sub.js | 41 + .../node_modules/redis/examples/simple.js | 17 + .../node_modules/redis/examples/subqueries.js | 15 + .../node_modules/redis/examples/subquery.js | 19 + .../redis/examples/unix_socket.js | 29 + .../node_modules/redis/examples/web_server.js | 31 + .../node_modules/redis/generate_commands.js | 40 + .../socket.io/node_modules/redis/index.js | 860 + .../node_modules/redis/lib/commands.js | 126 + .../node_modules/redis/lib/parser/hiredis.js | 41 + .../redis/lib/parser/javascript.js | 316 + .../socket.io/node_modules/redis/lib/queue.js | 58 + .../node_modules/redis/lib/to_array.js | 12 + .../socket.io/node_modules/redis/lib/util.js | 6 + .../node_modules/redis/multi_bench.js | 135 + .../socket.io/node_modules/redis/package.json | 67 + .../node_modules/redis/simple_test.js | 3 + .../socket.io/node_modules/redis/test.js | 1248 + .../node_modules/redis/tests/buffer_bench.js | 89 + .../redis/tests/reconnect_test.js | 27 + .../node_modules/redis/tests/stress/codec.js | 16 + .../redis/tests/stress/pubsub/pub.js | 38 + .../redis/tests/stress/pubsub/run | 10 + .../redis/tests/stress/pubsub/server.js | 23 + .../redis/tests/stress/rpushblpop/pub.js | 49 + .../redis/tests/stress/rpushblpop/run | 6 + .../redis/tests/stress/rpushblpop/server.js | 30 + .../node_modules/redis/tests/stress/speed/00 | 13 + .../redis/tests/stress/speed/plot | 13 + .../redis/tests/stress/speed/size-rate.png | Bin 0 -> 6672 bytes .../redis/tests/stress/speed/speed.js | 84 + .../node_modules/redis/tests/sub_quit_test.js | 18 + .../redis/tests/test_start_stop.js | 17 + .../node_modules/socket.io-client/.npmignore | 2 + .../node_modules/socket.io-client/History.md | 192 + .../node_modules/socket.io-client/Makefile | 20 + .../node_modules/socket.io-client/README.md | 246 + .../socket.io-client/bin/builder.js | 281 + .../socket.io-client/dist/WebSocketMain.swf | Bin 0 -> 175830 bytes .../dist/WebSocketMainInsecure.swf | Bin 0 -> 175953 bytes .../socket.io-client/dist/socket.io.js | 3788 + .../socket.io-client/dist/socket.io.min.js | 2 + .../socket.io-client/lib/events.js | 184 + .../node_modules/socket.io-client/lib/io.js | 206 + .../node_modules/socket.io-client/lib/json.js | 322 + .../socket.io-client/lib/namespace.js | 242 + .../socket.io-client/lib/parser.js | 262 + .../socket.io-client/lib/socket.io-client.js | 1 + .../socket.io-client/lib/socket.js | 551 + .../socket.io-client/lib/transport.js | 245 + .../lib/transports/flashsocket.js | 191 + .../lib/transports/htmlfile.js | 171 + .../lib/transports/jsonp-polling.js | 256 + .../lib/transports/websocket.js | 184 + .../lib/transports/xhr-polling.js | 161 + .../socket.io-client/lib/transports/xhr.js | 217 + .../node_modules/socket.io-client/lib/util.js | 356 + .../lib/vendor/web-socket-js/.npmignore | 1 + .../lib/vendor/web-socket-js/README.md | 157 + .../vendor/web-socket-js/WebSocketMain.swf | Bin 0 -> 175830 bytes .../web-socket-js/WebSocketMainInsecure.zip | Bin 0 -> 166610 bytes .../flash-src/IWebSocketLogger.as | 8 + .../web-socket-js/flash-src/WebSocket.as | 464 + .../web-socket-js/flash-src/WebSocketEvent.as | 33 + .../web-socket-js/flash-src/WebSocketMain.as | 150 + .../flash-src/WebSocketMainInsecure.as | 19 + .../vendor/web-socket-js/flash-src/build.sh | 10 + .../com/adobe/net/proxies/RFC2817Socket.as | 204 + .../flash-src/com/gsolo/encryption/MD5.as | 375 + .../flash-src/com/hurlant/crypto/Crypto.as | 287 + .../crypto/cert/MozillaRootCertificates.as | 3235 + .../hurlant/crypto/cert/X509Certificate.as | 218 + .../crypto/cert/X509CertificateCollection.as | 57 + .../flash-src/com/hurlant/crypto/hash/HMAC.as | 82 + .../com/hurlant/crypto/hash/IHMAC.as | 27 + .../com/hurlant/crypto/hash/IHash.as | 21 + .../flash-src/com/hurlant/crypto/hash/MAC.as | 137 + .../flash-src/com/hurlant/crypto/hash/MD2.as | 124 + .../flash-src/com/hurlant/crypto/hash/MD5.as | 204 + .../flash-src/com/hurlant/crypto/hash/SHA1.as | 106 + .../com/hurlant/crypto/hash/SHA224.as | 28 + .../com/hurlant/crypto/hash/SHA256.as | 115 + .../com/hurlant/crypto/hash/SHABase.as | 71 + .../flash-src/com/hurlant/crypto/prng/ARC4.as | 90 + .../com/hurlant/crypto/prng/IPRNG.as | 20 + .../com/hurlant/crypto/prng/Random.as | 119 + .../com/hurlant/crypto/prng/TLSPRF.as | 142 + .../com/hurlant/crypto/rsa/RSAKey.as | 339 + .../com/hurlant/crypto/symmetric/AESKey.as | 2797 + .../hurlant/crypto/symmetric/BlowFishKey.as | 375 + .../com/hurlant/crypto/symmetric/CBCMode.as | 55 + .../com/hurlant/crypto/symmetric/CFB8Mode.as | 61 + .../com/hurlant/crypto/symmetric/CFBMode.as | 64 + .../com/hurlant/crypto/symmetric/CTRMode.as | 58 + .../com/hurlant/crypto/symmetric/DESKey.as | 365 + .../com/hurlant/crypto/symmetric/ECBMode.as | 86 + .../com/hurlant/crypto/symmetric/ICipher.as | 21 + .../com/hurlant/crypto/symmetric/IMode.as | 15 + .../com/hurlant/crypto/symmetric/IPad.as | 32 + .../hurlant/crypto/symmetric/IStreamCipher.as | 21 + .../hurlant/crypto/symmetric/ISymmetricKey.as | 35 + .../com/hurlant/crypto/symmetric/IVMode.as | 110 + .../com/hurlant/crypto/symmetric/NullPad.as | 34 + .../com/hurlant/crypto/symmetric/OFBMode.as | 52 + .../com/hurlant/crypto/symmetric/PKCS5.as | 44 + .../com/hurlant/crypto/symmetric/SSLPad.as | 44 + .../hurlant/crypto/symmetric/SimpleIVMode.as | 60 + .../com/hurlant/crypto/symmetric/TLSPad.as | 42 + .../hurlant/crypto/symmetric/TripleDESKey.as | 88 + .../com/hurlant/crypto/symmetric/XTeaKey.as | 94 + .../com/hurlant/crypto/symmetric/aeskey.pl | 29 + .../com/hurlant/crypto/symmetric/dump.txt | 2304 + .../com/hurlant/crypto/tests/AESKeyTest.as | 1220 + .../com/hurlant/crypto/tests/ARC4Test.as | 58 + .../hurlant/crypto/tests/BigIntegerTest.as | 39 + .../hurlant/crypto/tests/BlowFishKeyTest.as | 148 + .../com/hurlant/crypto/tests/CBCModeTest.as | 160 + .../com/hurlant/crypto/tests/CFB8ModeTest.as | 71 + .../com/hurlant/crypto/tests/CFBModeTest.as | 98 + .../com/hurlant/crypto/tests/CTRModeTest.as | 109 + .../com/hurlant/crypto/tests/DESKeyTest.as | 112 + .../com/hurlant/crypto/tests/ECBModeTest.as | 151 + .../com/hurlant/crypto/tests/HMACTest.as | 184 + .../com/hurlant/crypto/tests/ITestHarness.as | 20 + .../com/hurlant/crypto/tests/MD2Test.as | 56 + .../com/hurlant/crypto/tests/MD5Test.as | 58 + .../com/hurlant/crypto/tests/OFBModeTest.as | 101 + .../com/hurlant/crypto/tests/RSAKeyTest.as | 92 + .../com/hurlant/crypto/tests/SHA1Test.as | 198 + .../com/hurlant/crypto/tests/SHA224Test.as | 58 + .../com/hurlant/crypto/tests/SHA256Test.as | 60 + .../com/hurlant/crypto/tests/TLSPRFTest.as | 51 + .../com/hurlant/crypto/tests/TestCase.as | 42 + .../hurlant/crypto/tests/TripleDESKeyTest.as | 59 + .../com/hurlant/crypto/tests/XTeaKeyTest.as | 66 + .../com/hurlant/crypto/tls/BulkCiphers.as | 102 + .../com/hurlant/crypto/tls/CipherSuites.as | 117 + .../hurlant/crypto/tls/IConnectionState.as | 14 + .../hurlant/crypto/tls/ISecurityParameters.as | 29 + .../com/hurlant/crypto/tls/KeyExchanges.as | 24 + .../flash-src/com/hurlant/crypto/tls/MACs.as | 38 + .../hurlant/crypto/tls/SSLConnectionState.as | 171 + .../com/hurlant/crypto/tls/SSLEvent.as | 26 + .../crypto/tls/SSLSecurityParameters.as | 340 + .../com/hurlant/crypto/tls/TLSConfig.as | 70 + .../hurlant/crypto/tls/TLSConnectionState.as | 151 + .../com/hurlant/crypto/tls/TLSEngine.as | 895 + .../com/hurlant/crypto/tls/TLSError.as | 39 + .../com/hurlant/crypto/tls/TLSEvent.as | 27 + .../crypto/tls/TLSSecurityParameters.as | 197 + .../com/hurlant/crypto/tls/TLSSocket.as | 370 + .../com/hurlant/crypto/tls/TLSSocketEvent.as | 26 + .../com/hurlant/crypto/tls/TLSTest.as | 180 + .../com/hurlant/math/BarrettReduction.as | 90 + .../flash-src/com/hurlant/math/BigInteger.as | 1543 + .../com/hurlant/math/ClassicReduction.as | 35 + .../flash-src/com/hurlant/math/IReduction.as | 11 + .../com/hurlant/math/MontgomeryReduction.as | 85 + .../com/hurlant/math/NullReduction.as | 34 + .../flash-src/com/hurlant/math/bi_internal.as | 11 + .../flash-src/com/hurlant/util/ArrayUtil.as | 25 + .../flash-src/com/hurlant/util/Base64.as | 189 + .../flash-src/com/hurlant/util/Hex.as | 66 + .../flash-src/com/hurlant/util/Memory.as | 28 + .../com/hurlant/util/der/ByteString.as | 43 + .../flash-src/com/hurlant/util/der/DER.as | 210 + .../com/hurlant/util/der/IAsn1Type.as | 21 + .../flash-src/com/hurlant/util/der/Integer.as | 44 + .../flash-src/com/hurlant/util/der/OID.as | 35 + .../com/hurlant/util/der/ObjectIdentifier.as | 112 + .../flash-src/com/hurlant/util/der/PEM.as | 118 + .../com/hurlant/util/der/PrintableString.as | 49 + .../com/hurlant/util/der/Sequence.as | 90 + .../flash-src/com/hurlant/util/der/Set.as | 27 + .../flash-src/com/hurlant/util/der/Type.as | 94 + .../flash-src/com/hurlant/util/der/UTCTime.as | 60 + .../lib/vendor/web-socket-js/sample.html | 75 + .../lib/vendor/web-socket-js/swfobject.js | 6 + .../lib/vendor/web-socket-js/web_socket.js | 349 + .../node_modules/.bin/uglifyjs | 1 + .../socket.io-client/node_modules/.bin/wscat | 1 + .../active-x-obfuscator/..gitignore.un~ | Bin 0 -> 1811 bytes .../active-x-obfuscator/.Readme.md.un~ | Bin 0 -> 1508 bytes .../active-x-obfuscator/.index.js.un~ | Bin 0 -> 220177 bytes .../active-x-obfuscator/.npmignore | 2 + .../active-x-obfuscator/.package.json.un~ | Bin 0 -> 1015 bytes .../active-x-obfuscator/.test.js.un~ | Bin 0 -> 76173 bytes .../active-x-obfuscator/Readme.md | 33 + .../node_modules/active-x-obfuscator/index.js | 83 + .../node_modules/zeparser/.npmignore | 1 + .../node_modules/zeparser/LICENSE | 19 + .../node_modules/zeparser/README | 37 + .../node_modules/zeparser/Tokenizer.js | 646 + .../node_modules/zeparser/ZeParser.js | 2180 + .../node_modules/zeparser/benchmark.html | 111608 +++++++++++++++ .../node_modules/zeparser/index.js | 1 + .../node_modules/zeparser/package.json | 30 + .../node_modules/zeparser/test-parser.html | 26 + .../node_modules/zeparser/test-tokenizer.html | 23 + .../node_modules/zeparser/tests.js | 478 + .../zeparser/unicodecategories.js | 49 + .../active-x-obfuscator/package.json | 36 + .../node_modules/active-x-obfuscator/test.js | 53 + .../node_modules/uglify-js/.npmignore | 4 + .../node_modules/uglify-js/README.html | 981 + .../node_modules/uglify-js/README.org | 574 + .../node_modules/uglify-js/bin/uglifyjs | 323 + .../node_modules/uglify-js/docstyle.css | 75 + .../node_modules/uglify-js/lib/object-ast.js | 75 + .../node_modules/uglify-js/lib/parse-js.js | 1342 + .../node_modules/uglify-js/lib/process.js | 2011 + .../uglify-js/lib/squeeze-more.js | 69 + .../node_modules/uglify-js/package.json | 33 + .../node_modules/uglify-js/package.json~ | 24 + .../node_modules/uglify-js/test/beautify.js | 28 + .../node_modules/uglify-js/test/testparser.js | 403 + .../test/unit/compress/expected/array1.js | 1 + .../test/unit/compress/expected/array2.js | 1 + .../test/unit/compress/expected/array3.js | 1 + .../test/unit/compress/expected/array4.js | 1 + .../test/unit/compress/expected/assignment.js | 1 + .../unit/compress/expected/concatstring.js | 1 + .../test/unit/compress/expected/const.js | 1 + .../unit/compress/expected/empty-blocks.js | 1 + .../unit/compress/expected/forstatement.js | 1 + .../test/unit/compress/expected/if.js | 1 + .../test/unit/compress/expected/ifreturn.js | 1 + .../test/unit/compress/expected/ifreturn2.js | 1 + .../test/unit/compress/expected/issue10.js | 1 + .../test/unit/compress/expected/issue11.js | 1 + .../test/unit/compress/expected/issue13.js | 1 + .../test/unit/compress/expected/issue14.js | 1 + .../test/unit/compress/expected/issue16.js | 1 + .../test/unit/compress/expected/issue17.js | 1 + .../test/unit/compress/expected/issue20.js | 1 + .../test/unit/compress/expected/issue21.js | 1 + .../test/unit/compress/expected/issue25.js | 1 + .../test/unit/compress/expected/issue27.js | 1 + .../test/unit/compress/expected/issue278.js | 1 + .../test/unit/compress/expected/issue28.js | 1 + .../test/unit/compress/expected/issue29.js | 1 + .../test/unit/compress/expected/issue30.js | 1 + .../test/unit/compress/expected/issue34.js | 1 + .../test/unit/compress/expected/issue4.js | 1 + .../test/unit/compress/expected/issue48.js | 1 + .../test/unit/compress/expected/issue50.js | 1 + .../test/unit/compress/expected/issue53.js | 1 + .../test/unit/compress/expected/issue54.1.js | 1 + .../test/unit/compress/expected/issue68.js | 1 + .../test/unit/compress/expected/issue69.js | 1 + .../test/unit/compress/expected/issue9.js | 1 + .../test/unit/compress/expected/mangle.js | 1 + .../unit/compress/expected/null_string.js | 1 + .../unit/compress/expected/strict-equals.js | 1 + .../test/unit/compress/expected/var.js | 1 + .../test/unit/compress/expected/whitespace.js | 1 + .../test/unit/compress/expected/with.js | 1 + .../test/unit/compress/test/array1.js | 3 + .../test/unit/compress/test/array2.js | 4 + .../test/unit/compress/test/array3.js | 4 + .../test/unit/compress/test/array4.js | 6 + .../test/unit/compress/test/assignment.js | 20 + .../test/unit/compress/test/concatstring.js | 3 + .../test/unit/compress/test/const.js | 5 + .../test/unit/compress/test/empty-blocks.js | 4 + .../test/unit/compress/test/forstatement.js | 10 + .../uglify-js/test/unit/compress/test/if.js | 6 + .../test/unit/compress/test/ifreturn.js | 9 + .../test/unit/compress/test/ifreturn2.js | 16 + .../test/unit/compress/test/issue10.js | 1 + .../test/unit/compress/test/issue11.js | 3 + .../test/unit/compress/test/issue13.js | 1 + .../test/unit/compress/test/issue14.js | 1 + .../test/unit/compress/test/issue16.js | 1 + .../test/unit/compress/test/issue17.js | 4 + .../test/unit/compress/test/issue20.js | 1 + .../test/unit/compress/test/issue21.js | 6 + .../test/unit/compress/test/issue25.js | 7 + .../test/unit/compress/test/issue27.js | 1 + .../test/unit/compress/test/issue278.js | 1 + .../test/unit/compress/test/issue28.js | 3 + .../test/unit/compress/test/issue29.js | 1 + .../test/unit/compress/test/issue30.js | 3 + .../test/unit/compress/test/issue34.js | 3 + .../test/unit/compress/test/issue4.js | 3 + .../test/unit/compress/test/issue48.js | 1 + .../test/unit/compress/test/issue50.js | 9 + .../test/unit/compress/test/issue53.js | 1 + .../test/unit/compress/test/issue54.1.js | 3 + .../test/unit/compress/test/issue68.js | 5 + .../test/unit/compress/test/issue69.js | 1 + .../test/unit/compress/test/issue9.js | 4 + .../test/unit/compress/test/mangle.js | 5 + .../test/unit/compress/test/null_string.js | 1 + .../test/unit/compress/test/strict-equals.js | 3 + .../uglify-js/test/unit/compress/test/var.js | 3 + .../test/unit/compress/test/whitespace.js | 21 + .../uglify-js/test/unit/compress/test/with.js | 2 + .../uglify-js/test/unit/scripts.js | 55 + .../node_modules/uglify-js/tmp/269.js | 13 + .../node_modules/uglify-js/tmp/app.js | 22315 +++ .../uglify-js/tmp/embed-tokens.js | 15 + .../node_modules/uglify-js/tmp/goto.js | 26 + .../node_modules/uglify-js/tmp/goto2.js | 8 + .../node_modules/uglify-js/tmp/hoist.js | 33 + .../node_modules/uglify-js/tmp/instrument.js | 97 + .../node_modules/uglify-js/tmp/instrument2.js | 138 + .../node_modules/uglify-js/tmp/liftvars.js | 8 + .../node_modules/uglify-js/tmp/test.js | 30 + .../uglify-js/tmp/uglify-hangs.js | 3930 + .../uglify-js/tmp/uglify-hangs2.js | 166 + .../node_modules/uglify-js/uglify-js.js | 17 + .../node_modules/ws/.npmignore | 6 + .../node_modules/ws/.travis.yml | 5 + .../node_modules/ws/History.md | 220 + .../socket.io-client/node_modules/ws/Makefile | 38 + .../node_modules/ws/README.md | 159 + .../node_modules/ws/bench/parser.benchmark.js | 115 + .../node_modules/ws/bench/sender.benchmark.js | 66 + .../node_modules/ws/bench/speed.js | 105 + .../node_modules/ws/bench/util.js | 105 + .../node_modules/ws/bin/wscat | 185 + .../node_modules/ws/binding.gyp | 14 + .../node_modules/ws/doc/ws.md | 156 + .../ws/examples/fileapi/.npmignore | 1 + .../ws/examples/fileapi/package.json | 18 + .../ws/examples/fileapi/public/app.js | 39 + .../ws/examples/fileapi/public/index.html | 22 + .../ws/examples/fileapi/public/uploader.js | 55 + .../ws/examples/fileapi/server.js | 103 + .../serverstats-express_3/package.json | 17 + .../serverstats-express_3/public/index.html | 33 + .../examples/serverstats-express_3/server.js | 21 + .../ws/examples/serverstats/package.json | 17 + .../ws/examples/serverstats/public/index.html | 33 + .../ws/examples/serverstats/server.js | 19 + .../socket.io-client/node_modules/ws/index.js | 10 + .../node_modules/ws/install.js | 28 + .../node_modules/ws/lib/BufferPool.js | 59 + .../node_modules/ws/lib/BufferUtil.js | 16 + .../node_modules/ws/lib/BufferUtilWindows.js | 51 + .../node_modules/ws/lib/ErrorCodes.js | 24 + .../node_modules/ws/lib/Receiver.hixie.js | 142 + .../node_modules/ws/lib/Receiver.js | 586 + .../node_modules/ws/lib/Sender.hixie.js | 109 + .../node_modules/ws/lib/Sender.js | 211 + .../node_modules/ws/lib/Validation.js | 16 + .../node_modules/ws/lib/ValidationWindows.js | 16 + .../node_modules/ws/lib/WebSocket.js | 630 + .../node_modules/ws/lib/WebSocketServer.js | 417 + .../ws/node_modules/commander/.npmignore | 4 + .../ws/node_modules/commander/.travis.yml | 4 + .../ws/node_modules/commander/History.md | 99 + .../ws/node_modules/commander/Makefile | 7 + .../ws/node_modules/commander/Readme.md | 263 + .../ws/node_modules/commander/index.js | 2 + .../node_modules/commander/lib/commander.js | 992 + .../ws/node_modules/commander/package.json | 41 + .../ws/node_modules/options/.npmignore | 5 + .../ws/node_modules/options/Makefile | 12 + .../ws/node_modules/options/README.md | 3 + .../ws/node_modules/options/lib/options.js | 75 + .../ws/node_modules/options/package.json | 36 + .../options/test/fixtures/test.conf | 4 + .../node_modules/options/test/options.test.js | 119 + .../ws/node_modules/tinycolor/.npmignore | 5 + .../ws/node_modules/tinycolor/README.md | 3 + .../ws/node_modules/tinycolor/example.js | 3 + .../ws/node_modules/tinycolor/package.json | 30 + .../ws/node_modules/tinycolor/tinycolor.js | 31 + .../node_modules/ws/package.json | 49 + .../node_modules/ws/src/bufferutil.cc | 115 + .../node_modules/ws/src/validation.cc | 143 + .../node_modules/ws/test/BufferPool.test.js | 63 + .../ws/test/Receiver.hixie.test.js | 132 + .../node_modules/ws/test/Receiver.test.js | 255 + .../node_modules/ws/test/Sender.hixie.test.js | 116 + .../node_modules/ws/test/Sender.test.js | 24 + .../node_modules/ws/test/Validation.test.js | 23 + .../ws/test/WebSocket.integration.js | 42 + .../node_modules/ws/test/WebSocket.test.js | 1424 + .../ws/test/WebSocketServer.test.js | 1011 + .../node_modules/ws/test/autobahn-server.js | 29 + .../node_modules/ws/test/autobahn.js | 52 + .../ws/test/fixtures/certificate.pem | 13 + .../node_modules/ws/test/fixtures/key.pem | 15 + .../node_modules/ws/test/fixtures/request.pem | 11 + .../node_modules/ws/test/fixtures/textfile | 9 + .../node_modules/ws/test/hybi-common.js | 99 + .../node_modules/ws/test/testserver.js | 168 + .../node_modules/xmlhttprequest/README.md | 19 + .../xmlhttprequest/XMLHttpRequest.js | 309 + .../xmlhttprequest/autotest.watchr | 8 + .../node_modules/xmlhttprequest/demo.js | 16 + .../node_modules/xmlhttprequest/package.json | 37 + .../xmlhttprequest/tests/test-constants.js | 13 + .../xmlhttprequest/tests/test-headers.js | 35 + .../xmlhttprequest/tests/test-request.js | 62 + .../socket.io-client/package.json | 69 + .../socket.io-client/test/events.test.js | 121 + .../socket.io-client/test/io.test.js | 31 + .../test/node/builder.common.js | 102 + .../test/node/builder.test.js | 131 + .../socket.io-client/test/parser.test.js | 360 + .../socket.io-client/test/socket.test.js | 379 + .../socket.io-client/test/util.test.js | 156 + .../socket.io-client/test/worker.js | 20 + .../node_modules/socket.io/package.json | 69 + .../socket.io/restrict_jsonp.patch | 95 + .../support/node-websocket-client/LICENSE | 27 + .../support/node-websocket-client/Makefile | 22 + .../support/node-websocket-client/README.md | 41 + .../examples/client-unix.js | 12 + .../node-websocket-client/examples/client.js | 10 + .../examples/server-unix.js | 13 + .../node-websocket-client/lib/websocket.js | 617 + .../node-websocket-client/package.json | 22 + .../node-websocket-client/test/test-basic.js | 68 + .../test/test-client-close.js | 43 + .../test/test-readonly-attrs.js | 43 + .../test/test-ready-state.js | 26 + .../test/test-server-close.js | 41 + .../test/test-unix-send-fd.js | 63 + .../test/test-unix-sockets.js | 46 + 506 files changed, 228337 insertions(+) create mode 100644 networking/app.js create mode 100644 networking/app.js~ create mode 100644 networking/box2d.js create mode 100644 networking/client.js create mode 100644 networking/client.js~ create mode 100644 networking/common.js create mode 100644 networking/common.js~ create mode 100644 networking/index.html create mode 100644 networking/index.html~ create mode 100644 networking/node_modules/box2d/README create mode 100644 networking/node_modules/box2d/box2dnode.js create mode 100644 networking/node_modules/box2d/package.json create mode 100644 networking/node_modules/socket.io/.npmignore create mode 100644 networking/node_modules/socket.io/.travis.yml create mode 100644 networking/node_modules/socket.io/History.md create mode 100644 networking/node_modules/socket.io/Makefile create mode 100644 networking/node_modules/socket.io/Readme.md create mode 100644 networking/node_modules/socket.io/benchmarks/decode.bench.js create mode 100644 networking/node_modules/socket.io/benchmarks/encode.bench.js create mode 100644 networking/node_modules/socket.io/benchmarks/runner.js create mode 100644 networking/node_modules/socket.io/examples/chat/app.js create mode 100644 networking/node_modules/socket.io/examples/chat/index.jade create mode 100644 networking/node_modules/socket.io/examples/chat/package.json create mode 100644 networking/node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl create mode 100644 networking/node_modules/socket.io/examples/chat/public/stylesheets/style.css create mode 100644 networking/node_modules/socket.io/examples/chat/public/stylesheets/style.styl create mode 100644 networking/node_modules/socket.io/examples/irc-output/app.js create mode 100644 networking/node_modules/socket.io/examples/irc-output/index.jade create mode 100644 networking/node_modules/socket.io/examples/irc-output/irc.js create mode 100644 networking/node_modules/socket.io/examples/irc-output/package.json create mode 100644 networking/node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl create mode 100644 networking/node_modules/socket.io/index.js create mode 100644 networking/node_modules/socket.io/lib/client.js create mode 100644 networking/node_modules/socket.io/lib/logger.js create mode 100644 networking/node_modules/socket.io/lib/manager.js create mode 100644 networking/node_modules/socket.io/lib/namespace.js create mode 100644 networking/node_modules/socket.io/lib/parser.js create mode 100644 networking/node_modules/socket.io/lib/socket.io.js create mode 100644 networking/node_modules/socket.io/lib/socket.js create mode 100644 networking/node_modules/socket.io/lib/static.js create mode 100644 networking/node_modules/socket.io/lib/store.js create mode 100644 networking/node_modules/socket.io/lib/stores/memory.js create mode 100644 networking/node_modules/socket.io/lib/stores/redis.js create mode 100644 networking/node_modules/socket.io/lib/transport.js create mode 100644 networking/node_modules/socket.io/lib/transports/flashsocket.js create mode 100644 networking/node_modules/socket.io/lib/transports/htmlfile.js create mode 100644 networking/node_modules/socket.io/lib/transports/http-polling.js create mode 100644 networking/node_modules/socket.io/lib/transports/http.js create mode 100644 networking/node_modules/socket.io/lib/transports/index.js create mode 100644 networking/node_modules/socket.io/lib/transports/jsonp-polling.js create mode 100644 networking/node_modules/socket.io/lib/transports/websocket.js create mode 100644 networking/node_modules/socket.io/lib/transports/websocket/default.js create mode 100644 networking/node_modules/socket.io/lib/transports/websocket/hybi-07-12.js create mode 100644 networking/node_modules/socket.io/lib/transports/websocket/hybi-16.js create mode 100644 networking/node_modules/socket.io/lib/transports/websocket/index.js create mode 100644 networking/node_modules/socket.io/lib/transports/xhr-polling.js create mode 100644 networking/node_modules/socket.io/lib/util.js create mode 100644 networking/node_modules/socket.io/node_modules/policyfile/.npmignore create mode 100644 networking/node_modules/socket.io/node_modules/policyfile/LICENSE create mode 100644 networking/node_modules/socket.io/node_modules/policyfile/Makefile create mode 100644 networking/node_modules/socket.io/node_modules/policyfile/README.md create mode 100644 networking/node_modules/socket.io/node_modules/policyfile/doc/index.html create mode 100644 networking/node_modules/socket.io/node_modules/policyfile/examples/basic.fallback.js create mode 100644 networking/node_modules/socket.io/node_modules/policyfile/examples/basic.js create mode 100644 networking/node_modules/socket.io/node_modules/policyfile/index.js create mode 100644 networking/node_modules/socket.io/node_modules/policyfile/lib/server.js create mode 100644 networking/node_modules/socket.io/node_modules/policyfile/package.json create mode 100644 networking/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.crt create mode 100644 networking/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.private.key create mode 100644 networking/node_modules/socket.io/node_modules/policyfile/tests/unit.test.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/README.md create mode 100644 networking/node_modules/socket.io/node_modules/redis/changelog.md create mode 100644 networking/node_modules/socket.io/node_modules/redis/eval_test.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/auth.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/backpressure_drain.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/extend.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/file.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/mget.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/monitor.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/multi.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/multi2.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/psubscribe.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/pub_sub.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/simple.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/subqueries.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/subquery.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/unix_socket.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/examples/web_server.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/generate_commands.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/index.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/lib/commands.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/lib/parser/hiredis.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/lib/queue.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/lib/to_array.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/lib/util.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/multi_bench.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/package.json create mode 100644 networking/node_modules/socket.io/node_modules/redis/simple_test.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/test.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/tests/buffer_bench.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/tests/reconnect_test.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/tests/stress/codec.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/tests/stress/pubsub/pub.js create mode 100755 networking/node_modules/socket.io/node_modules/redis/tests/stress/pubsub/run create mode 100644 networking/node_modules/socket.io/node_modules/redis/tests/stress/pubsub/server.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/tests/stress/rpushblpop/pub.js create mode 100755 networking/node_modules/socket.io/node_modules/redis/tests/stress/rpushblpop/run create mode 100644 networking/node_modules/socket.io/node_modules/redis/tests/stress/rpushblpop/server.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/00 create mode 100755 networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/plot create mode 100644 networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/size-rate.png create mode 100644 networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/speed.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/tests/sub_quit_test.js create mode 100644 networking/node_modules/socket.io/node_modules/redis/tests/test_start_stop.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/.npmignore create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/History.md create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/Makefile create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/README.md create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/bin/builder.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/dist/WebSocketMain.swf create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/dist/WebSocketMainInsecure.swf create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.min.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/events.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/io.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/json.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/namespace.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/parser.js create mode 120000 networking/node_modules/socket.io/node_modules/socket.io-client/lib/socket.io-client.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/socket.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/transport.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/transports/flashsocket.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/transports/htmlfile.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/transports/jsonp-polling.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/transports/websocket.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/transports/xhr-polling.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/transports/xhr.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/util.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/.npmignore create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/README.md create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/WebSocketMain.swf create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/WebSocketMainInsecure.zip create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/IWebSocketLogger.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/WebSocket.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/WebSocketEvent.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/WebSocketMain.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/WebSocketMainInsecure.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/build.sh create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/adobe/net/proxies/RFC2817Socket.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/gsolo/encryption/MD5.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/Crypto.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/cert/MozillaRootCertificates.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/cert/X509Certificate.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/cert/X509CertificateCollection.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/HMAC.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/IHMAC.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/IHash.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/MAC.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/MD2.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/MD5.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHA1.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHA224.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHA256.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHABase.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/ARC4.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/IPRNG.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/Random.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/TLSPRF.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/rsa/RSAKey.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/AESKey.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/BlowFishKey.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CBCMode.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CFB8Mode.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CFBMode.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CTRMode.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/DESKey.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/ECBMode.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/ICipher.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IMode.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IPad.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IStreamCipher.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/ISymmetricKey.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IVMode.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/NullPad.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/OFBMode.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/PKCS5.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/SSLPad.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/SimpleIVMode.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/TLSPad.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/TripleDESKey.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/XTeaKey.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/aeskey.pl create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/dump.txt create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/AESKeyTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/ARC4Test.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/BigIntegerTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/BlowFishKeyTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CBCModeTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CFB8ModeTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CFBModeTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CTRModeTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/DESKeyTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/ECBModeTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/HMACTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/ITestHarness.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/MD2Test.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/MD5Test.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/OFBModeTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/RSAKeyTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/SHA1Test.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/SHA224Test.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/SHA256Test.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/TLSPRFTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/TestCase.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/TripleDESKeyTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/XTeaKeyTest.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/BulkCiphers.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/CipherSuites.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/IConnectionState.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/ISecurityParameters.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/KeyExchanges.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/MACs.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/SSLConnectionState.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/SSLEvent.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/SSLSecurityParameters.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSConfig.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSConnectionState.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSEngine.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSError.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSEvent.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSSecurityParameters.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSSocket.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSSocketEvent.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSTest.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/BarrettReduction.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/BigInteger.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/ClassicReduction.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/IReduction.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/MontgomeryReduction.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/NullReduction.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/bi_internal.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/ArrayUtil.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/Base64.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/Hex.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/Memory.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/ByteString.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/DER.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/IAsn1Type.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/Integer.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/OID.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/ObjectIdentifier.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/PEM.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/PrintableString.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/Sequence.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/Set.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/Type.as create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/UTCTime.as create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/sample.html create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/swfobject.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/web_socket.js create mode 120000 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/.bin/uglifyjs create mode 120000 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/.bin/wscat create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/..gitignore.un~ create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/.Readme.md.un~ create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/.index.js.un~ create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/.npmignore create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/.package.json.un~ create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/.test.js.un~ create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/Readme.md create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/index.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/.npmignore create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/LICENSE create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/README create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/Tokenizer.js create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/ZeParser.js create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/benchmark.html create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/index.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/package.json create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-parser.html create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-tokenizer.html create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/tests.js create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/unicodecategories.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/package.json create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/.npmignore create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/README.html create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/README.org create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/bin/uglifyjs create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/docstyle.css create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/lib/object-ast.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/lib/parse-js.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/lib/process.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/lib/squeeze-more.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/package.json create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/package.json~ create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/beautify.js create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/testparser.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/array1.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/array2.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/array3.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/array4.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/assignment.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/concatstring.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/const.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/empty-blocks.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/forstatement.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/if.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/ifreturn.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/ifreturn2.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue10.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue11.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue13.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue14.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue16.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue17.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue20.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue21.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue25.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue27.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue278.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue28.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue29.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue30.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue34.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue4.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue48.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue50.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue53.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue54.1.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue68.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue69.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue9.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/mangle.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/null_string.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/strict-equals.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/var.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/whitespace.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/with.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/array1.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/array2.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/array3.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/array4.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/assignment.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/concatstring.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/const.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/empty-blocks.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/forstatement.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/if.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/ifreturn.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/ifreturn2.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue10.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue11.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue13.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue14.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue16.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue17.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue20.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue21.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue25.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue27.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue278.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue28.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue29.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue30.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue34.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue4.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue48.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue50.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue53.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue54.1.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue68.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue69.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue9.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/mangle.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/null_string.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/strict-equals.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/var.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/whitespace.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/with.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/scripts.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/269.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/app.js create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/embed-tokens.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto2.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/hoist.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument2.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/liftvars.js create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/uglify-hangs.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/uglify-hangs2.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/uglify-js.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/.npmignore create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/.travis.yml create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/History.md create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/Makefile create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/README.md create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/parser.benchmark.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/sender.benchmark.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/speed.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bench/util.js create mode 100755 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/bin/wscat create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/binding.gyp create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/doc/ws.md create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/.npmignore create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/package.json create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/public/app.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/public/index.html create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/public/uploader.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/fileapi/server.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats-express_3/package.json create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats-express_3/public/index.html create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats-express_3/server.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats/package.json create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats/public/index.html create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/examples/serverstats/server.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/index.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/install.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/BufferPool.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/BufferUtil.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/BufferUtilWindows.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/ErrorCodes.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Receiver.hixie.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Receiver.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Sender.hixie.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Sender.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/Validation.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/ValidationWindows.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/WebSocket.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/lib/WebSocketServer.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/.npmignore create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/.travis.yml create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/History.md create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/Makefile create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/Readme.md create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/index.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/lib/commander.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/commander/package.json create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/.npmignore create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/Makefile create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/README.md create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/lib/options.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/package.json create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/test/fixtures/test.conf create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/options/test/options.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/.npmignore create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/README.md create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/example.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/package.json create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/node_modules/tinycolor/tinycolor.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/package.json create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/src/bufferutil.cc create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/src/validation.cc create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/BufferPool.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Receiver.hixie.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Receiver.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Sender.hixie.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Sender.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/Validation.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/WebSocket.integration.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/WebSocket.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/WebSocketServer.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/autobahn-server.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/autobahn.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/certificate.pem create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/key.pem create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/request.pem create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/fixtures/textfile create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/hybi-common.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws/test/testserver.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/README.md create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/XMLHttpRequest.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/autotest.watchr create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/demo.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/package.json create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-constants.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-headers.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/xmlhttprequest/tests/test-request.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/package.json create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/test/events.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/test/io.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/test/node/builder.common.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/test/node/builder.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/test/parser.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/test/socket.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/test/util.test.js create mode 100644 networking/node_modules/socket.io/node_modules/socket.io-client/test/worker.js create mode 100644 networking/node_modules/socket.io/package.json create mode 100644 networking/node_modules/socket.io/restrict_jsonp.patch create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/LICENSE create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/Makefile create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/README.md create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/examples/client-unix.js create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/examples/client.js create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/examples/server-unix.js create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/lib/websocket.js create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/package.json create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/test/test-basic.js create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/test/test-client-close.js create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/test/test-readonly-attrs.js create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/test/test-ready-state.js create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/test/test-server-close.js create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/test/test-unix-send-fd.js create mode 100644 networking/node_modules/socket.io/support/node-websocket-client/test/test-unix-sockets.js diff --git a/networking/app.js b/networking/app.js new file mode 100644 index 0000000..0bc5121 --- /dev/null +++ b/networking/app.js @@ -0,0 +1,94 @@ +var http = require('http'), + io = require('socket.io'), + fs = require('fs'), + Box2D = require('./box2d.js'); + +eval(fs.readFileSync('common.js') + ''); + +var clients = []; + +function update() { + world.Step(1 / 60, 10, 10); + world.ClearForces(); +} + +setInterval(update, 1000 / 60); +setInterval(updateClients, 500); + +function updateClients() { + var body = world.GetBodyList(); + var update = {}; + + do { + var userData = body.GetUserData(); + + if(userData && userData.bodyId){ + update[userData.bodyId] = { + p: body.GetPosition(), + a: body.GetAngle(), + v: body.GetLinearVelocity(), + }; + } + } while (body = body.GetNext()); + + sendToClients('world-update', update); +} + +function sendToClients(message, data) { + var packet = { + m: message, + d: data + } + //console.log(JSON.stringify(packet)); + for (var i = 0; i < clients.length; i++) { + clients[i].send(JSON.stringify(packet)); + } +} + + + +setupWorld(); +//update(); + +// SOCKETS + +var server = http.createServer( + function(req, res){ + res.writeHead(200, {'Content-Type': 'text/html'}); + res.end('

Hello world

'); + } +); + + +server.listen(xport, xhost); +console.log('port', xport); +var socket = io.listen(server); + +socket.configure('development', function(){ + socket.set('log level', 0); +}); + +socket.on('connection', function(client) { + clients.push(client); + console.log("Total clients: " + clients.length); + + client.send(JSON.stringify({"startId" : clients.length})); + + client.on('message', function(data){ + data = JSON.parse(data); + + if(data && data.m){ + switch(data.m){ + case 'jump': + jump(); + break; + default: + break; + } + } + }); + + client.on('disconnect', function(){ + console.log("disconnect"); + }); +}); diff --git a/networking/app.js~ b/networking/app.js~ new file mode 100644 index 0000000..0bc5121 --- /dev/null +++ b/networking/app.js~ @@ -0,0 +1,94 @@ +var http = require('http'), + io = require('socket.io'), + fs = require('fs'), + Box2D = require('./box2d.js'); + +eval(fs.readFileSync('common.js') + ''); + +var clients = []; + +function update() { + world.Step(1 / 60, 10, 10); + world.ClearForces(); +} + +setInterval(update, 1000 / 60); +setInterval(updateClients, 500); + +function updateClients() { + var body = world.GetBodyList(); + var update = {}; + + do { + var userData = body.GetUserData(); + + if(userData && userData.bodyId){ + update[userData.bodyId] = { + p: body.GetPosition(), + a: body.GetAngle(), + v: body.GetLinearVelocity(), + }; + } + } while (body = body.GetNext()); + + sendToClients('world-update', update); +} + +function sendToClients(message, data) { + var packet = { + m: message, + d: data + } + //console.log(JSON.stringify(packet)); + for (var i = 0; i < clients.length; i++) { + clients[i].send(JSON.stringify(packet)); + } +} + + + +setupWorld(); +//update(); + +// SOCKETS + +var server = http.createServer( + function(req, res){ + res.writeHead(200, {'Content-Type': 'text/html'}); + res.end('

Hello world

'); + } +); + + +server.listen(xport, xhost); +console.log('port', xport); +var socket = io.listen(server); + +socket.configure('development', function(){ + socket.set('log level', 0); +}); + +socket.on('connection', function(client) { + clients.push(client); + console.log("Total clients: " + clients.length); + + client.send(JSON.stringify({"startId" : clients.length})); + + client.on('message', function(data){ + data = JSON.parse(data); + + if(data && data.m){ + switch(data.m){ + case 'jump': + jump(); + break; + default: + break; + } + } + }); + + client.on('disconnect', function(){ + console.log("disconnect"); + }); +}); diff --git a/networking/box2d.js b/networking/box2d.js new file mode 100644 index 0000000..60f84c9 --- /dev/null +++ b/networking/box2d.js @@ -0,0 +1,10864 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ +var Box2D = {}; + +(function (a2j, undefined) { + + function emptyFn() {}; + a2j.inherit = function(cls, base) { + var tmpCtr = cls; + emptyFn.prototype = base.prototype; + cls.prototype = new emptyFn; + cls.prototype.constructor = tmpCtr; + }; + + a2j.generateCallback = function generateCallback(context, cb) { + return function () { + cb.apply(context, arguments); + }; + }; + + a2j.NVector = function NVector(length) { + if (length === undefined) length = 0; + var tmp = new Array(length || 0); + for (var i = 0; i < length; ++i) + tmp[i] = 0; + return tmp; + }; + + a2j.is = function is(o1, o2) { + if (o1 === null) return false; + if ((o2 instanceof Function) && (o1 instanceof o2)) return true; + if ((o1.constructor.__implements != undefined) && (o1.constructor.__implements[o2])) return true; + return false; + }; + + a2j.parseUInt = function(v) { + return Math.abs(parseInt(v)); + } + +})(Box2D); + +//#TODO remove assignments from global namespace +var Vector = Array; +var Vector_a2j_Number = Box2D.NVector; +//package structure +if (typeof(Box2D) === "undefined") Box2D = {}; +if (typeof(Box2D.Collision) === "undefined") Box2D.Collision = {}; +if (typeof(Box2D.Collision.Shapes) === "undefined") Box2D.Collision.Shapes = {}; +if (typeof(Box2D.Common) === "undefined") Box2D.Common = {}; +if (typeof(Box2D.Common.Math) === "undefined") Box2D.Common.Math = {}; +if (typeof(Box2D.Dynamics) === "undefined") Box2D.Dynamics = {}; +if (typeof(Box2D.Dynamics.Contacts) === "undefined") Box2D.Dynamics.Contacts = {}; +if (typeof(Box2D.Dynamics.Controllers) === "undefined") Box2D.Dynamics.Controllers = {}; +if (typeof(Box2D.Dynamics.Joints) === "undefined") Box2D.Dynamics.Joints = {}; +//pre-definitions +(function () { + Box2D.Collision.IBroadPhase = 'Box2D.Collision.IBroadPhase'; + + function b2AABB() { + b2AABB.b2AABB.apply(this, arguments); + }; + Box2D.Collision.b2AABB = b2AABB; + + function b2Bound() { + b2Bound.b2Bound.apply(this, arguments); + }; + Box2D.Collision.b2Bound = b2Bound; + + function b2BoundValues() { + b2BoundValues.b2BoundValues.apply(this, arguments); + if (this.constructor === b2BoundValues) this.b2BoundValues.apply(this, arguments); + }; + Box2D.Collision.b2BoundValues = b2BoundValues; + + function b2Collision() { + b2Collision.b2Collision.apply(this, arguments); + }; + Box2D.Collision.b2Collision = b2Collision; + + function b2ContactID() { + b2ContactID.b2ContactID.apply(this, arguments); + if (this.constructor === b2ContactID) this.b2ContactID.apply(this, arguments); + }; + Box2D.Collision.b2ContactID = b2ContactID; + + function b2ContactPoint() { + b2ContactPoint.b2ContactPoint.apply(this, arguments); + }; + Box2D.Collision.b2ContactPoint = b2ContactPoint; + + function b2Distance() { + b2Distance.b2Distance.apply(this, arguments); + }; + Box2D.Collision.b2Distance = b2Distance; + + function b2DistanceInput() { + b2DistanceInput.b2DistanceInput.apply(this, arguments); + }; + Box2D.Collision.b2DistanceInput = b2DistanceInput; + + function b2DistanceOutput() { + b2DistanceOutput.b2DistanceOutput.apply(this, arguments); + }; + Box2D.Collision.b2DistanceOutput = b2DistanceOutput; + + function b2DistanceProxy() { + b2DistanceProxy.b2DistanceProxy.apply(this, arguments); + }; + Box2D.Collision.b2DistanceProxy = b2DistanceProxy; + + function b2DynamicTree() { + b2DynamicTree.b2DynamicTree.apply(this, arguments); + if (this.constructor === b2DynamicTree) this.b2DynamicTree.apply(this, arguments); + }; + Box2D.Collision.b2DynamicTree = b2DynamicTree; + + function b2DynamicTreeBroadPhase() { + b2DynamicTreeBroadPhase.b2DynamicTreeBroadPhase.apply(this, arguments); + }; + Box2D.Collision.b2DynamicTreeBroadPhase = b2DynamicTreeBroadPhase; + + function b2DynamicTreeNode() { + b2DynamicTreeNode.b2DynamicTreeNode.apply(this, arguments); + }; + Box2D.Collision.b2DynamicTreeNode = b2DynamicTreeNode; + + function b2DynamicTreePair() { + b2DynamicTreePair.b2DynamicTreePair.apply(this, arguments); + }; + Box2D.Collision.b2DynamicTreePair = b2DynamicTreePair; + + function b2Manifold() { + b2Manifold.b2Manifold.apply(this, arguments); + if (this.constructor === b2Manifold) this.b2Manifold.apply(this, arguments); + }; + Box2D.Collision.b2Manifold = b2Manifold; + + function b2ManifoldPoint() { + b2ManifoldPoint.b2ManifoldPoint.apply(this, arguments); + if (this.constructor === b2ManifoldPoint) this.b2ManifoldPoint.apply(this, arguments); + }; + Box2D.Collision.b2ManifoldPoint = b2ManifoldPoint; + + function b2Point() { + b2Point.b2Point.apply(this, arguments); + }; + Box2D.Collision.b2Point = b2Point; + + function b2RayCastInput() { + b2RayCastInput.b2RayCastInput.apply(this, arguments); + if (this.constructor === b2RayCastInput) this.b2RayCastInput.apply(this, arguments); + }; + Box2D.Collision.b2RayCastInput = b2RayCastInput; + + function b2RayCastOutput() { + b2RayCastOutput.b2RayCastOutput.apply(this, arguments); + }; + Box2D.Collision.b2RayCastOutput = b2RayCastOutput; + + function b2Segment() { + b2Segment.b2Segment.apply(this, arguments); + }; + Box2D.Collision.b2Segment = b2Segment; + + function b2SeparationFunction() { + b2SeparationFunction.b2SeparationFunction.apply(this, arguments); + }; + Box2D.Collision.b2SeparationFunction = b2SeparationFunction; + + function b2Simplex() { + b2Simplex.b2Simplex.apply(this, arguments); + if (this.constructor === b2Simplex) this.b2Simplex.apply(this, arguments); + }; + Box2D.Collision.b2Simplex = b2Simplex; + + function b2SimplexCache() { + b2SimplexCache.b2SimplexCache.apply(this, arguments); + }; + Box2D.Collision.b2SimplexCache = b2SimplexCache; + + function b2SimplexVertex() { + b2SimplexVertex.b2SimplexVertex.apply(this, arguments); + }; + Box2D.Collision.b2SimplexVertex = b2SimplexVertex; + + function b2TimeOfImpact() { + b2TimeOfImpact.b2TimeOfImpact.apply(this, arguments); + }; + Box2D.Collision.b2TimeOfImpact = b2TimeOfImpact; + + function b2TOIInput() { + b2TOIInput.b2TOIInput.apply(this, arguments); + }; + Box2D.Collision.b2TOIInput = b2TOIInput; + + function b2WorldManifold() { + b2WorldManifold.b2WorldManifold.apply(this, arguments); + if (this.constructor === b2WorldManifold) this.b2WorldManifold.apply(this, arguments); + }; + Box2D.Collision.b2WorldManifold = b2WorldManifold; + + function ClipVertex() { + ClipVertex.ClipVertex.apply(this, arguments); + }; + Box2D.Collision.ClipVertex = ClipVertex; + + function Features() { + Features.Features.apply(this, arguments); + }; + Box2D.Collision.Features = Features; + + function b2CircleShape() { + b2CircleShape.b2CircleShape.apply(this, arguments); + if (this.constructor === b2CircleShape) this.b2CircleShape.apply(this, arguments); + }; + Box2D.Collision.Shapes.b2CircleShape = b2CircleShape; + + function b2EdgeChainDef() { + b2EdgeChainDef.b2EdgeChainDef.apply(this, arguments); + if (this.constructor === b2EdgeChainDef) this.b2EdgeChainDef.apply(this, arguments); + }; + Box2D.Collision.Shapes.b2EdgeChainDef = b2EdgeChainDef; + + function b2EdgeShape() { + b2EdgeShape.b2EdgeShape.apply(this, arguments); + if (this.constructor === b2EdgeShape) this.b2EdgeShape.apply(this, arguments); + }; + Box2D.Collision.Shapes.b2EdgeShape = b2EdgeShape; + + function b2MassData() { + b2MassData.b2MassData.apply(this, arguments); + }; + Box2D.Collision.Shapes.b2MassData = b2MassData; + + function b2PolygonShape() { + b2PolygonShape.b2PolygonShape.apply(this, arguments); + if (this.constructor === b2PolygonShape) this.b2PolygonShape.apply(this, arguments); + }; + Box2D.Collision.Shapes.b2PolygonShape = b2PolygonShape; + + function b2Shape() { + b2Shape.b2Shape.apply(this, arguments); + if (this.constructor === b2Shape) this.b2Shape.apply(this, arguments); + }; + Box2D.Collision.Shapes.b2Shape = b2Shape; + Box2D.Common.b2internal = 'Box2D.Common.b2internal'; + + function b2Color() { + b2Color.b2Color.apply(this, arguments); + if (this.constructor === b2Color) this.b2Color.apply(this, arguments); + }; + Box2D.Common.b2Color = b2Color; + + function b2Settings() { + b2Settings.b2Settings.apply(this, arguments); + }; + Box2D.Common.b2Settings = b2Settings; + + function b2Mat22() { + b2Mat22.b2Mat22.apply(this, arguments); + if (this.constructor === b2Mat22) this.b2Mat22.apply(this, arguments); + }; + Box2D.Common.Math.b2Mat22 = b2Mat22; + + function b2Mat33() { + b2Mat33.b2Mat33.apply(this, arguments); + if (this.constructor === b2Mat33) this.b2Mat33.apply(this, arguments); + }; + Box2D.Common.Math.b2Mat33 = b2Mat33; + + function b2Math() { + b2Math.b2Math.apply(this, arguments); + }; + Box2D.Common.Math.b2Math = b2Math; + + function b2Sweep() { + b2Sweep.b2Sweep.apply(this, arguments); + }; + Box2D.Common.Math.b2Sweep = b2Sweep; + + function b2Transform() { + b2Transform.b2Transform.apply(this, arguments); + if (this.constructor === b2Transform) this.b2Transform.apply(this, arguments); + }; + Box2D.Common.Math.b2Transform = b2Transform; + + function b2Vec2() { + b2Vec2.b2Vec2.apply(this, arguments); + if (this.constructor === b2Vec2) this.b2Vec2.apply(this, arguments); + }; + Box2D.Common.Math.b2Vec2 = b2Vec2; + + function b2Vec3() { + b2Vec3.b2Vec3.apply(this, arguments); + if (this.constructor === b2Vec3) this.b2Vec3.apply(this, arguments); + }; + Box2D.Common.Math.b2Vec3 = b2Vec3; + + function b2Body() { + b2Body.b2Body.apply(this, arguments); + if (this.constructor === b2Body) this.b2Body.apply(this, arguments); + }; + Box2D.Dynamics.b2Body = b2Body; + + function b2BodyDef() { + b2BodyDef.b2BodyDef.apply(this, arguments); + if (this.constructor === b2BodyDef) this.b2BodyDef.apply(this, arguments); + }; + Box2D.Dynamics.b2BodyDef = b2BodyDef; + + function b2ContactFilter() { + b2ContactFilter.b2ContactFilter.apply(this, arguments); + }; + Box2D.Dynamics.b2ContactFilter = b2ContactFilter; + + function b2ContactImpulse() { + b2ContactImpulse.b2ContactImpulse.apply(this, arguments); + }; + Box2D.Dynamics.b2ContactImpulse = b2ContactImpulse; + + function b2ContactListener() { + b2ContactListener.b2ContactListener.apply(this, arguments); + }; + Box2D.Dynamics.b2ContactListener = b2ContactListener; + + function b2ContactManager() { + b2ContactManager.b2ContactManager.apply(this, arguments); + if (this.constructor === b2ContactManager) this.b2ContactManager.apply(this, arguments); + }; + Box2D.Dynamics.b2ContactManager = b2ContactManager; + + function b2DebugDraw() { + b2DebugDraw.b2DebugDraw.apply(this, arguments); + if (this.constructor === b2DebugDraw) this.b2DebugDraw.apply(this, arguments); + }; + Box2D.Dynamics.b2DebugDraw = b2DebugDraw; + + function b2DestructionListener() { + b2DestructionListener.b2DestructionListener.apply(this, arguments); + }; + Box2D.Dynamics.b2DestructionListener = b2DestructionListener; + + function b2FilterData() { + b2FilterData.b2FilterData.apply(this, arguments); + }; + Box2D.Dynamics.b2FilterData = b2FilterData; + + function b2Fixture() { + b2Fixture.b2Fixture.apply(this, arguments); + if (this.constructor === b2Fixture) this.b2Fixture.apply(this, arguments); + }; + Box2D.Dynamics.b2Fixture = b2Fixture; + + function b2FixtureDef() { + b2FixtureDef.b2FixtureDef.apply(this, arguments); + if (this.constructor === b2FixtureDef) this.b2FixtureDef.apply(this, arguments); + }; + Box2D.Dynamics.b2FixtureDef = b2FixtureDef; + + function b2Island() { + b2Island.b2Island.apply(this, arguments); + if (this.constructor === b2Island) this.b2Island.apply(this, arguments); + }; + Box2D.Dynamics.b2Island = b2Island; + + function b2TimeStep() { + b2TimeStep.b2TimeStep.apply(this, arguments); + }; + Box2D.Dynamics.b2TimeStep = b2TimeStep; + + function b2World() { + b2World.b2World.apply(this, arguments); + if (this.constructor === b2World) this.b2World.apply(this, arguments); + }; + Box2D.Dynamics.b2World = b2World; + + function b2CircleContact() { + b2CircleContact.b2CircleContact.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2CircleContact = b2CircleContact; + + function b2Contact() { + b2Contact.b2Contact.apply(this, arguments); + if (this.constructor === b2Contact) this.b2Contact.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2Contact = b2Contact; + + function b2ContactConstraint() { + b2ContactConstraint.b2ContactConstraint.apply(this, arguments); + if (this.constructor === b2ContactConstraint) this.b2ContactConstraint.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2ContactConstraint = b2ContactConstraint; + + function b2ContactConstraintPoint() { + b2ContactConstraintPoint.b2ContactConstraintPoint.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2ContactConstraintPoint = b2ContactConstraintPoint; + + function b2ContactEdge() { + b2ContactEdge.b2ContactEdge.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2ContactEdge = b2ContactEdge; + + function b2ContactFactory() { + b2ContactFactory.b2ContactFactory.apply(this, arguments); + if (this.constructor === b2ContactFactory) this.b2ContactFactory.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2ContactFactory = b2ContactFactory; + + function b2ContactRegister() { + b2ContactRegister.b2ContactRegister.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2ContactRegister = b2ContactRegister; + + function b2ContactResult() { + b2ContactResult.b2ContactResult.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2ContactResult = b2ContactResult; + + function b2ContactSolver() { + b2ContactSolver.b2ContactSolver.apply(this, arguments); + if (this.constructor === b2ContactSolver) this.b2ContactSolver.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2ContactSolver = b2ContactSolver; + + function b2EdgeAndCircleContact() { + b2EdgeAndCircleContact.b2EdgeAndCircleContact.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2EdgeAndCircleContact = b2EdgeAndCircleContact; + + function b2NullContact() { + b2NullContact.b2NullContact.apply(this, arguments); + if (this.constructor === b2NullContact) this.b2NullContact.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2NullContact = b2NullContact; + + function b2PolyAndCircleContact() { + b2PolyAndCircleContact.b2PolyAndCircleContact.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2PolyAndCircleContact = b2PolyAndCircleContact; + + function b2PolyAndEdgeContact() { + b2PolyAndEdgeContact.b2PolyAndEdgeContact.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2PolyAndEdgeContact = b2PolyAndEdgeContact; + + function b2PolygonContact() { + b2PolygonContact.b2PolygonContact.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2PolygonContact = b2PolygonContact; + + function b2PositionSolverManifold() { + b2PositionSolverManifold.b2PositionSolverManifold.apply(this, arguments); + if (this.constructor === b2PositionSolverManifold) this.b2PositionSolverManifold.apply(this, arguments); + }; + Box2D.Dynamics.Contacts.b2PositionSolverManifold = b2PositionSolverManifold; + + function b2BuoyancyController() { + b2BuoyancyController.b2BuoyancyController.apply(this, arguments); + }; + Box2D.Dynamics.Controllers.b2BuoyancyController = b2BuoyancyController; + + function b2ConstantAccelController() { + b2ConstantAccelController.b2ConstantAccelController.apply(this, arguments); + }; + Box2D.Dynamics.Controllers.b2ConstantAccelController = b2ConstantAccelController; + + function b2ConstantForceController() { + b2ConstantForceController.b2ConstantForceController.apply(this, arguments); + }; + Box2D.Dynamics.Controllers.b2ConstantForceController = b2ConstantForceController; + + function b2Controller() { + b2Controller.b2Controller.apply(this, arguments); + }; + Box2D.Dynamics.Controllers.b2Controller = b2Controller; + + function b2ControllerEdge() { + b2ControllerEdge.b2ControllerEdge.apply(this, arguments); + }; + Box2D.Dynamics.Controllers.b2ControllerEdge = b2ControllerEdge; + + function b2GravityController() { + b2GravityController.b2GravityController.apply(this, arguments); + }; + Box2D.Dynamics.Controllers.b2GravityController = b2GravityController; + + function b2TensorDampingController() { + b2TensorDampingController.b2TensorDampingController.apply(this, arguments); + }; + Box2D.Dynamics.Controllers.b2TensorDampingController = b2TensorDampingController; + + function b2DistanceJoint() { + b2DistanceJoint.b2DistanceJoint.apply(this, arguments); + if (this.constructor === b2DistanceJoint) this.b2DistanceJoint.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2DistanceJoint = b2DistanceJoint; + + function b2DistanceJointDef() { + b2DistanceJointDef.b2DistanceJointDef.apply(this, arguments); + if (this.constructor === b2DistanceJointDef) this.b2DistanceJointDef.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2DistanceJointDef = b2DistanceJointDef; + + function b2FrictionJoint() { + b2FrictionJoint.b2FrictionJoint.apply(this, arguments); + if (this.constructor === b2FrictionJoint) this.b2FrictionJoint.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2FrictionJoint = b2FrictionJoint; + + function b2FrictionJointDef() { + b2FrictionJointDef.b2FrictionJointDef.apply(this, arguments); + if (this.constructor === b2FrictionJointDef) this.b2FrictionJointDef.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2FrictionJointDef = b2FrictionJointDef; + + function b2GearJoint() { + b2GearJoint.b2GearJoint.apply(this, arguments); + if (this.constructor === b2GearJoint) this.b2GearJoint.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2GearJoint = b2GearJoint; + + function b2GearJointDef() { + b2GearJointDef.b2GearJointDef.apply(this, arguments); + if (this.constructor === b2GearJointDef) this.b2GearJointDef.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2GearJointDef = b2GearJointDef; + + function b2Jacobian() { + b2Jacobian.b2Jacobian.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2Jacobian = b2Jacobian; + + function b2Joint() { + b2Joint.b2Joint.apply(this, arguments); + if (this.constructor === b2Joint) this.b2Joint.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2Joint = b2Joint; + + function b2JointDef() { + b2JointDef.b2JointDef.apply(this, arguments); + if (this.constructor === b2JointDef) this.b2JointDef.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2JointDef = b2JointDef; + + function b2JointEdge() { + b2JointEdge.b2JointEdge.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2JointEdge = b2JointEdge; + + function b2LineJoint() { + b2LineJoint.b2LineJoint.apply(this, arguments); + if (this.constructor === b2LineJoint) this.b2LineJoint.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2LineJoint = b2LineJoint; + + function b2LineJointDef() { + b2LineJointDef.b2LineJointDef.apply(this, arguments); + if (this.constructor === b2LineJointDef) this.b2LineJointDef.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2LineJointDef = b2LineJointDef; + + function b2MouseJoint() { + b2MouseJoint.b2MouseJoint.apply(this, arguments); + if (this.constructor === b2MouseJoint) this.b2MouseJoint.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2MouseJoint = b2MouseJoint; + + function b2MouseJointDef() { + b2MouseJointDef.b2MouseJointDef.apply(this, arguments); + if (this.constructor === b2MouseJointDef) this.b2MouseJointDef.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2MouseJointDef = b2MouseJointDef; + + function b2PrismaticJoint() { + b2PrismaticJoint.b2PrismaticJoint.apply(this, arguments); + if (this.constructor === b2PrismaticJoint) this.b2PrismaticJoint.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2PrismaticJoint = b2PrismaticJoint; + + function b2PrismaticJointDef() { + b2PrismaticJointDef.b2PrismaticJointDef.apply(this, arguments); + if (this.constructor === b2PrismaticJointDef) this.b2PrismaticJointDef.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2PrismaticJointDef = b2PrismaticJointDef; + + function b2PulleyJoint() { + b2PulleyJoint.b2PulleyJoint.apply(this, arguments); + if (this.constructor === b2PulleyJoint) this.b2PulleyJoint.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2PulleyJoint = b2PulleyJoint; + + function b2PulleyJointDef() { + b2PulleyJointDef.b2PulleyJointDef.apply(this, arguments); + if (this.constructor === b2PulleyJointDef) this.b2PulleyJointDef.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2PulleyJointDef = b2PulleyJointDef; + + function b2RevoluteJoint() { + b2RevoluteJoint.b2RevoluteJoint.apply(this, arguments); + if (this.constructor === b2RevoluteJoint) this.b2RevoluteJoint.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2RevoluteJoint = b2RevoluteJoint; + + function b2RevoluteJointDef() { + b2RevoluteJointDef.b2RevoluteJointDef.apply(this, arguments); + if (this.constructor === b2RevoluteJointDef) this.b2RevoluteJointDef.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2RevoluteJointDef = b2RevoluteJointDef; + + function b2WeldJoint() { + b2WeldJoint.b2WeldJoint.apply(this, arguments); + if (this.constructor === b2WeldJoint) this.b2WeldJoint.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2WeldJoint = b2WeldJoint; + + function b2WeldJointDef() { + b2WeldJointDef.b2WeldJointDef.apply(this, arguments); + if (this.constructor === b2WeldJointDef) this.b2WeldJointDef.apply(this, arguments); + }; + Box2D.Dynamics.Joints.b2WeldJointDef = b2WeldJointDef; +})(); //definitions +Box2D.postDefs = []; +(function () { + var b2CircleShape = Box2D.Collision.Shapes.b2CircleShape, + b2EdgeChainDef = Box2D.Collision.Shapes.b2EdgeChainDef, + b2EdgeShape = Box2D.Collision.Shapes.b2EdgeShape, + b2MassData = Box2D.Collision.Shapes.b2MassData, + b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape, + b2Shape = Box2D.Collision.Shapes.b2Shape, + b2Color = Box2D.Common.b2Color, + b2internal = Box2D.Common.b2internal, + b2Settings = Box2D.Common.b2Settings, + b2Mat22 = Box2D.Common.Math.b2Mat22, + b2Mat33 = Box2D.Common.Math.b2Mat33, + b2Math = Box2D.Common.Math.b2Math, + b2Sweep = Box2D.Common.Math.b2Sweep, + b2Transform = Box2D.Common.Math.b2Transform, + b2Vec2 = Box2D.Common.Math.b2Vec2, + b2Vec3 = Box2D.Common.Math.b2Vec3, + b2AABB = Box2D.Collision.b2AABB, + b2Bound = Box2D.Collision.b2Bound, + b2BoundValues = Box2D.Collision.b2BoundValues, + b2Collision = Box2D.Collision.b2Collision, + b2ContactID = Box2D.Collision.b2ContactID, + b2ContactPoint = Box2D.Collision.b2ContactPoint, + b2Distance = Box2D.Collision.b2Distance, + b2DistanceInput = Box2D.Collision.b2DistanceInput, + b2DistanceOutput = Box2D.Collision.b2DistanceOutput, + b2DistanceProxy = Box2D.Collision.b2DistanceProxy, + b2DynamicTree = Box2D.Collision.b2DynamicTree, + b2DynamicTreeBroadPhase = Box2D.Collision.b2DynamicTreeBroadPhase, + b2DynamicTreeNode = Box2D.Collision.b2DynamicTreeNode, + b2DynamicTreePair = Box2D.Collision.b2DynamicTreePair, + b2Manifold = Box2D.Collision.b2Manifold, + b2ManifoldPoint = Box2D.Collision.b2ManifoldPoint, + b2Point = Box2D.Collision.b2Point, + b2RayCastInput = Box2D.Collision.b2RayCastInput, + b2RayCastOutput = Box2D.Collision.b2RayCastOutput, + b2Segment = Box2D.Collision.b2Segment, + b2SeparationFunction = Box2D.Collision.b2SeparationFunction, + b2Simplex = Box2D.Collision.b2Simplex, + b2SimplexCache = Box2D.Collision.b2SimplexCache, + b2SimplexVertex = Box2D.Collision.b2SimplexVertex, + b2TimeOfImpact = Box2D.Collision.b2TimeOfImpact, + b2TOIInput = Box2D.Collision.b2TOIInput, + b2WorldManifold = Box2D.Collision.b2WorldManifold, + ClipVertex = Box2D.Collision.ClipVertex, + Features = Box2D.Collision.Features, + IBroadPhase = Box2D.Collision.IBroadPhase; + + b2AABB.b2AABB = function () { + this.lowerBound = new b2Vec2(); + this.upperBound = new b2Vec2(); + }; + b2AABB.prototype.IsValid = function () { + var dX = this.upperBound.x - this.lowerBound.x; + var dY = this.upperBound.y - this.lowerBound.y; + var valid = dX >= 0.0 && dY >= 0.0; + valid = valid && this.lowerBound.IsValid() && this.upperBound.IsValid(); + return valid; + } + b2AABB.prototype.GetCenter = function () { + return new b2Vec2((this.lowerBound.x + this.upperBound.x) / 2, (this.lowerBound.y + this.upperBound.y) / 2); + } + b2AABB.prototype.GetExtents = function () { + return new b2Vec2((this.upperBound.x - this.lowerBound.x) / 2, (this.upperBound.y - this.lowerBound.y) / 2); + } + b2AABB.prototype.Contains = function (aabb) { + var result = true; + result = result && this.lowerBound.x <= aabb.lowerBound.x; + result = result && this.lowerBound.y <= aabb.lowerBound.y; + result = result && aabb.upperBound.x <= this.upperBound.x; + result = result && aabb.upperBound.y <= this.upperBound.y; + return result; + } + b2AABB.prototype.RayCast = function (output, input) { + var tmin = (-Number.MAX_VALUE); + var tmax = Number.MAX_VALUE; + var pX = input.p1.x; + var pY = input.p1.y; + var dX = input.p2.x - input.p1.x; + var dY = input.p2.y - input.p1.y; + var absDX = Math.abs(dX); + var absDY = Math.abs(dY); + var normal = output.normal; + var inv_d = 0; + var t1 = 0; + var t2 = 0; + var t3 = 0; + var s = 0; { + if (absDX < Number.MIN_VALUE) { + if (pX < this.lowerBound.x || this.upperBound.x < pX) return false; + } + else { + inv_d = 1.0 / dX; + t1 = (this.lowerBound.x - pX) * inv_d; + t2 = (this.upperBound.x - pX) * inv_d; + s = (-1.0); + if (t1 > t2) { + t3 = t1; + t1 = t2; + t2 = t3; + s = 1.0; + } + if (t1 > tmin) { + normal.x = s; + normal.y = 0; + tmin = t1; + } + tmax = Math.min(tmax, t2); + if (tmin > tmax) return false; + } + } { + if (absDY < Number.MIN_VALUE) { + if (pY < this.lowerBound.y || this.upperBound.y < pY) return false; + } + else { + inv_d = 1.0 / dY; + t1 = (this.lowerBound.y - pY) * inv_d; + t2 = (this.upperBound.y - pY) * inv_d; + s = (-1.0); + if (t1 > t2) { + t3 = t1; + t1 = t2; + t2 = t3; + s = 1.0; + } + if (t1 > tmin) { + normal.y = s; + normal.x = 0; + tmin = t1; + } + tmax = Math.min(tmax, t2); + if (tmin > tmax) return false; + } + } + output.fraction = tmin; + return true; + } + b2AABB.prototype.TestOverlap = function (other) { + var d1X = other.lowerBound.x - this.upperBound.x; + var d1Y = other.lowerBound.y - this.upperBound.y; + var d2X = this.lowerBound.x - other.upperBound.x; + var d2Y = this.lowerBound.y - other.upperBound.y; + if (d1X > 0.0 || d1Y > 0.0) return false; + if (d2X > 0.0 || d2Y > 0.0) return false; + return true; + } + b2AABB.Combine = function (aabb1, aabb2) { + var aabb = new b2AABB(); + aabb.Combine(aabb1, aabb2); + return aabb; + } + b2AABB.prototype.Combine = function (aabb1, aabb2) { + this.lowerBound.x = Math.min(aabb1.lowerBound.x, aabb2.lowerBound.x); + this.lowerBound.y = Math.min(aabb1.lowerBound.y, aabb2.lowerBound.y); + this.upperBound.x = Math.max(aabb1.upperBound.x, aabb2.upperBound.x); + this.upperBound.y = Math.max(aabb1.upperBound.y, aabb2.upperBound.y); + } + b2Bound.b2Bound = function () {}; + b2Bound.prototype.IsLower = function () { + return (this.value & 1) == 0; + } + b2Bound.prototype.IsUpper = function () { + return (this.value & 1) == 1; + } + b2Bound.prototype.Swap = function (b) { + var tempValue = this.value; + var tempProxy = this.proxy; + var tempStabbingCount = this.stabbingCount; + this.value = b.value; + this.proxy = b.proxy; + this.stabbingCount = b.stabbingCount; + b.value = tempValue; + b.proxy = tempProxy; + b.stabbingCount = tempStabbingCount; + } + b2BoundValues.b2BoundValues = function () {}; + b2BoundValues.prototype.b2BoundValues = function () { + this.lowerValues = new Vector_a2j_Number(); + this.lowerValues[0] = 0.0; + this.lowerValues[1] = 0.0; + this.upperValues = new Vector_a2j_Number(); + this.upperValues[0] = 0.0; + this.upperValues[1] = 0.0; + } + b2Collision.b2Collision = function () {}; + b2Collision.ClipSegmentToLine = function (vOut, vIn, normal, offset) { + if (offset === undefined) offset = 0; + var cv; + var numOut = 0; + cv = vIn[0]; + var vIn0 = cv.v; + cv = vIn[1]; + var vIn1 = cv.v; + var distance0 = normal.x * vIn0.x + normal.y * vIn0.y - offset; + var distance1 = normal.x * vIn1.x + normal.y * vIn1.y - offset; + if (distance0 <= 0.0) vOut[numOut++].Set(vIn[0]); + if (distance1 <= 0.0) vOut[numOut++].Set(vIn[1]); + if (distance0 * distance1 < 0.0) { + var interp = distance0 / (distance0 - distance1); + cv = vOut[numOut]; + var tVec = cv.v; + tVec.x = vIn0.x + interp * (vIn1.x - vIn0.x); + tVec.y = vIn0.y + interp * (vIn1.y - vIn0.y); + cv = vOut[numOut]; + var cv2; + if (distance0 > 0.0) { + cv2 = vIn[0]; + cv.id = cv2.id; + } + else { + cv2 = vIn[1]; + cv.id = cv2.id; + }++numOut; + } + return numOut; + } + b2Collision.EdgeSeparation = function (poly1, xf1, edge1, poly2, xf2) { + if (edge1 === undefined) edge1 = 0; + var count1 = parseInt(poly1.m_vertexCount); + var vertices1 = poly1.m_vertices; + var normals1 = poly1.m_normals; + var count2 = parseInt(poly2.m_vertexCount); + var vertices2 = poly2.m_vertices; + var tMat; + var tVec; + tMat = xf1.R; + tVec = normals1[edge1]; + var normal1WorldX = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var normal1WorldY = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = xf2.R; + var normal1X = (tMat.col1.x * normal1WorldX + tMat.col1.y * normal1WorldY); + var normal1Y = (tMat.col2.x * normal1WorldX + tMat.col2.y * normal1WorldY); + var index = 0; + var minDot = Number.MAX_VALUE; + for (var i = 0; i < count2; ++i) { + tVec = vertices2[i]; + var dot = tVec.x * normal1X + tVec.y * normal1Y; + if (dot < minDot) { + minDot = dot; + index = i; + } + } + tVec = vertices1[edge1]; + tMat = xf1.R; + var v1X = xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var v1Y = xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tVec = vertices2[index]; + tMat = xf2.R; + var v2X = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var v2Y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + v2X -= v1X; + v2Y -= v1Y; + var separation = v2X * normal1WorldX + v2Y * normal1WorldY; + return separation; + } + b2Collision.FindMaxSeparation = function (edgeIndex, poly1, xf1, poly2, xf2) { + var count1 = parseInt(poly1.m_vertexCount); + var normals1 = poly1.m_normals; + var tVec; + var tMat; + tMat = xf2.R; + tVec = poly2.m_centroid; + var dX = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var dY = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = xf1.R; + tVec = poly1.m_centroid; + dX -= xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + dY -= xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + var dLocal1X = (dX * xf1.R.col1.x + dY * xf1.R.col1.y); + var dLocal1Y = (dX * xf1.R.col2.x + dY * xf1.R.col2.y); + var edge = 0; + var maxDot = (-Number.MAX_VALUE); + for (var i = 0; i < count1; ++i) { + tVec = normals1[i]; + var dot = (tVec.x * dLocal1X + tVec.y * dLocal1Y); + if (dot > maxDot) { + maxDot = dot; + edge = i; + } + } + var s = b2Collision.EdgeSeparation(poly1, xf1, edge, poly2, xf2); + var prevEdge = parseInt(edge - 1 >= 0 ? edge - 1 : count1 - 1); + var sPrev = b2Collision.EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); + var nextEdge = parseInt(edge + 1 < count1 ? edge + 1 : 0); + var sNext = b2Collision.EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); + var bestEdge = 0; + var bestSeparation = 0; + var increment = 0; + if (sPrev > s && sPrev > sNext) { + increment = (-1); + bestEdge = prevEdge; + bestSeparation = sPrev; + } + else if (sNext > s) { + increment = 1; + bestEdge = nextEdge; + bestSeparation = sNext; + } + else { + edgeIndex[0] = edge; + return s; + } + while (true) { + if (increment == (-1)) edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; + else edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;s = b2Collision.EdgeSeparation(poly1, xf1, edge, poly2, xf2); + if (s > bestSeparation) { + bestEdge = edge; + bestSeparation = s; + } + else { + break; + } + } + edgeIndex[0] = bestEdge; + return bestSeparation; + } + b2Collision.FindIncidentEdge = function (c, poly1, xf1, edge1, poly2, xf2) { + if (edge1 === undefined) edge1 = 0; + var count1 = parseInt(poly1.m_vertexCount); + var normals1 = poly1.m_normals; + var count2 = parseInt(poly2.m_vertexCount); + var vertices2 = poly2.m_vertices; + var normals2 = poly2.m_normals; + var tMat; + var tVec; + tMat = xf1.R; + tVec = normals1[edge1]; + var normal1X = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var normal1Y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = xf2.R; + var tX = (tMat.col1.x * normal1X + tMat.col1.y * normal1Y); + normal1Y = (tMat.col2.x * normal1X + tMat.col2.y * normal1Y); + normal1X = tX; + var index = 0; + var minDot = Number.MAX_VALUE; + for (var i = 0; i < count2; ++i) { + tVec = normals2[i]; + var dot = (normal1X * tVec.x + normal1Y * tVec.y); + if (dot < minDot) { + minDot = dot; + index = i; + } + } + var tClip; + var i1 = parseInt(index); + var i2 = parseInt(i1 + 1 < count2 ? i1 + 1 : 0); + tClip = c[0]; + tVec = vertices2[i1]; + tMat = xf2.R; + tClip.v.x = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + tClip.v.y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tClip.id.features.referenceEdge = edge1; + tClip.id.features.incidentEdge = i1; + tClip.id.features.incidentVertex = 0; + tClip = c[1]; + tVec = vertices2[i2]; + tMat = xf2.R; + tClip.v.x = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + tClip.v.y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tClip.id.features.referenceEdge = edge1; + tClip.id.features.incidentEdge = i2; + tClip.id.features.incidentVertex = 1; + } + b2Collision.MakeClipPointVector = function () { + var r = new Vector(2); + r[0] = new ClipVertex(); + r[1] = new ClipVertex(); + return r; + } + b2Collision.CollidePolygons = function (manifold, polyA, xfA, polyB, xfB) { + var cv; + manifold.m_pointCount = 0; + var totalRadius = polyA.m_radius + polyB.m_radius; + var edgeA = 0; + b2Collision.s_edgeAO[0] = edgeA; + var separationA = b2Collision.FindMaxSeparation(b2Collision.s_edgeAO, polyA, xfA, polyB, xfB); + edgeA = b2Collision.s_edgeAO[0]; + if (separationA > totalRadius) return; + var edgeB = 0; + b2Collision.s_edgeBO[0] = edgeB; + var separationB = b2Collision.FindMaxSeparation(b2Collision.s_edgeBO, polyB, xfB, polyA, xfA); + edgeB = b2Collision.s_edgeBO[0]; + if (separationB > totalRadius) return; + var poly1; + var poly2; + var xf1; + var xf2; + var edge1 = 0; + var flip = 0; + var k_relativeTol = 0.98; + var k_absoluteTol = 0.001; + var tMat; + if (separationB > k_relativeTol * separationA + k_absoluteTol) { + poly1 = polyB; + poly2 = polyA; + xf1 = xfB; + xf2 = xfA; + edge1 = edgeB; + manifold.m_type = b2Manifold.e_faceB; + flip = 1; + } + else { + poly1 = polyA; + poly2 = polyB; + xf1 = xfA; + xf2 = xfB; + edge1 = edgeA; + manifold.m_type = b2Manifold.e_faceA; + flip = 0; + } + var incidentEdge = b2Collision.s_incidentEdge; + b2Collision.FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); + var count1 = parseInt(poly1.m_vertexCount); + var vertices1 = poly1.m_vertices; + var local_v11 = vertices1[edge1]; + var local_v12; + if (edge1 + 1 < count1) { + local_v12 = vertices1[parseInt(edge1 + 1)]; + } + else { + local_v12 = vertices1[0]; + } + var localTangent = b2Collision.s_localTangent; + localTangent.Set(local_v12.x - local_v11.x, local_v12.y - local_v11.y); + localTangent.Normalize(); + var localNormal = b2Collision.s_localNormal; + localNormal.x = localTangent.y; + localNormal.y = (-localTangent.x); + var planePoint = b2Collision.s_planePoint; + planePoint.Set(0.5 * (local_v11.x + local_v12.x), 0.5 * (local_v11.y + local_v12.y)); + var tangent = b2Collision.s_tangent; + tMat = xf1.R; + tangent.x = (tMat.col1.x * localTangent.x + tMat.col2.x * localTangent.y); + tangent.y = (tMat.col1.y * localTangent.x + tMat.col2.y * localTangent.y); + var tangent2 = b2Collision.s_tangent2; + tangent2.x = (-tangent.x); + tangent2.y = (-tangent.y); + var normal = b2Collision.s_normal; + normal.x = tangent.y; + normal.y = (-tangent.x); + var v11 = b2Collision.s_v11; + var v12 = b2Collision.s_v12; + v11.x = xf1.position.x + (tMat.col1.x * local_v11.x + tMat.col2.x * local_v11.y); + v11.y = xf1.position.y + (tMat.col1.y * local_v11.x + tMat.col2.y * local_v11.y); + v12.x = xf1.position.x + (tMat.col1.x * local_v12.x + tMat.col2.x * local_v12.y); + v12.y = xf1.position.y + (tMat.col1.y * local_v12.x + tMat.col2.y * local_v12.y); + var frontOffset = normal.x * v11.x + normal.y * v11.y; + var sideOffset1 = (-tangent.x * v11.x) - tangent.y * v11.y + totalRadius; + var sideOffset2 = tangent.x * v12.x + tangent.y * v12.y + totalRadius; + var clipPoints1 = b2Collision.s_clipPoints1; + var clipPoints2 = b2Collision.s_clipPoints2; + var np = 0; + np = b2Collision.ClipSegmentToLine(clipPoints1, incidentEdge, tangent2, sideOffset1); + if (np < 2) return; + np = b2Collision.ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2); + if (np < 2) return; + manifold.m_localPlaneNormal.SetV(localNormal); + manifold.m_localPoint.SetV(planePoint); + var pointCount = 0; + for (var i = 0; i < b2Settings.b2_maxManifoldPoints; ++i) { + cv = clipPoints2[i]; + var separation = normal.x * cv.v.x + normal.y * cv.v.y - frontOffset; + if (separation <= totalRadius) { + var cp = manifold.m_points[pointCount]; + tMat = xf2.R; + var tX = cv.v.x - xf2.position.x; + var tY = cv.v.y - xf2.position.y; + cp.m_localPoint.x = (tX * tMat.col1.x + tY * tMat.col1.y); + cp.m_localPoint.y = (tX * tMat.col2.x + tY * tMat.col2.y); + cp.m_id.Set(cv.id); + cp.m_id.features.flip = flip; + ++pointCount; + } + } + manifold.m_pointCount = pointCount; + } + b2Collision.CollideCircles = function (manifold, circle1, xf1, circle2, xf2) { + manifold.m_pointCount = 0; + var tMat; + var tVec; + tMat = xf1.R; + tVec = circle1.m_p; + var p1X = xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var p1Y = xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = xf2.R; + tVec = circle2.m_p; + var p2X = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var p2Y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + var dX = p2X - p1X; + var dY = p2Y - p1Y; + var distSqr = dX * dX + dY * dY; + var radius = circle1.m_radius + circle2.m_radius; + if (distSqr > radius * radius) { + return; + } + manifold.m_type = b2Manifold.e_circles; + manifold.m_localPoint.SetV(circle1.m_p); + manifold.m_localPlaneNormal.SetZero(); + manifold.m_pointCount = 1; + manifold.m_points[0].m_localPoint.SetV(circle2.m_p); + manifold.m_points[0].m_id.key = 0; + } + b2Collision.CollidePolygonAndCircle = function (manifold, polygon, xf1, circle, xf2) { + manifold.m_pointCount = 0; + var tPoint; + var dX = 0; + var dY = 0; + var positionX = 0; + var positionY = 0; + var tVec; + var tMat; + tMat = xf2.R; + tVec = circle.m_p; + var cX = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var cY = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + dX = cX - xf1.position.x; + dY = cY - xf1.position.y; + tMat = xf1.R; + var cLocalX = (dX * tMat.col1.x + dY * tMat.col1.y); + var cLocalY = (dX * tMat.col2.x + dY * tMat.col2.y); + var dist = 0; + var normalIndex = 0; + var separation = (-Number.MAX_VALUE); + var radius = polygon.m_radius + circle.m_radius; + var vertexCount = parseInt(polygon.m_vertexCount); + var vertices = polygon.m_vertices; + var normals = polygon.m_normals; + for (var i = 0; i < vertexCount; ++i) { + tVec = vertices[i]; + dX = cLocalX - tVec.x; + dY = cLocalY - tVec.y; + tVec = normals[i]; + var s = tVec.x * dX + tVec.y * dY; + if (s > radius) { + return; + } + if (s > separation) { + separation = s; + normalIndex = i; + } + } + var vertIndex1 = parseInt(normalIndex); + var vertIndex2 = parseInt(vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0); + var v1 = vertices[vertIndex1]; + var v2 = vertices[vertIndex2]; + if (separation < Number.MIN_VALUE) { + manifold.m_pointCount = 1; + manifold.m_type = b2Manifold.e_faceA; + manifold.m_localPlaneNormal.SetV(normals[normalIndex]); + manifold.m_localPoint.x = 0.5 * (v1.x + v2.x); + manifold.m_localPoint.y = 0.5 * (v1.y + v2.y); + manifold.m_points[0].m_localPoint.SetV(circle.m_p); + manifold.m_points[0].m_id.key = 0; + return; + } + var u1 = (cLocalX - v1.x) * (v2.x - v1.x) + (cLocalY - v1.y) * (v2.y - v1.y); + var u2 = (cLocalX - v2.x) * (v1.x - v2.x) + (cLocalY - v2.y) * (v1.y - v2.y); + if (u1 <= 0.0) { + if ((cLocalX - v1.x) * (cLocalX - v1.x) + (cLocalY - v1.y) * (cLocalY - v1.y) > radius * radius) return; + manifold.m_pointCount = 1; + manifold.m_type = b2Manifold.e_faceA; + manifold.m_localPlaneNormal.x = cLocalX - v1.x; + manifold.m_localPlaneNormal.y = cLocalY - v1.y; + manifold.m_localPlaneNormal.Normalize(); + manifold.m_localPoint.SetV(v1); + manifold.m_points[0].m_localPoint.SetV(circle.m_p); + manifold.m_points[0].m_id.key = 0; + } + else if (u2 <= 0) { + if ((cLocalX - v2.x) * (cLocalX - v2.x) + (cLocalY - v2.y) * (cLocalY - v2.y) > radius * radius) return; + manifold.m_pointCount = 1; + manifold.m_type = b2Manifold.e_faceA; + manifold.m_localPlaneNormal.x = cLocalX - v2.x; + manifold.m_localPlaneNormal.y = cLocalY - v2.y; + manifold.m_localPlaneNormal.Normalize(); + manifold.m_localPoint.SetV(v2); + manifold.m_points[0].m_localPoint.SetV(circle.m_p); + manifold.m_points[0].m_id.key = 0; + } + else { + var faceCenterX = 0.5 * (v1.x + v2.x); + var faceCenterY = 0.5 * (v1.y + v2.y); + separation = (cLocalX - faceCenterX) * normals[vertIndex1].x + (cLocalY - faceCenterY) * normals[vertIndex1].y; + if (separation > radius) return; + manifold.m_pointCount = 1; + manifold.m_type = b2Manifold.e_faceA; + manifold.m_localPlaneNormal.x = normals[vertIndex1].x; + manifold.m_localPlaneNormal.y = normals[vertIndex1].y; + manifold.m_localPlaneNormal.Normalize(); + manifold.m_localPoint.Set(faceCenterX, faceCenterY); + manifold.m_points[0].m_localPoint.SetV(circle.m_p); + manifold.m_points[0].m_id.key = 0; + } + } + b2Collision.TestOverlap = function (a, b) { + var t1 = b.lowerBound; + var t2 = a.upperBound; + var d1X = t1.x - t2.x; + var d1Y = t1.y - t2.y; + t1 = a.lowerBound; + t2 = b.upperBound; + var d2X = t1.x - t2.x; + var d2Y = t1.y - t2.y; + if (d1X > 0.0 || d1Y > 0.0) return false; + if (d2X > 0.0 || d2Y > 0.0) return false; + return true; + } + Box2D.postDefs.push(function () { + Box2D.Collision.b2Collision.s_incidentEdge = b2Collision.MakeClipPointVector(); + Box2D.Collision.b2Collision.s_clipPoints1 = b2Collision.MakeClipPointVector(); + Box2D.Collision.b2Collision.s_clipPoints2 = b2Collision.MakeClipPointVector(); + Box2D.Collision.b2Collision.s_edgeAO = new Vector_a2j_Number(1); + Box2D.Collision.b2Collision.s_edgeBO = new Vector_a2j_Number(1); + Box2D.Collision.b2Collision.s_localTangent = new b2Vec2(); + Box2D.Collision.b2Collision.s_localNormal = new b2Vec2(); + Box2D.Collision.b2Collision.s_planePoint = new b2Vec2(); + Box2D.Collision.b2Collision.s_normal = new b2Vec2(); + Box2D.Collision.b2Collision.s_tangent = new b2Vec2(); + Box2D.Collision.b2Collision.s_tangent2 = new b2Vec2(); + Box2D.Collision.b2Collision.s_v11 = new b2Vec2(); + Box2D.Collision.b2Collision.s_v12 = new b2Vec2(); + Box2D.Collision.b2Collision.b2CollidePolyTempVec = new b2Vec2(); + Box2D.Collision.b2Collision.b2_nullFeature = 0x000000ff; + }); + b2ContactID.b2ContactID = function () { + this.features = new Features(); + }; + b2ContactID.prototype.b2ContactID = function () { + this.features._m_id = this; + } + b2ContactID.prototype.Set = function (id) { + this.key = id._key; + } + b2ContactID.prototype.Copy = function () { + var id = new b2ContactID(); + id.key = this.key; + return id; + } + Object.defineProperty(b2ContactID.prototype, 'key', { + enumerable: false, + configurable: true, + get: function () { + return this._key; + } + }); + Object.defineProperty(b2ContactID.prototype, 'key', { + enumerable: false, + configurable: true, + set: function (value) { + if (value === undefined) value = 0; + this._key = value; + this.features._referenceEdge = this._key & 0x000000ff; + this.features._incidentEdge = ((this._key & 0x0000ff00) >> 8) & 0x000000ff; + this.features._incidentVertex = ((this._key & 0x00ff0000) >> 16) & 0x000000ff; + this.features._flip = ((this._key & 0xff000000) >> 24) & 0x000000ff; + } + }); + b2ContactPoint.b2ContactPoint = function () { + this.position = new b2Vec2(); + this.velocity = new b2Vec2(); + this.normal = new b2Vec2(); + this.id = new b2ContactID(); + }; + b2Distance.b2Distance = function () {}; + b2Distance.Distance = function (output, cache, input) { + ++b2Distance.b2_gjkCalls; + var proxyA = input.proxyA; + var proxyB = input.proxyB; + var transformA = input.transformA; + var transformB = input.transformB; + var simplex = b2Distance.s_simplex; + simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB); + var vertices = simplex.m_vertices; + var k_maxIters = 20; + var saveA = b2Distance.s_saveA; + var saveB = b2Distance.s_saveB; + var saveCount = 0; + var closestPoint = simplex.GetClosestPoint(); + var distanceSqr1 = closestPoint.LengthSquared(); + var distanceSqr2 = distanceSqr1; + var i = 0; + var p; + var iter = 0; + while (iter < k_maxIters) { + saveCount = simplex.m_count; + for (i = 0; + i < saveCount; i++) { + saveA[i] = vertices[i].indexA; + saveB[i] = vertices[i].indexB; + } + switch (simplex.m_count) { + case 1: + break; + case 2: + simplex.Solve2(); + break; + case 3: + simplex.Solve3(); + break; + default: + b2Settings.b2Assert(false); + } + if (simplex.m_count == 3) { + break; + } + p = simplex.GetClosestPoint(); + distanceSqr2 = p.LengthSquared(); + if (distanceSqr2 > distanceSqr1) {} + distanceSqr1 = distanceSqr2; + var d = simplex.GetSearchDirection(); + if (d.LengthSquared() < Number.MIN_VALUE * Number.MIN_VALUE) { + break; + } + var vertex = vertices[simplex.m_count]; + vertex.indexA = proxyA.GetSupport(b2Math.MulTMV(transformA.R, d.GetNegative())); + vertex.wA = b2Math.MulX(transformA, proxyA.GetVertex(vertex.indexA)); + vertex.indexB = proxyB.GetSupport(b2Math.MulTMV(transformB.R, d)); + vertex.wB = b2Math.MulX(transformB, proxyB.GetVertex(vertex.indexB)); + vertex.w = b2Math.SubtractVV(vertex.wB, vertex.wA); + ++iter; + ++b2Distance.b2_gjkIters; + var duplicate = false; + for (i = 0; + i < saveCount; i++) { + if (vertex.indexA == saveA[i] && vertex.indexB == saveB[i]) { + duplicate = true; + break; + } + } + if (duplicate) { + break; + }++simplex.m_count; + } + b2Distance.b2_gjkMaxIters = b2Math.Max(b2Distance.b2_gjkMaxIters, iter); + simplex.GetWitnessPoints(output.pointA, output.pointB); + output.distance = b2Math.SubtractVV(output.pointA, output.pointB).Length(); + output.iterations = iter; + simplex.WriteCache(cache); + if (input.useRadii) { + var rA = proxyA.m_radius; + var rB = proxyB.m_radius; + if (output.distance > rA + rB && output.distance > Number.MIN_VALUE) { + output.distance -= rA + rB; + var normal = b2Math.SubtractVV(output.pointB, output.pointA); + normal.Normalize(); + output.pointA.x += rA * normal.x; + output.pointA.y += rA * normal.y; + output.pointB.x -= rB * normal.x; + output.pointB.y -= rB * normal.y; + } + else { + p = new b2Vec2(); + p.x = .5 * (output.pointA.x + output.pointB.x); + p.y = .5 * (output.pointA.y + output.pointB.y); + output.pointA.x = output.pointB.x = p.x; + output.pointA.y = output.pointB.y = p.y; + output.distance = 0.0; + } + } + } + Box2D.postDefs.push(function () { + Box2D.Collision.b2Distance.s_simplex = new b2Simplex(); + Box2D.Collision.b2Distance.s_saveA = new Vector_a2j_Number(3); + Box2D.Collision.b2Distance.s_saveB = new Vector_a2j_Number(3); + }); + b2DistanceInput.b2DistanceInput = function () {}; + b2DistanceOutput.b2DistanceOutput = function () { + this.pointA = new b2Vec2(); + this.pointB = new b2Vec2(); + }; + b2DistanceProxy.b2DistanceProxy = function () {}; + b2DistanceProxy.prototype.Set = function (shape) { + switch (shape.GetType()) { + case b2Shape.e_circleShape: + { + var circle = (shape instanceof b2CircleShape ? shape : null); + this.m_vertices = new Vector(1, true); + this.m_vertices[0] = circle.m_p; + this.m_count = 1; + this.m_radius = circle.m_radius; + } + break; + case b2Shape.e_polygonShape: + { + var polygon = (shape instanceof b2PolygonShape ? shape : null); + this.m_vertices = polygon.m_vertices; + this.m_count = polygon.m_vertexCount; + this.m_radius = polygon.m_radius; + } + break; + default: + b2Settings.b2Assert(false); + } + } + b2DistanceProxy.prototype.GetSupport = function (d) { + var bestIndex = 0; + var bestValue = this.m_vertices[0].x * d.x + this.m_vertices[0].y * d.y; + for (var i = 1; i < this.m_count; ++i) { + var value = this.m_vertices[i].x * d.x + this.m_vertices[i].y * d.y; + if (value > bestValue) { + bestIndex = i; + bestValue = value; + } + } + return bestIndex; + } + b2DistanceProxy.prototype.GetSupportVertex = function (d) { + var bestIndex = 0; + var bestValue = this.m_vertices[0].x * d.x + this.m_vertices[0].y * d.y; + for (var i = 1; i < this.m_count; ++i) { + var value = this.m_vertices[i].x * d.x + this.m_vertices[i].y * d.y; + if (value > bestValue) { + bestIndex = i; + bestValue = value; + } + } + return this.m_vertices[bestIndex]; + } + b2DistanceProxy.prototype.GetVertexCount = function () { + return this.m_count; + } + b2DistanceProxy.prototype.GetVertex = function (index) { + if (index === undefined) index = 0; + b2Settings.b2Assert(0 <= index && index < this.m_count); + return this.m_vertices[index]; + } + b2DynamicTree.b2DynamicTree = function () {}; + b2DynamicTree.prototype.b2DynamicTree = function () { + this.m_root = null; + this.m_freeList = null; + this.m_path = 0; + this.m_insertionCount = 0; + } + b2DynamicTree.prototype.CreateProxy = function (aabb, userData) { + var node = this.AllocateNode(); + var extendX = b2Settings.b2_aabbExtension; + var extendY = b2Settings.b2_aabbExtension; + node.aabb.lowerBound.x = aabb.lowerBound.x - extendX; + node.aabb.lowerBound.y = aabb.lowerBound.y - extendY; + node.aabb.upperBound.x = aabb.upperBound.x + extendX; + node.aabb.upperBound.y = aabb.upperBound.y + extendY; + node.userData = userData; + this.InsertLeaf(node); + return node; + } + b2DynamicTree.prototype.DestroyProxy = function (proxy) { + this.RemoveLeaf(proxy); + this.FreeNode(proxy); + } + b2DynamicTree.prototype.MoveProxy = function (proxy, aabb, displacement) { + b2Settings.b2Assert(proxy.IsLeaf()); + if (proxy.aabb.Contains(aabb)) { + return false; + } + this.RemoveLeaf(proxy); + var extendX = b2Settings.b2_aabbExtension + b2Settings.b2_aabbMultiplier * (displacement.x > 0 ? displacement.x : (-displacement.x)); + var extendY = b2Settings.b2_aabbExtension + b2Settings.b2_aabbMultiplier * (displacement.y > 0 ? displacement.y : (-displacement.y)); + proxy.aabb.lowerBound.x = aabb.lowerBound.x - extendX; + proxy.aabb.lowerBound.y = aabb.lowerBound.y - extendY; + proxy.aabb.upperBound.x = aabb.upperBound.x + extendX; + proxy.aabb.upperBound.y = aabb.upperBound.y + extendY; + this.InsertLeaf(proxy); + return true; + } + b2DynamicTree.prototype.Rebalance = function (iterations) { + if (iterations === undefined) iterations = 0; + if (this.m_root == null) return; + for (var i = 0; i < iterations; i++) { + var node = this.m_root; + var bit = 0; + while (node.IsLeaf() == false) { + node = (this.m_path >> bit) & 1 ? node.child2 : node.child1; + bit = (bit + 1) & 31; + }++this.m_path; + this.RemoveLeaf(node); + this.InsertLeaf(node); + } + } + b2DynamicTree.prototype.GetFatAABB = function (proxy) { + return proxy.aabb; + } + b2DynamicTree.prototype.GetUserData = function (proxy) { + return proxy.userData; + } + b2DynamicTree.prototype.Query = function (callback, aabb) { + if (this.m_root == null) return; + var stack = new Vector(); + var count = 0; + stack[count++] = this.m_root; + while (count > 0) { + var node = stack[--count]; + if (node.aabb.TestOverlap(aabb)) { + if (node.IsLeaf()) { + var proceed = callback(node); + if (!proceed) return; + } + else { + stack[count++] = node.child1; + stack[count++] = node.child2; + } + } + } + } + b2DynamicTree.prototype.RayCast = function (callback, input) { + if (this.m_root == null) return; + var p1 = input.p1; + var p2 = input.p2; + var r = b2Math.SubtractVV(p1, p2); + r.Normalize(); + var v = b2Math.CrossFV(1.0, r); + var abs_v = b2Math.AbsV(v); + var maxFraction = input.maxFraction; + var segmentAABB = new b2AABB(); + var tX = 0; + var tY = 0; { + tX = p1.x + maxFraction * (p2.x - p1.x); + tY = p1.y + maxFraction * (p2.y - p1.y); + segmentAABB.lowerBound.x = Math.min(p1.x, tX); + segmentAABB.lowerBound.y = Math.min(p1.y, tY); + segmentAABB.upperBound.x = Math.max(p1.x, tX); + segmentAABB.upperBound.y = Math.max(p1.y, tY); + } + var stack = new Vector(); + var count = 0; + stack[count++] = this.m_root; + while (count > 0) { + var node = stack[--count]; + if (node.aabb.TestOverlap(segmentAABB) == false) { + continue; + } + var c = node.aabb.GetCenter(); + var h = node.aabb.GetExtents(); + var separation = Math.abs(v.x * (p1.x - c.x) + v.y * (p1.y - c.y)) - abs_v.x * h.x - abs_v.y * h.y; + if (separation > 0.0) continue; + if (node.IsLeaf()) { + var subInput = new b2RayCastInput(); + subInput.p1 = input.p1; + subInput.p2 = input.p2; + subInput.maxFraction = input.maxFraction; + maxFraction = callback(subInput, node); + if (maxFraction == 0.0) return; + if (maxFraction > 0.0) { + tX = p1.x + maxFraction * (p2.x - p1.x); + tY = p1.y + maxFraction * (p2.y - p1.y); + segmentAABB.lowerBound.x = Math.min(p1.x, tX); + segmentAABB.lowerBound.y = Math.min(p1.y, tY); + segmentAABB.upperBound.x = Math.max(p1.x, tX); + segmentAABB.upperBound.y = Math.max(p1.y, tY); + } + } + else { + stack[count++] = node.child1; + stack[count++] = node.child2; + } + } + } + b2DynamicTree.prototype.AllocateNode = function () { + if (this.m_freeList) { + var node = this.m_freeList; + this.m_freeList = node.parent; + node.parent = null; + node.child1 = null; + node.child2 = null; + return node; + } + return new b2DynamicTreeNode(); + } + b2DynamicTree.prototype.FreeNode = function (node) { + node.parent = this.m_freeList; + this.m_freeList = node; + } + b2DynamicTree.prototype.InsertLeaf = function (leaf) { + ++this.m_insertionCount; + if (this.m_root == null) { + this.m_root = leaf; + this.m_root.parent = null; + return; + } + var center = leaf.aabb.GetCenter(); + var sibling = this.m_root; + if (sibling.IsLeaf() == false) { + do { + var child1 = sibling.child1; + var child2 = sibling.child2; + var norm1 = Math.abs((child1.aabb.lowerBound.x + child1.aabb.upperBound.x) / 2 - center.x) + Math.abs((child1.aabb.lowerBound.y + child1.aabb.upperBound.y) / 2 - center.y); + var norm2 = Math.abs((child2.aabb.lowerBound.x + child2.aabb.upperBound.x) / 2 - center.x) + Math.abs((child2.aabb.lowerBound.y + child2.aabb.upperBound.y) / 2 - center.y); + if (norm1 < norm2) { + sibling = child1; + } + else { + sibling = child2; + } + } + while (sibling.IsLeaf() == false) + } + var node1 = sibling.parent; + var node2 = this.AllocateNode(); + node2.parent = node1; + node2.userData = null; + node2.aabb.Combine(leaf.aabb, sibling.aabb); + if (node1) { + if (sibling.parent.child1 == sibling) { + node1.child1 = node2; + } + else { + node1.child2 = node2; + } + node2.child1 = sibling; + node2.child2 = leaf; + sibling.parent = node2; + leaf.parent = node2; + do { + if (node1.aabb.Contains(node2.aabb)) break; + node1.aabb.Combine(node1.child1.aabb, node1.child2.aabb); + node2 = node1; + node1 = node1.parent; + } + while (node1) + } + else { + node2.child1 = sibling; + node2.child2 = leaf; + sibling.parent = node2; + leaf.parent = node2; + this.m_root = node2; + } + } + b2DynamicTree.prototype.RemoveLeaf = function (leaf) { + if (leaf == this.m_root) { + this.m_root = null; + return; + } + var node2 = leaf.parent; + var node1 = node2.parent; + var sibling; + if (node2.child1 == leaf) { + sibling = node2.child2; + } + else { + sibling = node2.child1; + } + if (node1) { + if (node1.child1 == node2) { + node1.child1 = sibling; + } + else { + node1.child2 = sibling; + } + sibling.parent = node1; + this.FreeNode(node2); + while (node1) { + var oldAABB = node1.aabb; + node1.aabb = b2AABB.Combine(node1.child1.aabb, node1.child2.aabb); + if (oldAABB.Contains(node1.aabb)) break; + node1 = node1.parent; + } + } + else { + this.m_root = sibling; + sibling.parent = null; + this.FreeNode(node2); + } + } + b2DynamicTreeBroadPhase.b2DynamicTreeBroadPhase = function () { + this.m_tree = new b2DynamicTree(); + this.m_moveBuffer = new Vector(); + this.m_pairBuffer = new Vector(); + this.m_pairCount = 0; + }; + b2DynamicTreeBroadPhase.prototype.CreateProxy = function (aabb, userData) { + var proxy = this.m_tree.CreateProxy(aabb, userData); + ++this.m_proxyCount; + this.BufferMove(proxy); + return proxy; + } + b2DynamicTreeBroadPhase.prototype.DestroyProxy = function (proxy) { + this.UnBufferMove(proxy); + --this.m_proxyCount; + this.m_tree.DestroyProxy(proxy); + } + b2DynamicTreeBroadPhase.prototype.MoveProxy = function (proxy, aabb, displacement) { + var buffer = this.m_tree.MoveProxy(proxy, aabb, displacement); + if (buffer) { + this.BufferMove(proxy); + } + } + b2DynamicTreeBroadPhase.prototype.TestOverlap = function (proxyA, proxyB) { + var aabbA = this.m_tree.GetFatAABB(proxyA); + var aabbB = this.m_tree.GetFatAABB(proxyB); + return aabbA.TestOverlap(aabbB); + } + b2DynamicTreeBroadPhase.prototype.GetUserData = function (proxy) { + return this.m_tree.GetUserData(proxy); + } + b2DynamicTreeBroadPhase.prototype.GetFatAABB = function (proxy) { + return this.m_tree.GetFatAABB(proxy); + } + b2DynamicTreeBroadPhase.prototype.GetProxyCount = function () { + return this.m_proxyCount; + } + b2DynamicTreeBroadPhase.prototype.UpdatePairs = function (callback) { + var __this = this; + __this.m_pairCount = 0; + var i = 0, + queryProxy; + for (i = 0; + i < __this.m_moveBuffer.length; ++i) { + queryProxy = __this.m_moveBuffer[i]; + + function QueryCallback(proxy) { + if (proxy == queryProxy) return true; + if (__this.m_pairCount == __this.m_pairBuffer.length) { + __this.m_pairBuffer[__this.m_pairCount] = new b2DynamicTreePair(); + } + var pair = __this.m_pairBuffer[__this.m_pairCount]; + pair.proxyA = proxy < queryProxy ? proxy : queryProxy; + pair.proxyB = proxy >= queryProxy ? proxy : queryProxy;++__this.m_pairCount; + return true; + }; + var fatAABB = __this.m_tree.GetFatAABB(queryProxy); + __this.m_tree.Query(QueryCallback, fatAABB); + } + __this.m_moveBuffer.length = 0; + for (var i = 0; i < __this.m_pairCount;) { + var primaryPair = __this.m_pairBuffer[i]; + var userDataA = __this.m_tree.GetUserData(primaryPair.proxyA); + var userDataB = __this.m_tree.GetUserData(primaryPair.proxyB); + callback(userDataA, userDataB); + ++i; + while (i < __this.m_pairCount) { + var pair = __this.m_pairBuffer[i]; + if (pair.proxyA != primaryPair.proxyA || pair.proxyB != primaryPair.proxyB) { + break; + }++i; + } + } + } + b2DynamicTreeBroadPhase.prototype.Query = function (callback, aabb) { + this.m_tree.Query(callback, aabb); + } + b2DynamicTreeBroadPhase.prototype.RayCast = function (callback, input) { + this.m_tree.RayCast(callback, input); + } + b2DynamicTreeBroadPhase.prototype.Validate = function () {} + b2DynamicTreeBroadPhase.prototype.Rebalance = function (iterations) { + if (iterations === undefined) iterations = 0; + this.m_tree.Rebalance(iterations); + } + b2DynamicTreeBroadPhase.prototype.BufferMove = function (proxy) { + this.m_moveBuffer[this.m_moveBuffer.length] = proxy; + } + b2DynamicTreeBroadPhase.prototype.UnBufferMove = function (proxy) { + var i = parseInt(this.m_moveBuffer.indexOf(proxy)); + this.m_moveBuffer.splice(i, 1); + } + b2DynamicTreeBroadPhase.prototype.ComparePairs = function (pair1, pair2) { + return 0; + } + b2DynamicTreeBroadPhase.__implements = {}; + b2DynamicTreeBroadPhase.__implements[IBroadPhase] = true; + b2DynamicTreeNode.b2DynamicTreeNode = function () { + this.aabb = new b2AABB(); + }; + b2DynamicTreeNode.prototype.IsLeaf = function () { + return this.child1 == null; + } + b2DynamicTreePair.b2DynamicTreePair = function () {}; + b2Manifold.b2Manifold = function () { + this.m_pointCount = 0; + }; + b2Manifold.prototype.b2Manifold = function () { + this.m_points = new Vector(b2Settings.b2_maxManifoldPoints); + for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++) { + this.m_points[i] = new b2ManifoldPoint(); + } + this.m_localPlaneNormal = new b2Vec2(); + this.m_localPoint = new b2Vec2(); + } + b2Manifold.prototype.Reset = function () { + for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++) { + ((this.m_points[i] instanceof b2ManifoldPoint ? this.m_points[i] : null)).Reset(); + } + this.m_localPlaneNormal.SetZero(); + this.m_localPoint.SetZero(); + this.m_type = 0; + this.m_pointCount = 0; + } + b2Manifold.prototype.Set = function (m) { + this.m_pointCount = m.m_pointCount; + for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++) { + ((this.m_points[i] instanceof b2ManifoldPoint ? this.m_points[i] : null)).Set(m.m_points[i]); + } + this.m_localPlaneNormal.SetV(m.m_localPlaneNormal); + this.m_localPoint.SetV(m.m_localPoint); + this.m_type = m.m_type; + } + b2Manifold.prototype.Copy = function () { + var copy = new b2Manifold(); + copy.Set(this); + return copy; + } + Box2D.postDefs.push(function () { + Box2D.Collision.b2Manifold.e_circles = 0x0001; + Box2D.Collision.b2Manifold.e_faceA = 0x0002; + Box2D.Collision.b2Manifold.e_faceB = 0x0004; + }); + b2ManifoldPoint.b2ManifoldPoint = function () { + this.m_localPoint = new b2Vec2(); + this.m_id = new b2ContactID(); + }; + b2ManifoldPoint.prototype.b2ManifoldPoint = function () { + this.Reset(); + } + b2ManifoldPoint.prototype.Reset = function () { + this.m_localPoint.SetZero(); + this.m_normalImpulse = 0.0; + this.m_tangentImpulse = 0.0; + this.m_id.key = 0; + } + b2ManifoldPoint.prototype.Set = function (m) { + this.m_localPoint.SetV(m.m_localPoint); + this.m_normalImpulse = m.m_normalImpulse; + this.m_tangentImpulse = m.m_tangentImpulse; + this.m_id.Set(m.m_id); + } + b2Point.b2Point = function () { + this.p = new b2Vec2(); + }; + b2Point.prototype.Support = function (xf, vX, vY) { + if (vX === undefined) vX = 0; + if (vY === undefined) vY = 0; + return this.p; + } + b2Point.prototype.GetFirstVertex = function (xf) { + return this.p; + } + b2RayCastInput.b2RayCastInput = function () { + this.p1 = new b2Vec2(); + this.p2 = new b2Vec2(); + }; + b2RayCastInput.prototype.b2RayCastInput = function (p1, p2, maxFraction) { + if (p1 === undefined) p1 = null; + if (p2 === undefined) p2 = null; + if (maxFraction === undefined) maxFraction = 1; + if (p1) this.p1.SetV(p1); + if (p2) this.p2.SetV(p2); + this.maxFraction = maxFraction; + } + b2RayCastOutput.b2RayCastOutput = function () { + this.normal = new b2Vec2(); + }; + b2Segment.b2Segment = function () { + this.p1 = new b2Vec2(); + this.p2 = new b2Vec2(); + }; + b2Segment.prototype.TestSegment = function (lambda, normal, segment, maxLambda) { + if (maxLambda === undefined) maxLambda = 0; + var s = segment.p1; + var rX = segment.p2.x - s.x; + var rY = segment.p2.y - s.y; + var dX = this.p2.x - this.p1.x; + var dY = this.p2.y - this.p1.y; + var nX = dY; + var nY = (-dX); + var k_slop = 100.0 * Number.MIN_VALUE; + var denom = (-(rX * nX + rY * nY)); + if (denom > k_slop) { + var bX = s.x - this.p1.x; + var bY = s.y - this.p1.y; + var a = (bX * nX + bY * nY); + if (0.0 <= a && a <= maxLambda * denom) { + var mu2 = (-rX * bY) + rY * bX; + if ((-k_slop * denom) <= mu2 && mu2 <= denom * (1.0 + k_slop)) { + a /= denom; + var nLen = Math.sqrt(nX * nX + nY * nY); + nX /= nLen; + nY /= nLen; + lambda[0] = a; + normal.Set(nX, nY); + return true; + } + } + } + return false; + } + b2Segment.prototype.Extend = function (aabb) { + this.ExtendForward(aabb); + this.ExtendBackward(aabb); + } + + + + + b2Segment.prototype.ExtendForward = function (aabb) { + var dX = this.p2.x - this.p1.x; + var dY = this.p2.y - this.p1.y; + var lambda = Math.min(dX > 0 ? (aabb.upperBound.x - this.p1.x) / dX : dX < 0 ? (aabb.lowerBound.x - this.p1.x) / dX : Number.POSITIVE_INFINITY, + dY > 0 ? (aabb.upperBound.y - this.p1.y) / dY : dY < 0 ? (aabb.lowerBound.y - this.p1.y) / dY : Number.POSITIVE_INFINITY); + this.p2.x = this.p1.x + dX * lambda; + this.p2.y = this.p1.y + dY * lambda; + } + b2Segment.prototype.ExtendBackward = function (aabb) { + var dX = (-this.p2.x) + this.p1.x; + var dY = (-this.p2.y) + this.p1.y; + var lambda = Math.min(dX > 0 ? (aabb.upperBound.x - this.p2.x) / dX : dX < 0 ? (aabb.lowerBound.x - this.p2.x) / dX : Number.POSITIVE_INFINITY, + dY > 0 ? (aabb.upperBound.y - this.p2.y) / dY : dY < 0 ? (aabb.lowerBound.y - this.p2.y) / dY : Number.POSITIVE_INFINITY); + this.p1.x = this.p2.x + dX * lambda; + this.p1.y = this.p2.y + dY * lambda; + } + b2SeparationFunction.b2SeparationFunction = function () { + this.m_localPoint = new b2Vec2(); + this.m_axis = new b2Vec2(); + }; + b2SeparationFunction.prototype.Initialize = function (cache, proxyA, transformA, proxyB, transformB) { + this.m_proxyA = proxyA; + this.m_proxyB = proxyB; + var count = parseInt(cache.count); + b2Settings.b2Assert(0 < count && count < 3); + var localPointA; + var localPointA1; + var localPointA2; + var localPointB; + var localPointB1; + var localPointB2; + var pointAX = 0; + var pointAY = 0; + var pointBX = 0; + var pointBY = 0; + var normalX = 0; + var normalY = 0; + var tMat; + var tVec; + var s = 0; + var sgn = 0; + if (count == 1) { + this.m_type = b2SeparationFunction.e_points; + localPointA = this.m_proxyA.GetVertex(cache.indexA[0]); + localPointB = this.m_proxyB.GetVertex(cache.indexB[0]); + tVec = localPointA; + tMat = transformA.R; + pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tVec = localPointB; + tMat = transformB.R; + pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + this.m_axis.x = pointBX - pointAX; + this.m_axis.y = pointBY - pointAY; + this.m_axis.Normalize(); + } + else if (cache.indexB[0] == cache.indexB[1]) { + this.m_type = b2SeparationFunction.e_faceA; + localPointA1 = this.m_proxyA.GetVertex(cache.indexA[0]); + localPointA2 = this.m_proxyA.GetVertex(cache.indexA[1]); + localPointB = this.m_proxyB.GetVertex(cache.indexB[0]); + this.m_localPoint.x = 0.5 * (localPointA1.x + localPointA2.x); + this.m_localPoint.y = 0.5 * (localPointA1.y + localPointA2.y); + this.m_axis = b2Math.CrossVF(b2Math.SubtractVV(localPointA2, localPointA1), 1.0); + this.m_axis.Normalize(); + tVec = this.m_axis; + tMat = transformA.R; + normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tVec = this.m_localPoint; + tMat = transformA.R; + pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tVec = localPointB; + tMat = transformB.R; + pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + s = (pointBX - pointAX) * normalX + (pointBY - pointAY) * normalY; + if (s < 0.0) { + this.m_axis.NegativeSelf(); + } + } + else if (cache.indexA[0] == cache.indexA[0]) { + this.m_type = b2SeparationFunction.e_faceB; + localPointB1 = this.m_proxyB.GetVertex(cache.indexB[0]); + localPointB2 = this.m_proxyB.GetVertex(cache.indexB[1]); + localPointA = this.m_proxyA.GetVertex(cache.indexA[0]); + this.m_localPoint.x = 0.5 * (localPointB1.x + localPointB2.x); + this.m_localPoint.y = 0.5 * (localPointB1.y + localPointB2.y); + this.m_axis = b2Math.CrossVF(b2Math.SubtractVV(localPointB2, localPointB1), 1.0); + this.m_axis.Normalize(); + tVec = this.m_axis; + tMat = transformB.R; + normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tVec = this.m_localPoint; + tMat = transformB.R; + pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tVec = localPointA; + tMat = transformA.R; + pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + s = (pointAX - pointBX) * normalX + (pointAY - pointBY) * normalY; + if (s < 0.0) { + this.m_axis.NegativeSelf(); + } + } + else { + localPointA1 = this.m_proxyA.GetVertex(cache.indexA[0]); + localPointA2 = this.m_proxyA.GetVertex(cache.indexA[1]); + localPointB1 = this.m_proxyB.GetVertex(cache.indexB[0]); + localPointB2 = this.m_proxyB.GetVertex(cache.indexB[1]); + var pA = b2Math.MulX(transformA, localPointA); + var dA = b2Math.MulMV(transformA.R, b2Math.SubtractVV(localPointA2, localPointA1)); + var pB = b2Math.MulX(transformB, localPointB); + var dB = b2Math.MulMV(transformB.R, b2Math.SubtractVV(localPointB2, localPointB1)); + var a = dA.x * dA.x + dA.y * dA.y; + var e = dB.x * dB.x + dB.y * dB.y; + var r = b2Math.SubtractVV(dB, dA); + var c = dA.x * r.x + dA.y * r.y; + var f = dB.x * r.x + dB.y * r.y; + var b = dA.x * dB.x + dA.y * dB.y; + var denom = a * e - b * b; + s = 0.0; + if (denom != 0.0) { + s = b2Math.Clamp((b * f - c * e) / denom, 0.0, 1.0); + } + var t = (b * s + f) / e; + if (t < 0.0) { + t = 0.0; + s = b2Math.Clamp((b - c) / a, 0.0, 1.0); + } + localPointA = new b2Vec2(); + localPointA.x = localPointA1.x + s * (localPointA2.x - localPointA1.x); + localPointA.y = localPointA1.y + s * (localPointA2.y - localPointA1.y); + localPointB = new b2Vec2(); + localPointB.x = localPointB1.x + s * (localPointB2.x - localPointB1.x); + localPointB.y = localPointB1.y + s * (localPointB2.y - localPointB1.y); + if (s == 0.0 || s == 1.0) { + this.m_type = b2SeparationFunction.e_faceB; + this.m_axis = b2Math.CrossVF(b2Math.SubtractVV(localPointB2, localPointB1), 1.0); + this.m_axis.Normalize(); + this.m_localPoint = localPointB; + tVec = this.m_axis; + tMat = transformB.R; + normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tVec = this.m_localPoint; + tMat = transformB.R; + pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tVec = localPointA; + tMat = transformA.R; + pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + sgn = (pointAX - pointBX) * normalX + (pointAY - pointBY) * normalY; + if (s < 0.0) { + this.m_axis.NegativeSelf(); + } + } + else { + this.m_type = b2SeparationFunction.e_faceA; + this.m_axis = b2Math.CrossVF(b2Math.SubtractVV(localPointA2, localPointA1), 1.0); + this.m_localPoint = localPointA; + tVec = this.m_axis; + tMat = transformA.R; + normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tVec = this.m_localPoint; + tMat = transformA.R; + pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tVec = localPointB; + tMat = transformB.R; + pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + sgn = (pointBX - pointAX) * normalX + (pointBY - pointAY) * normalY; + if (s < 0.0) { + this.m_axis.NegativeSelf(); + } + } + } + } + b2SeparationFunction.prototype.Evaluate = function (transformA, transformB) { + var axisA; + var axisB; + var localPointA; + var localPointB; + var pointA; + var pointB; + var seperation = 0; + var normal; + switch (this.m_type) { + case b2SeparationFunction.e_points: + { + axisA = b2Math.MulTMV(transformA.R, this.m_axis); + axisB = b2Math.MulTMV(transformB.R, this.m_axis.GetNegative()); + localPointA = this.m_proxyA.GetSupportVertex(axisA); + localPointB = this.m_proxyB.GetSupportVertex(axisB); + pointA = b2Math.MulX(transformA, localPointA); + pointB = b2Math.MulX(transformB, localPointB); + seperation = (pointB.x - pointA.x) * this.m_axis.x + (pointB.y - pointA.y) * this.m_axis.y; + return seperation; + } + case b2SeparationFunction.e_faceA: + { + normal = b2Math.MulMV(transformA.R, this.m_axis); + pointA = b2Math.MulX(transformA, this.m_localPoint); + axisB = b2Math.MulTMV(transformB.R, normal.GetNegative()); + localPointB = this.m_proxyB.GetSupportVertex(axisB); + pointB = b2Math.MulX(transformB, localPointB); + seperation = (pointB.x - pointA.x) * normal.x + (pointB.y - pointA.y) * normal.y; + return seperation; + } + case b2SeparationFunction.e_faceB: + { + normal = b2Math.MulMV(transformB.R, this.m_axis); + pointB = b2Math.MulX(transformB, this.m_localPoint); + axisA = b2Math.MulTMV(transformA.R, normal.GetNegative()); + localPointA = this.m_proxyA.GetSupportVertex(axisA); + pointA = b2Math.MulX(transformA, localPointA); + seperation = (pointA.x - pointB.x) * normal.x + (pointA.y - pointB.y) * normal.y; + return seperation; + } + default: + b2Settings.b2Assert(false); + return 0.0; + } + } + Box2D.postDefs.push(function () { + Box2D.Collision.b2SeparationFunction.e_points = 0x01; + Box2D.Collision.b2SeparationFunction.e_faceA = 0x02; + Box2D.Collision.b2SeparationFunction.e_faceB = 0x04; + }); + b2Simplex.b2Simplex = function () { + this.m_v1 = new b2SimplexVertex(); + this.m_v2 = new b2SimplexVertex(); + this.m_v3 = new b2SimplexVertex(); + this.m_vertices = new Vector(3); + }; + b2Simplex.prototype.b2Simplex = function () { + this.m_vertices[0] = this.m_v1; + this.m_vertices[1] = this.m_v2; + this.m_vertices[2] = this.m_v3; + } + b2Simplex.prototype.ReadCache = function (cache, proxyA, transformA, proxyB, transformB) { + b2Settings.b2Assert(0 <= cache.count && cache.count <= 3); + var wALocal; + var wBLocal; + this.m_count = cache.count; + var vertices = this.m_vertices; + for (var i = 0; i < this.m_count; i++) { + var v = vertices[i]; + v.indexA = cache.indexA[i]; + v.indexB = cache.indexB[i]; + wALocal = proxyA.GetVertex(v.indexA); + wBLocal = proxyB.GetVertex(v.indexB); + v.wA = b2Math.MulX(transformA, wALocal); + v.wB = b2Math.MulX(transformB, wBLocal); + v.w = b2Math.SubtractVV(v.wB, v.wA); + v.a = 0; + } + if (this.m_count > 1) { + var metric1 = cache.metric; + var metric2 = this.GetMetric(); + if (metric2 < .5 * metric1 || 2.0 * metric1 < metric2 || metric2 < Number.MIN_VALUE) { + this.m_count = 0; + } + } + if (this.m_count == 0) { + v = vertices[0]; + v.indexA = 0; + v.indexB = 0; + wALocal = proxyA.GetVertex(0); + wBLocal = proxyB.GetVertex(0); + v.wA = b2Math.MulX(transformA, wALocal); + v.wB = b2Math.MulX(transformB, wBLocal); + v.w = b2Math.SubtractVV(v.wB, v.wA); + this.m_count = 1; + } + } + b2Simplex.prototype.WriteCache = function (cache) { + cache.metric = this.GetMetric(); + cache.count = Box2D.parseUInt(this.m_count); + var vertices = this.m_vertices; + for (var i = 0; i < this.m_count; i++) { + cache.indexA[i] = Box2D.parseUInt(vertices[i].indexA); + cache.indexB[i] = Box2D.parseUInt(vertices[i].indexB); + } + } + b2Simplex.prototype.GetSearchDirection = function () { + switch (this.m_count) { + case 1: + return this.m_v1.w.GetNegative(); + case 2: + { + var e12 = b2Math.SubtractVV(this.m_v2.w, this.m_v1.w); + var sgn = b2Math.CrossVV(e12, this.m_v1.w.GetNegative()); + if (sgn > 0.0) { + return b2Math.CrossFV(1.0, e12); + } + else { + return b2Math.CrossVF(e12, 1.0); + } + } + default: + b2Settings.b2Assert(false); + return new b2Vec2(); + } + } + b2Simplex.prototype.GetClosestPoint = function () { + switch (this.m_count) { + case 0: + b2Settings.b2Assert(false); + return new b2Vec2(); + case 1: + return this.m_v1.w; + case 2: + return new b2Vec2(this.m_v1.a * this.m_v1.w.x + this.m_v2.a * this.m_v2.w.x, this.m_v1.a * this.m_v1.w.y + this.m_v2.a * this.m_v2.w.y); + default: + b2Settings.b2Assert(false); + return new b2Vec2(); + } + } + b2Simplex.prototype.GetWitnessPoints = function (pA, pB) { + switch (this.m_count) { + case 0: + b2Settings.b2Assert(false); + break; + case 1: + pA.SetV(this.m_v1.wA); + pB.SetV(this.m_v1.wB); + break; + case 2: + pA.x = this.m_v1.a * this.m_v1.wA.x + this.m_v2.a * this.m_v2.wA.x; + pA.y = this.m_v1.a * this.m_v1.wA.y + this.m_v2.a * this.m_v2.wA.y; + pB.x = this.m_v1.a * this.m_v1.wB.x + this.m_v2.a * this.m_v2.wB.x; + pB.y = this.m_v1.a * this.m_v1.wB.y + this.m_v2.a * this.m_v2.wB.y; + break; + case 3: + pB.x = pA.x = this.m_v1.a * this.m_v1.wA.x + this.m_v2.a * this.m_v2.wA.x + this.m_v3.a * this.m_v3.wA.x; + pB.y = pA.y = this.m_v1.a * this.m_v1.wA.y + this.m_v2.a * this.m_v2.wA.y + this.m_v3.a * this.m_v3.wA.y; + break; + default: + b2Settings.b2Assert(false); + break; + } + } + b2Simplex.prototype.GetMetric = function () { + switch (this.m_count) { + case 0: + b2Settings.b2Assert(false); + return 0.0; + case 1: + return 0.0; + case 2: + return b2Math.SubtractVV(this.m_v1.w, this.m_v2.w).Length(); + case 3: + return b2Math.CrossVV(b2Math.SubtractVV(this.m_v2.w, this.m_v1.w), b2Math.SubtractVV(this.m_v3.w, this.m_v1.w)); + default: + b2Settings.b2Assert(false); + return 0.0; + } + } + b2Simplex.prototype.Solve2 = function () { + var w1 = this.m_v1.w; + var w2 = this.m_v2.w; + var e12 = b2Math.SubtractVV(w2, w1); + var d12_2 = (-(w1.x * e12.x + w1.y * e12.y)); + if (d12_2 <= 0.0) { + this.m_v1.a = 1.0; + this.m_count = 1; + return; + } + var d12_1 = (w2.x * e12.x + w2.y * e12.y); + if (d12_1 <= 0.0) { + this.m_v2.a = 1.0; + this.m_count = 1; + this.m_v1.Set(this.m_v2); + return; + } + var inv_d12 = 1.0 / (d12_1 + d12_2); + this.m_v1.a = d12_1 * inv_d12; + this.m_v2.a = d12_2 * inv_d12; + this.m_count = 2; + } + b2Simplex.prototype.Solve3 = function () { + var w1 = this.m_v1.w; + var w2 = this.m_v2.w; + var w3 = this.m_v3.w; + var e12 = b2Math.SubtractVV(w2, w1); + var w1e12 = b2Math.Dot(w1, e12); + var w2e12 = b2Math.Dot(w2, e12); + var d12_1 = w2e12; + var d12_2 = (-w1e12); + var e13 = b2Math.SubtractVV(w3, w1); + var w1e13 = b2Math.Dot(w1, e13); + var w3e13 = b2Math.Dot(w3, e13); + var d13_1 = w3e13; + var d13_2 = (-w1e13); + var e23 = b2Math.SubtractVV(w3, w2); + var w2e23 = b2Math.Dot(w2, e23); + var w3e23 = b2Math.Dot(w3, e23); + var d23_1 = w3e23; + var d23_2 = (-w2e23); + var n123 = b2Math.CrossVV(e12, e13); + var d123_1 = n123 * b2Math.CrossVV(w2, w3); + var d123_2 = n123 * b2Math.CrossVV(w3, w1); + var d123_3 = n123 * b2Math.CrossVV(w1, w2); + if (d12_2 <= 0.0 && d13_2 <= 0.0) { + this.m_v1.a = 1.0; + this.m_count = 1; + return; + } + if (d12_1 > 0.0 && d12_2 > 0.0 && d123_3 <= 0.0) { + var inv_d12 = 1.0 / (d12_1 + d12_2); + this.m_v1.a = d12_1 * inv_d12; + this.m_v2.a = d12_2 * inv_d12; + this.m_count = 2; + return; + } + if (d13_1 > 0.0 && d13_2 > 0.0 && d123_2 <= 0.0) { + var inv_d13 = 1.0 / (d13_1 + d13_2); + this.m_v1.a = d13_1 * inv_d13; + this.m_v3.a = d13_2 * inv_d13; + this.m_count = 2; + this.m_v2.Set(this.m_v3); + return; + } + if (d12_1 <= 0.0 && d23_2 <= 0.0) { + this.m_v2.a = 1.0; + this.m_count = 1; + this.m_v1.Set(this.m_v2); + return; + } + if (d13_1 <= 0.0 && d23_1 <= 0.0) { + this.m_v3.a = 1.0; + this.m_count = 1; + this.m_v1.Set(this.m_v3); + return; + } + if (d23_1 > 0.0 && d23_2 > 0.0 && d123_1 <= 0.0) { + var inv_d23 = 1.0 / (d23_1 + d23_2); + this.m_v2.a = d23_1 * inv_d23; + this.m_v3.a = d23_2 * inv_d23; + this.m_count = 2; + this.m_v1.Set(this.m_v3); + return; + } + var inv_d123 = 1.0 / (d123_1 + d123_2 + d123_3); + this.m_v1.a = d123_1 * inv_d123; + this.m_v2.a = d123_2 * inv_d123; + this.m_v3.a = d123_3 * inv_d123; + this.m_count = 3; + } + b2SimplexCache.b2SimplexCache = function () { + this.indexA = new Vector_a2j_Number(3); + this.indexB = new Vector_a2j_Number(3); + }; + b2SimplexVertex.b2SimplexVertex = function () {}; + b2SimplexVertex.prototype.Set = function (other) { + this.wA.SetV(other.wA); + this.wB.SetV(other.wB); + this.w.SetV(other.w); + this.a = other.a; + this.indexA = other.indexA; + this.indexB = other.indexB; + } + b2TimeOfImpact.b2TimeOfImpact = function () {}; + b2TimeOfImpact.TimeOfImpact = function (input) { + ++b2TimeOfImpact.b2_toiCalls; + var proxyA = input.proxyA; + var proxyB = input.proxyB; + var sweepA = input.sweepA; + var sweepB = input.sweepB; + b2Settings.b2Assert(sweepA.t0 == sweepB.t0); + b2Settings.b2Assert(1.0 - sweepA.t0 > Number.MIN_VALUE); + var radius = proxyA.m_radius + proxyB.m_radius; + var tolerance = input.tolerance; + var alpha = 0.0; + var k_maxIterations = 1000; + var iter = 0; + var target = 0.0; + b2TimeOfImpact.s_cache.count = 0; + b2TimeOfImpact.s_distanceInput.useRadii = false; + for (;;) { + sweepA.GetTransform(b2TimeOfImpact.s_xfA, alpha); + sweepB.GetTransform(b2TimeOfImpact.s_xfB, alpha); + b2TimeOfImpact.s_distanceInput.proxyA = proxyA; + b2TimeOfImpact.s_distanceInput.proxyB = proxyB; + b2TimeOfImpact.s_distanceInput.transformA = b2TimeOfImpact.s_xfA; + b2TimeOfImpact.s_distanceInput.transformB = b2TimeOfImpact.s_xfB; + b2Distance.Distance(b2TimeOfImpact.s_distanceOutput, b2TimeOfImpact.s_cache, b2TimeOfImpact.s_distanceInput); + if (b2TimeOfImpact.s_distanceOutput.distance <= 0.0) { + alpha = 1.0; + break; + } + b2TimeOfImpact.s_fcn.Initialize(b2TimeOfImpact.s_cache, proxyA, b2TimeOfImpact.s_xfA, proxyB, b2TimeOfImpact.s_xfB); + var separation = b2TimeOfImpact.s_fcn.Evaluate(b2TimeOfImpact.s_xfA, b2TimeOfImpact.s_xfB); + if (separation <= 0.0) { + alpha = 1.0; + break; + } + if (iter == 0) { + if (separation > radius) { + target = b2Math.Max(radius - tolerance, 0.75 * radius); + } + else { + target = b2Math.Max(separation - tolerance, 0.02 * radius); + } + } + if (separation - target < 0.5 * tolerance) { + if (iter == 0) { + alpha = 1.0; + break; + } + break; + } + var newAlpha = alpha; { + var x1 = alpha; + var x2 = 1.0; + var f1 = separation; + sweepA.GetTransform(b2TimeOfImpact.s_xfA, x2); + sweepB.GetTransform(b2TimeOfImpact.s_xfB, x2); + var f2 = b2TimeOfImpact.s_fcn.Evaluate(b2TimeOfImpact.s_xfA, b2TimeOfImpact.s_xfB); + if (f2 >= target) { + alpha = 1.0; + break; + } + var rootIterCount = 0; + for (;;) { + var x = 0; + if (rootIterCount & 1) { + x = x1 + (target - f1) * (x2 - x1) / (f2 - f1); + } + else { + x = 0.5 * (x1 + x2); + } + sweepA.GetTransform(b2TimeOfImpact.s_xfA, x); + sweepB.GetTransform(b2TimeOfImpact.s_xfB, x); + var f = b2TimeOfImpact.s_fcn.Evaluate(b2TimeOfImpact.s_xfA, b2TimeOfImpact.s_xfB); + if (b2Math.Abs(f - target) < 0.025 * tolerance) { + newAlpha = x; + break; + } + if (f > target) { + x1 = x; + f1 = f; + } + else { + x2 = x; + f2 = f; + }++rootIterCount; + ++b2TimeOfImpact.b2_toiRootIters; + if (rootIterCount == 50) { + break; + } + } + b2TimeOfImpact.b2_toiMaxRootIters = b2Math.Max(b2TimeOfImpact.b2_toiMaxRootIters, rootIterCount); + } + if (newAlpha < (1.0 + 100.0 * Number.MIN_VALUE) * alpha) { + break; + } + alpha = newAlpha; + iter++; + ++b2TimeOfImpact.b2_toiIters; + if (iter == k_maxIterations) { + break; + } + } + b2TimeOfImpact.b2_toiMaxIters = b2Math.Max(b2TimeOfImpact.b2_toiMaxIters, iter); + return alpha; + } + Box2D.postDefs.push(function () { + Box2D.Collision.b2TimeOfImpact.b2_toiCalls = 0; + Box2D.Collision.b2TimeOfImpact.b2_toiIters = 0; + Box2D.Collision.b2TimeOfImpact.b2_toiMaxIters = 0; + Box2D.Collision.b2TimeOfImpact.b2_toiRootIters = 0; + Box2D.Collision.b2TimeOfImpact.b2_toiMaxRootIters = 0; + Box2D.Collision.b2TimeOfImpact.s_cache = new b2SimplexCache(); + Box2D.Collision.b2TimeOfImpact.s_distanceInput = new b2DistanceInput(); + Box2D.Collision.b2TimeOfImpact.s_xfA = new b2Transform(); + Box2D.Collision.b2TimeOfImpact.s_xfB = new b2Transform(); + Box2D.Collision.b2TimeOfImpact.s_fcn = new b2SeparationFunction(); + Box2D.Collision.b2TimeOfImpact.s_distanceOutput = new b2DistanceOutput(); + }); + b2TOIInput.b2TOIInput = function () { + this.proxyA = new b2DistanceProxy(); + this.proxyB = new b2DistanceProxy(); + this.sweepA = new b2Sweep(); + this.sweepB = new b2Sweep(); + }; + b2WorldManifold.b2WorldManifold = function () { + this.m_normal = new b2Vec2(); + }; + b2WorldManifold.prototype.b2WorldManifold = function () { + this.m_points = new Vector(b2Settings.b2_maxManifoldPoints); + for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++) { + this.m_points[i] = new b2Vec2(); + } + } + b2WorldManifold.prototype.Initialize = function (manifold, xfA, radiusA, xfB, radiusB) { + if (radiusA === undefined) radiusA = 0; + if (radiusB === undefined) radiusB = 0; + if (manifold.m_pointCount == 0) { + return; + } + var i = 0; + var tVec; + var tMat; + var normalX = 0; + var normalY = 0; + var planePointX = 0; + var planePointY = 0; + var clipPointX = 0; + var clipPointY = 0; + switch (manifold.m_type) { + case b2Manifold.e_circles: + { + tMat = xfA.R; + tVec = manifold.m_localPoint; + var pointAX = xfA.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + var pointAY = xfA.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = xfB.R; + tVec = manifold.m_points[0].m_localPoint; + var pointBX = xfB.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + var pointBY = xfB.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + var dX = pointBX - pointAX; + var dY = pointBY - pointAY; + var d2 = dX * dX + dY * dY; + if (d2 > Number.MIN_VALUE * Number.MIN_VALUE) { + var d = Math.sqrt(d2); + this.m_normal.x = dX / d; + this.m_normal.y = dY / d; + } + else { + this.m_normal.x = 1; + this.m_normal.y = 0; + } + var cAX = pointAX + radiusA * this.m_normal.x; + var cAY = pointAY + radiusA * this.m_normal.y; + var cBX = pointBX - radiusB * this.m_normal.x; + var cBY = pointBY - radiusB * this.m_normal.y; + this.m_points[0].x = 0.5 * (cAX + cBX); + this.m_points[0].y = 0.5 * (cAY + cBY); + } + break; + case b2Manifold.e_faceA: + { + tMat = xfA.R; + tVec = manifold.m_localPlaneNormal; + normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = xfA.R; + tVec = manifold.m_localPoint; + planePointX = xfA.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + planePointY = xfA.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + this.m_normal.x = normalX; + this.m_normal.y = normalY; + for (i = 0; + i < manifold.m_pointCount; i++) { + tMat = xfB.R; + tVec = manifold.m_points[i].m_localPoint; + clipPointX = xfB.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + clipPointY = xfB.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + this.m_points[i].x = clipPointX + 0.5 * (radiusA - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusB) * normalX; + this.m_points[i].y = clipPointY + 0.5 * (radiusA - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusB) * normalY; + } + } + break; + case b2Manifold.e_faceB: + { + tMat = xfB.R; + tVec = manifold.m_localPlaneNormal; + normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = xfB.R; + tVec = manifold.m_localPoint; + planePointX = xfB.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + planePointY = xfB.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + this.m_normal.x = (-normalX); + this.m_normal.y = (-normalY); + for (i = 0; + i < manifold.m_pointCount; i++) { + tMat = xfA.R; + tVec = manifold.m_points[i].m_localPoint; + clipPointX = xfA.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + clipPointY = xfA.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + this.m_points[i].x = clipPointX + 0.5 * (radiusB - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusA) * normalX; + this.m_points[i].y = clipPointY + 0.5 * (radiusB - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusA) * normalY; + } + } + break; + } + } + ClipVertex.ClipVertex = function () { + this.v = new b2Vec2(); + this.id = new b2ContactID(); + }; + ClipVertex.prototype.Set = function (other) { + this.v.SetV(other.v); + this.id.Set(other.id); + } + Features.Features = function () {}; + Object.defineProperty(Features.prototype, 'referenceEdge', { + enumerable: false, + configurable: true, + get: function () { + return this._referenceEdge; + } + }); + Object.defineProperty(Features.prototype, 'referenceEdge', { + enumerable: false, + configurable: true, + set: function (value) { + if (value === undefined) value = 0; + this._referenceEdge = value; + this._m_id._key = (this._m_id._key & 0xffffff00) | (this._referenceEdge & 0x000000ff); + } + }); + Object.defineProperty(Features.prototype, 'incidentEdge', { + enumerable: false, + configurable: true, + get: function () { + return this._incidentEdge; + } + }); + Object.defineProperty(Features.prototype, 'incidentEdge', { + enumerable: false, + configurable: true, + set: function (value) { + if (value === undefined) value = 0; + this._incidentEdge = value; + this._m_id._key = (this._m_id._key & 0xffff00ff) | ((this._incidentEdge << 8) & 0x0000ff00); + } + }); + Object.defineProperty(Features.prototype, 'incidentVertex', { + enumerable: false, + configurable: true, + get: function () { + return this._incidentVertex; + } + }); + Object.defineProperty(Features.prototype, 'incidentVertex', { + enumerable: false, + configurable: true, + set: function (value) { + if (value === undefined) value = 0; + this._incidentVertex = value; + this._m_id._key = (this._m_id._key & 0xff00ffff) | ((this._incidentVertex << 16) & 0x00ff0000); + } + }); + Object.defineProperty(Features.prototype, 'flip', { + enumerable: false, + configurable: true, + get: function () { + return this._flip; + } + }); + Object.defineProperty(Features.prototype, 'flip', { + enumerable: false, + configurable: true, + set: function (value) { + if (value === undefined) value = 0; + this._flip = value; + this._m_id._key = (this._m_id._key & 0x00ffffff) | ((this._flip << 24) & 0xff000000); + } + }); +})(); +(function () { + var b2Color = Box2D.Common.b2Color, + b2internal = Box2D.Common.b2internal, + b2Settings = Box2D.Common.b2Settings, + b2CircleShape = Box2D.Collision.Shapes.b2CircleShape, + b2EdgeChainDef = Box2D.Collision.Shapes.b2EdgeChainDef, + b2EdgeShape = Box2D.Collision.Shapes.b2EdgeShape, + b2MassData = Box2D.Collision.Shapes.b2MassData, + b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape, + b2Shape = Box2D.Collision.Shapes.b2Shape, + b2Mat22 = Box2D.Common.Math.b2Mat22, + b2Mat33 = Box2D.Common.Math.b2Mat33, + b2Math = Box2D.Common.Math.b2Math, + b2Sweep = Box2D.Common.Math.b2Sweep, + b2Transform = Box2D.Common.Math.b2Transform, + b2Vec2 = Box2D.Common.Math.b2Vec2, + b2Vec3 = Box2D.Common.Math.b2Vec3, + b2Body = Box2D.Dynamics.b2Body, + b2BodyDef = Box2D.Dynamics.b2BodyDef, + b2ContactFilter = Box2D.Dynamics.b2ContactFilter, + b2ContactImpulse = Box2D.Dynamics.b2ContactImpulse, + b2ContactListener = Box2D.Dynamics.b2ContactListener, + b2ContactManager = Box2D.Dynamics.b2ContactManager, + b2DebugDraw = Box2D.Dynamics.b2DebugDraw, + b2DestructionListener = Box2D.Dynamics.b2DestructionListener, + b2FilterData = Box2D.Dynamics.b2FilterData, + b2Fixture = Box2D.Dynamics.b2Fixture, + b2FixtureDef = Box2D.Dynamics.b2FixtureDef, + b2Island = Box2D.Dynamics.b2Island, + b2TimeStep = Box2D.Dynamics.b2TimeStep, + b2World = Box2D.Dynamics.b2World, + b2AABB = Box2D.Collision.b2AABB, + b2Bound = Box2D.Collision.b2Bound, + b2BoundValues = Box2D.Collision.b2BoundValues, + b2Collision = Box2D.Collision.b2Collision, + b2ContactID = Box2D.Collision.b2ContactID, + b2ContactPoint = Box2D.Collision.b2ContactPoint, + b2Distance = Box2D.Collision.b2Distance, + b2DistanceInput = Box2D.Collision.b2DistanceInput, + b2DistanceOutput = Box2D.Collision.b2DistanceOutput, + b2DistanceProxy = Box2D.Collision.b2DistanceProxy, + b2DynamicTree = Box2D.Collision.b2DynamicTree, + b2DynamicTreeBroadPhase = Box2D.Collision.b2DynamicTreeBroadPhase, + b2DynamicTreeNode = Box2D.Collision.b2DynamicTreeNode, + b2DynamicTreePair = Box2D.Collision.b2DynamicTreePair, + b2Manifold = Box2D.Collision.b2Manifold, + b2ManifoldPoint = Box2D.Collision.b2ManifoldPoint, + b2Point = Box2D.Collision.b2Point, + b2RayCastInput = Box2D.Collision.b2RayCastInput, + b2RayCastOutput = Box2D.Collision.b2RayCastOutput, + b2Segment = Box2D.Collision.b2Segment, + b2SeparationFunction = Box2D.Collision.b2SeparationFunction, + b2Simplex = Box2D.Collision.b2Simplex, + b2SimplexCache = Box2D.Collision.b2SimplexCache, + b2SimplexVertex = Box2D.Collision.b2SimplexVertex, + b2TimeOfImpact = Box2D.Collision.b2TimeOfImpact, + b2TOIInput = Box2D.Collision.b2TOIInput, + b2WorldManifold = Box2D.Collision.b2WorldManifold, + ClipVertex = Box2D.Collision.ClipVertex, + Features = Box2D.Collision.Features, + IBroadPhase = Box2D.Collision.IBroadPhase; + + Box2D.inherit(b2CircleShape, Box2D.Collision.Shapes.b2Shape); + b2CircleShape.prototype.__super = Box2D.Collision.Shapes.b2Shape.prototype; + b2CircleShape.b2CircleShape = function () { + Box2D.Collision.Shapes.b2Shape.b2Shape.apply(this, arguments); + this.m_p = new b2Vec2(); + }; + b2CircleShape.prototype.Copy = function () { + var s = new b2CircleShape(); + s.Set(this); + return s; + } + b2CircleShape.prototype.Set = function (other) { + this.__super.Set.call(this, other); + if (Box2D.is(other, b2CircleShape)) { + var other2 = (other instanceof b2CircleShape ? other : null); + this.m_p.SetV(other2.m_p); + } + } + b2CircleShape.prototype.TestPoint = function (transform, p) { + var tMat = transform.R; + var dX = transform.position.x + (tMat.col1.x * this.m_p.x + tMat.col2.x * this.m_p.y); + var dY = transform.position.y + (tMat.col1.y * this.m_p.x + tMat.col2.y * this.m_p.y); + dX = p.x - dX; + dY = p.y - dY; + return (dX * dX + dY * dY) <= this.m_radius * this.m_radius; + } + b2CircleShape.prototype.RayCast = function (output, input, transform) { + var tMat = transform.R; + var positionX = transform.position.x + (tMat.col1.x * this.m_p.x + tMat.col2.x * this.m_p.y); + var positionY = transform.position.y + (tMat.col1.y * this.m_p.x + tMat.col2.y * this.m_p.y); + var sX = input.p1.x - positionX; + var sY = input.p1.y - positionY; + var b = (sX * sX + sY * sY) - this.m_radius * this.m_radius; + var rX = input.p2.x - input.p1.x; + var rY = input.p2.y - input.p1.y; + var c = (sX * rX + sY * rY); + var rr = (rX * rX + rY * rY); + var sigma = c * c - rr * b; + if (sigma < 0.0 || rr < Number.MIN_VALUE) { + return false; + } + var a = (-(c + Math.sqrt(sigma))); + if (0.0 <= a && a <= input.maxFraction * rr) { + a /= rr; + output.fraction = a; + output.normal.x = sX + a * rX; + output.normal.y = sY + a * rY; + output.normal.Normalize(); + return true; + } + return false; + } + b2CircleShape.prototype.ComputeAABB = function (aabb, transform) { + var tMat = transform.R; + var pX = transform.position.x + (tMat.col1.x * this.m_p.x + tMat.col2.x * this.m_p.y); + var pY = transform.position.y + (tMat.col1.y * this.m_p.x + tMat.col2.y * this.m_p.y); + aabb.lowerBound.Set(pX - this.m_radius, pY - this.m_radius); + aabb.upperBound.Set(pX + this.m_radius, pY + this.m_radius); + } + b2CircleShape.prototype.ComputeMass = function (massData, density) { + if (density === undefined) density = 0; + massData.mass = density * b2Settings.b2_pi * this.m_radius * this.m_radius; + massData.center.SetV(this.m_p); + massData.I = massData.mass * (0.5 * this.m_radius * this.m_radius + (this.m_p.x * this.m_p.x + this.m_p.y * this.m_p.y)); + } + b2CircleShape.prototype.ComputeSubmergedArea = function (normal, offset, xf, c) { + if (offset === undefined) offset = 0; + var p = b2Math.MulX(xf, this.m_p); + var l = (-(b2Math.Dot(normal, p) - offset)); + if (l < (-this.m_radius) + Number.MIN_VALUE) { + return 0; + } + if (l > this.m_radius) { + c.SetV(p); + return Math.PI * this.m_radius * this.m_radius; + } + var r2 = this.m_radius * this.m_radius; + var l2 = l * l; + var area = r2 * (Math.asin(l / this.m_radius) + Math.PI / 2) + l * Math.sqrt(r2 - l2); + var com = (-2 / 3 * Math.pow(r2 - l2, 1.5) / area); + c.x = p.x + normal.x * com; + c.y = p.y + normal.y * com; + return area; + } + b2CircleShape.prototype.GetLocalPosition = function () { + return this.m_p; + } + b2CircleShape.prototype.SetLocalPosition = function (position) { + this.m_p.SetV(position); + } + b2CircleShape.prototype.GetRadius = function () { + return this.m_radius; + } + b2CircleShape.prototype.SetRadius = function (radius) { + if (radius === undefined) radius = 0; + this.m_radius = radius; + } + b2CircleShape.prototype.b2CircleShape = function (radius) { + if (radius === undefined) radius = 0; + this.__super.b2Shape.call(this); + this.m_type = b2Shape.e_circleShape; + this.m_radius = radius; + } + b2EdgeChainDef.b2EdgeChainDef = function () {}; + b2EdgeChainDef.prototype.b2EdgeChainDef = function () { + this.vertexCount = 0; + this.isALoop = true; + this.vertices = []; + } + Box2D.inherit(b2EdgeShape, Box2D.Collision.Shapes.b2Shape); + b2EdgeShape.prototype.__super = Box2D.Collision.Shapes.b2Shape.prototype; + b2EdgeShape.b2EdgeShape = function () { + Box2D.Collision.Shapes.b2Shape.b2Shape.apply(this, arguments); + this.s_supportVec = new b2Vec2(); + this.m_v1 = new b2Vec2(); + this.m_v2 = new b2Vec2(); + this.m_coreV1 = new b2Vec2(); + this.m_coreV2 = new b2Vec2(); + this.m_normal = new b2Vec2(); + this.m_direction = new b2Vec2(); + this.m_cornerDir1 = new b2Vec2(); + this.m_cornerDir2 = new b2Vec2(); + }; + b2EdgeShape.prototype.TestPoint = function (transform, p) { + return false; + } + b2EdgeShape.prototype.RayCast = function (output, input, transform) { + var tMat; + var rX = input.p2.x - input.p1.x; + var rY = input.p2.y - input.p1.y; + tMat = transform.R; + var v1X = transform.position.x + (tMat.col1.x * this.m_v1.x + tMat.col2.x * this.m_v1.y); + var v1Y = transform.position.y + (tMat.col1.y * this.m_v1.x + tMat.col2.y * this.m_v1.y); + var nX = transform.position.y + (tMat.col1.y * this.m_v2.x + tMat.col2.y * this.m_v2.y) - v1Y; + var nY = (-(transform.position.x + (tMat.col1.x * this.m_v2.x + tMat.col2.x * this.m_v2.y) - v1X)); + var k_slop = 100.0 * Number.MIN_VALUE; + var denom = (-(rX * nX + rY * nY)); + if (denom > k_slop) { + var bX = input.p1.x - v1X; + var bY = input.p1.y - v1Y; + var a = (bX * nX + bY * nY); + if (0.0 <= a && a <= input.maxFraction * denom) { + var mu2 = (-rX * bY) + rY * bX; + if ((-k_slop * denom) <= mu2 && mu2 <= denom * (1.0 + k_slop)) { + a /= denom; + output.fraction = a; + var nLen = Math.sqrt(nX * nX + nY * nY); + output.normal.x = nX / nLen; + output.normal.y = nY / nLen; + return true; + } + } + } + return false; + } + b2EdgeShape.prototype.ComputeAABB = function (aabb, transform) { + var tMat = transform.R; + var v1X = transform.position.x + (tMat.col1.x * this.m_v1.x + tMat.col2.x * this.m_v1.y); + var v1Y = transform.position.y + (tMat.col1.y * this.m_v1.x + tMat.col2.y * this.m_v1.y); + var v2X = transform.position.x + (tMat.col1.x * this.m_v2.x + tMat.col2.x * this.m_v2.y); + var v2Y = transform.position.y + (tMat.col1.y * this.m_v2.x + tMat.col2.y * this.m_v2.y); + if (v1X < v2X) { + aabb.lowerBound.x = v1X; + aabb.upperBound.x = v2X; + } + else { + aabb.lowerBound.x = v2X; + aabb.upperBound.x = v1X; + } + if (v1Y < v2Y) { + aabb.lowerBound.y = v1Y; + aabb.upperBound.y = v2Y; + } + else { + aabb.lowerBound.y = v2Y; + aabb.upperBound.y = v1Y; + } + } + b2EdgeShape.prototype.ComputeMass = function (massData, density) { + if (density === undefined) density = 0; + massData.mass = 0; + massData.center.SetV(this.m_v1); + massData.I = 0; + } + b2EdgeShape.prototype.ComputeSubmergedArea = function (normal, offset, xf, c) { + if (offset === undefined) offset = 0; + var v0 = new b2Vec2(normal.x * offset, normal.y * offset); + var v1 = b2Math.MulX(xf, this.m_v1); + var v2 = b2Math.MulX(xf, this.m_v2); + var d1 = b2Math.Dot(normal, v1) - offset; + var d2 = b2Math.Dot(normal, v2) - offset; + if (d1 > 0) { + if (d2 > 0) { + return 0; + } + else { + v1.x = (-d2 / (d1 - d2) * v1.x) + d1 / (d1 - d2) * v2.x; + v1.y = (-d2 / (d1 - d2) * v1.y) + d1 / (d1 - d2) * v2.y; + } + } + else { + if (d2 > 0) { + v2.x = (-d2 / (d1 - d2) * v1.x) + d1 / (d1 - d2) * v2.x; + v2.y = (-d2 / (d1 - d2) * v1.y) + d1 / (d1 - d2) * v2.y; + } + else {} + } + c.x = (v0.x + v1.x + v2.x) / 3; + c.y = (v0.y + v1.y + v2.y) / 3; + return 0.5 * ((v1.x - v0.x) * (v2.y - v0.y) - (v1.y - v0.y) * (v2.x - v0.x)); + } + b2EdgeShape.prototype.GetLength = function () { + return this.m_length; + } + b2EdgeShape.prototype.GetVertex1 = function () { + return this.m_v1; + } + b2EdgeShape.prototype.GetVertex2 = function () { + return this.m_v2; + } + b2EdgeShape.prototype.GetCoreVertex1 = function () { + return this.m_coreV1; + } + b2EdgeShape.prototype.GetCoreVertex2 = function () { + return this.m_coreV2; + } + b2EdgeShape.prototype.GetNormalVector = function () { + return this.m_normal; + } + b2EdgeShape.prototype.GetDirectionVector = function () { + return this.m_direction; + } + b2EdgeShape.prototype.GetCorner1Vector = function () { + return this.m_cornerDir1; + } + b2EdgeShape.prototype.GetCorner2Vector = function () { + return this.m_cornerDir2; + } + b2EdgeShape.prototype.Corner1IsConvex = function () { + return this.m_cornerConvex1; + } + b2EdgeShape.prototype.Corner2IsConvex = function () { + return this.m_cornerConvex2; + } + b2EdgeShape.prototype.GetFirstVertex = function (xf) { + var tMat = xf.R; + return new b2Vec2(xf.position.x + (tMat.col1.x * this.m_coreV1.x + tMat.col2.x * this.m_coreV1.y), xf.position.y + (tMat.col1.y * this.m_coreV1.x + tMat.col2.y * this.m_coreV1.y)); + } + b2EdgeShape.prototype.GetNextEdge = function () { + return this.m_nextEdge; + } + b2EdgeShape.prototype.GetPrevEdge = function () { + return this.m_prevEdge; + } + b2EdgeShape.prototype.Support = function (xf, dX, dY) { + if (dX === undefined) dX = 0; + if (dY === undefined) dY = 0; + var tMat = xf.R; + var v1X = xf.position.x + (tMat.col1.x * this.m_coreV1.x + tMat.col2.x * this.m_coreV1.y); + var v1Y = xf.position.y + (tMat.col1.y * this.m_coreV1.x + tMat.col2.y * this.m_coreV1.y); + var v2X = xf.position.x + (tMat.col1.x * this.m_coreV2.x + tMat.col2.x * this.m_coreV2.y); + var v2Y = xf.position.y + (tMat.col1.y * this.m_coreV2.x + tMat.col2.y * this.m_coreV2.y); + if ((v1X * dX + v1Y * dY) > (v2X * dX + v2Y * dY)) { + this.s_supportVec.x = v1X; + this.s_supportVec.y = v1Y; + } + else { + this.s_supportVec.x = v2X; + this.s_supportVec.y = v2Y; + } + return this.s_supportVec; + } + b2EdgeShape.prototype.b2EdgeShape = function (v1, v2) { + this.__super.b2Shape.call(this); + this.m_type = b2Shape.e_edgeShape; + this.m_prevEdge = null; + this.m_nextEdge = null; + this.m_v1 = v1; + this.m_v2 = v2; + this.m_direction.Set(this.m_v2.x - this.m_v1.x, this.m_v2.y - this.m_v1.y); + this.m_length = this.m_direction.Normalize(); + this.m_normal.Set(this.m_direction.y, (-this.m_direction.x)); + this.m_coreV1.Set((-b2Settings.b2_toiSlop * (this.m_normal.x - this.m_direction.x)) + this.m_v1.x, (-b2Settings.b2_toiSlop * (this.m_normal.y - this.m_direction.y)) + this.m_v1.y); + this.m_coreV2.Set((-b2Settings.b2_toiSlop * (this.m_normal.x + this.m_direction.x)) + this.m_v2.x, (-b2Settings.b2_toiSlop * (this.m_normal.y + this.m_direction.y)) + this.m_v2.y); + this.m_cornerDir1 = this.m_normal; + this.m_cornerDir2.Set((-this.m_normal.x), (-this.m_normal.y)); + } + b2EdgeShape.prototype.SetPrevEdge = function (edge, core, cornerDir, convex) { + this.m_prevEdge = edge; + this.m_coreV1 = core; + this.m_cornerDir1 = cornerDir; + this.m_cornerConvex1 = convex; + } + b2EdgeShape.prototype.SetNextEdge = function (edge, core, cornerDir, convex) { + this.m_nextEdge = edge; + this.m_coreV2 = core; + this.m_cornerDir2 = cornerDir; + this.m_cornerConvex2 = convex; + } + b2MassData.b2MassData = function () { + this.mass = 0.0; + this.center = new b2Vec2(0, 0); + this.I = 0.0; + }; + Box2D.inherit(b2PolygonShape, Box2D.Collision.Shapes.b2Shape); + b2PolygonShape.prototype.__super = Box2D.Collision.Shapes.b2Shape.prototype; + b2PolygonShape.b2PolygonShape = function () { + Box2D.Collision.Shapes.b2Shape.b2Shape.apply(this, arguments); + }; + b2PolygonShape.prototype.Copy = function () { + var s = new b2PolygonShape(); + s.Set(this); + return s; + } + b2PolygonShape.prototype.Set = function (other) { + this.__super.Set.call(this, other); + if (Box2D.is(other, b2PolygonShape)) { + var other2 = (other instanceof b2PolygonShape ? other : null); + this.m_centroid.SetV(other2.m_centroid); + this.m_vertexCount = other2.m_vertexCount; + this.Reserve(this.m_vertexCount); + for (var i = 0; i < this.m_vertexCount; i++) { + this.m_vertices[i].SetV(other2.m_vertices[i]); + this.m_normals[i].SetV(other2.m_normals[i]); + } + } + } + b2PolygonShape.prototype.SetAsArray = function (vertices, vertexCount) { + if (vertexCount === undefined) vertexCount = 0; + var v = new Vector(); + var i = 0, + tVec; + for (i = 0; + i < vertices.length; ++i) { + tVec = vertices[i]; + v.push(tVec); + } + this.SetAsVector(v, vertexCount); + } + b2PolygonShape.AsArray = function (vertices, vertexCount) { + if (vertexCount === undefined) vertexCount = 0; + var polygonShape = new b2PolygonShape(); + polygonShape.SetAsArray(vertices, vertexCount); + return polygonShape; + } + b2PolygonShape.prototype.SetAsVector = function (vertices, vertexCount) { + if (vertexCount === undefined) vertexCount = 0; + if (vertexCount == 0) vertexCount = vertices.length; + b2Settings.b2Assert(2 <= vertexCount); + this.m_vertexCount = vertexCount; + this.Reserve(vertexCount); + var i = 0; + for (i = 0; + i < this.m_vertexCount; i++) { + this.m_vertices[i].SetV(vertices[i]); + } + for (i = 0; + i < this.m_vertexCount; ++i) { + var i1 = parseInt(i); + var i2 = parseInt(i + 1 < this.m_vertexCount ? i + 1 : 0); + var edge = b2Math.SubtractVV(this.m_vertices[i2], this.m_vertices[i1]); + b2Settings.b2Assert(edge.LengthSquared() > Number.MIN_VALUE); + this.m_normals[i].SetV(b2Math.CrossVF(edge, 1.0)); + this.m_normals[i].Normalize(); + } + this.m_centroid = b2PolygonShape.ComputeCentroid(this.m_vertices, this.m_vertexCount); + } + b2PolygonShape.AsVector = function (vertices, vertexCount) { + if (vertexCount === undefined) vertexCount = 0; + var polygonShape = new b2PolygonShape(); + polygonShape.SetAsVector(vertices, vertexCount); + return polygonShape; + } + b2PolygonShape.prototype.SetAsBox = function (hx, hy) { + if (hx === undefined) hx = 0; + if (hy === undefined) hy = 0; + this.m_vertexCount = 4; + this.Reserve(4); + this.m_vertices[0].Set((-hx), (-hy)); + this.m_vertices[1].Set(hx, (-hy)); + this.m_vertices[2].Set(hx, hy); + this.m_vertices[3].Set((-hx), hy); + this.m_normals[0].Set(0.0, (-1.0)); + this.m_normals[1].Set(1.0, 0.0); + this.m_normals[2].Set(0.0, 1.0); + this.m_normals[3].Set((-1.0), 0.0); + this.m_centroid.SetZero(); + } + b2PolygonShape.AsBox = function (hx, hy) { + if (hx === undefined) hx = 0; + if (hy === undefined) hy = 0; + var polygonShape = new b2PolygonShape(); + polygonShape.SetAsBox(hx, hy); + return polygonShape; + } + b2PolygonShape.prototype.SetAsOrientedBox = function (hx, hy, center, angle) { + if (hx === undefined) hx = 0; + if (hy === undefined) hy = 0; + if (center === undefined) center = null; + if (angle === undefined) angle = 0.0; + this.m_vertexCount = 4; + this.Reserve(4); + this.m_vertices[0].Set((-hx), (-hy)); + this.m_vertices[1].Set(hx, (-hy)); + this.m_vertices[2].Set(hx, hy); + this.m_vertices[3].Set((-hx), hy); + this.m_normals[0].Set(0.0, (-1.0)); + this.m_normals[1].Set(1.0, 0.0); + this.m_normals[2].Set(0.0, 1.0); + this.m_normals[3].Set((-1.0), 0.0); + this.m_centroid = center; + var xf = new b2Transform(); + xf.position = center; + xf.R.Set(angle); + for (var i = 0; i < this.m_vertexCount; ++i) { + this.m_vertices[i] = b2Math.MulX(xf, this.m_vertices[i]); + this.m_normals[i] = b2Math.MulMV(xf.R, this.m_normals[i]); + } + } + b2PolygonShape.AsOrientedBox = function (hx, hy, center, angle) { + if (hx === undefined) hx = 0; + if (hy === undefined) hy = 0; + if (center === undefined) center = null; + if (angle === undefined) angle = 0.0; + var polygonShape = new b2PolygonShape(); + polygonShape.SetAsOrientedBox(hx, hy, center, angle); + return polygonShape; + } + b2PolygonShape.prototype.SetAsEdge = function (v1, v2) { + this.m_vertexCount = 2; + this.Reserve(2); + this.m_vertices[0].SetV(v1); + this.m_vertices[1].SetV(v2); + this.m_centroid.x = 0.5 * (v1.x + v2.x); + this.m_centroid.y = 0.5 * (v1.y + v2.y); + this.m_normals[0] = b2Math.CrossVF(b2Math.SubtractVV(v2, v1), 1.0); + this.m_normals[0].Normalize(); + this.m_normals[1].x = (-this.m_normals[0].x); + this.m_normals[1].y = (-this.m_normals[0].y); + } + b2PolygonShape.AsEdge = function (v1, v2) { + var polygonShape = new b2PolygonShape(); + polygonShape.SetAsEdge(v1, v2); + return polygonShape; + } + b2PolygonShape.prototype.TestPoint = function (xf, p) { + var tVec; + var tMat = xf.R; + var tX = p.x - xf.position.x; + var tY = p.y - xf.position.y; + var pLocalX = (tX * tMat.col1.x + tY * tMat.col1.y); + var pLocalY = (tX * tMat.col2.x + tY * tMat.col2.y); + for (var i = 0; i < this.m_vertexCount; ++i) { + tVec = this.m_vertices[i]; + tX = pLocalX - tVec.x; + tY = pLocalY - tVec.y; + tVec = this.m_normals[i]; + var dot = (tVec.x * tX + tVec.y * tY); + if (dot > 0.0) { + return false; + } + } + return true; + } + b2PolygonShape.prototype.RayCast = function (output, input, transform) { + var lower = 0.0; + var upper = input.maxFraction; + var tX = 0; + var tY = 0; + var tMat; + var tVec; + tX = input.p1.x - transform.position.x; + tY = input.p1.y - transform.position.y; + tMat = transform.R; + var p1X = (tX * tMat.col1.x + tY * tMat.col1.y); + var p1Y = (tX * tMat.col2.x + tY * tMat.col2.y); + tX = input.p2.x - transform.position.x; + tY = input.p2.y - transform.position.y; + tMat = transform.R; + var p2X = (tX * tMat.col1.x + tY * tMat.col1.y); + var p2Y = (tX * tMat.col2.x + tY * tMat.col2.y); + var dX = p2X - p1X; + var dY = p2Y - p1Y; + var index = parseInt((-1)); + for (var i = 0; i < this.m_vertexCount; ++i) { + tVec = this.m_vertices[i]; + tX = tVec.x - p1X; + tY = tVec.y - p1Y; + tVec = this.m_normals[i]; + var numerator = (tVec.x * tX + tVec.y * tY); + var denominator = (tVec.x * dX + tVec.y * dY); + if (denominator == 0.0) { + if (numerator < 0.0) { + return false; + } + } + else { + if (denominator < 0.0 && numerator < lower * denominator) { + lower = numerator / denominator; + index = i; + } + else if (denominator > 0.0 && numerator < upper * denominator) { + upper = numerator / denominator; + } + } + if (upper < lower - Number.MIN_VALUE) { + return false; + } + } + if (index >= 0) { + output.fraction = lower; + tMat = transform.R; + tVec = this.m_normals[index]; + output.normal.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + output.normal.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + return true; + } + return false; + } + b2PolygonShape.prototype.ComputeAABB = function (aabb, xf) { + var tMat = xf.R; + var tVec = this.m_vertices[0]; + var lowerX = xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var lowerY = xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + var upperX = lowerX; + var upperY = lowerY; + for (var i = 1; i < this.m_vertexCount; ++i) { + tVec = this.m_vertices[i]; + var vX = xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var vY = xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + lowerX = lowerX < vX ? lowerX : vX; + lowerY = lowerY < vY ? lowerY : vY; + upperX = upperX > vX ? upperX : vX; + upperY = upperY > vY ? upperY : vY; + } + aabb.lowerBound.x = lowerX - this.m_radius; + aabb.lowerBound.y = lowerY - this.m_radius; + aabb.upperBound.x = upperX + this.m_radius; + aabb.upperBound.y = upperY + this.m_radius; + } + b2PolygonShape.prototype.ComputeMass = function (massData, density) { + if (density === undefined) density = 0; + if (this.m_vertexCount == 2) { + massData.center.x = 0.5 * (this.m_vertices[0].x + this.m_vertices[1].x); + massData.center.y = 0.5 * (this.m_vertices[0].y + this.m_vertices[1].y); + massData.mass = 0.0; + massData.I = 0.0; + return; + } + var centerX = 0.0; + var centerY = 0.0; + var area = 0.0; + var I = 0.0; + var p1X = 0.0; + var p1Y = 0.0; + var k_inv3 = 1.0 / 3.0; + for (var i = 0; i < this.m_vertexCount; ++i) { + var p2 = this.m_vertices[i]; + var p3 = i + 1 < this.m_vertexCount ? this.m_vertices[parseInt(i + 1)] : this.m_vertices[0]; + var e1X = p2.x - p1X; + var e1Y = p2.y - p1Y; + var e2X = p3.x - p1X; + var e2Y = p3.y - p1Y; + var D = e1X * e2Y - e1Y * e2X; + var triangleArea = 0.5 * D;area += triangleArea; + centerX += triangleArea * k_inv3 * (p1X + p2.x + p3.x); + centerY += triangleArea * k_inv3 * (p1Y + p2.y + p3.y); + var px = p1X; + var py = p1Y; + var ex1 = e1X; + var ey1 = e1Y; + var ex2 = e2X; + var ey2 = e2Y; + var intx2 = k_inv3 * (0.25 * (ex1 * ex1 + ex2 * ex1 + ex2 * ex2) + (px * ex1 + px * ex2)) + 0.5 * px * px; + var inty2 = k_inv3 * (0.25 * (ey1 * ey1 + ey2 * ey1 + ey2 * ey2) + (py * ey1 + py * ey2)) + 0.5 * py * py;I += D * (intx2 + inty2); + } + massData.mass = density * area; + centerX *= 1.0 / area; + centerY *= 1.0 / area; + massData.center.Set(centerX, centerY); + massData.I = density * I; + } + b2PolygonShape.prototype.ComputeSubmergedArea = function (normal, offset, xf, c) { + if (offset === undefined) offset = 0; + var normalL = b2Math.MulTMV(xf.R, normal); + var offsetL = offset - b2Math.Dot(normal, xf.position); + var depths = new Vector_a2j_Number(); + var diveCount = 0; + var intoIndex = parseInt((-1)); + var outoIndex = parseInt((-1)); + var lastSubmerged = false; + var i = 0; + for (i = 0; + i < this.m_vertexCount; ++i) { + depths[i] = b2Math.Dot(normalL, this.m_vertices[i]) - offsetL; + var isSubmerged = depths[i] < (-Number.MIN_VALUE); + if (i > 0) { + if (isSubmerged) { + if (!lastSubmerged) { + intoIndex = i - 1; + diveCount++; + } + } + else { + if (lastSubmerged) { + outoIndex = i - 1; + diveCount++; + } + } + } + lastSubmerged = isSubmerged; + } + switch (diveCount) { + case 0: + if (lastSubmerged) { + var md = new b2MassData(); + this.ComputeMass(md, 1); + c.SetV(b2Math.MulX(xf, md.center)); + return md.mass; + } + else { + return 0; + } + break; + case 1: + if (intoIndex == (-1)) { + intoIndex = this.m_vertexCount - 1; + } + else { + outoIndex = this.m_vertexCount - 1; + } + break; + } + var intoIndex2 = parseInt((intoIndex + 1) % this.m_vertexCount); + var outoIndex2 = parseInt((outoIndex + 1) % this.m_vertexCount); + var intoLamdda = (0 - depths[intoIndex]) / (depths[intoIndex2] - depths[intoIndex]); + var outoLamdda = (0 - depths[outoIndex]) / (depths[outoIndex2] - depths[outoIndex]); + var intoVec = new b2Vec2(this.m_vertices[intoIndex].x * (1 - intoLamdda) + this.m_vertices[intoIndex2].x * intoLamdda, this.m_vertices[intoIndex].y * (1 - intoLamdda) + this.m_vertices[intoIndex2].y * intoLamdda); + var outoVec = new b2Vec2(this.m_vertices[outoIndex].x * (1 - outoLamdda) + this.m_vertices[outoIndex2].x * outoLamdda, this.m_vertices[outoIndex].y * (1 - outoLamdda) + this.m_vertices[outoIndex2].y * outoLamdda); + var area = 0; + var center = new b2Vec2(); + var p2 = this.m_vertices[intoIndex2]; + var p3; + i = intoIndex2; + while (i != outoIndex2) { + i = (i + 1) % this.m_vertexCount; + if (i == outoIndex2) p3 = outoVec; + else p3 = this.m_vertices[i]; + var triangleArea = 0.5 * ((p2.x - intoVec.x) * (p3.y - intoVec.y) - (p2.y - intoVec.y) * (p3.x - intoVec.x)); + area += triangleArea; + center.x += triangleArea * (intoVec.x + p2.x + p3.x) / 3; + center.y += triangleArea * (intoVec.y + p2.y + p3.y) / 3; + p2 = p3; + } + center.Multiply(1 / area); + c.SetV(b2Math.MulX(xf, center)); + return area; + } + b2PolygonShape.prototype.GetVertexCount = function () { + return this.m_vertexCount; + } + b2PolygonShape.prototype.GetVertices = function () { + return this.m_vertices; + } + b2PolygonShape.prototype.GetNormals = function () { + return this.m_normals; + } + b2PolygonShape.prototype.GetSupport = function (d) { + var bestIndex = 0; + var bestValue = this.m_vertices[0].x * d.x + this.m_vertices[0].y * d.y; + for (var i = 1; i < this.m_vertexCount; ++i) { + var value = this.m_vertices[i].x * d.x + this.m_vertices[i].y * d.y; + if (value > bestValue) { + bestIndex = i; + bestValue = value; + } + } + return bestIndex; + } + b2PolygonShape.prototype.GetSupportVertex = function (d) { + var bestIndex = 0; + var bestValue = this.m_vertices[0].x * d.x + this.m_vertices[0].y * d.y; + for (var i = 1; i < this.m_vertexCount; ++i) { + var value = this.m_vertices[i].x * d.x + this.m_vertices[i].y * d.y; + if (value > bestValue) { + bestIndex = i; + bestValue = value; + } + } + return this.m_vertices[bestIndex]; + } + b2PolygonShape.prototype.Validate = function () { + return false; + } + b2PolygonShape.prototype.b2PolygonShape = function () { + this.__super.b2Shape.call(this); + this.m_type = b2Shape.e_polygonShape; + this.m_centroid = new b2Vec2(); + this.m_vertices = new Vector(); + this.m_normals = new Vector(); + } + b2PolygonShape.prototype.Reserve = function (count) { + if (count === undefined) count = 0; + for (var i = parseInt(this.m_vertices.length); i < count; i++) { + this.m_vertices[i] = new b2Vec2(); + this.m_normals[i] = new b2Vec2(); + } + } + b2PolygonShape.ComputeCentroid = function (vs, count) { + if (count === undefined) count = 0; + var c = new b2Vec2(); + var area = 0.0; + var p1X = 0.0; + var p1Y = 0.0; + var inv3 = 1.0 / 3.0; + for (var i = 0; i < count; ++i) { + var p2 = vs[i]; + var p3 = i + 1 < count ? vs[parseInt(i + 1)] : vs[0]; + var e1X = p2.x - p1X; + var e1Y = p2.y - p1Y; + var e2X = p3.x - p1X; + var e2Y = p3.y - p1Y; + var D = (e1X * e2Y - e1Y * e2X); + var triangleArea = 0.5 * D;area += triangleArea; + c.x += triangleArea * inv3 * (p1X + p2.x + p3.x); + c.y += triangleArea * inv3 * (p1Y + p2.y + p3.y); + } + c.x *= 1.0 / area; + c.y *= 1.0 / area; + return c; + } + b2PolygonShape.ComputeOBB = function (obb, vs, count) { + if (count === undefined) count = 0; + var i = 0; + var p = new Vector(count + 1); + for (i = 0; + i < count; ++i) { + p[i] = vs[i]; + } + p[count] = p[0]; + var minArea = Number.MAX_VALUE; + for (i = 1; + i <= count; ++i) { + var root = p[parseInt(i - 1)]; + var uxX = p[i].x - root.x; + var uxY = p[i].y - root.y; + var length = Math.sqrt(uxX * uxX + uxY * uxY); + uxX /= length; + uxY /= length; + var uyX = (-uxY); + var uyY = uxX; + var lowerX = Number.MAX_VALUE; + var lowerY = Number.MAX_VALUE; + var upperX = (-Number.MAX_VALUE); + var upperY = (-Number.MAX_VALUE); + for (var j = 0; j < count; ++j) { + var dX = p[j].x - root.x; + var dY = p[j].y - root.y; + var rX = (uxX * dX + uxY * dY); + var rY = (uyX * dX + uyY * dY); + if (rX < lowerX) lowerX = rX; + if (rY < lowerY) lowerY = rY; + if (rX > upperX) upperX = rX; + if (rY > upperY) upperY = rY; + } + var area = (upperX - lowerX) * (upperY - lowerY); + if (area < 0.95 * minArea) { + minArea = area; + obb.R.col1.x = uxX; + obb.R.col1.y = uxY; + obb.R.col2.x = uyX; + obb.R.col2.y = uyY; + var centerX = 0.5 * (lowerX + upperX); + var centerY = 0.5 * (lowerY + upperY); + var tMat = obb.R; + obb.center.x = root.x + (tMat.col1.x * centerX + tMat.col2.x * centerY); + obb.center.y = root.y + (tMat.col1.y * centerX + tMat.col2.y * centerY); + obb.extents.x = 0.5 * (upperX - lowerX); + obb.extents.y = 0.5 * (upperY - lowerY); + } + } + } + Box2D.postDefs.push(function () { + Box2D.Collision.Shapes.b2PolygonShape.s_mat = new b2Mat22(); + }); + b2Shape.b2Shape = function () {}; + b2Shape.prototype.Copy = function () { + return null; + } + b2Shape.prototype.Set = function (other) { + this.m_radius = other.m_radius; + } + b2Shape.prototype.GetType = function () { + return this.m_type; + } + b2Shape.prototype.TestPoint = function (xf, p) { + return false; + } + b2Shape.prototype.RayCast = function (output, input, transform) { + return false; + } + b2Shape.prototype.ComputeAABB = function (aabb, xf) {} + b2Shape.prototype.ComputeMass = function (massData, density) { + if (density === undefined) density = 0; + } + b2Shape.prototype.ComputeSubmergedArea = function (normal, offset, xf, c) { + if (offset === undefined) offset = 0; + return 0; + } + b2Shape.TestOverlap = function (shape1, transform1, shape2, transform2) { + var input = new b2DistanceInput(); + input.proxyA = new b2DistanceProxy(); + input.proxyA.Set(shape1); + input.proxyB = new b2DistanceProxy(); + input.proxyB.Set(shape2); + input.transformA = transform1; + input.transformB = transform2; + input.useRadii = true; + var simplexCache = new b2SimplexCache(); + simplexCache.count = 0; + var output = new b2DistanceOutput(); + b2Distance.Distance(output, simplexCache, input); + return output.distance < 10.0 * Number.MIN_VALUE; + } + b2Shape.prototype.b2Shape = function () { + this.m_type = b2Shape.e_unknownShape; + this.m_radius = b2Settings.b2_linearSlop; + } + Box2D.postDefs.push(function () { + Box2D.Collision.Shapes.b2Shape.e_unknownShape = parseInt((-1)); + Box2D.Collision.Shapes.b2Shape.e_circleShape = 0; + Box2D.Collision.Shapes.b2Shape.e_polygonShape = 1; + Box2D.Collision.Shapes.b2Shape.e_edgeShape = 2; + Box2D.Collision.Shapes.b2Shape.e_shapeTypeCount = 3; + Box2D.Collision.Shapes.b2Shape.e_hitCollide = 1; + Box2D.Collision.Shapes.b2Shape.e_missCollide = 0; + Box2D.Collision.Shapes.b2Shape.e_startsInsideCollide = parseInt((-1)); + }); +})(); +(function () { + var b2Color = Box2D.Common.b2Color, + b2internal = Box2D.Common.b2internal, + b2Settings = Box2D.Common.b2Settings, + b2Mat22 = Box2D.Common.Math.b2Mat22, + b2Mat33 = Box2D.Common.Math.b2Mat33, + b2Math = Box2D.Common.Math.b2Math, + b2Sweep = Box2D.Common.Math.b2Sweep, + b2Transform = Box2D.Common.Math.b2Transform, + b2Vec2 = Box2D.Common.Math.b2Vec2, + b2Vec3 = Box2D.Common.Math.b2Vec3; + + b2Color.b2Color = function () { + this._r = 0; + this._g = 0; + this._b = 0; + }; + b2Color.prototype.b2Color = function (rr, gg, bb) { + if (rr === undefined) rr = 0; + if (gg === undefined) gg = 0; + if (bb === undefined) bb = 0; + this._r = Box2D.parseUInt(255 * b2Math.Clamp(rr, 0.0, 1.0)); + this._g = Box2D.parseUInt(255 * b2Math.Clamp(gg, 0.0, 1.0)); + this._b = Box2D.parseUInt(255 * b2Math.Clamp(bb, 0.0, 1.0)); + } + b2Color.prototype.Set = function (rr, gg, bb) { + if (rr === undefined) rr = 0; + if (gg === undefined) gg = 0; + if (bb === undefined) bb = 0; + this._r = Box2D.parseUInt(255 * b2Math.Clamp(rr, 0.0, 1.0)); + this._g = Box2D.parseUInt(255 * b2Math.Clamp(gg, 0.0, 1.0)); + this._b = Box2D.parseUInt(255 * b2Math.Clamp(bb, 0.0, 1.0)); + } + Object.defineProperty(b2Color.prototype, 'r', { + enumerable: false, + configurable: true, + set: function (rr) { + if (rr === undefined) rr = 0; + this._r = Box2D.parseUInt(255 * b2Math.Clamp(rr, 0.0, 1.0)); + } + }); + Object.defineProperty(b2Color.prototype, 'g', { + enumerable: false, + configurable: true, + set: function (gg) { + if (gg === undefined) gg = 0; + this._g = Box2D.parseUInt(255 * b2Math.Clamp(gg, 0.0, 1.0)); + } + }); + Object.defineProperty(b2Color.prototype, 'b', { + enumerable: false, + configurable: true, + set: function (bb) { + if (bb === undefined) bb = 0; + this._b = Box2D.parseUInt(255 * b2Math.Clamp(bb, 0.0, 1.0)); + } + }); + Object.defineProperty(b2Color.prototype, 'color', { + enumerable: false, + configurable: true, + get: function () { + return (this._r << 16) | (this._g << 8) | (this._b); + } + }); + b2Settings.b2Settings = function () {}; + b2Settings.b2MixFriction = function (friction1, friction2) { + if (friction1 === undefined) friction1 = 0; + if (friction2 === undefined) friction2 = 0; + return Math.sqrt(friction1 * friction2); + } + b2Settings.b2MixRestitution = function (restitution1, restitution2) { + if (restitution1 === undefined) restitution1 = 0; + if (restitution2 === undefined) restitution2 = 0; + return restitution1 > restitution2 ? restitution1 : restitution2; + } + b2Settings.b2Assert = function (a) { + if (!a) { + throw "Assertion Failed"; + } + } + Box2D.postDefs.push(function () { + Box2D.Common.b2Settings.VERSION = "2.1alpha"; + Box2D.Common.b2Settings.USHRT_MAX = 0x0000ffff; + Box2D.Common.b2Settings.b2_pi = Math.PI; + Box2D.Common.b2Settings.b2_maxManifoldPoints = 2; + Box2D.Common.b2Settings.b2_aabbExtension = 0.1; + Box2D.Common.b2Settings.b2_aabbMultiplier = 2.0; + Box2D.Common.b2Settings.b2_polygonRadius = 2.0 * b2Settings.b2_linearSlop; + Box2D.Common.b2Settings.b2_linearSlop = 0.005; + Box2D.Common.b2Settings.b2_angularSlop = 2.0 / 180.0 * b2Settings.b2_pi; + Box2D.Common.b2Settings.b2_toiSlop = 8.0 * b2Settings.b2_linearSlop; + Box2D.Common.b2Settings.b2_maxTOIContactsPerIsland = 32; + Box2D.Common.b2Settings.b2_maxTOIJointsPerIsland = 32; + Box2D.Common.b2Settings.b2_velocityThreshold = 1.0; + Box2D.Common.b2Settings.b2_maxLinearCorrection = 0.2; + Box2D.Common.b2Settings.b2_maxAngularCorrection = 8.0 / 180.0 * b2Settings.b2_pi; + Box2D.Common.b2Settings.b2_maxTranslation = 2.0; + Box2D.Common.b2Settings.b2_maxTranslationSquared = b2Settings.b2_maxTranslation * b2Settings.b2_maxTranslation; + Box2D.Common.b2Settings.b2_maxRotation = 0.5 * b2Settings.b2_pi; + Box2D.Common.b2Settings.b2_maxRotationSquared = b2Settings.b2_maxRotation * b2Settings.b2_maxRotation; + Box2D.Common.b2Settings.b2_contactBaumgarte = 0.2; + Box2D.Common.b2Settings.b2_timeToSleep = 0.5; + Box2D.Common.b2Settings.b2_linearSleepTolerance = 0.01; + Box2D.Common.b2Settings.b2_angularSleepTolerance = 2.0 / 180.0 * b2Settings.b2_pi; + }); +})(); +(function () { + var b2AABB = Box2D.Collision.b2AABB, + b2Color = Box2D.Common.b2Color, + b2internal = Box2D.Common.b2internal, + b2Settings = Box2D.Common.b2Settings, + b2Mat22 = Box2D.Common.Math.b2Mat22, + b2Mat33 = Box2D.Common.Math.b2Mat33, + b2Math = Box2D.Common.Math.b2Math, + b2Sweep = Box2D.Common.Math.b2Sweep, + b2Transform = Box2D.Common.Math.b2Transform, + b2Vec2 = Box2D.Common.Math.b2Vec2, + b2Vec3 = Box2D.Common.Math.b2Vec3; + + b2Mat22.b2Mat22 = function () { + this.col1 = new b2Vec2(); + this.col2 = new b2Vec2(); + }; + b2Mat22.prototype.b2Mat22 = function () { + this.SetIdentity(); + } + b2Mat22.FromAngle = function (angle) { + if (angle === undefined) angle = 0; + var mat = new b2Mat22(); + mat.Set(angle); + return mat; + } + b2Mat22.FromVV = function (c1, c2) { + var mat = new b2Mat22(); + mat.SetVV(c1, c2); + return mat; + } + b2Mat22.prototype.Set = function (angle) { + if (angle === undefined) angle = 0; + var c = Math.cos(angle); + var s = Math.sin(angle); + this.col1.x = c; + this.col2.x = (-s); + this.col1.y = s; + this.col2.y = c; + } + b2Mat22.prototype.SetVV = function (c1, c2) { + this.col1.SetV(c1); + this.col2.SetV(c2); + } + b2Mat22.prototype.Copy = function () { + var mat = new b2Mat22(); + mat.SetM(this); + return mat; + } + b2Mat22.prototype.SetM = function (m) { + this.col1.SetV(m.col1); + this.col2.SetV(m.col2); + } + b2Mat22.prototype.AddM = function (m) { + this.col1.x += m.col1.x; + this.col1.y += m.col1.y; + this.col2.x += m.col2.x; + this.col2.y += m.col2.y; + } + b2Mat22.prototype.SetIdentity = function () { + this.col1.x = 1.0; + this.col2.x = 0.0; + this.col1.y = 0.0; + this.col2.y = 1.0; + } + b2Mat22.prototype.SetZero = function () { + this.col1.x = 0.0; + this.col2.x = 0.0; + this.col1.y = 0.0; + this.col2.y = 0.0; + } + b2Mat22.prototype.GetAngle = function () { + return Math.atan2(this.col1.y, this.col1.x); + } + b2Mat22.prototype.GetInverse = function (out) { + var a = this.col1.x; + var b = this.col2.x; + var c = this.col1.y; + var d = this.col2.y; + var det = a * d - b * c; + if (det != 0.0) { + det = 1.0 / det; + } + out.col1.x = det * d; + out.col2.x = (-det * b); + out.col1.y = (-det * c); + out.col2.y = det * a; + return out; + } + b2Mat22.prototype.Solve = function (out, bX, bY) { + if (bX === undefined) bX = 0; + if (bY === undefined) bY = 0; + var a11 = this.col1.x; + var a12 = this.col2.x; + var a21 = this.col1.y; + var a22 = this.col2.y; + var det = a11 * a22 - a12 * a21; + if (det != 0.0) { + det = 1.0 / det; + } + out.x = det * (a22 * bX - a12 * bY); + out.y = det * (a11 * bY - a21 * bX); + return out; + } + b2Mat22.prototype.Abs = function () { + this.col1.Abs(); + this.col2.Abs(); + } + b2Mat33.b2Mat33 = function () { + this.col1 = new b2Vec3(); + this.col2 = new b2Vec3(); + this.col3 = new b2Vec3(); + }; + b2Mat33.prototype.b2Mat33 = function (c1, c2, c3) { + if (c1 === undefined) c1 = null; + if (c2 === undefined) c2 = null; + if (c3 === undefined) c3 = null; + if (!c1 && !c2 && !c3) { + this.col1.SetZero(); + this.col2.SetZero(); + this.col3.SetZero(); + } + else { + this.col1.SetV(c1); + this.col2.SetV(c2); + this.col3.SetV(c3); + } + } + b2Mat33.prototype.SetVVV = function (c1, c2, c3) { + this.col1.SetV(c1); + this.col2.SetV(c2); + this.col3.SetV(c3); + } + b2Mat33.prototype.Copy = function () { + return new b2Mat33(this.col1, this.col2, this.col3); + } + b2Mat33.prototype.SetM = function (m) { + this.col1.SetV(m.col1); + this.col2.SetV(m.col2); + this.col3.SetV(m.col3); + } + b2Mat33.prototype.AddM = function (m) { + this.col1.x += m.col1.x; + this.col1.y += m.col1.y; + this.col1.z += m.col1.z; + this.col2.x += m.col2.x; + this.col2.y += m.col2.y; + this.col2.z += m.col2.z; + this.col3.x += m.col3.x; + this.col3.y += m.col3.y; + this.col3.z += m.col3.z; + } + b2Mat33.prototype.SetIdentity = function () { + this.col1.x = 1.0; + this.col2.x = 0.0; + this.col3.x = 0.0; + this.col1.y = 0.0; + this.col2.y = 1.0; + this.col3.y = 0.0; + this.col1.z = 0.0; + this.col2.z = 0.0; + this.col3.z = 1.0; + } + b2Mat33.prototype.SetZero = function () { + this.col1.x = 0.0; + this.col2.x = 0.0; + this.col3.x = 0.0; + this.col1.y = 0.0; + this.col2.y = 0.0; + this.col3.y = 0.0; + this.col1.z = 0.0; + this.col2.z = 0.0; + this.col3.z = 0.0; + } + b2Mat33.prototype.Solve22 = function (out, bX, bY) { + if (bX === undefined) bX = 0; + if (bY === undefined) bY = 0; + var a11 = this.col1.x; + var a12 = this.col2.x; + var a21 = this.col1.y; + var a22 = this.col2.y; + var det = a11 * a22 - a12 * a21; + if (det != 0.0) { + det = 1.0 / det; + } + out.x = det * (a22 * bX - a12 * bY); + out.y = det * (a11 * bY - a21 * bX); + return out; + } + b2Mat33.prototype.Solve33 = function (out, bX, bY, bZ) { + if (bX === undefined) bX = 0; + if (bY === undefined) bY = 0; + if (bZ === undefined) bZ = 0; + var a11 = this.col1.x; + var a21 = this.col1.y; + var a31 = this.col1.z; + var a12 = this.col2.x; + var a22 = this.col2.y; + var a32 = this.col2.z; + var a13 = this.col3.x; + var a23 = this.col3.y; + var a33 = this.col3.z; + var det = a11 * (a22 * a33 - a32 * a23) + a21 * (a32 * a13 - a12 * a33) + a31 * (a12 * a23 - a22 * a13); + if (det != 0.0) { + det = 1.0 / det; + } + out.x = det * (bX * (a22 * a33 - a32 * a23) + bY * (a32 * a13 - a12 * a33) + bZ * (a12 * a23 - a22 * a13)); + out.y = det * (a11 * (bY * a33 - bZ * a23) + a21 * (bZ * a13 - bX * a33) + a31 * (bX * a23 - bY * a13)); + out.z = det * (a11 * (a22 * bZ - a32 * bY) + a21 * (a32 * bX - a12 * bZ) + a31 * (a12 * bY - a22 * bX)); + return out; + } + b2Math.b2Math = function () {}; + b2Math.IsValid = function (x) { + if (x === undefined) x = 0; + return isFinite(x); + } + b2Math.Dot = function (a, b) { + return a.x * b.x + a.y * b.y; + } + b2Math.CrossVV = function (a, b) { + return a.x * b.y - a.y * b.x; + } + b2Math.CrossVF = function (a, s) { + if (s === undefined) s = 0; + var v = new b2Vec2(s * a.y, (-s * a.x)); + return v; + } + b2Math.CrossFV = function (s, a) { + if (s === undefined) s = 0; + var v = new b2Vec2((-s * a.y), s * a.x); + return v; + } + b2Math.MulMV = function (A, v) { + var u = new b2Vec2(A.col1.x * v.x + A.col2.x * v.y, A.col1.y * v.x + A.col2.y * v.y); + return u; + } + b2Math.MulTMV = function (A, v) { + var u = new b2Vec2(b2Math.Dot(v, A.col1), b2Math.Dot(v, A.col2)); + return u; + } + b2Math.MulX = function (T, v) { + var a = b2Math.MulMV(T.R, v); + a.x += T.position.x; + a.y += T.position.y; + return a; + } + b2Math.MulXT = function (T, v) { + var a = b2Math.SubtractVV(v, T.position); + var tX = (a.x * T.R.col1.x + a.y * T.R.col1.y); + a.y = (a.x * T.R.col2.x + a.y * T.R.col2.y); + a.x = tX; + return a; + } + b2Math.AddVV = function (a, b) { + var v = new b2Vec2(a.x + b.x, a.y + b.y); + return v; + } + b2Math.SubtractVV = function (a, b) { + var v = new b2Vec2(a.x - b.x, a.y - b.y); + return v; + } + b2Math.Distance = function (a, b) { + var cX = a.x - b.x; + var cY = a.y - b.y; + return Math.sqrt(cX * cX + cY * cY); + } + b2Math.DistanceSquared = function (a, b) { + var cX = a.x - b.x; + var cY = a.y - b.y; + return (cX * cX + cY * cY); + } + b2Math.MulFV = function (s, a) { + if (s === undefined) s = 0; + var v = new b2Vec2(s * a.x, s * a.y); + return v; + } + b2Math.AddMM = function (A, B) { + var C = b2Mat22.FromVV(b2Math.AddVV(A.col1, B.col1), b2Math.AddVV(A.col2, B.col2)); + return C; + } + b2Math.MulMM = function (A, B) { + var C = b2Mat22.FromVV(b2Math.MulMV(A, B.col1), b2Math.MulMV(A, B.col2)); + return C; + } + b2Math.MulTMM = function (A, B) { + var c1 = new b2Vec2(b2Math.Dot(A.col1, B.col1), b2Math.Dot(A.col2, B.col1)); + var c2 = new b2Vec2(b2Math.Dot(A.col1, B.col2), b2Math.Dot(A.col2, B.col2)); + var C = b2Mat22.FromVV(c1, c2); + return C; + } + b2Math.Abs = function (a) { + if (a === undefined) a = 0; + return a > 0.0 ? a : (-a); + } + b2Math.AbsV = function (a) { + var b = new b2Vec2(b2Math.Abs(a.x), b2Math.Abs(a.y)); + return b; + } + b2Math.AbsM = function (A) { + var B = b2Mat22.FromVV(b2Math.AbsV(A.col1), b2Math.AbsV(A.col2)); + return B; + } + b2Math.Min = function (a, b) { + if (a === undefined) a = 0; + if (b === undefined) b = 0; + return a < b ? a : b; + } + b2Math.MinV = function (a, b) { + var c = new b2Vec2(b2Math.Min(a.x, b.x), b2Math.Min(a.y, b.y)); + return c; + } + b2Math.Max = function (a, b) { + if (a === undefined) a = 0; + if (b === undefined) b = 0; + return a > b ? a : b; + } + b2Math.MaxV = function (a, b) { + var c = new b2Vec2(b2Math.Max(a.x, b.x), b2Math.Max(a.y, b.y)); + return c; + } + b2Math.Clamp = function (a, low, high) { + if (a === undefined) a = 0; + if (low === undefined) low = 0; + if (high === undefined) high = 0; + return a < low ? low : a > high ? high : a; + } + b2Math.ClampV = function (a, low, high) { + return b2Math.MaxV(low, b2Math.MinV(a, high)); + } + b2Math.Swap = function (a, b) { + var tmp = a[0]; + a[0] = b[0]; + b[0] = tmp; + } + b2Math.Random = function () { + return Math.random() * 2 - 1; + } + b2Math.RandomRange = function (lo, hi) { + if (lo === undefined) lo = 0; + if (hi === undefined) hi = 0; + var r = Math.random(); + r = (hi - lo) * r + lo; + return r; + } + b2Math.NextPowerOfTwo = function (x) { + if (x === undefined) x = 0; + x |= (x >> 1) & 0x7FFFFFFF; + x |= (x >> 2) & 0x3FFFFFFF; + x |= (x >> 4) & 0x0FFFFFFF; + x |= (x >> 8) & 0x00FFFFFF; + x |= (x >> 16) & 0x0000FFFF; + return x + 1; + } + b2Math.IsPowerOfTwo = function (x) { + if (x === undefined) x = 0; + var result = x > 0 && (x & (x - 1)) == 0; + return result; + } + Box2D.postDefs.push(function () { + Box2D.Common.Math.b2Math.b2Vec2_zero = new b2Vec2(0.0, 0.0); + Box2D.Common.Math.b2Math.b2Mat22_identity = b2Mat22.FromVV(new b2Vec2(1.0, 0.0), new b2Vec2(0.0, 1.0)); + Box2D.Common.Math.b2Math.b2Transform_identity = new b2Transform(b2Math.b2Vec2_zero, b2Math.b2Mat22_identity); + }); + b2Sweep.b2Sweep = function () { + this.localCenter = new b2Vec2(); + this.c0 = new b2Vec2; + this.c = new b2Vec2(); + }; + b2Sweep.prototype.Set = function (other) { + this.localCenter.SetV(other.localCenter); + this.c0.SetV(other.c0); + this.c.SetV(other.c); + this.a0 = other.a0; + this.a = other.a; + this.t0 = other.t0; + } + b2Sweep.prototype.Copy = function () { + var copy = new b2Sweep(); + copy.localCenter.SetV(this.localCenter); + copy.c0.SetV(this.c0); + copy.c.SetV(this.c); + copy.a0 = this.a0; + copy.a = this.a; + copy.t0 = this.t0; + return copy; + } + b2Sweep.prototype.GetTransform = function (xf, alpha) { + if (alpha === undefined) alpha = 0; + xf.position.x = (1.0 - alpha) * this.c0.x + alpha * this.c.x; + xf.position.y = (1.0 - alpha) * this.c0.y + alpha * this.c.y; + var angle = (1.0 - alpha) * this.a0 + alpha * this.a; + xf.R.Set(angle); + var tMat = xf.R; + xf.position.x -= (tMat.col1.x * this.localCenter.x + tMat.col2.x * this.localCenter.y); + xf.position.y -= (tMat.col1.y * this.localCenter.x + tMat.col2.y * this.localCenter.y); + } + b2Sweep.prototype.Advance = function (t) { + if (t === undefined) t = 0; + if (this.t0 < t && 1.0 - this.t0 > Number.MIN_VALUE) { + var alpha = (t - this.t0) / (1.0 - this.t0); + this.c0.x = (1.0 - alpha) * this.c0.x + alpha * this.c.x; + this.c0.y = (1.0 - alpha) * this.c0.y + alpha * this.c.y; + this.a0 = (1.0 - alpha) * this.a0 + alpha * this.a; + this.t0 = t; + } + } + b2Transform.b2Transform = function () { + this.position = new b2Vec2; + this.R = new b2Mat22(); + }; + b2Transform.prototype.b2Transform = function (pos, r) { + if (pos === undefined) pos = null; + if (r === undefined) r = null; + if (pos) { + this.position.SetV(pos); + this.R.SetM(r); + } + } + b2Transform.prototype.Initialize = function (pos, r) { + this.position.SetV(pos); + this.R.SetM(r); + } + b2Transform.prototype.SetIdentity = function () { + this.position.SetZero(); + this.R.SetIdentity(); + } + b2Transform.prototype.Set = function (x) { + this.position.SetV(x.position); + this.R.SetM(x.R); + } + b2Transform.prototype.GetAngle = function () { + return Math.atan2(this.R.col1.y, this.R.col1.x); + } + b2Vec2.b2Vec2 = function () {}; + b2Vec2.prototype.b2Vec2 = function (x_, y_) { + if (x_ === undefined) x_ = 0; + if (y_ === undefined) y_ = 0; + this.x = x_; + this.y = y_; + } + b2Vec2.prototype.SetZero = function () { + this.x = 0.0; + this.y = 0.0; + } + b2Vec2.prototype.Set = function (x_, y_) { + if (x_ === undefined) x_ = 0; + if (y_ === undefined) y_ = 0; + this.x = x_; + this.y = y_; + } + b2Vec2.prototype.SetV = function (v) { + this.x = v.x; + this.y = v.y; + } + b2Vec2.prototype.GetNegative = function () { + return new b2Vec2((-this.x), (-this.y)); + } + b2Vec2.prototype.NegativeSelf = function () { + this.x = (-this.x); + this.y = (-this.y); + } + b2Vec2.Make = function (x_, y_) { + if (x_ === undefined) x_ = 0; + if (y_ === undefined) y_ = 0; + return new b2Vec2(x_, y_); + } + b2Vec2.prototype.Copy = function () { + return new b2Vec2(this.x, this.y); + } + b2Vec2.prototype.Add = function (v) { + this.x += v.x; + this.y += v.y; + } + b2Vec2.prototype.Subtract = function (v) { + this.x -= v.x; + this.y -= v.y; + } + b2Vec2.prototype.Multiply = function (a) { + if (a === undefined) a = 0; + this.x *= a; + this.y *= a; + } + b2Vec2.prototype.MulM = function (A) { + var tX = this.x; + this.x = A.col1.x * tX + A.col2.x * this.y; + this.y = A.col1.y * tX + A.col2.y * this.y; + } + b2Vec2.prototype.MulTM = function (A) { + var tX = b2Math.Dot(this, A.col1); + this.y = b2Math.Dot(this, A.col2); + this.x = tX; + } + b2Vec2.prototype.CrossVF = function (s) { + if (s === undefined) s = 0; + var tX = this.x; + this.x = s * this.y; + this.y = (-s * tX); + } + b2Vec2.prototype.CrossFV = function (s) { + if (s === undefined) s = 0; + var tX = this.x; + this.x = (-s * this.y); + this.y = s * tX; + } + b2Vec2.prototype.MinV = function (b) { + this.x = this.x < b.x ? this.x : b.x; + this.y = this.y < b.y ? this.y : b.y; + } + b2Vec2.prototype.MaxV = function (b) { + this.x = this.x > b.x ? this.x : b.x; + this.y = this.y > b.y ? this.y : b.y; + } + b2Vec2.prototype.Abs = function () { + if (this.x < 0) this.x = (-this.x); + if (this.y < 0) this.y = (-this.y); + } + b2Vec2.prototype.Length = function () { + return Math.sqrt(this.x * this.x + this.y * this.y); + } + b2Vec2.prototype.LengthSquared = function () { + return (this.x * this.x + this.y * this.y); + } + b2Vec2.prototype.Normalize = function () { + var length = Math.sqrt(this.x * this.x + this.y * this.y); + if (length < Number.MIN_VALUE) { + return 0.0; + } + var invLength = 1.0 / length; + this.x *= invLength; + this.y *= invLength; + return length; + } + b2Vec2.prototype.IsValid = function () { + return b2Math.IsValid(this.x) && b2Math.IsValid(this.y); + } + b2Vec3.b2Vec3 = function () {}; + b2Vec3.prototype.b2Vec3 = function (x, y, z) { + if (x === undefined) x = 0; + if (y === undefined) y = 0; + if (z === undefined) z = 0; + this.x = x; + this.y = y; + this.z = z; + } + b2Vec3.prototype.SetZero = function () { + this.x = this.y = this.z = 0.0; + } + b2Vec3.prototype.Set = function (x, y, z) { + if (x === undefined) x = 0; + if (y === undefined) y = 0; + if (z === undefined) z = 0; + this.x = x; + this.y = y; + this.z = z; + } + b2Vec3.prototype.SetV = function (v) { + this.x = v.x; + this.y = v.y; + this.z = v.z; + } + b2Vec3.prototype.GetNegative = function () { + return new b2Vec3((-this.x), (-this.y), (-this.z)); + } + b2Vec3.prototype.NegativeSelf = function () { + this.x = (-this.x); + this.y = (-this.y); + this.z = (-this.z); + } + b2Vec3.prototype.Copy = function () { + return new b2Vec3(this.x, this.y, this.z); + } + b2Vec3.prototype.Add = function (v) { + this.x += v.x; + this.y += v.y; + this.z += v.z; + } + b2Vec3.prototype.Subtract = function (v) { + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + } + b2Vec3.prototype.Multiply = function (a) { + if (a === undefined) a = 0; + this.x *= a; + this.y *= a; + this.z *= a; + } +})(); +(function () { + var b2ControllerEdge = Box2D.Dynamics.Controllers.b2ControllerEdge, + b2Mat22 = Box2D.Common.Math.b2Mat22, + b2Mat33 = Box2D.Common.Math.b2Mat33, + b2Math = Box2D.Common.Math.b2Math, + b2Sweep = Box2D.Common.Math.b2Sweep, + b2Transform = Box2D.Common.Math.b2Transform, + b2Vec2 = Box2D.Common.Math.b2Vec2, + b2Vec3 = Box2D.Common.Math.b2Vec3, + b2Color = Box2D.Common.b2Color, + b2internal = Box2D.Common.b2internal, + b2Settings = Box2D.Common.b2Settings, + b2AABB = Box2D.Collision.b2AABB, + b2Bound = Box2D.Collision.b2Bound, + b2BoundValues = Box2D.Collision.b2BoundValues, + b2Collision = Box2D.Collision.b2Collision, + b2ContactID = Box2D.Collision.b2ContactID, + b2ContactPoint = Box2D.Collision.b2ContactPoint, + b2Distance = Box2D.Collision.b2Distance, + b2DistanceInput = Box2D.Collision.b2DistanceInput, + b2DistanceOutput = Box2D.Collision.b2DistanceOutput, + b2DistanceProxy = Box2D.Collision.b2DistanceProxy, + b2DynamicTree = Box2D.Collision.b2DynamicTree, + b2DynamicTreeBroadPhase = Box2D.Collision.b2DynamicTreeBroadPhase, + b2DynamicTreeNode = Box2D.Collision.b2DynamicTreeNode, + b2DynamicTreePair = Box2D.Collision.b2DynamicTreePair, + b2Manifold = Box2D.Collision.b2Manifold, + b2ManifoldPoint = Box2D.Collision.b2ManifoldPoint, + b2Point = Box2D.Collision.b2Point, + b2RayCastInput = Box2D.Collision.b2RayCastInput, + b2RayCastOutput = Box2D.Collision.b2RayCastOutput, + b2Segment = Box2D.Collision.b2Segment, + b2SeparationFunction = Box2D.Collision.b2SeparationFunction, + b2Simplex = Box2D.Collision.b2Simplex, + b2SimplexCache = Box2D.Collision.b2SimplexCache, + b2SimplexVertex = Box2D.Collision.b2SimplexVertex, + b2TimeOfImpact = Box2D.Collision.b2TimeOfImpact, + b2TOIInput = Box2D.Collision.b2TOIInput, + b2WorldManifold = Box2D.Collision.b2WorldManifold, + ClipVertex = Box2D.Collision.ClipVertex, + Features = Box2D.Collision.Features, + IBroadPhase = Box2D.Collision.IBroadPhase, + b2CircleShape = Box2D.Collision.Shapes.b2CircleShape, + b2EdgeChainDef = Box2D.Collision.Shapes.b2EdgeChainDef, + b2EdgeShape = Box2D.Collision.Shapes.b2EdgeShape, + b2MassData = Box2D.Collision.Shapes.b2MassData, + b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape, + b2Shape = Box2D.Collision.Shapes.b2Shape, + b2Body = Box2D.Dynamics.b2Body, + b2BodyDef = Box2D.Dynamics.b2BodyDef, + b2ContactFilter = Box2D.Dynamics.b2ContactFilter, + b2ContactImpulse = Box2D.Dynamics.b2ContactImpulse, + b2ContactListener = Box2D.Dynamics.b2ContactListener, + b2ContactManager = Box2D.Dynamics.b2ContactManager, + b2DebugDraw = Box2D.Dynamics.b2DebugDraw, + b2DestructionListener = Box2D.Dynamics.b2DestructionListener, + b2FilterData = Box2D.Dynamics.b2FilterData, + b2Fixture = Box2D.Dynamics.b2Fixture, + b2FixtureDef = Box2D.Dynamics.b2FixtureDef, + b2Island = Box2D.Dynamics.b2Island, + b2TimeStep = Box2D.Dynamics.b2TimeStep, + b2World = Box2D.Dynamics.b2World, + b2CircleContact = Box2D.Dynamics.Contacts.b2CircleContact, + b2Contact = Box2D.Dynamics.Contacts.b2Contact, + b2ContactConstraint = Box2D.Dynamics.Contacts.b2ContactConstraint, + b2ContactConstraintPoint = Box2D.Dynamics.Contacts.b2ContactConstraintPoint, + b2ContactEdge = Box2D.Dynamics.Contacts.b2ContactEdge, + b2ContactFactory = Box2D.Dynamics.Contacts.b2ContactFactory, + b2ContactRegister = Box2D.Dynamics.Contacts.b2ContactRegister, + b2ContactResult = Box2D.Dynamics.Contacts.b2ContactResult, + b2ContactSolver = Box2D.Dynamics.Contacts.b2ContactSolver, + b2EdgeAndCircleContact = Box2D.Dynamics.Contacts.b2EdgeAndCircleContact, + b2NullContact = Box2D.Dynamics.Contacts.b2NullContact, + b2PolyAndCircleContact = Box2D.Dynamics.Contacts.b2PolyAndCircleContact, + b2PolyAndEdgeContact = Box2D.Dynamics.Contacts.b2PolyAndEdgeContact, + b2PolygonContact = Box2D.Dynamics.Contacts.b2PolygonContact, + b2PositionSolverManifold = Box2D.Dynamics.Contacts.b2PositionSolverManifold, + b2Controller = Box2D.Dynamics.Controllers.b2Controller, + b2DistanceJoint = Box2D.Dynamics.Joints.b2DistanceJoint, + b2DistanceJointDef = Box2D.Dynamics.Joints.b2DistanceJointDef, + b2FrictionJoint = Box2D.Dynamics.Joints.b2FrictionJoint, + b2FrictionJointDef = Box2D.Dynamics.Joints.b2FrictionJointDef, + b2GearJoint = Box2D.Dynamics.Joints.b2GearJoint, + b2GearJointDef = Box2D.Dynamics.Joints.b2GearJointDef, + b2Jacobian = Box2D.Dynamics.Joints.b2Jacobian, + b2Joint = Box2D.Dynamics.Joints.b2Joint, + b2JointDef = Box2D.Dynamics.Joints.b2JointDef, + b2JointEdge = Box2D.Dynamics.Joints.b2JointEdge, + b2LineJoint = Box2D.Dynamics.Joints.b2LineJoint, + b2LineJointDef = Box2D.Dynamics.Joints.b2LineJointDef, + b2MouseJoint = Box2D.Dynamics.Joints.b2MouseJoint, + b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef, + b2PrismaticJoint = Box2D.Dynamics.Joints.b2PrismaticJoint, + b2PrismaticJointDef = Box2D.Dynamics.Joints.b2PrismaticJointDef, + b2PulleyJoint = Box2D.Dynamics.Joints.b2PulleyJoint, + b2PulleyJointDef = Box2D.Dynamics.Joints.b2PulleyJointDef, + b2RevoluteJoint = Box2D.Dynamics.Joints.b2RevoluteJoint, + b2RevoluteJointDef = Box2D.Dynamics.Joints.b2RevoluteJointDef, + b2WeldJoint = Box2D.Dynamics.Joints.b2WeldJoint, + b2WeldJointDef = Box2D.Dynamics.Joints.b2WeldJointDef; + + b2Body.b2Body = function () { + this.m_xf = new b2Transform(); + this.m_sweep = new b2Sweep(); + this.m_linearVelocity = new b2Vec2(); + this.m_force = new b2Vec2(); + }; + b2Body.prototype.connectEdges = function (s1, s2, angle1) { + if (angle1 === undefined) angle1 = 0; + var angle2 = Math.atan2(s2.GetDirectionVector().y, s2.GetDirectionVector().x); + var coreOffset = Math.tan((angle2 - angle1) * 0.5); + var core = b2Math.MulFV(coreOffset, s2.GetDirectionVector()); + core = b2Math.SubtractVV(core, s2.GetNormalVector()); + core = b2Math.MulFV(b2Settings.b2_toiSlop, core); + core = b2Math.AddVV(core, s2.GetVertex1()); + var cornerDir = b2Math.AddVV(s1.GetDirectionVector(), s2.GetDirectionVector()); + cornerDir.Normalize(); + var convex = b2Math.Dot(s1.GetDirectionVector(), s2.GetNormalVector()) > 0.0; + s1.SetNextEdge(s2, core, cornerDir, convex); + s2.SetPrevEdge(s1, core, cornerDir, convex); + return angle2; + } + b2Body.prototype.CreateFixture = function (def) { + if (this.m_world.IsLocked() == true) { + return null; + } + var fixture = new b2Fixture(); + fixture.Create(this, this.m_xf, def); + if (this.m_flags & b2Body.e_activeFlag) { + var broadPhase = this.m_world.m_contactManager.m_broadPhase; + fixture.CreateProxy(broadPhase, this.m_xf); + } + fixture.m_next = this.m_fixtureList; + this.m_fixtureList = fixture; + ++this.m_fixtureCount; + fixture.m_body = this; + if (fixture.m_density > 0.0) { + this.ResetMassData(); + } + this.m_world.m_flags |= b2World.e_newFixture; + return fixture; + } + b2Body.prototype.CreateFixture2 = function (shape, density) { + if (density === undefined) density = 0.0; + var def = new b2FixtureDef(); + def.shape = shape; + def.density = density; + return this.CreateFixture(def); + } + b2Body.prototype.DestroyFixture = function (fixture) { + if (this.m_world.IsLocked() == true) { + return; + } + var node = this.m_fixtureList; + var ppF = null; + var found = false; + while (node != null) { + if (node == fixture) { + if (ppF) ppF.m_next = fixture.m_next; + else this.m_fixtureList = fixture.m_next; + found = true; + break; + } + ppF = node; + node = node.m_next; + } + var edge = this.m_contactList; + while (edge) { + var c = edge.contact; + edge = edge.next; + var fixtureA = c.GetFixtureA(); + var fixtureB = c.GetFixtureB(); + if (fixture == fixtureA || fixture == fixtureB) { + this.m_world.m_contactManager.Destroy(c); + } + } + if (this.m_flags & b2Body.e_activeFlag) { + var broadPhase = this.m_world.m_contactManager.m_broadPhase; + fixture.DestroyProxy(broadPhase); + } + else {} + fixture.Destroy(); + fixture.m_body = null; + fixture.m_next = null; + --this.m_fixtureCount; + this.ResetMassData(); + } + b2Body.prototype.SetPositionAndAngle = function (position, angle) { + if (angle === undefined) angle = 0; + var f; + if (this.m_world.IsLocked() == true) { + return; + } + this.m_xf.R.Set(angle); + this.m_xf.position.SetV(position); + var tMat = this.m_xf.R; + var tVec = this.m_sweep.localCenter; + this.m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + this.m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + this.m_sweep.c.x += this.m_xf.position.x; + this.m_sweep.c.y += this.m_xf.position.y; + this.m_sweep.c0.SetV(this.m_sweep.c); + this.m_sweep.a0 = this.m_sweep.a = angle; + var broadPhase = this.m_world.m_contactManager.m_broadPhase; + for (f = this.m_fixtureList; + f; f = f.m_next) { + f.Synchronize(broadPhase, this.m_xf, this.m_xf); + } + this.m_world.m_contactManager.FindNewContacts(); + } + b2Body.prototype.SetTransform = function (xf) { + this.SetPositionAndAngle(xf.position, xf.GetAngle()); + } + b2Body.prototype.GetTransform = function () { + return this.m_xf; + } + b2Body.prototype.GetPosition = function () { + return this.m_xf.position; + } + b2Body.prototype.SetPosition = function (position) { + this.SetPositionAndAngle(position, this.GetAngle()); + } + b2Body.prototype.GetAngle = function () { + return this.m_sweep.a; + } + b2Body.prototype.SetAngle = function (angle) { + if (angle === undefined) angle = 0; + this.SetPositionAndAngle(this.GetPosition(), angle); + } + b2Body.prototype.GetWorldCenter = function () { + return this.m_sweep.c; + } + b2Body.prototype.GetLocalCenter = function () { + return this.m_sweep.localCenter; + } + b2Body.prototype.SetLinearVelocity = function (v) { + if (this.m_type == b2Body.b2_staticBody) { + return; + } + this.m_linearVelocity.SetV(v); + } + b2Body.prototype.GetLinearVelocity = function () { + return this.m_linearVelocity; + } + b2Body.prototype.SetAngularVelocity = function (omega) { + if (omega === undefined) omega = 0; + if (this.m_type == b2Body.b2_staticBody) { + return; + } + this.m_angularVelocity = omega; + } + b2Body.prototype.GetAngularVelocity = function () { + return this.m_angularVelocity; + } + b2Body.prototype.GetDefinition = function () { + var bd = new b2BodyDef(); + bd.type = this.GetType(); + bd.allowSleep = (this.m_flags & b2Body.e_allowSleepFlag) == b2Body.e_allowSleepFlag; + bd.angle = this.GetAngle(); + bd.angularDamping = this.m_angularDamping; + bd.angularVelocity = this.m_angularVelocity; + bd.fixedRotation = (this.m_flags & b2Body.e_fixedRotationFlag) == b2Body.e_fixedRotationFlag; + bd.bullet = (this.m_flags & b2Body.e_bulletFlag) == b2Body.e_bulletFlag; + bd.awake = (this.m_flags & b2Body.e_awakeFlag) == b2Body.e_awakeFlag; + bd.linearDamping = this.m_linearDamping; + bd.linearVelocity.SetV(this.GetLinearVelocity()); + bd.position = this.GetPosition(); + bd.userData = this.GetUserData(); + return bd; + } + b2Body.prototype.ApplyForce = function (force, point) { + if (this.m_type != b2Body.b2_dynamicBody) { + return; + } + if (this.IsAwake() == false) { + this.SetAwake(true); + } + this.m_force.x += force.x; + this.m_force.y += force.y; + this.m_torque += ((point.x - this.m_sweep.c.x) * force.y - (point.y - this.m_sweep.c.y) * force.x); + } + b2Body.prototype.ApplyTorque = function (torque) { + if (torque === undefined) torque = 0; + if (this.m_type != b2Body.b2_dynamicBody) { + return; + } + if (this.IsAwake() == false) { + this.SetAwake(true); + } + this.m_torque += torque; + } + b2Body.prototype.ApplyImpulse = function (impulse, point) { + if (this.m_type != b2Body.b2_dynamicBody) { + return; + } + if (this.IsAwake() == false) { + this.SetAwake(true); + } + this.m_linearVelocity.x += this.m_invMass * impulse.x; + this.m_linearVelocity.y += this.m_invMass * impulse.y; + this.m_angularVelocity += this.m_invI * ((point.x - this.m_sweep.c.x) * impulse.y - (point.y - this.m_sweep.c.y) * impulse.x); + } + b2Body.prototype.Split = function (callback) { + var linearVelocity = this.GetLinearVelocity().Copy(); + var angularVelocity = this.GetAngularVelocity(); + var center = this.GetWorldCenter(); + var body1 = this; + var body2 = this.m_world.CreateBody(this.GetDefinition()); + var prev; + for (var f = body1.m_fixtureList; f;) { + if (callback(f)) { + var next = f.m_next; + if (prev) { + prev.m_next = next; + } + else { + body1.m_fixtureList = next; + } + body1.m_fixtureCount--; + f.m_next = body2.m_fixtureList; + body2.m_fixtureList = f; + body2.m_fixtureCount++; + f.m_body = body2; + f = next; + } + else { + prev = f; + f = f.m_next; + } + } + body1.ResetMassData(); + body2.ResetMassData(); + var center1 = body1.GetWorldCenter(); + var center2 = body2.GetWorldCenter(); + var velocity1 = b2Math.AddVV(linearVelocity, b2Math.CrossFV(angularVelocity, b2Math.SubtractVV(center1, center))); + var velocity2 = b2Math.AddVV(linearVelocity, b2Math.CrossFV(angularVelocity, b2Math.SubtractVV(center2, center))); + body1.SetLinearVelocity(velocity1); + body2.SetLinearVelocity(velocity2); + body1.SetAngularVelocity(angularVelocity); + body2.SetAngularVelocity(angularVelocity); + body1.SynchronizeFixtures(); + body2.SynchronizeFixtures(); + return body2; + } + b2Body.prototype.Merge = function (other) { + var f; + for (f = other.m_fixtureList; + f;) { + var next = f.m_next; + other.m_fixtureCount--; + f.m_next = this.m_fixtureList; + this.m_fixtureList = f; + this.m_fixtureCount++; + f.m_body = body2; + f = next; + } + body1.m_fixtureCount = 0; + var body1 = this; + + var body2 = other; + var center1 = body1.GetWorldCenter(); + var center2 = body2.GetWorldCenter(); + var velocity1 = body1.GetLinearVelocity().Copy(); + var velocity2 = body2.GetLinearVelocity().Copy(); + var angular1 = body1.GetAngularVelocity(); + var angular = body2.GetAngularVelocity(); + body1.ResetMassData(); + this.SynchronizeFixtures(); + } + b2Body.prototype.GetMass = function () { + return this.m_mass; + } + b2Body.prototype.GetInertia = function () { + return this.m_I; + } + b2Body.prototype.GetMassData = function (data) { + data.mass = this.m_mass; + data.I = this.m_I; + data.center.SetV(this.m_sweep.localCenter); + } + b2Body.prototype.SetMassData = function (massData) { + b2Settings.b2Assert(this.m_world.IsLocked() == false); + if (this.m_world.IsLocked() == true) { + return; + } + if (this.m_type != b2Body.b2_dynamicBody) { + return; + } + this.m_invMass = 0.0; + this.m_I = 0.0; + this.m_invI = 0.0; + this.m_mass = massData.mass; + if (this.m_mass <= 0.0) { + this.m_mass = 1.0; + } + this.m_invMass = 1.0 / this.m_mass; + if (massData.I > 0.0 && (this.m_flags & b2Body.e_fixedRotationFlag) == 0) { + this.m_I = massData.I - this.m_mass * (massData.center.x * massData.center.x + massData.center.y * massData.center.y); + this.m_invI = 1.0 / this.m_I; + } + var oldCenter = this.m_sweep.c.Copy(); + this.m_sweep.localCenter.SetV(massData.center); + this.m_sweep.c0.SetV(b2Math.MulX(this.m_xf, this.m_sweep.localCenter)); + this.m_sweep.c.SetV(this.m_sweep.c0); + this.m_linearVelocity.x += this.m_angularVelocity * (-(this.m_sweep.c.y - oldCenter.y)); + this.m_linearVelocity.y += this.m_angularVelocity * (+(this.m_sweep.c.x - oldCenter.x)); + } + b2Body.prototype.ResetMassData = function () { + this.m_mass = 0.0; + this.m_invMass = 0.0; + this.m_I = 0.0; + this.m_invI = 0.0; + this.m_sweep.localCenter.SetZero(); + if (this.m_type == b2Body.b2_staticBody || this.m_type == b2Body.b2_kinematicBody) { + return; + } + var center = b2Vec2.Make(0, 0); + for (var f = this.m_fixtureList; f; f = f.m_next) { + if (f.m_density == 0.0) { + continue; + } + var massData = f.GetMassData(); + this.m_mass += massData.mass; + center.x += massData.center.x * massData.mass; + center.y += massData.center.y * massData.mass; + this.m_I += massData.I; + } + if (this.m_mass > 0.0) { + this.m_invMass = 1.0 / this.m_mass; + center.x *= this.m_invMass; + center.y *= this.m_invMass; + } + else { + this.m_mass = 1.0; + this.m_invMass = 1.0; + } + if (this.m_I > 0.0 && (this.m_flags & b2Body.e_fixedRotationFlag) == 0) { + this.m_I -= this.m_mass * (center.x * center.x + center.y * center.y); + this.m_I *= this.m_inertiaScale; + b2Settings.b2Assert(this.m_I > 0); + this.m_invI = 1.0 / this.m_I; + } + else { + this.m_I = 0.0; + this.m_invI = 0.0; + } + var oldCenter = this.m_sweep.c.Copy(); + this.m_sweep.localCenter.SetV(center); + this.m_sweep.c0.SetV(b2Math.MulX(this.m_xf, this.m_sweep.localCenter)); + this.m_sweep.c.SetV(this.m_sweep.c0); + this.m_linearVelocity.x += this.m_angularVelocity * (-(this.m_sweep.c.y - oldCenter.y)); + this.m_linearVelocity.y += this.m_angularVelocity * (+(this.m_sweep.c.x - oldCenter.x)); + } + b2Body.prototype.GetWorldPoint = function (localPoint) { + var A = this.m_xf.R; + var u = new b2Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, A.col1.y * localPoint.x + A.col2.y * localPoint.y); + u.x += this.m_xf.position.x; + u.y += this.m_xf.position.y; + return u; + } + b2Body.prototype.GetWorldVector = function (localVector) { + return b2Math.MulMV(this.m_xf.R, localVector); + } + b2Body.prototype.GetLocalPoint = function (worldPoint) { + return b2Math.MulXT(this.m_xf, worldPoint); + } + b2Body.prototype.GetLocalVector = function (worldVector) { + return b2Math.MulTMV(this.m_xf.R, worldVector); + } + b2Body.prototype.GetLinearVelocityFromWorldPoint = function (worldPoint) { + return new b2Vec2(this.m_linearVelocity.x - this.m_angularVelocity * (worldPoint.y - this.m_sweep.c.y), this.m_linearVelocity.y + this.m_angularVelocity * (worldPoint.x - this.m_sweep.c.x)); + } + b2Body.prototype.GetLinearVelocityFromLocalPoint = function (localPoint) { + var A = this.m_xf.R; + var worldPoint = new b2Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, A.col1.y * localPoint.x + A.col2.y * localPoint.y); + worldPoint.x += this.m_xf.position.x; + worldPoint.y += this.m_xf.position.y; + return new b2Vec2(this.m_linearVelocity.x - this.m_angularVelocity * (worldPoint.y - this.m_sweep.c.y), this.m_linearVelocity.y + this.m_angularVelocity * (worldPoint.x - this.m_sweep.c.x)); + } + b2Body.prototype.GetLinearDamping = function () { + return this.m_linearDamping; + } + b2Body.prototype.SetLinearDamping = function (linearDamping) { + if (linearDamping === undefined) linearDamping = 0; + this.m_linearDamping = linearDamping; + } + b2Body.prototype.GetAngularDamping = function () { + return this.m_angularDamping; + } + b2Body.prototype.SetAngularDamping = function (angularDamping) { + if (angularDamping === undefined) angularDamping = 0; + this.m_angularDamping = angularDamping; + } + b2Body.prototype.SetType = function (type) { + if (type === undefined) type = 0; + if (this.m_type == type) { + return; + } + this.m_type = type; + this.ResetMassData(); + if (this.m_type == b2Body.b2_staticBody) { + this.m_linearVelocity.SetZero(); + this.m_angularVelocity = 0.0; + } + this.SetAwake(true); + this.m_force.SetZero(); + this.m_torque = 0.0; + for (var ce = this.m_contactList; ce; ce = ce.next) { + ce.contact.FlagForFiltering(); + } + } + b2Body.prototype.GetType = function () { + return this.m_type; + } + b2Body.prototype.SetBullet = function (flag) { + if (flag) { + this.m_flags |= b2Body.e_bulletFlag; + } + else { + this.m_flags &= ~b2Body.e_bulletFlag; + } + } + b2Body.prototype.IsBullet = function () { + return (this.m_flags & b2Body.e_bulletFlag) == b2Body.e_bulletFlag; + } + b2Body.prototype.SetSleepingAllowed = function (flag) { + if (flag) { + this.m_flags |= b2Body.e_allowSleepFlag; + } + else { + this.m_flags &= ~b2Body.e_allowSleepFlag; + this.SetAwake(true); + } + } + b2Body.prototype.SetAwake = function (flag) { + if (flag) { + this.m_flags |= b2Body.e_awakeFlag; + this.m_sleepTime = 0.0; + } + else { + this.m_flags &= ~b2Body.e_awakeFlag; + this.m_sleepTime = 0.0; + this.m_linearVelocity.SetZero(); + this.m_angularVelocity = 0.0; + this.m_force.SetZero(); + this.m_torque = 0.0; + } + } + b2Body.prototype.IsAwake = function () { + return (this.m_flags & b2Body.e_awakeFlag) == b2Body.e_awakeFlag; + } + b2Body.prototype.SetFixedRotation = function (fixed) { + if (fixed) { + this.m_flags |= b2Body.e_fixedRotationFlag; + } + else { + this.m_flags &= ~b2Body.e_fixedRotationFlag; + } + this.ResetMassData(); + } + b2Body.prototype.IsFixedRotation = function () { + return (this.m_flags & b2Body.e_fixedRotationFlag) == b2Body.e_fixedRotationFlag; + } + b2Body.prototype.SetActive = function (flag) { + if (flag == this.IsActive()) { + return; + } + var broadPhase; + var f; + if (flag) { + this.m_flags |= b2Body.e_activeFlag; + broadPhase = this.m_world.m_contactManager.m_broadPhase; + for (f = this.m_fixtureList; + f; f = f.m_next) { + f.CreateProxy(broadPhase, this.m_xf); + } + } + else { + this.m_flags &= ~b2Body.e_activeFlag; + broadPhase = this.m_world.m_contactManager.m_broadPhase; + for (f = this.m_fixtureList; + f; f = f.m_next) { + f.DestroyProxy(broadPhase); + } + var ce = this.m_contactList; + while (ce) { + var ce0 = ce; + ce = ce.next; + this.m_world.m_contactManager.Destroy(ce0.contact); + } + this.m_contactList = null; + } + } + b2Body.prototype.IsActive = function () { + return (this.m_flags & b2Body.e_activeFlag) == b2Body.e_activeFlag; + } + b2Body.prototype.IsSleepingAllowed = function () { + return (this.m_flags & b2Body.e_allowSleepFlag) == b2Body.e_allowSleepFlag; + } + b2Body.prototype.GetFixtureList = function () { + return this.m_fixtureList; + } + b2Body.prototype.GetJointList = function () { + return this.m_jointList; + } + b2Body.prototype.GetControllerList = function () { + return this.m_controllerList; + } + b2Body.prototype.GetContactList = function () { + return this.m_contactList; + } + b2Body.prototype.GetNext = function () { + return this.m_next; + } + b2Body.prototype.GetUserData = function () { + return this.m_userData; + } + b2Body.prototype.SetUserData = function (data) { + this.m_userData = data; + } + b2Body.prototype.GetWorld = function () { + return this.m_world; + } + b2Body.prototype.b2Body = function (bd, world) { + this.m_flags = 0; + if (bd.bullet) { + this.m_flags |= b2Body.e_bulletFlag; + } + if (bd.fixedRotation) { + this.m_flags |= b2Body.e_fixedRotationFlag; + } + if (bd.allowSleep) { + this.m_flags |= b2Body.e_allowSleepFlag; + } + if (bd.awake) { + this.m_flags |= b2Body.e_awakeFlag; + } + if (bd.active) { + this.m_flags |= b2Body.e_activeFlag; + } + this.m_world = world; + this.m_xf.position.SetV(bd.position); + this.m_xf.R.Set(bd.angle); + this.m_sweep.localCenter.SetZero(); + this.m_sweep.t0 = 1.0; + this.m_sweep.a0 = this.m_sweep.a = bd.angle; + var tMat = this.m_xf.R; + var tVec = this.m_sweep.localCenter; + this.m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + this.m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + this.m_sweep.c.x += this.m_xf.position.x; + this.m_sweep.c.y += this.m_xf.position.y; + this.m_sweep.c0.SetV(this.m_sweep.c); + this.m_jointList = null; + this.m_controllerList = null; + this.m_contactList = null; + this.m_controllerCount = 0; + this.m_prev = null; + this.m_next = null; + this.m_linearVelocity.SetV(bd.linearVelocity); + this.m_angularVelocity = bd.angularVelocity; + this.m_linearDamping = bd.linearDamping; + this.m_angularDamping = bd.angularDamping; + this.m_force.Set(0.0, 0.0); + this.m_torque = 0.0; + this.m_sleepTime = 0.0; + this.m_type = bd.type; + if (this.m_type == b2Body.b2_dynamicBody) { + this.m_mass = 1.0; + this.m_invMass = 1.0; + } + else { + this.m_mass = 0.0; + this.m_invMass = 0.0; + } + this.m_I = 0.0; + this.m_invI = 0.0; + this.m_inertiaScale = bd.inertiaScale; + this.m_userData = bd.userData; + this.m_fixtureList = null; + this.m_fixtureCount = 0; + } + b2Body.prototype.SynchronizeFixtures = function () { + var xf1 = b2Body.s_xf1; + xf1.R.Set(this.m_sweep.a0); + var tMat = xf1.R; + var tVec = this.m_sweep.localCenter; + xf1.position.x = this.m_sweep.c0.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + xf1.position.y = this.m_sweep.c0.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + var f; + var broadPhase = this.m_world.m_contactManager.m_broadPhase; + for (f = this.m_fixtureList; + f; f = f.m_next) { + f.Synchronize(broadPhase, xf1, this.m_xf); + } + } + b2Body.prototype.SynchronizeTransform = function () { + this.m_xf.R.Set(this.m_sweep.a); + var tMat = this.m_xf.R; + var tVec = this.m_sweep.localCenter; + this.m_xf.position.x = this.m_sweep.c.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + this.m_xf.position.y = this.m_sweep.c.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + } + b2Body.prototype.ShouldCollide = function (other) { + if (this.m_type != b2Body.b2_dynamicBody && other.m_type != b2Body.b2_dynamicBody) { + return false; + } + for (var jn = this.m_jointList; jn; jn = jn.next) { + if (jn.other == other) if (jn.joint.m_collideConnected == false) { + return false; + } + } + return true; + } + b2Body.prototype.Advance = function (t) { + if (t === undefined) t = 0; + this.m_sweep.Advance(t); + this.m_sweep.c.SetV(this.m_sweep.c0); + this.m_sweep.a = this.m_sweep.a0; + this.SynchronizeTransform(); + } + Box2D.postDefs.push(function () { + Box2D.Dynamics.b2Body.s_xf1 = new b2Transform(); + Box2D.Dynamics.b2Body.e_islandFlag = 0x0001; + Box2D.Dynamics.b2Body.e_awakeFlag = 0x0002; + Box2D.Dynamics.b2Body.e_allowSleepFlag = 0x0004; + Box2D.Dynamics.b2Body.e_bulletFlag = 0x0008; + Box2D.Dynamics.b2Body.e_fixedRotationFlag = 0x0010; + Box2D.Dynamics.b2Body.e_activeFlag = 0x0020; + Box2D.Dynamics.b2Body.b2_staticBody = 0; + Box2D.Dynamics.b2Body.b2_kinematicBody = 1; + Box2D.Dynamics.b2Body.b2_dynamicBody = 2; + }); + b2BodyDef.b2BodyDef = function () { + this.position = new b2Vec2(); + this.linearVelocity = new b2Vec2(); + }; + b2BodyDef.prototype.b2BodyDef = function () { + this.userData = null; + this.position.Set(0.0, 0.0); + this.angle = 0.0; + this.linearVelocity.Set(0, 0); + this.angularVelocity = 0.0; + this.linearDamping = 0.0; + this.angularDamping = 0.0; + this.allowSleep = true; + this.awake = true; + this.fixedRotation = false; + this.bullet = false; + this.type = b2Body.b2_staticBody; + this.active = true; + this.inertiaScale = 1.0; + } + b2ContactFilter.b2ContactFilter = function () {}; + b2ContactFilter.prototype.ShouldCollide = function (fixtureA, fixtureB) { + var filter1 = fixtureA.GetFilterData(); + var filter2 = fixtureB.GetFilterData(); + if (filter1.groupIndex == filter2.groupIndex && filter1.groupIndex != 0) { + return filter1.groupIndex > 0; + } + var collide = (filter1.maskBits & filter2.categoryBits) != 0 && (filter1.categoryBits & filter2.maskBits) != 0; + return collide; + } + b2ContactFilter.prototype.RayCollide = function (userData, fixture) { + if (!userData) return true; + return this.ShouldCollide((userData instanceof b2Fixture ? userData : null), fixture); + } + Box2D.postDefs.push(function () { + Box2D.Dynamics.b2ContactFilter.b2_defaultFilter = new b2ContactFilter(); + }); + b2ContactImpulse.b2ContactImpulse = function () { + this.normalImpulses = new Vector_a2j_Number(b2Settings.b2_maxManifoldPoints); + this.tangentImpulses = new Vector_a2j_Number(b2Settings.b2_maxManifoldPoints); + }; + b2ContactListener.b2ContactListener = function () {}; + b2ContactListener.prototype.BeginContact = function (contact) {} + b2ContactListener.prototype.EndContact = function (contact) {} + b2ContactListener.prototype.PreSolve = function (contact, oldManifold) {} + b2ContactListener.prototype.PostSolve = function (contact, impulse) {} + Box2D.postDefs.push(function () { + Box2D.Dynamics.b2ContactListener.b2_defaultListener = new b2ContactListener(); + }); + b2ContactManager.b2ContactManager = function () {}; + b2ContactManager.prototype.b2ContactManager = function () { + this.m_world = null; + this.m_contactCount = 0; + this.m_contactFilter = b2ContactFilter.b2_defaultFilter; + this.m_contactListener = b2ContactListener.b2_defaultListener; + this.m_contactFactory = new b2ContactFactory(this.m_allocator); + this.m_broadPhase = new b2DynamicTreeBroadPhase(); + } + b2ContactManager.prototype.AddPair = function (proxyUserDataA, proxyUserDataB) { + var fixtureA = (proxyUserDataA instanceof b2Fixture ? proxyUserDataA : null); + var fixtureB = (proxyUserDataB instanceof b2Fixture ? proxyUserDataB : null); + var bodyA = fixtureA.GetBody(); + var bodyB = fixtureB.GetBody(); + if (bodyA == bodyB) return; + var edge = bodyB.GetContactList(); + while (edge) { + if (edge.other == bodyA) { + var fA = edge.contact.GetFixtureA(); + var fB = edge.contact.GetFixtureB(); + if (fA == fixtureA && fB == fixtureB) return; + if (fA == fixtureB && fB == fixtureA) return; + } + edge = edge.next; + } + if (bodyB.ShouldCollide(bodyA) == false) { + return; + } + if (this.m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false) { + return; + } + var c = this.m_contactFactory.Create(fixtureA, fixtureB); + fixtureA = c.GetFixtureA(); + fixtureB = c.GetFixtureB(); + bodyA = fixtureA.m_body; + bodyB = fixtureB.m_body; + c.m_prev = null; + c.m_next = this.m_world.m_contactList; + if (this.m_world.m_contactList != null) { + this.m_world.m_contactList.m_prev = c; + } + this.m_world.m_contactList = c; + c.m_nodeA.contact = c; + c.m_nodeA.other = bodyB; + c.m_nodeA.prev = null; + c.m_nodeA.next = bodyA.m_contactList; + if (bodyA.m_contactList != null) { + bodyA.m_contactList.prev = c.m_nodeA; + } + bodyA.m_contactList = c.m_nodeA; + c.m_nodeB.contact = c; + c.m_nodeB.other = bodyA; + c.m_nodeB.prev = null; + c.m_nodeB.next = bodyB.m_contactList; + if (bodyB.m_contactList != null) { + bodyB.m_contactList.prev = c.m_nodeB; + } + bodyB.m_contactList = c.m_nodeB; + ++this.m_world.m_contactCount; + return; + } + b2ContactManager.prototype.FindNewContacts = function () { + this.m_broadPhase.UpdatePairs(Box2D.generateCallback(this, this.AddPair)); + } + b2ContactManager.prototype.Destroy = function (c) { + var fixtureA = c.GetFixtureA(); + var fixtureB = c.GetFixtureB(); + var bodyA = fixtureA.GetBody(); + var bodyB = fixtureB.GetBody(); + if (c.IsTouching()) { + this.m_contactListener.EndContact(c); + } + if (c.m_prev) { + c.m_prev.m_next = c.m_next; + } + if (c.m_next) { + c.m_next.m_prev = c.m_prev; + } + if (c == this.m_world.m_contactList) { + this.m_world.m_contactList = c.m_next; + } + if (c.m_nodeA.prev) { + c.m_nodeA.prev.next = c.m_nodeA.next; + } + if (c.m_nodeA.next) { + c.m_nodeA.next.prev = c.m_nodeA.prev; + } + if (c.m_nodeA == bodyA.m_contactList) { + bodyA.m_contactList = c.m_nodeA.next; + } + if (c.m_nodeB.prev) { + c.m_nodeB.prev.next = c.m_nodeB.next; + } + if (c.m_nodeB.next) { + c.m_nodeB.next.prev = c.m_nodeB.prev; + } + if (c.m_nodeB == bodyB.m_contactList) { + bodyB.m_contactList = c.m_nodeB.next; + } + this.m_contactFactory.Destroy(c); + --this.m_contactCount; + } + b2ContactManager.prototype.Collide = function () { + var c = this.m_world.m_contactList; + while (c) { + var fixtureA = c.GetFixtureA(); + var fixtureB = c.GetFixtureB(); + var bodyA = fixtureA.GetBody(); + var bodyB = fixtureB.GetBody(); + if (bodyA.IsAwake() == false && bodyB.IsAwake() == false) { + c = c.GetNext(); + continue; + } + if (c.m_flags & b2Contact.e_filterFlag) { + if (bodyB.ShouldCollide(bodyA) == false) { + var cNuke = c; + c = cNuke.GetNext(); + this.Destroy(cNuke); + continue; + } + if (this.m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false) { + cNuke = c; + c = cNuke.GetNext(); + this.Destroy(cNuke); + continue; + } + c.m_flags &= ~b2Contact.e_filterFlag; + } + var proxyA = fixtureA.m_proxy; + var proxyB = fixtureB.m_proxy; + var overlap = this.m_broadPhase.TestOverlap(proxyA, proxyB); + if (overlap == false) { + cNuke = c; + c = cNuke.GetNext(); + this.Destroy(cNuke); + continue; + } + c.Update(this.m_contactListener); + c = c.GetNext(); + } + } + Box2D.postDefs.push(function () { + Box2D.Dynamics.b2ContactManager.s_evalCP = new b2ContactPoint(); + }); + b2DebugDraw.b2DebugDraw = function () {}; + b2DebugDraw.prototype.b2DebugDraw = function () {} + b2DebugDraw.prototype.SetFlags = function (flags) { + if (flags === undefined) flags = 0; + } + b2DebugDraw.prototype.GetFlags = function () {} + b2DebugDraw.prototype.AppendFlags = function (flags) { + if (flags === undefined) flags = 0; + } + b2DebugDraw.prototype.ClearFlags = function (flags) { + if (flags === undefined) flags = 0; + } + b2DebugDraw.prototype.SetSprite = function (sprite) {} + b2DebugDraw.prototype.GetSprite = function () {} + b2DebugDraw.prototype.SetDrawScale = function (drawScale) { + if (drawScale === undefined) drawScale = 0; + } + b2DebugDraw.prototype.GetDrawScale = function () {} + b2DebugDraw.prototype.SetLineThickness = function (lineThickness) { + if (lineThickness === undefined) lineThickness = 0; + } + b2DebugDraw.prototype.GetLineThickness = function () {} + b2DebugDraw.prototype.SetAlpha = function (alpha) { + if (alpha === undefined) alpha = 0; + } + b2DebugDraw.prototype.GetAlpha = function () {} + b2DebugDraw.prototype.SetFillAlpha = function (alpha) { + if (alpha === undefined) alpha = 0; + } + b2DebugDraw.prototype.GetFillAlpha = function () {} + b2DebugDraw.prototype.SetXFormScale = function (xformScale) { + if (xformScale === undefined) xformScale = 0; + } + b2DebugDraw.prototype.GetXFormScale = function () {} + b2DebugDraw.prototype.DrawPolygon = function (vertices, vertexCount, color) { + if (vertexCount === undefined) vertexCount = 0; + } + b2DebugDraw.prototype.DrawSolidPolygon = function (vertices, vertexCount, color) { + if (vertexCount === undefined) vertexCount = 0; + } + b2DebugDraw.prototype.DrawCircle = function (center, radius, color) { + if (radius === undefined) radius = 0; + } + b2DebugDraw.prototype.DrawSolidCircle = function (center, radius, axis, color) { + if (radius === undefined) radius = 0; + } + b2DebugDraw.prototype.DrawSegment = function (p1, p2, color) {} + b2DebugDraw.prototype.DrawTransform = function (xf) {} + Box2D.postDefs.push(function () { + Box2D.Dynamics.b2DebugDraw.e_shapeBit = 0x0001; + Box2D.Dynamics.b2DebugDraw.e_jointBit = 0x0002; + Box2D.Dynamics.b2DebugDraw.e_aabbBit = 0x0004; + Box2D.Dynamics.b2DebugDraw.e_pairBit = 0x0008; + Box2D.Dynamics.b2DebugDraw.e_centerOfMassBit = 0x0010; + Box2D.Dynamics.b2DebugDraw.e_controllerBit = 0x0020; + }); + b2DestructionListener.b2DestructionListener = function () {}; + b2DestructionListener.prototype.SayGoodbyeJoint = function (joint) {} + b2DestructionListener.prototype.SayGoodbyeFixture = function (fixture) {} + b2FilterData.b2FilterData = function () { + this.categoryBits = 0x0001; + this.maskBits = 0xFFFF; + this.groupIndex = 0; + }; + b2FilterData.prototype.Copy = function () { + var copy = new b2FilterData(); + copy.categoryBits = this.categoryBits; + copy.maskBits = this.maskBits; + copy.groupIndex = this.groupIndex; + return copy; + } + b2Fixture.b2Fixture = function () { + this.m_filter = new b2FilterData(); + }; + b2Fixture.prototype.GetType = function () { + return this.m_shape.GetType(); + } + b2Fixture.prototype.GetShape = function () { + return this.m_shape; + } + b2Fixture.prototype.SetSensor = function (sensor) { + if (this.m_isSensor == sensor) return; + this.m_isSensor = sensor; + if (this.m_body == null) return; + var edge = this.m_body.GetContactList(); + while (edge) { + var contact = edge.contact; + var fixtureA = contact.GetFixtureA(); + var fixtureB = contact.GetFixtureB(); + if (fixtureA == this || fixtureB == this) contact.SetSensor(fixtureA.IsSensor() || fixtureB.IsSensor()); + edge = edge.next; + } + } + b2Fixture.prototype.IsSensor = function () { + return this.m_isSensor; + } + b2Fixture.prototype.SetFilterData = function (filter) { + this.m_filter = filter.Copy(); + if (this.m_body) return; + var edge = this.m_body.GetContactList(); + while (edge) { + var contact = edge.contact; + var fixtureA = contact.GetFixtureA(); + var fixtureB = contact.GetFixtureB(); + if (fixtureA == this || fixtureB == this) contact.FlagForFiltering(); + edge = edge.next; + } + } + b2Fixture.prototype.GetFilterData = function () { + return this.m_filter.Copy(); + } + b2Fixture.prototype.GetBody = function () { + return this.m_body; + } + b2Fixture.prototype.GetNext = function () { + return this.m_next; + } + b2Fixture.prototype.GetUserData = function () { + return this.m_userData; + } + b2Fixture.prototype.SetUserData = function (data) { + this.m_userData = data; + } + b2Fixture.prototype.TestPoint = function (p) { + return this.m_shape.TestPoint(this.m_body.GetTransform(), p); + } + b2Fixture.prototype.RayCast = function (output, input) { + return this.m_shape.RayCast(output, input, this.m_body.GetTransform()); + } + b2Fixture.prototype.GetMassData = function (massData) { + if (massData === undefined) massData = null; + if (massData == null) { + massData = new b2MassData(); + } + this.m_shape.ComputeMass(massData, this.m_density); + return massData; + } + b2Fixture.prototype.SetDensity = function (density) { + if (density === undefined) density = 0; + this.m_density = density; + } + b2Fixture.prototype.GetDensity = function () { + return this.m_density; + } + b2Fixture.prototype.GetFriction = function () { + return this.m_friction; + } + b2Fixture.prototype.SetFriction = function (friction) { + if (friction === undefined) friction = 0; + this.m_friction = friction; + } + b2Fixture.prototype.GetRestitution = function () { + return this.m_restitution; + } + b2Fixture.prototype.SetRestitution = function (restitution) { + if (restitution === undefined) restitution = 0; + this.m_restitution = restitution; + } + b2Fixture.prototype.GetAABB = function () { + return this.m_aabb; + } + b2Fixture.prototype.b2Fixture = function () { + this.m_aabb = new b2AABB(); + this.m_userData = null; + this.m_body = null; + this.m_next = null; + this.m_shape = null; + this.m_density = 0.0; + this.m_friction = 0.0; + this.m_restitution = 0.0; + } + b2Fixture.prototype.Create = function (body, xf, def) { + this.m_userData = def.userData; + this.m_friction = def.friction; + this.m_restitution = def.restitution; + this.m_body = body; + this.m_next = null; + this.m_filter = def.filter.Copy(); + this.m_isSensor = def.isSensor; + this.m_shape = def.shape.Copy(); + this.m_density = def.density; + } + b2Fixture.prototype.Destroy = function () { + this.m_shape = null; + } + b2Fixture.prototype.CreateProxy = function (broadPhase, xf) { + this.m_shape.ComputeAABB(this.m_aabb, xf); + this.m_proxy = broadPhase.CreateProxy(this.m_aabb, this); + } + b2Fixture.prototype.DestroyProxy = function (broadPhase) { + if (this.m_proxy == null) { + return; + } + broadPhase.DestroyProxy(this.m_proxy); + this.m_proxy = null; + } + b2Fixture.prototype.Synchronize = function (broadPhase, transform1, transform2) { + if (!this.m_proxy) return; + var aabb1 = new b2AABB(); + var aabb2 = new b2AABB(); + this.m_shape.ComputeAABB(aabb1, transform1); + this.m_shape.ComputeAABB(aabb2, transform2); + this.m_aabb.Combine(aabb1, aabb2); + var displacement = b2Math.SubtractVV(transform2.position, transform1.position); + broadPhase.MoveProxy(this.m_proxy, this.m_aabb, displacement); + } + b2FixtureDef.b2FixtureDef = function () { + this.filter = new b2FilterData(); + }; + b2FixtureDef.prototype.b2FixtureDef = function () { + this.shape = null; + this.userData = null; + this.friction = 0.2; + this.restitution = 0.0; + this.density = 0.0; + this.filter.categoryBits = 0x0001; + this.filter.maskBits = 0xFFFF; + this.filter.groupIndex = 0; + this.isSensor = false; + } + b2Island.b2Island = function () {}; + b2Island.prototype.b2Island = function () { + this.m_bodies = new Vector(); + this.m_contacts = new Vector(); + this.m_joints = new Vector(); + } + b2Island.prototype.Initialize = function (bodyCapacity, contactCapacity, jointCapacity, allocator, listener, contactSolver) { + if (bodyCapacity === undefined) bodyCapacity = 0; + if (contactCapacity === undefined) contactCapacity = 0; + if (jointCapacity === undefined) jointCapacity = 0; + var i = 0; + this.m_bodyCapacity = bodyCapacity; + this.m_contactCapacity = contactCapacity; + this.m_jointCapacity = jointCapacity; + this.m_bodyCount = 0; + this.m_contactCount = 0; + this.m_jointCount = 0; + this.m_allocator = allocator; + this.m_listener = listener; + this.m_contactSolver = contactSolver; + for (i = this.m_bodies.length; + i < bodyCapacity; i++) + this.m_bodies[i] = null; + for (i = this.m_contacts.length; + i < contactCapacity; i++) + this.m_contacts[i] = null; + for (i = this.m_joints.length; + i < jointCapacity; i++) + this.m_joints[i] = null; + } + b2Island.prototype.Clear = function () { + this.m_bodyCount = 0; + this.m_contactCount = 0; + this.m_jointCount = 0; + } + b2Island.prototype.Solve = function (step, gravity, allowSleep) { + var i = 0; + var j = 0; + var b; + var joint; + for (i = 0; + i < this.m_bodyCount; ++i) { + b = this.m_bodies[i]; + if (b.GetType() != b2Body.b2_dynamicBody) continue; + b.m_linearVelocity.x += step.dt * (gravity.x + b.m_invMass * b.m_force.x); + b.m_linearVelocity.y += step.dt * (gravity.y + b.m_invMass * b.m_force.y); + b.m_angularVelocity += step.dt * b.m_invI * b.m_torque; + b.m_linearVelocity.Multiply(b2Math.Clamp(1.0 - step.dt * b.m_linearDamping, 0.0, 1.0)); + b.m_angularVelocity *= b2Math.Clamp(1.0 - step.dt * b.m_angularDamping, 0.0, 1.0); + } + this.m_contactSolver.Initialize(step, this.m_contacts, this.m_contactCount, this.m_allocator); + var contactSolver = this.m_contactSolver; + contactSolver.InitVelocityConstraints(step); + for (i = 0; + i < this.m_jointCount; ++i) { + joint = this.m_joints[i]; + joint.InitVelocityConstraints(step); + } + for (i = 0; + i < step.velocityIterations; ++i) { + for (j = 0; + j < this.m_jointCount; ++j) { + joint = this.m_joints[j]; + joint.SolveVelocityConstraints(step); + } + contactSolver.SolveVelocityConstraints(); + } + for (i = 0; + i < this.m_jointCount; ++i) { + joint = this.m_joints[i]; + joint.FinalizeVelocityConstraints(); + } + contactSolver.FinalizeVelocityConstraints(); + for (i = 0; + i < this.m_bodyCount; ++i) { + b = this.m_bodies[i]; + if (b.GetType() == b2Body.b2_staticBody) continue; + var translationX = step.dt * b.m_linearVelocity.x; + var translationY = step.dt * b.m_linearVelocity.y; + if ((translationX * translationX + translationY * translationY) > b2Settings.b2_maxTranslationSquared) { + b.m_linearVelocity.Normalize(); + b.m_linearVelocity.x *= b2Settings.b2_maxTranslation * step.inv_dt; + b.m_linearVelocity.y *= b2Settings.b2_maxTranslation * step.inv_dt; + } + var rotation = step.dt * b.m_angularVelocity; + if (rotation * rotation > b2Settings.b2_maxRotationSquared) { + if (b.m_angularVelocity < 0.0) { + b.m_angularVelocity = (-b2Settings.b2_maxRotation * step.inv_dt); + } + else { + b.m_angularVelocity = b2Settings.b2_maxRotation * step.inv_dt; + } + } + b.m_sweep.c0.SetV(b.m_sweep.c); + b.m_sweep.a0 = b.m_sweep.a; + b.m_sweep.c.x += step.dt * b.m_linearVelocity.x; + b.m_sweep.c.y += step.dt * b.m_linearVelocity.y; + b.m_sweep.a += step.dt * b.m_angularVelocity; + b.SynchronizeTransform(); + } + for (i = 0; + i < step.positionIterations; ++i) { + var contactsOkay = contactSolver.SolvePositionConstraints(b2Settings.b2_contactBaumgarte); + var jointsOkay = true; + for (j = 0; + j < this.m_jointCount; ++j) { + joint = this.m_joints[j]; + var jointOkay = joint.SolvePositionConstraints(b2Settings.b2_contactBaumgarte); + jointsOkay = jointsOkay && jointOkay; + } + if (contactsOkay && jointsOkay) { + break; + } + } + this.Report(contactSolver.m_constraints); + if (allowSleep) { + var minSleepTime = Number.MAX_VALUE; + var linTolSqr = b2Settings.b2_linearSleepTolerance * b2Settings.b2_linearSleepTolerance; + var angTolSqr = b2Settings.b2_angularSleepTolerance * b2Settings.b2_angularSleepTolerance; + for (i = 0; + i < this.m_bodyCount; ++i) { + b = this.m_bodies[i]; + if (b.GetType() == b2Body.b2_staticBody) { + continue; + } + if ((b.m_flags & b2Body.e_allowSleepFlag) == 0) { + b.m_sleepTime = 0.0; + minSleepTime = 0.0; + } + if ((b.m_flags & b2Body.e_allowSleepFlag) == 0 || b.m_angularVelocity * b.m_angularVelocity > angTolSqr || b2Math.Dot(b.m_linearVelocity, b.m_linearVelocity) > linTolSqr) { + b.m_sleepTime = 0.0; + minSleepTime = 0.0; + } + else { + b.m_sleepTime += step.dt; + minSleepTime = b2Math.Min(minSleepTime, b.m_sleepTime); + } + } + if (minSleepTime >= b2Settings.b2_timeToSleep) { + for (i = 0; + i < this.m_bodyCount; ++i) { + b = this.m_bodies[i]; + b.SetAwake(false); + } + } + } + } + b2Island.prototype.SolveTOI = function (subStep) { + var i = 0; + var j = 0; + this.m_contactSolver.Initialize(subStep, this.m_contacts, this.m_contactCount, this.m_allocator); + var contactSolver = this.m_contactSolver; + for (i = 0; + i < this.m_jointCount; ++i) { + this.m_joints[i].InitVelocityConstraints(subStep); + } + for (i = 0; + i < subStep.velocityIterations; ++i) { + contactSolver.SolveVelocityConstraints(); + for (j = 0; + j < this.m_jointCount; ++j) { + this.m_joints[j].SolveVelocityConstraints(subStep); + } + } + for (i = 0; + i < this.m_bodyCount; ++i) { + var b = this.m_bodies[i]; + if (b.GetType() == b2Body.b2_staticBody) continue; + var translationX = subStep.dt * b.m_linearVelocity.x; + var translationY = subStep.dt * b.m_linearVelocity.y; + if ((translationX * translationX + translationY * translationY) > b2Settings.b2_maxTranslationSquared) { + b.m_linearVelocity.Normalize(); + b.m_linearVelocity.x *= b2Settings.b2_maxTranslation * subStep.inv_dt; + b.m_linearVelocity.y *= b2Settings.b2_maxTranslation * subStep.inv_dt; + } + var rotation = subStep.dt * b.m_angularVelocity; + if (rotation * rotation > b2Settings.b2_maxRotationSquared) { + if (b.m_angularVelocity < 0.0) { + b.m_angularVelocity = (-b2Settings.b2_maxRotation * subStep.inv_dt); + } + else { + b.m_angularVelocity = b2Settings.b2_maxRotation * subStep.inv_dt; + } + } + b.m_sweep.c0.SetV(b.m_sweep.c); + b.m_sweep.a0 = b.m_sweep.a; + b.m_sweep.c.x += subStep.dt * b.m_linearVelocity.x; + b.m_sweep.c.y += subStep.dt * b.m_linearVelocity.y; + b.m_sweep.a += subStep.dt * b.m_angularVelocity; + b.SynchronizeTransform(); + } + var k_toiBaumgarte = 0.75; + for (i = 0; + i < subStep.positionIterations; ++i) { + var contactsOkay = contactSolver.SolvePositionConstraints(k_toiBaumgarte); + var jointsOkay = true; + for (j = 0; + j < this.m_jointCount; ++j) { + var jointOkay = this.m_joints[j].SolvePositionConstraints(b2Settings.b2_contactBaumgarte); + jointsOkay = jointsOkay && jointOkay; + } + if (contactsOkay && jointsOkay) { + break; + } + } + this.Report(contactSolver.m_constraints); + } + b2Island.prototype.Report = function (constraints) { + if (this.m_listener == null) { + return; + } + for (var i = 0; i < this.m_contactCount; ++i) { + var c = this.m_contacts[i]; + var cc = constraints[i]; + for (var j = 0; j < cc.pointCount; ++j) { + b2Island.s_impulse.normalImpulses[j] = cc.points[j].normalImpulse; + b2Island.s_impulse.tangentImpulses[j] = cc.points[j].tangentImpulse; + } + this.m_listener.PostSolve(c, b2Island.s_impulse); + } + } + b2Island.prototype.AddBody = function (body) { + body.m_islandIndex = this.m_bodyCount; + this.m_bodies[this.m_bodyCount++] = body; + } + b2Island.prototype.AddContact = function (contact) { + this.m_contacts[this.m_contactCount++] = contact; + } + b2Island.prototype.AddJoint = function (joint) { + this.m_joints[this.m_jointCount++] = joint; + } + Box2D.postDefs.push(function () { + Box2D.Dynamics.b2Island.s_impulse = new b2ContactImpulse(); + }); + b2TimeStep.b2TimeStep = function () {}; + b2TimeStep.prototype.Set = function (step) { + this.dt = step.dt; + this.inv_dt = step.inv_dt; + this.positionIterations = step.positionIterations; + this.velocityIterations = step.velocityIterations; + this.warmStarting = step.warmStarting; + } + b2World.b2World = function () { + this.s_stack = new Vector(); + this.m_contactManager = new b2ContactManager(); + this.m_contactSolver = new b2ContactSolver(); + this.m_island = new b2Island(); + }; + b2World.prototype.b2World = function (gravity, doSleep) { + this.m_destructionListener = null; + this.m_debugDraw = null; + this.m_bodyList = null; + this.m_contactList = null; + this.m_jointList = null; + this.m_controllerList = null; + this.m_bodyCount = 0; + this.m_contactCount = 0; + this.m_jointCount = 0; + this.m_controllerCount = 0; + b2World.m_warmStarting = true; + b2World.m_continuousPhysics = true; + this.m_allowSleep = doSleep; + this.m_gravity = gravity; + this.m_inv_dt0 = 0.0; + this.m_contactManager.m_world = this; + var bd = new b2BodyDef(); + this.m_groundBody = this.CreateBody(bd); + } + b2World.prototype.SetDestructionListener = function (listener) { + this.m_destructionListener = listener; + } + b2World.prototype.SetContactFilter = function (filter) { + this.m_contactManager.m_contactFilter = filter; + } + b2World.prototype.SetContactListener = function (listener) { + this.m_contactManager.m_contactListener = listener; + } + b2World.prototype.SetDebugDraw = function (debugDraw) { + this.m_debugDraw = debugDraw; + } + b2World.prototype.SetBroadPhase = function (broadPhase) { + var oldBroadPhase = this.m_contactManager.m_broadPhase; + this.m_contactManager.m_broadPhase = broadPhase; + for (var b = this.m_bodyList; b; b = b.m_next) { + for (var f = b.m_fixtureList; f; f = f.m_next) { + f.m_proxy = broadPhase.CreateProxy(oldBroadPhase.GetFatAABB(f.m_proxy), f); + } + } + } + b2World.prototype.Validate = function () { + this.m_contactManager.m_broadPhase.Validate(); + } + b2World.prototype.GetProxyCount = function () { + return this.m_contactManager.m_broadPhase.GetProxyCount(); + } + b2World.prototype.CreateBody = function (def) { + if (this.IsLocked() == true) { + return null; + } + var b = new b2Body(def, this); + b.m_prev = null; + b.m_next = this.m_bodyList; + if (this.m_bodyList) { + this.m_bodyList.m_prev = b; + } + this.m_bodyList = b; + ++this.m_bodyCount; + return b; + } + b2World.prototype.DestroyBody = function (b) { + if (this.IsLocked() == true) { + return; + } + var jn = b.m_jointList; + while (jn) { + var jn0 = jn; + jn = jn.next; + if (this.m_destructionListener) { + this.m_destructionListener.SayGoodbyeJoint(jn0.joint); + } + this.DestroyJoint(jn0.joint); + } + var coe = b.m_controllerList; + while (coe) { + var coe0 = coe; + coe = coe.nextController; + coe0.controller.RemoveBody(b); + } + var ce = b.m_contactList; + while (ce) { + var ce0 = ce; + ce = ce.next; + this.m_contactManager.Destroy(ce0.contact); + } + b.m_contactList = null; + var f = b.m_fixtureList; + while (f) { + var f0 = f; + f = f.m_next; + if (this.m_destructionListener) { + this.m_destructionListener.SayGoodbyeFixture(f0); + } + f0.DestroyProxy(this.m_contactManager.m_broadPhase); + f0.Destroy(); + } + b.m_fixtureList = null; + b.m_fixtureCount = 0; + if (b.m_prev) { + b.m_prev.m_next = b.m_next; + } + if (b.m_next) { + b.m_next.m_prev = b.m_prev; + } + if (b == this.m_bodyList) { + this.m_bodyList = b.m_next; + }--this.m_bodyCount; + } + b2World.prototype.CreateJoint = function (def) { + var j = b2Joint.Create(def, null); + j.m_prev = null; + j.m_next = this.m_jointList; + if (this.m_jointList) { + this.m_jointList.m_prev = j; + } + this.m_jointList = j; + ++this.m_jointCount; + j.m_edgeA.joint = j; + j.m_edgeA.other = j.m_bodyB; + j.m_edgeA.prev = null; + j.m_edgeA.next = j.m_bodyA.m_jointList; + if (j.m_bodyA.m_jointList) j.m_bodyA.m_jointList.prev = j.m_edgeA; + j.m_bodyA.m_jointList = j.m_edgeA; + j.m_edgeB.joint = j; + j.m_edgeB.other = j.m_bodyA; + j.m_edgeB.prev = null; + j.m_edgeB.next = j.m_bodyB.m_jointList; + if (j.m_bodyB.m_jointList) j.m_bodyB.m_jointList.prev = j.m_edgeB; + j.m_bodyB.m_jointList = j.m_edgeB; + var bodyA = def.bodyA; + var bodyB = def.bodyB; + if (def.collideConnected == false) { + var edge = bodyB.GetContactList(); + while (edge) { + if (edge.other == bodyA) { + edge.contact.FlagForFiltering(); + } + edge = edge.next; + } + } + return j; + } + b2World.prototype.DestroyJoint = function (j) { + var collideConnected = j.m_collideConnected; + if (j.m_prev) { + j.m_prev.m_next = j.m_next; + } + if (j.m_next) { + j.m_next.m_prev = j.m_prev; + } + if (j == this.m_jointList) { + this.m_jointList = j.m_next; + } + var bodyA = j.m_bodyA; + var bodyB = j.m_bodyB; + bodyA.SetAwake(true); + bodyB.SetAwake(true); + if (j.m_edgeA.prev) { + j.m_edgeA.prev.next = j.m_edgeA.next; + } + if (j.m_edgeA.next) { + j.m_edgeA.next.prev = j.m_edgeA.prev; + } + if (j.m_edgeA == bodyA.m_jointList) { + bodyA.m_jointList = j.m_edgeA.next; + } + j.m_edgeA.prev = null; + j.m_edgeA.next = null; + if (j.m_edgeB.prev) { + j.m_edgeB.prev.next = j.m_edgeB.next; + } + if (j.m_edgeB.next) { + j.m_edgeB.next.prev = j.m_edgeB.prev; + } + if (j.m_edgeB == bodyB.m_jointList) { + bodyB.m_jointList = j.m_edgeB.next; + } + j.m_edgeB.prev = null; + j.m_edgeB.next = null; + b2Joint.Destroy(j, null); + --this.m_jointCount; + if (collideConnected == false) { + var edge = bodyB.GetContactList(); + while (edge) { + if (edge.other == bodyA) { + edge.contact.FlagForFiltering(); + } + edge = edge.next; + } + } + } + b2World.prototype.AddController = function (c) { + c.m_next = this.m_controllerList; + c.m_prev = null; + this.m_controllerList = c; + c.m_world = this; + this.m_controllerCount++; + return c; + } + b2World.prototype.RemoveController = function (c) { + if (c.m_prev) c.m_prev.m_next = c.m_next; + if (c.m_next) c.m_next.m_prev = c.m_prev; + if (this.m_controllerList == c) this.m_controllerList = c.m_next; + this.m_controllerCount--; + } + b2World.prototype.CreateController = function (controller) { + if (controller.m_world != this) throw new Error("Controller can only be a member of one world"); + controller.m_next = this.m_controllerList; + controller.m_prev = null; + if (this.m_controllerList) this.m_controllerList.m_prev = controller; + this.m_controllerList = controller; + ++this.m_controllerCount; + controller.m_world = this; + return controller; + } + b2World.prototype.DestroyController = function (controller) { + controller.Clear(); + if (controller.m_next) controller.m_next.m_prev = controller.m_prev; + if (controller.m_prev) controller.m_prev.m_next = controller.m_next; + if (controller == this.m_controllerList) this.m_controllerList = controller.m_next; + --this.m_controllerCount; + } + b2World.prototype.SetWarmStarting = function (flag) { + b2World.m_warmStarting = flag; + } + b2World.prototype.SetContinuousPhysics = function (flag) { + b2World.m_continuousPhysics = flag; + } + b2World.prototype.GetBodyCount = function () { + return this.m_bodyCount; + } + b2World.prototype.GetJointCount = function () { + return this.m_jointCount; + } + b2World.prototype.GetContactCount = function () { + return this.m_contactCount; + } + b2World.prototype.SetGravity = function (gravity) { + this.m_gravity = gravity; + } + b2World.prototype.GetGravity = function () { + return this.m_gravity; + } + b2World.prototype.GetGroundBody = function () { + return this.m_groundBody; + } + b2World.prototype.Step = function (dt, velocityIterations, positionIterations) { + if (dt === undefined) dt = 0; + if (velocityIterations === undefined) velocityIterations = 0; + if (positionIterations === undefined) positionIterations = 0; + if (this.m_flags & b2World.e_newFixture) { + this.m_contactManager.FindNewContacts(); + this.m_flags &= ~b2World.e_newFixture; + } + this.m_flags |= b2World.e_locked; + var step = b2World.s_timestep2; + step.dt = dt; + step.velocityIterations = velocityIterations; + step.positionIterations = positionIterations; + if (dt > 0.0) { + step.inv_dt = 1.0 / dt; + } + else { + step.inv_dt = 0.0; + } + step.dtRatio = this.m_inv_dt0 * dt; + step.warmStarting = b2World.m_warmStarting; + this.m_contactManager.Collide(); + if (step.dt > 0.0) { + this.Solve(step); + } + if (b2World.m_continuousPhysics && step.dt > 0.0) { + this.SolveTOI(step); + } + if (step.dt > 0.0) { + this.m_inv_dt0 = step.inv_dt; + } + this.m_flags &= ~b2World.e_locked; + } + b2World.prototype.ClearForces = function () { + for (var body = this.m_bodyList; body; body = body.m_next) { + body.m_force.SetZero(); + body.m_torque = 0.0; + } + } + b2World.prototype.DrawDebugData = function () { + if (this.m_debugDraw == null) { + return; + } + this.m_debugDraw.m_sprite.graphics.clear(); + var flags = this.m_debugDraw.GetFlags(); + var i = 0; + var b; + var f; + var s; + var j; + var bp; + var invQ = new b2Vec2; + var x1 = new b2Vec2; + var x2 = new b2Vec2; + var xf; + var b1 = new b2AABB(); + var b2 = new b2AABB(); + var vs = [new b2Vec2(), new b2Vec2(), new b2Vec2(), new b2Vec2()]; + var color = new b2Color(0, 0, 0); + if (flags & b2DebugDraw.e_shapeBit) { + for (b = this.m_bodyList; + b; b = b.m_next) { + xf = b.m_xf; + for (f = b.GetFixtureList(); + f; f = f.m_next) { + s = f.GetShape(); + if (b.IsActive() == false) { + color.Set(0.5, 0.5, 0.3); + this.DrawShape(s, xf, color); + } + else if (b.GetType() == b2Body.b2_staticBody) { + color.Set(0.5, 0.9, 0.5); + this.DrawShape(s, xf, color); + } + else if (b.GetType() == b2Body.b2_kinematicBody) { + color.Set(0.5, 0.5, 0.9); + this.DrawShape(s, xf, color); + } + else if (b.IsAwake() == false) { + color.Set(0.6, 0.6, 0.6); + this.DrawShape(s, xf, color); + } + else { + color.Set(0.9, 0.7, 0.7); + this.DrawShape(s, xf, color); + } + } + } + } + if (flags & b2DebugDraw.e_jointBit) { + for (j = this.m_jointList; + j; j = j.m_next) { + this.DrawJoint(j); + } + } + if (flags & b2DebugDraw.e_controllerBit) { + for (var c = this.m_controllerList; c; c = c.m_next) { + c.Draw(this.m_debugDraw); + } + } + if (flags & b2DebugDraw.e_pairBit) { + color.Set(0.3, 0.9, 0.9); + for (var contact = this.m_contactManager.m_contactList; contact; contact = contact.GetNext()) { + var fixtureA = contact.GetFixtureA(); + var fixtureB = contact.GetFixtureB(); + var cA = fixtureA.GetAABB().GetCenter(); + var cB = fixtureB.GetAABB().GetCenter(); + this.m_debugDraw.DrawSegment(cA, cB, color); + } + } + if (flags & b2DebugDraw.e_aabbBit) { + bp = this.m_contactManager.m_broadPhase; + vs = [new b2Vec2(), new b2Vec2(), new b2Vec2(), new b2Vec2()]; + for (b = this.m_bodyList; + b; b = b.GetNext()) { + if (b.IsActive() == false) { + continue; + } + for (f = b.GetFixtureList(); + f; f = f.GetNext()) { + var aabb = bp.GetFatAABB(f.m_proxy); + vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y); + vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y); + vs[2].Set(aabb.upperBound.x, aabb.upperBound.y); + vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y); + this.m_debugDraw.DrawPolygon(vs, 4, color); + } + } + } + if (flags & b2DebugDraw.e_centerOfMassBit) { + for (b = this.m_bodyList; + b; b = b.m_next) { + xf = b2World.s_xf; + xf.R = b.m_xf.R; + xf.position = b.GetWorldCenter(); + this.m_debugDraw.DrawTransform(xf); + } + } + } + b2World.prototype.QueryAABB = function (callback, aabb) { + var __this = this; + var broadPhase = __this.m_contactManager.m_broadPhase; + + function WorldQueryWrapper(proxy) { + return callback(broadPhase.GetUserData(proxy)); + }; + broadPhase.Query(WorldQueryWrapper, aabb); + } + b2World.prototype.QueryShape = function (callback, shape, transform) { + var __this = this; + if (transform === undefined) transform = null; + if (transform == null) { + transform = new b2Transform(); + transform.SetIdentity(); + } + var broadPhase = __this.m_contactManager.m_broadPhase; + + function WorldQueryWrapper(proxy) { + var fixture = (broadPhase.GetUserData(proxy) instanceof b2Fixture ? broadPhase.GetUserData(proxy) : null); + if (b2Shape.TestOverlap(shape, transform, fixture.GetShape(), fixture.GetBody().GetTransform())) return callback(fixture); + return true; + }; + var aabb = new b2AABB(); + shape.ComputeAABB(aabb, transform); + broadPhase.Query(WorldQueryWrapper, aabb); + } + b2World.prototype.QueryPoint = function (callback, p) { + var __this = this; + var broadPhase = __this.m_contactManager.m_broadPhase; + + function WorldQueryWrapper(proxy) { + var fixture = (broadPhase.GetUserData(proxy) instanceof b2Fixture ? broadPhase.GetUserData(proxy) : null); + if (fixture.TestPoint(p)) return callback(fixture); + return true; + }; + var aabb = new b2AABB(); + aabb.lowerBound.Set(p.x - b2Settings.b2_linearSlop, p.y - b2Settings.b2_linearSlop); + aabb.upperBound.Set(p.x + b2Settings.b2_linearSlop, p.y + b2Settings.b2_linearSlop); + broadPhase.Query(WorldQueryWrapper, aabb); + } + b2World.prototype.RayCast = function (callback, point1, point2) { + var __this = this; + var broadPhase = __this.m_contactManager.m_broadPhase; + var output = new b2RayCastOutput; + + function RayCastWrapper(input, proxy) { + var userData = broadPhase.GetUserData(proxy); + var fixture = (userData instanceof b2Fixture ? userData : null); + var hit = fixture.RayCast(output, input); + if (hit) { + var fraction = output.fraction; + var point = new b2Vec2((1.0 - fraction) * point1.x + fraction * point2.x, (1.0 - fraction) * point1.y + fraction * point2.y); + return callback(fixture, point, output.normal, fraction); + } + return input.maxFraction; + }; + var input = new b2RayCastInput(point1, point2); + broadPhase.RayCast(RayCastWrapper, input); + } + b2World.prototype.RayCastOne = function (point1, point2) { + var __this = this; + var result; + + function RayCastOneWrapper(fixture, point, normal, fraction) { + if (fraction === undefined) fraction = 0; + result = fixture; + return fraction; + }; + __this.RayCast(RayCastOneWrapper, point1, point2); + return result; + } + b2World.prototype.RayCastAll = function (point1, point2) { + var __this = this; + var result = new Vector(); + + function RayCastAllWrapper(fixture, point, normal, fraction) { + if (fraction === undefined) fraction = 0; + result[result.length] = fixture; + return 1; + }; + __this.RayCast(RayCastAllWrapper, point1, point2); + return result; + } + b2World.prototype.GetBodyList = function () { + return this.m_bodyList; + } + b2World.prototype.GetJointList = function () { + return this.m_jointList; + } + b2World.prototype.GetContactList = function () { + return this.m_contactList; + } + b2World.prototype.IsLocked = function () { + return (this.m_flags & b2World.e_locked) > 0; + } + b2World.prototype.Solve = function (step) { + var b; + for (var controller = this.m_controllerList; controller; controller = controller.m_next) { + controller.Step(step); + } + var island = this.m_island; + island.Initialize(this.m_bodyCount, this.m_contactCount, this.m_jointCount, null, this.m_contactManager.m_contactListener, this.m_contactSolver); + for (b = this.m_bodyList; + b; b = b.m_next) { + b.m_flags &= ~b2Body.e_islandFlag; + } + for (var c = this.m_contactList; c; c = c.m_next) { + c.m_flags &= ~b2Contact.e_islandFlag; + } + for (var j = this.m_jointList; j; j = j.m_next) { + j.m_islandFlag = false; + } + var stackSize = parseInt(this.m_bodyCount); + var stack = this.s_stack; + for (var seed = this.m_bodyList; seed; seed = seed.m_next) { + if (seed.m_flags & b2Body.e_islandFlag) { + continue; + } + if (seed.IsAwake() == false || seed.IsActive() == false) { + continue; + } + if (seed.GetType() == b2Body.b2_staticBody) { + continue; + } + island.Clear(); + var stackCount = 0; + stack[stackCount++] = seed; + seed.m_flags |= b2Body.e_islandFlag; + while (stackCount > 0) { + b = stack[--stackCount]; + island.AddBody(b); + if (b.IsAwake() == false) { + b.SetAwake(true); + } + if (b.GetType() == b2Body.b2_staticBody) { + continue; + } + var other; + for (var ce = b.m_contactList; ce; ce = ce.next) { + if (ce.contact.m_flags & b2Contact.e_islandFlag) { + continue; + } + if (ce.contact.IsSensor() == true || ce.contact.IsEnabled() == false || ce.contact.IsTouching() == false) { + continue; + } + island.AddContact(ce.contact); + ce.contact.m_flags |= b2Contact.e_islandFlag; + other = ce.other; + if (other.m_flags & b2Body.e_islandFlag) { + continue; + } + stack[stackCount++] = other; + other.m_flags |= b2Body.e_islandFlag; + } + for (var jn = b.m_jointList; jn; jn = jn.next) { + if (jn.joint.m_islandFlag == true) { + continue; + } + other = jn.other; + if (other.IsActive() == false) { + continue; + } + island.AddJoint(jn.joint); + jn.joint.m_islandFlag = true; + if (other.m_flags & b2Body.e_islandFlag) { + continue; + } + stack[stackCount++] = other; + other.m_flags |= b2Body.e_islandFlag; + } + } + island.Solve(step, this.m_gravity, this.m_allowSleep); + for (var i = 0; i < island.m_bodyCount; ++i) { + b = island.m_bodies[i]; + if (b.GetType() == b2Body.b2_staticBody) { + b.m_flags &= ~b2Body.e_islandFlag; + } + } + } + for (i = 0; + i < stack.length; ++i) { + if (!stack[i]) break; + stack[i] = null; + } + for (b = this.m_bodyList; + b; b = b.m_next) { + if (b.IsAwake() == false || b.IsActive() == false) { + continue; + } + if (b.GetType() == b2Body.b2_staticBody) { + continue; + } + b.SynchronizeFixtures(); + } + this.m_contactManager.FindNewContacts(); + } + b2World.prototype.SolveTOI = function (step) { + var b; + var fA; + var fB; + var bA; + var bB; + var cEdge; + var j; + var island = this.m_island; + island.Initialize(this.m_bodyCount, b2Settings.b2_maxTOIContactsPerIsland, b2Settings.b2_maxTOIJointsPerIsland, null, this.m_contactManager.m_contactListener, this.m_contactSolver); + var queue = b2World.s_queue; + for (b = this.m_bodyList; + b; b = b.m_next) { + b.m_flags &= ~b2Body.e_islandFlag; + b.m_sweep.t0 = 0.0; + } + var c; + for (c = this.m_contactList; + c; c = c.m_next) { + c.m_flags &= ~ (b2Contact.e_toiFlag | b2Contact.e_islandFlag); + } + for (j = this.m_jointList; + j; j = j.m_next) { + j.m_islandFlag = false; + } + for (;;) { + var minContact = null; + var minTOI = 1.0; + for (c = this.m_contactList; + c; c = c.m_next) { + if (c.IsSensor() == true || c.IsEnabled() == false || c.IsContinuous() == false) { + continue; + } + var toi = 1.0; + if (c.m_flags & b2Contact.e_toiFlag) { + toi = c.m_toi; + } + else { + fA = c.m_fixtureA; + fB = c.m_fixtureB; + bA = fA.m_body; + bB = fB.m_body; + if ((bA.GetType() != b2Body.b2_dynamicBody || bA.IsAwake() == false) && (bB.GetType() != b2Body.b2_dynamicBody || bB.IsAwake() == false)) { + continue; + } + var t0 = bA.m_sweep.t0; + if (bA.m_sweep.t0 < bB.m_sweep.t0) { + t0 = bB.m_sweep.t0; + bA.m_sweep.Advance(t0); + } + else if (bB.m_sweep.t0 < bA.m_sweep.t0) { + t0 = bA.m_sweep.t0; + bB.m_sweep.Advance(t0); + } + toi = c.ComputeTOI(bA.m_sweep, bB.m_sweep); + b2Settings.b2Assert(0.0 <= toi && toi <= 1.0); + if (toi > 0.0 && toi < 1.0) { + toi = (1.0 - toi) * t0 + toi; + if (toi > 1) toi = 1; + } + c.m_toi = toi; + c.m_flags |= b2Contact.e_toiFlag; + } + if (Number.MIN_VALUE < toi && toi < minTOI) { + minContact = c; + minTOI = toi; + } + } + if (minContact == null || 1.0 - 100.0 * Number.MIN_VALUE < minTOI) { + break; + } + fA = minContact.m_fixtureA; + fB = minContact.m_fixtureB; + bA = fA.m_body; + bB = fB.m_body; + b2World.s_backupA.Set(bA.m_sweep); + b2World.s_backupB.Set(bB.m_sweep); + bA.Advance(minTOI); + bB.Advance(minTOI); + minContact.Update(this.m_contactManager.m_contactListener); + minContact.m_flags &= ~b2Contact.e_toiFlag; + if (minContact.IsSensor() == true || minContact.IsEnabled() == false) { + bA.m_sweep.Set(b2World.s_backupA); + bB.m_sweep.Set(b2World.s_backupB); + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + continue; + } + if (minContact.IsTouching() == false) { + continue; + } + var seed = bA; + if (seed.GetType() != b2Body.b2_dynamicBody) { + seed = bB; + } + island.Clear(); + var queueStart = 0; + var queueSize = 0; + queue[queueStart + queueSize++] = seed; + seed.m_flags |= b2Body.e_islandFlag; + while (queueSize > 0) { + b = queue[queueStart++]; + --queueSize; + island.AddBody(b); + if (b.IsAwake() == false) { + b.SetAwake(true); + } + if (b.GetType() != b2Body.b2_dynamicBody) { + continue; + } + for (cEdge = b.m_contactList; + cEdge; cEdge = cEdge.next) { + if (island.m_contactCount == island.m_contactCapacity) { + break; + } + if (cEdge.contact.m_flags & b2Contact.e_islandFlag) { + continue; + } + if (cEdge.contact.IsSensor() == true || cEdge.contact.IsEnabled() == false || cEdge.contact.IsTouching() == false) { + continue; + } + island.AddContact(cEdge.contact); + cEdge.contact.m_flags |= b2Contact.e_islandFlag; + var other = cEdge.other; + if (other.m_flags & b2Body.e_islandFlag) { + continue; + } + if (other.GetType() != b2Body.b2_staticBody) { + other.Advance(minTOI); + other.SetAwake(true); + } + queue[queueStart + queueSize] = other; + ++queueSize; + other.m_flags |= b2Body.e_islandFlag; + } + for (var jEdge = b.m_jointList; jEdge; jEdge = jEdge.next) { + if (island.m_jointCount == island.m_jointCapacity) continue; + if (jEdge.joint.m_islandFlag == true) continue; + other = jEdge.other; + if (other.IsActive() == false) { + continue; + } + island.AddJoint(jEdge.joint); + jEdge.joint.m_islandFlag = true; + if (other.m_flags & b2Body.e_islandFlag) continue; + if (other.GetType() != b2Body.b2_staticBody) { + other.Advance(minTOI); + other.SetAwake(true); + } + queue[queueStart + queueSize] = other; + ++queueSize; + other.m_flags |= b2Body.e_islandFlag; + } + } + var subStep = b2World.s_timestep; + subStep.warmStarting = false; + subStep.dt = (1.0 - minTOI) * step.dt; + subStep.inv_dt = 1.0 / subStep.dt; + subStep.dtRatio = 0.0; + subStep.velocityIterations = step.velocityIterations; + subStep.positionIterations = step.positionIterations; + island.SolveTOI(subStep); + var i = 0; + for (i = 0; + i < island.m_bodyCount; ++i) { + b = island.m_bodies[i]; + b.m_flags &= ~b2Body.e_islandFlag; + if (b.IsAwake() == false) { + continue; + } + if (b.GetType() != b2Body.b2_dynamicBody) { + continue; + } + b.SynchronizeFixtures(); + for (cEdge = b.m_contactList; + cEdge; cEdge = cEdge.next) { + cEdge.contact.m_flags &= ~b2Contact.e_toiFlag; + } + } + for (i = 0; + i < island.m_contactCount; ++i) { + c = island.m_contacts[i]; + c.m_flags &= ~ (b2Contact.e_toiFlag | b2Contact.e_islandFlag); + } + for (i = 0; + i < island.m_jointCount; ++i) { + j = island.m_joints[i]; + j.m_islandFlag = false; + } + this.m_contactManager.FindNewContacts(); + } + } + b2World.prototype.DrawJoint = function (joint) { + var b1 = joint.GetBodyA(); + var b2 = joint.GetBodyB(); + var xf1 = b1.m_xf; + var xf2 = b2.m_xf; + var x1 = xf1.position; + var x2 = xf2.position; + var p1 = joint.GetAnchorA(); + var p2 = joint.GetAnchorB(); + var color = b2World.s_jointColor; + switch (joint.m_type) { + case b2Joint.e_distanceJoint: + this.m_debugDraw.DrawSegment(p1, p2, color); + break; + case b2Joint.e_pulleyJoint: + { + var pulley = ((joint instanceof b2PulleyJoint ? joint : null)); + var s1 = pulley.GetGroundAnchorA(); + var s2 = pulley.GetGroundAnchorB(); + this.m_debugDraw.DrawSegment(s1, p1, color); + this.m_debugDraw.DrawSegment(s2, p2, color); + this.m_debugDraw.DrawSegment(s1, s2, color); + } + break; + case b2Joint.e_mouseJoint: + this.m_debugDraw.DrawSegment(p1, p2, color); + break; + default: + if (b1 != this.m_groundBody) this.m_debugDraw.DrawSegment(x1, p1, color); + this.m_debugDraw.DrawSegment(p1, p2, color); + if (b2 != this.m_groundBody) this.m_debugDraw.DrawSegment(x2, p2, color); + } + } + b2World.prototype.DrawShape = function (shape, xf, color) { + switch (shape.m_type) { + case b2Shape.e_circleShape: + { + var circle = ((shape instanceof b2CircleShape ? shape : null)); + var center = b2Math.MulX(xf, circle.m_p); + var radius = circle.m_radius; + var axis = xf.R.col1; + this.m_debugDraw.DrawSolidCircle(center, radius, axis, color); + } + break; + case b2Shape.e_polygonShape: + { + var i = 0; + var poly = ((shape instanceof b2PolygonShape ? shape : null)); + var vertexCount = parseInt(poly.GetVertexCount()); + var localVertices = poly.GetVertices(); + var vertices = new Vector(vertexCount); + for (i = 0; + i < vertexCount; ++i) { + vertices[i] = b2Math.MulX(xf, localVertices[i]); + } + this.m_debugDraw.DrawSolidPolygon(vertices, vertexCount, color); + } + break; + case b2Shape.e_edgeShape: + { + var edge = (shape instanceof b2EdgeShape ? shape : null); + this.m_debugDraw.DrawSegment(b2Math.MulX(xf, edge.GetVertex1()), b2Math.MulX(xf, edge.GetVertex2()), color); + } + break; + } + } + Box2D.postDefs.push(function () { + Box2D.Dynamics.b2World.s_timestep2 = new b2TimeStep(); + Box2D.Dynamics.b2World.s_xf = new b2Transform(); + Box2D.Dynamics.b2World.s_backupA = new b2Sweep(); + Box2D.Dynamics.b2World.s_backupB = new b2Sweep(); + Box2D.Dynamics.b2World.s_timestep = new b2TimeStep(); + Box2D.Dynamics.b2World.s_queue = new Vector(); + Box2D.Dynamics.b2World.s_jointColor = new b2Color(0.5, 0.8, 0.8); + Box2D.Dynamics.b2World.e_newFixture = 0x0001; + Box2D.Dynamics.b2World.e_locked = 0x0002; + }); +})(); +(function () { + var b2CircleShape = Box2D.Collision.Shapes.b2CircleShape, + b2EdgeChainDef = Box2D.Collision.Shapes.b2EdgeChainDef, + b2EdgeShape = Box2D.Collision.Shapes.b2EdgeShape, + b2MassData = Box2D.Collision.Shapes.b2MassData, + b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape, + b2Shape = Box2D.Collision.Shapes.b2Shape, + b2CircleContact = Box2D.Dynamics.Contacts.b2CircleContact, + b2Contact = Box2D.Dynamics.Contacts.b2Contact, + b2ContactConstraint = Box2D.Dynamics.Contacts.b2ContactConstraint, + b2ContactConstraintPoint = Box2D.Dynamics.Contacts.b2ContactConstraintPoint, + b2ContactEdge = Box2D.Dynamics.Contacts.b2ContactEdge, + b2ContactFactory = Box2D.Dynamics.Contacts.b2ContactFactory, + b2ContactRegister = Box2D.Dynamics.Contacts.b2ContactRegister, + b2ContactResult = Box2D.Dynamics.Contacts.b2ContactResult, + b2ContactSolver = Box2D.Dynamics.Contacts.b2ContactSolver, + b2EdgeAndCircleContact = Box2D.Dynamics.Contacts.b2EdgeAndCircleContact, + b2NullContact = Box2D.Dynamics.Contacts.b2NullContact, + b2PolyAndCircleContact = Box2D.Dynamics.Contacts.b2PolyAndCircleContact, + b2PolyAndEdgeContact = Box2D.Dynamics.Contacts.b2PolyAndEdgeContact, + b2PolygonContact = Box2D.Dynamics.Contacts.b2PolygonContact, + b2PositionSolverManifold = Box2D.Dynamics.Contacts.b2PositionSolverManifold, + b2Body = Box2D.Dynamics.b2Body, + b2BodyDef = Box2D.Dynamics.b2BodyDef, + b2ContactFilter = Box2D.Dynamics.b2ContactFilter, + b2ContactImpulse = Box2D.Dynamics.b2ContactImpulse, + b2ContactListener = Box2D.Dynamics.b2ContactListener, + b2ContactManager = Box2D.Dynamics.b2ContactManager, + b2DebugDraw = Box2D.Dynamics.b2DebugDraw, + b2DestructionListener = Box2D.Dynamics.b2DestructionListener, + b2FilterData = Box2D.Dynamics.b2FilterData, + b2Fixture = Box2D.Dynamics.b2Fixture, + b2FixtureDef = Box2D.Dynamics.b2FixtureDef, + b2Island = Box2D.Dynamics.b2Island, + b2TimeStep = Box2D.Dynamics.b2TimeStep, + b2World = Box2D.Dynamics.b2World, + b2Color = Box2D.Common.b2Color, + b2internal = Box2D.Common.b2internal, + b2Settings = Box2D.Common.b2Settings, + b2Mat22 = Box2D.Common.Math.b2Mat22, + b2Mat33 = Box2D.Common.Math.b2Mat33, + b2Math = Box2D.Common.Math.b2Math, + b2Sweep = Box2D.Common.Math.b2Sweep, + b2Transform = Box2D.Common.Math.b2Transform, + b2Vec2 = Box2D.Common.Math.b2Vec2, + b2Vec3 = Box2D.Common.Math.b2Vec3, + b2AABB = Box2D.Collision.b2AABB, + b2Bound = Box2D.Collision.b2Bound, + b2BoundValues = Box2D.Collision.b2BoundValues, + b2Collision = Box2D.Collision.b2Collision, + b2ContactID = Box2D.Collision.b2ContactID, + b2ContactPoint = Box2D.Collision.b2ContactPoint, + b2Distance = Box2D.Collision.b2Distance, + b2DistanceInput = Box2D.Collision.b2DistanceInput, + b2DistanceOutput = Box2D.Collision.b2DistanceOutput, + b2DistanceProxy = Box2D.Collision.b2DistanceProxy, + b2DynamicTree = Box2D.Collision.b2DynamicTree, + b2DynamicTreeBroadPhase = Box2D.Collision.b2DynamicTreeBroadPhase, + b2DynamicTreeNode = Box2D.Collision.b2DynamicTreeNode, + b2DynamicTreePair = Box2D.Collision.b2DynamicTreePair, + b2Manifold = Box2D.Collision.b2Manifold, + b2ManifoldPoint = Box2D.Collision.b2ManifoldPoint, + b2Point = Box2D.Collision.b2Point, + b2RayCastInput = Box2D.Collision.b2RayCastInput, + b2RayCastOutput = Box2D.Collision.b2RayCastOutput, + b2Segment = Box2D.Collision.b2Segment, + b2SeparationFunction = Box2D.Collision.b2SeparationFunction, + b2Simplex = Box2D.Collision.b2Simplex, + b2SimplexCache = Box2D.Collision.b2SimplexCache, + b2SimplexVertex = Box2D.Collision.b2SimplexVertex, + b2TimeOfImpact = Box2D.Collision.b2TimeOfImpact, + b2TOIInput = Box2D.Collision.b2TOIInput, + b2WorldManifold = Box2D.Collision.b2WorldManifold, + ClipVertex = Box2D.Collision.ClipVertex, + Features = Box2D.Collision.Features, + IBroadPhase = Box2D.Collision.IBroadPhase; + + Box2D.inherit(b2CircleContact, Box2D.Dynamics.Contacts.b2Contact); + b2CircleContact.prototype.__super = Box2D.Dynamics.Contacts.b2Contact.prototype; + b2CircleContact.b2CircleContact = function () { + Box2D.Dynamics.Contacts.b2Contact.b2Contact.apply(this, arguments); + }; + b2CircleContact.Create = function (allocator) { + return new b2CircleContact(); + } + b2CircleContact.Destroy = function (contact, allocator) {} + b2CircleContact.prototype.Reset = function (fixtureA, fixtureB) { + this.__super.Reset.call(this, fixtureA, fixtureB); + } + b2CircleContact.prototype.Evaluate = function () { + var bA = this.m_fixtureA.GetBody(); + var bB = this.m_fixtureB.GetBody(); + b2Collision.CollideCircles(this.m_manifold, (this.m_fixtureA.GetShape() instanceof b2CircleShape ? this.m_fixtureA.GetShape() : null), bA.m_xf, (this.m_fixtureB.GetShape() instanceof b2CircleShape ? this.m_fixtureB.GetShape() : null), bB.m_xf); + } + b2Contact.b2Contact = function () { + this.m_nodeA = new b2ContactEdge(); + this.m_nodeB = new b2ContactEdge(); + this.m_manifold = new b2Manifold(); + this.m_oldManifold = new b2Manifold(); + }; + b2Contact.prototype.GetManifold = function () { + return this.m_manifold; + } + b2Contact.prototype.GetWorldManifold = function (worldManifold) { + var bodyA = this.m_fixtureA.GetBody(); + var bodyB = this.m_fixtureB.GetBody(); + var shapeA = this.m_fixtureA.GetShape(); + var shapeB = this.m_fixtureB.GetShape(); + worldManifold.Initialize(this.m_manifold, bodyA.GetTransform(), shapeA.m_radius, bodyB.GetTransform(), shapeB.m_radius); + } + b2Contact.prototype.IsTouching = function () { + return (this.m_flags & b2Contact.e_touchingFlag) == b2Contact.e_touchingFlag; + } + b2Contact.prototype.IsContinuous = function () { + return (this.m_flags & b2Contact.e_continuousFlag) == b2Contact.e_continuousFlag; + } + b2Contact.prototype.SetSensor = function (sensor) { + if (sensor) { + this.m_flags |= b2Contact.e_sensorFlag; + } + else { + this.m_flags &= ~b2Contact.e_sensorFlag; + } + } + b2Contact.prototype.IsSensor = function () { + return (this.m_flags & b2Contact.e_sensorFlag) == b2Contact.e_sensorFlag; + } + b2Contact.prototype.SetEnabled = function (flag) { + if (flag) { + this.m_flags |= b2Contact.e_enabledFlag; + } + else { + this.m_flags &= ~b2Contact.e_enabledFlag; + } + } + b2Contact.prototype.IsEnabled = function () { + return (this.m_flags & b2Contact.e_enabledFlag) == b2Contact.e_enabledFlag; + } + b2Contact.prototype.GetNext = function () { + return this.m_next; + } + b2Contact.prototype.GetFixtureA = function () { + return this.m_fixtureA; + } + b2Contact.prototype.GetFixtureB = function () { + return this.m_fixtureB; + } + b2Contact.prototype.FlagForFiltering = function () { + this.m_flags |= b2Contact.e_filterFlag; + } + b2Contact.prototype.b2Contact = function () {} + b2Contact.prototype.Reset = function (fixtureA, fixtureB) { + if (fixtureA === undefined) fixtureA = null; + if (fixtureB === undefined) fixtureB = null; + this.m_flags = b2Contact.e_enabledFlag; + if (!fixtureA || !fixtureB) { + this.m_fixtureA = null; + this.m_fixtureB = null; + return; + } + if (fixtureA.IsSensor() || fixtureB.IsSensor()) { + this.m_flags |= b2Contact.e_sensorFlag; + } + var bodyA = fixtureA.GetBody(); + var bodyB = fixtureB.GetBody(); + if (bodyA.GetType() != b2Body.b2_dynamicBody || bodyA.IsBullet() || bodyB.GetType() != b2Body.b2_dynamicBody || bodyB.IsBullet()) { + this.m_flags |= b2Contact.e_continuousFlag; + } + this.m_fixtureA = fixtureA; + this.m_fixtureB = fixtureB; + this.m_manifold.m_pointCount = 0; + this.m_prev = null; + this.m_next = null; + this.m_nodeA.contact = null; + this.m_nodeA.prev = null; + this.m_nodeA.next = null; + this.m_nodeA.other = null; + this.m_nodeB.contact = null; + this.m_nodeB.prev = null; + this.m_nodeB.next = null; + this.m_nodeB.other = null; + } + b2Contact.prototype.Update = function (listener) { + var tManifold = this.m_oldManifold; + this.m_oldManifold = this.m_manifold; + this.m_manifold = tManifold; + this.m_flags |= b2Contact.e_enabledFlag; + var touching = false; + var wasTouching = (this.m_flags & b2Contact.e_touchingFlag) == b2Contact.e_touchingFlag; + var bodyA = this.m_fixtureA.m_body; + var bodyB = this.m_fixtureB.m_body; + var aabbOverlap = this.m_fixtureA.m_aabb.TestOverlap(this.m_fixtureB.m_aabb); + if (this.m_flags & b2Contact.e_sensorFlag) { + if (aabbOverlap) { + var shapeA = this.m_fixtureA.GetShape(); + var shapeB = this.m_fixtureB.GetShape(); + var xfA = bodyA.GetTransform(); + var xfB = bodyB.GetTransform(); + touching = b2Shape.TestOverlap(shapeA, xfA, shapeB, xfB); + } + this.m_manifold.m_pointCount = 0; + } + else { + if (bodyA.GetType() != b2Body.b2_dynamicBody || bodyA.IsBullet() || bodyB.GetType() != b2Body.b2_dynamicBody || bodyB.IsBullet()) { + this.m_flags |= b2Contact.e_continuousFlag; + } + else { + this.m_flags &= ~b2Contact.e_continuousFlag; + } + if (aabbOverlap) { + this.Evaluate(); + touching = this.m_manifold.m_pointCount > 0; + for (var i = 0; i < this.m_manifold.m_pointCount; ++i) { + var mp2 = this.m_manifold.m_points[i]; + mp2.m_normalImpulse = 0.0; + mp2.m_tangentImpulse = 0.0; + var id2 = mp2.m_id; + for (var j = 0; j < this.m_oldManifold.m_pointCount; ++j) { + var mp1 = this.m_oldManifold.m_points[j]; + if (mp1.m_id.key == id2.key) { + mp2.m_normalImpulse = mp1.m_normalImpulse; + mp2.m_tangentImpulse = mp1.m_tangentImpulse; + break; + } + } + } + } + else { + this.m_manifold.m_pointCount = 0; + } + if (touching != wasTouching) { + bodyA.SetAwake(true); + bodyB.SetAwake(true); + } + } + if (touching) { + this.m_flags |= b2Contact.e_touchingFlag; + } + else { + this.m_flags &= ~b2Contact.e_touchingFlag; + } + if (wasTouching == false && touching == true) { + listener.BeginContact(this); + } + if (wasTouching == true && touching == false) { + listener.EndContact(this); + } + if ((this.m_flags & b2Contact.e_sensorFlag) == 0) { + listener.PreSolve(this, this.m_oldManifold); + } + } + b2Contact.prototype.Evaluate = function () {} + b2Contact.prototype.ComputeTOI = function (sweepA, sweepB) { + b2Contact.s_input.proxyA.Set(this.m_fixtureA.GetShape()); + b2Contact.s_input.proxyB.Set(this.m_fixtureB.GetShape()); + b2Contact.s_input.sweepA = sweepA; + b2Contact.s_input.sweepB = sweepB; + b2Contact.s_input.tolerance = b2Settings.b2_linearSlop; + return b2TimeOfImpact.TimeOfImpact(b2Contact.s_input); + } + Box2D.postDefs.push(function () { + Box2D.Dynamics.Contacts.b2Contact.e_sensorFlag = 0x0001; + Box2D.Dynamics.Contacts.b2Contact.e_continuousFlag = 0x0002; + Box2D.Dynamics.Contacts.b2Contact.e_islandFlag = 0x0004; + Box2D.Dynamics.Contacts.b2Contact.e_toiFlag = 0x0008; + Box2D.Dynamics.Contacts.b2Contact.e_touchingFlag = 0x0010; + Box2D.Dynamics.Contacts.b2Contact.e_enabledFlag = 0x0020; + Box2D.Dynamics.Contacts.b2Contact.e_filterFlag = 0x0040; + Box2D.Dynamics.Contacts.b2Contact.s_input = new b2TOIInput(); + }); + b2ContactConstraint.b2ContactConstraint = function () { + this.localPlaneNormal = new b2Vec2(); + this.localPoint = new b2Vec2(); + this.normal = new b2Vec2(); + this.normalMass = new b2Mat22(); + this.K = new b2Mat22(); + }; + b2ContactConstraint.prototype.b2ContactConstraint = function () { + this.points = new Vector(b2Settings.b2_maxManifoldPoints); + for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++) { + this.points[i] = new b2ContactConstraintPoint(); + } + } + b2ContactConstraintPoint.b2ContactConstraintPoint = function () { + this.localPoint = new b2Vec2(); + this.rA = new b2Vec2(); + this.rB = new b2Vec2(); + }; + b2ContactEdge.b2ContactEdge = function () {}; + b2ContactFactory.b2ContactFactory = function () {}; + b2ContactFactory.prototype.b2ContactFactory = function (allocator) { + this.m_allocator = allocator; + this.InitializeRegisters(); + } + b2ContactFactory.prototype.AddType = function (createFcn, destroyFcn, type1, type2) { + if (type1 === undefined) type1 = 0; + if (type2 === undefined) type2 = 0; + this.m_registers[type1][type2].createFcn = createFcn; + this.m_registers[type1][type2].destroyFcn = destroyFcn; + this.m_registers[type1][type2].primary = true; + if (type1 != type2) { + this.m_registers[type2][type1].createFcn = createFcn; + this.m_registers[type2][type1].destroyFcn = destroyFcn; + this.m_registers[type2][type1].primary = false; + } + } + b2ContactFactory.prototype.InitializeRegisters = function () { + this.m_registers = new Vector(b2Shape.e_shapeTypeCount); + for (var i = 0; i < b2Shape.e_shapeTypeCount; i++) { + this.m_registers[i] = new Vector(b2Shape.e_shapeTypeCount); + for (var j = 0; j < b2Shape.e_shapeTypeCount; j++) { + this.m_registers[i][j] = new b2ContactRegister(); + } + } + this.AddType(b2CircleContact.Create, b2CircleContact.Destroy, b2Shape.e_circleShape, b2Shape.e_circleShape); + this.AddType(b2PolyAndCircleContact.Create, b2PolyAndCircleContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_circleShape); + this.AddType(b2PolygonContact.Create, b2PolygonContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_polygonShape); + this.AddType(b2EdgeAndCircleContact.Create, b2EdgeAndCircleContact.Destroy, b2Shape.e_edgeShape, b2Shape.e_circleShape); + this.AddType(b2PolyAndEdgeContact.Create, b2PolyAndEdgeContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_edgeShape); + } + b2ContactFactory.prototype.Create = function (fixtureA, fixtureB) { + var type1 = parseInt(fixtureA.GetType()); + var type2 = parseInt(fixtureB.GetType()); + var reg = this.m_registers[type1][type2]; + var c; + if (reg.pool) { + c = reg.pool; + reg.pool = c.m_next; + reg.poolCount--; + c.Reset(fixtureA, fixtureB); + return c; + } + var createFcn = reg.createFcn; + if (createFcn != null) { + if (reg.primary) { + c = createFcn(this.m_allocator); + c.Reset(fixtureA, fixtureB); + return c; + } + else { + c = createFcn(this.m_allocator); + c.Reset(fixtureB, fixtureA); + return c; + } + } + else { + return null; + } + } + b2ContactFactory.prototype.Destroy = function (contact) { + if (contact.m_manifold.m_pointCount > 0) { + contact.m_fixtureA.m_body.SetAwake(true); + contact.m_fixtureB.m_body.SetAwake(true); + } + var type1 = parseInt(contact.m_fixtureA.GetType()); + var type2 = parseInt(contact.m_fixtureB.GetType()); + var reg = this.m_registers[type1][type2]; + if (true) { + reg.poolCount++; + contact.m_next = reg.pool; + reg.pool = contact; + } + var destroyFcn = reg.destroyFcn; + destroyFcn(contact, this.m_allocator); + } + b2ContactRegister.b2ContactRegister = function () {}; + b2ContactResult.b2ContactResult = function () { + this.position = new b2Vec2(); + this.normal = new b2Vec2(); + this.id = new b2ContactID(); + }; + b2ContactSolver.b2ContactSolver = function () { + this.m_step = new b2TimeStep(); + this.m_constraints = new Vector(); + }; + b2ContactSolver.prototype.b2ContactSolver = function () {} + b2ContactSolver.prototype.Initialize = function (step, contacts, contactCount, allocator) { + if (contactCount === undefined) contactCount = 0; + var contact; + this.m_step.Set(step); + this.m_allocator = allocator; + var i = 0; + var tVec; + var tMat; + this.m_constraintCount = contactCount; + while (this.m_constraints.length < this.m_constraintCount) { + this.m_constraints[this.m_constraints.length] = new b2ContactConstraint(); + } + for (i = 0; + i < contactCount; ++i) { + contact = contacts[i]; + var fixtureA = contact.m_fixtureA; + var fixtureB = contact.m_fixtureB; + var shapeA = fixtureA.m_shape; + var shapeB = fixtureB.m_shape; + var radiusA = shapeA.m_radius; + var radiusB = shapeB.m_radius; + var bodyA = fixtureA.m_body; + var bodyB = fixtureB.m_body; + var manifold = contact.GetManifold(); + var friction = b2Settings.b2MixFriction(fixtureA.GetFriction(), fixtureB.GetFriction()); + var restitution = b2Settings.b2MixRestitution(fixtureA.GetRestitution(), fixtureB.GetRestitution()); + var vAX = bodyA.m_linearVelocity.x; + var vAY = bodyA.m_linearVelocity.y; + var vBX = bodyB.m_linearVelocity.x; + var vBY = bodyB.m_linearVelocity.y; + var wA = bodyA.m_angularVelocity; + var wB = bodyB.m_angularVelocity; + b2Settings.b2Assert(manifold.m_pointCount > 0); + b2ContactSolver.s_worldManifold.Initialize(manifold, bodyA.m_xf, radiusA, bodyB.m_xf, radiusB); + var normalX = b2ContactSolver.s_worldManifold.m_normal.x; + var normalY = b2ContactSolver.s_worldManifold.m_normal.y; + var cc = this.m_constraints[i]; + cc.bodyA = bodyA; + cc.bodyB = bodyB; + cc.manifold = manifold; + cc.normal.x = normalX; + cc.normal.y = normalY; + cc.pointCount = manifold.m_pointCount; + cc.friction = friction; + cc.restitution = restitution; + cc.localPlaneNormal.x = manifold.m_localPlaneNormal.x; + cc.localPlaneNormal.y = manifold.m_localPlaneNormal.y; + cc.localPoint.x = manifold.m_localPoint.x; + cc.localPoint.y = manifold.m_localPoint.y; + cc.radius = radiusA + radiusB; + cc.type = manifold.m_type; + for (var k = 0; k < cc.pointCount; ++k) { + var cp = manifold.m_points[k]; + var ccp = cc.points[k]; + ccp.normalImpulse = cp.m_normalImpulse; + ccp.tangentImpulse = cp.m_tangentImpulse; + ccp.localPoint.SetV(cp.m_localPoint); + var rAX = ccp.rA.x = b2ContactSolver.s_worldManifold.m_points[k].x - bodyA.m_sweep.c.x; + var rAY = ccp.rA.y = b2ContactSolver.s_worldManifold.m_points[k].y - bodyA.m_sweep.c.y; + var rBX = ccp.rB.x = b2ContactSolver.s_worldManifold.m_points[k].x - bodyB.m_sweep.c.x; + var rBY = ccp.rB.y = b2ContactSolver.s_worldManifold.m_points[k].y - bodyB.m_sweep.c.y; + var rnA = rAX * normalY - rAY * normalX; + var rnB = rBX * normalY - rBY * normalX; + rnA *= rnA; + rnB *= rnB; + var kNormal = bodyA.m_invMass + bodyB.m_invMass + bodyA.m_invI * rnA + bodyB.m_invI * rnB; + ccp.normalMass = 1.0 / kNormal; + var kEqualized = bodyA.m_mass * bodyA.m_invMass + bodyB.m_mass * bodyB.m_invMass; + kEqualized += bodyA.m_mass * bodyA.m_invI * rnA + bodyB.m_mass * bodyB.m_invI * rnB; + ccp.equalizedMass = 1.0 / kEqualized; + var tangentX = normalY; + var tangentY = (-normalX); + var rtA = rAX * tangentY - rAY * tangentX; + var rtB = rBX * tangentY - rBY * tangentX; + rtA *= rtA; + rtB *= rtB; + var kTangent = bodyA.m_invMass + bodyB.m_invMass + bodyA.m_invI * rtA + bodyB.m_invI * rtB; + ccp.tangentMass = 1.0 / kTangent; + ccp.velocityBias = 0.0; + var tX = vBX + ((-wB * rBY)) - vAX - ((-wA * rAY)); + var tY = vBY + (wB * rBX) - vAY - (wA * rAX); + var vRel = cc.normal.x * tX + cc.normal.y * tY; + if (vRel < (-b2Settings.b2_velocityThreshold)) { + ccp.velocityBias += (-cc.restitution * vRel); + } + } + if (cc.pointCount == 2) { + var ccp1 = cc.points[0]; + var ccp2 = cc.points[1]; + var invMassA = bodyA.m_invMass; + var invIA = bodyA.m_invI; + var invMassB = bodyB.m_invMass; + var invIB = bodyB.m_invI; + var rn1A = ccp1.rA.x * normalY - ccp1.rA.y * normalX; + var rn1B = ccp1.rB.x * normalY - ccp1.rB.y * normalX; + var rn2A = ccp2.rA.x * normalY - ccp2.rA.y * normalX; + var rn2B = ccp2.rB.x * normalY - ccp2.rB.y * normalX; + var k11 = invMassA + invMassB + invIA * rn1A * rn1A + invIB * rn1B * rn1B; + var k22 = invMassA + invMassB + invIA * rn2A * rn2A + invIB * rn2B * rn2B; + var k12 = invMassA + invMassB + invIA * rn1A * rn2A + invIB * rn1B * rn2B; + var k_maxConditionNumber = 100.0; + if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12)) { + cc.K.col1.Set(k11, k12); + cc.K.col2.Set(k12, k22); + cc.K.GetInverse(cc.normalMass); + } + else { + cc.pointCount = 1; + } + } + } + } + b2ContactSolver.prototype.InitVelocityConstraints = function (step) { + var tVec; + var tVec2; + var tMat; + for (var i = 0; i < this.m_constraintCount; ++i) { + var c = this.m_constraints[i]; + var bodyA = c.bodyA; + var bodyB = c.bodyB; + var invMassA = bodyA.m_invMass; + var invIA = bodyA.m_invI; + var invMassB = bodyB.m_invMass; + var invIB = bodyB.m_invI; + var normalX = c.normal.x; + var normalY = c.normal.y; + var tangentX = normalY; + var tangentY = (-normalX); + var tX = 0; + var j = 0; + var tCount = 0; + if (step.warmStarting) { + tCount = c.pointCount; + for (j = 0; + j < tCount; ++j) { + var ccp = c.points[j]; + ccp.normalImpulse *= step.dtRatio; + ccp.tangentImpulse *= step.dtRatio; + var PX = ccp.normalImpulse * normalX + ccp.tangentImpulse * tangentX; + var PY = ccp.normalImpulse * normalY + ccp.tangentImpulse * tangentY; + bodyA.m_angularVelocity -= invIA * (ccp.rA.x * PY - ccp.rA.y * PX); + bodyA.m_linearVelocity.x -= invMassA * PX; + bodyA.m_linearVelocity.y -= invMassA * PY; + bodyB.m_angularVelocity += invIB * (ccp.rB.x * PY - ccp.rB.y * PX); + bodyB.m_linearVelocity.x += invMassB * PX; + bodyB.m_linearVelocity.y += invMassB * PY; + } + } + else { + tCount = c.pointCount; + for (j = 0; + j < tCount; ++j) { + var ccp2 = c.points[j]; + ccp2.normalImpulse = 0.0; + ccp2.tangentImpulse = 0.0; + } + } + } + } + b2ContactSolver.prototype.SolveVelocityConstraints = function () { + var j = 0; + var ccp; + var rAX = 0; + var rAY = 0; + var rBX = 0; + var rBY = 0; + var dvX = 0; + var dvY = 0; + var vn = 0; + var vt = 0; + var lambda = 0; + var maxFriction = 0; + var newImpulse = 0; + var PX = 0; + var PY = 0; + var dX = 0; + var dY = 0; + var P1X = 0; + var P1Y = 0; + var P2X = 0; + var P2Y = 0; + var tMat; + var tVec; + for (var i = 0; i < this.m_constraintCount; ++i) { + var c = this.m_constraints[i]; + var bodyA = c.bodyA; + var bodyB = c.bodyB; + var wA = bodyA.m_angularVelocity; + var wB = bodyB.m_angularVelocity; + var vA = bodyA.m_linearVelocity; + var vB = bodyB.m_linearVelocity; + var invMassA = bodyA.m_invMass; + var invIA = bodyA.m_invI; + var invMassB = bodyB.m_invMass; + var invIB = bodyB.m_invI; + var normalX = c.normal.x; + var normalY = c.normal.y; + var tangentX = normalY; + var tangentY = (-normalX); + var friction = c.friction; + var tX = 0; + for (j = 0; + j < c.pointCount; j++) { + ccp = c.points[j]; + dvX = vB.x - wB * ccp.rB.y - vA.x + wA * ccp.rA.y; + dvY = vB.y + wB * ccp.rB.x - vA.y - wA * ccp.rA.x; + vt = dvX * tangentX + dvY * tangentY; + lambda = ccp.tangentMass * (-vt); + maxFriction = friction * ccp.normalImpulse; + newImpulse = b2Math.Clamp(ccp.tangentImpulse + lambda, (-maxFriction), maxFriction); + lambda = newImpulse - ccp.tangentImpulse; + PX = lambda * tangentX; + PY = lambda * tangentY; + vA.x -= invMassA * PX; + vA.y -= invMassA * PY; + wA -= invIA * (ccp.rA.x * PY - ccp.rA.y * PX); + vB.x += invMassB * PX; + vB.y += invMassB * PY; + wB += invIB * (ccp.rB.x * PY - ccp.rB.y * PX); + ccp.tangentImpulse = newImpulse; + } + var tCount = parseInt(c.pointCount); + if (c.pointCount == 1) { + ccp = c.points[0]; + dvX = vB.x + ((-wB * ccp.rB.y)) - vA.x - ((-wA * ccp.rA.y)); + dvY = vB.y + (wB * ccp.rB.x) - vA.y - (wA * ccp.rA.x); + vn = dvX * normalX + dvY * normalY; + lambda = (-ccp.normalMass * (vn - ccp.velocityBias)); + newImpulse = ccp.normalImpulse + lambda; + newImpulse = newImpulse > 0 ? newImpulse : 0.0; + lambda = newImpulse - ccp.normalImpulse; + PX = lambda * normalX; + PY = lambda * normalY; + vA.x -= invMassA * PX; + vA.y -= invMassA * PY; + wA -= invIA * (ccp.rA.x * PY - ccp.rA.y * PX); + vB.x += invMassB * PX; + vB.y += invMassB * PY; + wB += invIB * (ccp.rB.x * PY - ccp.rB.y * PX); + ccp.normalImpulse = newImpulse; + } + else { + var cp1 = c.points[0]; + var cp2 = c.points[1]; + var aX = cp1.normalImpulse; + var aY = cp2.normalImpulse; + var dv1X = vB.x - wB * cp1.rB.y - vA.x + wA * cp1.rA.y; + var dv1Y = vB.y + wB * cp1.rB.x - vA.y - wA * cp1.rA.x; + var dv2X = vB.x - wB * cp2.rB.y - vA.x + wA * cp2.rA.y; + var dv2Y = vB.y + wB * cp2.rB.x - vA.y - wA * cp2.rA.x; + var vn1 = dv1X * normalX + dv1Y * normalY; + var vn2 = dv2X * normalX + dv2Y * normalY; + var bX = vn1 - cp1.velocityBias; + var bY = vn2 - cp2.velocityBias; + tMat = c.K; + bX -= tMat.col1.x * aX + tMat.col2.x * aY; + bY -= tMat.col1.y * aX + tMat.col2.y * aY; + var k_errorTol = 0.001; + for (;;) { + tMat = c.normalMass; + var xX = (-(tMat.col1.x * bX + tMat.col2.x * bY)); + var xY = (-(tMat.col1.y * bX + tMat.col2.y * bY)); + if (xX >= 0.0 && xY >= 0.0) { + dX = xX - aX; + dY = xY - aY; + P1X = dX * normalX; + P1Y = dX * normalY; + P2X = dY * normalX; + P2Y = dY * normalY; + vA.x -= invMassA * (P1X + P2X); + vA.y -= invMassA * (P1Y + P2Y); + wA -= invIA * (cp1.rA.x * P1Y - cp1.rA.y * P1X + cp2.rA.x * P2Y - cp2.rA.y * P2X); + vB.x += invMassB * (P1X + P2X); + vB.y += invMassB * (P1Y + P2Y); + wB += invIB * (cp1.rB.x * P1Y - cp1.rB.y * P1X + cp2.rB.x * P2Y - cp2.rB.y * P2X); + cp1.normalImpulse = xX; + cp2.normalImpulse = xY; + break; + } + xX = (-cp1.normalMass * bX); + xY = 0.0; + vn1 = 0.0; + vn2 = c.K.col1.y * xX + bY; + if (xX >= 0.0 && vn2 >= 0.0) { + dX = xX - aX; + dY = xY - aY; + P1X = dX * normalX; + P1Y = dX * normalY; + P2X = dY * normalX; + P2Y = dY * normalY; + vA.x -= invMassA * (P1X + P2X); + vA.y -= invMassA * (P1Y + P2Y); + wA -= invIA * (cp1.rA.x * P1Y - cp1.rA.y * P1X + cp2.rA.x * P2Y - cp2.rA.y * P2X); + vB.x += invMassB * (P1X + P2X); + vB.y += invMassB * (P1Y + P2Y); + wB += invIB * (cp1.rB.x * P1Y - cp1.rB.y * P1X + cp2.rB.x * P2Y - cp2.rB.y * P2X); + cp1.normalImpulse = xX; + cp2.normalImpulse = xY; + break; + } + xX = 0.0; + xY = (-cp2.normalMass * bY); + vn1 = c.K.col2.x * xY + bX; + vn2 = 0.0; + if (xY >= 0.0 && vn1 >= 0.0) { + dX = xX - aX; + dY = xY - aY; + P1X = dX * normalX; + P1Y = dX * normalY; + P2X = dY * normalX; + P2Y = dY * normalY; + vA.x -= invMassA * (P1X + P2X); + vA.y -= invMassA * (P1Y + P2Y); + wA -= invIA * (cp1.rA.x * P1Y - cp1.rA.y * P1X + cp2.rA.x * P2Y - cp2.rA.y * P2X); + vB.x += invMassB * (P1X + P2X); + vB.y += invMassB * (P1Y + P2Y); + wB += invIB * (cp1.rB.x * P1Y - cp1.rB.y * P1X + cp2.rB.x * P2Y - cp2.rB.y * P2X); + cp1.normalImpulse = xX; + cp2.normalImpulse = xY; + break; + } + xX = 0.0; + xY = 0.0; + vn1 = bX; + vn2 = bY; + if (vn1 >= 0.0 && vn2 >= 0.0) { + dX = xX - aX; + dY = xY - aY; + P1X = dX * normalX; + P1Y = dX * normalY; + P2X = dY * normalX; + P2Y = dY * normalY; + vA.x -= invMassA * (P1X + P2X); + vA.y -= invMassA * (P1Y + P2Y); + wA -= invIA * (cp1.rA.x * P1Y - cp1.rA.y * P1X + cp2.rA.x * P2Y - cp2.rA.y * P2X); + vB.x += invMassB * (P1X + P2X); + vB.y += invMassB * (P1Y + P2Y); + wB += invIB * (cp1.rB.x * P1Y - cp1.rB.y * P1X + cp2.rB.x * P2Y - cp2.rB.y * P2X); + cp1.normalImpulse = xX; + cp2.normalImpulse = xY; + break; + } + break; + } + } + bodyA.m_angularVelocity = wA; + bodyB.m_angularVelocity = wB; + } + } + b2ContactSolver.prototype.FinalizeVelocityConstraints = function () { + for (var i = 0; i < this.m_constraintCount; ++i) { + var c = this.m_constraints[i]; + var m = c.manifold; + for (var j = 0; j < c.pointCount; ++j) { + var point1 = m.m_points[j]; + var point2 = c.points[j]; + point1.m_normalImpulse = point2.normalImpulse; + point1.m_tangentImpulse = point2.tangentImpulse; + } + } + } + b2ContactSolver.prototype.SolvePositionConstraints = function (baumgarte) { + if (baumgarte === undefined) baumgarte = 0; + var minSeparation = 0.0; + for (var i = 0; i < this.m_constraintCount; i++) { + var c = this.m_constraints[i]; + var bodyA = c.bodyA; + var bodyB = c.bodyB; + var invMassA = bodyA.m_mass * bodyA.m_invMass; + var invIA = bodyA.m_mass * bodyA.m_invI; + var invMassB = bodyB.m_mass * bodyB.m_invMass; + var invIB = bodyB.m_mass * bodyB.m_invI; + b2ContactSolver.s_psm.Initialize(c); + var normal = b2ContactSolver.s_psm.m_normal; + for (var j = 0; j < c.pointCount; j++) { + var ccp = c.points[j]; + var point = b2ContactSolver.s_psm.m_points[j]; + var separation = b2ContactSolver.s_psm.m_separations[j]; + var rAX = point.x - bodyA.m_sweep.c.x; + var rAY = point.y - bodyA.m_sweep.c.y; + var rBX = point.x - bodyB.m_sweep.c.x; + var rBY = point.y - bodyB.m_sweep.c.y; + minSeparation = minSeparation < separation ? minSeparation : separation; + var C = b2Math.Clamp(baumgarte * (separation + b2Settings.b2_linearSlop), (-b2Settings.b2_maxLinearCorrection), 0.0); + var impulse = (-ccp.equalizedMass * C); + var PX = impulse * normal.x; + var PY = impulse * normal.y;bodyA.m_sweep.c.x -= invMassA * PX; + bodyA.m_sweep.c.y -= invMassA * PY; + bodyA.m_sweep.a -= invIA * (rAX * PY - rAY * PX); + bodyA.SynchronizeTransform(); + bodyB.m_sweep.c.x += invMassB * PX; + bodyB.m_sweep.c.y += invMassB * PY; + bodyB.m_sweep.a += invIB * (rBX * PY - rBY * PX); + bodyB.SynchronizeTransform(); + } + } + return minSeparation > (-1.5 * b2Settings.b2_linearSlop); + } + Box2D.postDefs.push(function () { + Box2D.Dynamics.Contacts.b2ContactSolver.s_worldManifold = new b2WorldManifold(); + Box2D.Dynamics.Contacts.b2ContactSolver.s_psm = new b2PositionSolverManifold(); + }); + Box2D.inherit(b2EdgeAndCircleContact, Box2D.Dynamics.Contacts.b2Contact); + b2EdgeAndCircleContact.prototype.__super = Box2D.Dynamics.Contacts.b2Contact.prototype; + b2EdgeAndCircleContact.b2EdgeAndCircleContact = function () { + Box2D.Dynamics.Contacts.b2Contact.b2Contact.apply(this, arguments); + }; + b2EdgeAndCircleContact.Create = function (allocator) { + return new b2EdgeAndCircleContact(); + } + b2EdgeAndCircleContact.Destroy = function (contact, allocator) {} + b2EdgeAndCircleContact.prototype.Reset = function (fixtureA, fixtureB) { + this.__super.Reset.call(this, fixtureA, fixtureB); + } + b2EdgeAndCircleContact.prototype.Evaluate = function () { + var bA = this.m_fixtureA.GetBody(); + var bB = this.m_fixtureB.GetBody(); + this.b2CollideEdgeAndCircle(this.m_manifold, (this.m_fixtureA.GetShape() instanceof b2EdgeShape ? this.m_fixtureA.GetShape() : null), bA.m_xf, (this.m_fixtureB.GetShape() instanceof b2CircleShape ? this.m_fixtureB.GetShape() : null), bB.m_xf); + } + b2EdgeAndCircleContact.prototype.b2CollideEdgeAndCircle = function (manifold, edge, xf1, circle, xf2) {} + Box2D.inherit(b2NullContact, Box2D.Dynamics.Contacts.b2Contact); + b2NullContact.prototype.__super = Box2D.Dynamics.Contacts.b2Contact.prototype; + b2NullContact.b2NullContact = function () { + Box2D.Dynamics.Contacts.b2Contact.b2Contact.apply(this, arguments); + }; + b2NullContact.prototype.b2NullContact = function () { + this.__super.b2Contact.call(this); + } + b2NullContact.prototype.Evaluate = function () {} + Box2D.inherit(b2PolyAndCircleContact, Box2D.Dynamics.Contacts.b2Contact); + b2PolyAndCircleContact.prototype.__super = Box2D.Dynamics.Contacts.b2Contact.prototype; + b2PolyAndCircleContact.b2PolyAndCircleContact = function () { + Box2D.Dynamics.Contacts.b2Contact.b2Contact.apply(this, arguments); + }; + b2PolyAndCircleContact.Create = function (allocator) { + return new b2PolyAndCircleContact(); + } + b2PolyAndCircleContact.Destroy = function (contact, allocator) {} + b2PolyAndCircleContact.prototype.Reset = function (fixtureA, fixtureB) { + this.__super.Reset.call(this, fixtureA, fixtureB); + b2Settings.b2Assert(fixtureA.GetType() == b2Shape.e_polygonShape); + b2Settings.b2Assert(fixtureB.GetType() == b2Shape.e_circleShape); + } + b2PolyAndCircleContact.prototype.Evaluate = function () { + var bA = this.m_fixtureA.m_body; + var bB = this.m_fixtureB.m_body; + b2Collision.CollidePolygonAndCircle(this.m_manifold, (this.m_fixtureA.GetShape() instanceof b2PolygonShape ? this.m_fixtureA.GetShape() : null), bA.m_xf, (this.m_fixtureB.GetShape() instanceof b2CircleShape ? this.m_fixtureB.GetShape() : null), bB.m_xf); + } + Box2D.inherit(b2PolyAndEdgeContact, Box2D.Dynamics.Contacts.b2Contact); + b2PolyAndEdgeContact.prototype.__super = Box2D.Dynamics.Contacts.b2Contact.prototype; + b2PolyAndEdgeContact.b2PolyAndEdgeContact = function () { + Box2D.Dynamics.Contacts.b2Contact.b2Contact.apply(this, arguments); + }; + b2PolyAndEdgeContact.Create = function (allocator) { + return new b2PolyAndEdgeContact(); + } + b2PolyAndEdgeContact.Destroy = function (contact, allocator) {} + b2PolyAndEdgeContact.prototype.Reset = function (fixtureA, fixtureB) { + this.__super.Reset.call(this, fixtureA, fixtureB); + b2Settings.b2Assert(fixtureA.GetType() == b2Shape.e_polygonShape); + b2Settings.b2Assert(fixtureB.GetType() == b2Shape.e_edgeShape); + } + b2PolyAndEdgeContact.prototype.Evaluate = function () { + var bA = this.m_fixtureA.GetBody(); + var bB = this.m_fixtureB.GetBody(); + this.b2CollidePolyAndEdge(this.m_manifold, (this.m_fixtureA.GetShape() instanceof b2PolygonShape ? this.m_fixtureA.GetShape() : null), bA.m_xf, (this.m_fixtureB.GetShape() instanceof b2EdgeShape ? this.m_fixtureB.GetShape() : null), bB.m_xf); + } + b2PolyAndEdgeContact.prototype.b2CollidePolyAndEdge = function (manifold, polygon, xf1, edge, xf2) {} + Box2D.inherit(b2PolygonContact, Box2D.Dynamics.Contacts.b2Contact); + b2PolygonContact.prototype.__super = Box2D.Dynamics.Contacts.b2Contact.prototype; + b2PolygonContact.b2PolygonContact = function () { + Box2D.Dynamics.Contacts.b2Contact.b2Contact.apply(this, arguments); + }; + b2PolygonContact.Create = function (allocator) { + return new b2PolygonContact(); + } + b2PolygonContact.Destroy = function (contact, allocator) {} + b2PolygonContact.prototype.Reset = function (fixtureA, fixtureB) { + this.__super.Reset.call(this, fixtureA, fixtureB); + } + b2PolygonContact.prototype.Evaluate = function () { + var bA = this.m_fixtureA.GetBody(); + var bB = this.m_fixtureB.GetBody(); + b2Collision.CollidePolygons(this.m_manifold, (this.m_fixtureA.GetShape() instanceof b2PolygonShape ? this.m_fixtureA.GetShape() : null), bA.m_xf, (this.m_fixtureB.GetShape() instanceof b2PolygonShape ? this.m_fixtureB.GetShape() : null), bB.m_xf); + } + b2PositionSolverManifold.b2PositionSolverManifold = function () {}; + b2PositionSolverManifold.prototype.b2PositionSolverManifold = function () { + this.m_normal = new b2Vec2(); + this.m_separations = new Vector_a2j_Number(b2Settings.b2_maxManifoldPoints); + this.m_points = new Vector(b2Settings.b2_maxManifoldPoints); + for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++) { + this.m_points[i] = new b2Vec2(); + } + } + b2PositionSolverManifold.prototype.Initialize = function (cc) { + b2Settings.b2Assert(cc.pointCount > 0); + var i = 0; + var clipPointX = 0; + var clipPointY = 0; + var tMat; + var tVec; + var planePointX = 0; + var planePointY = 0; + switch (cc.type) { + case b2Manifold.e_circles: + { + tMat = cc.bodyA.m_xf.R; + tVec = cc.localPoint; + var pointAX = cc.bodyA.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var pointAY = cc.bodyA.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = cc.bodyB.m_xf.R; + tVec = cc.points[0].localPoint; + var pointBX = cc.bodyB.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var pointBY = cc.bodyB.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + var dX = pointBX - pointAX; + var dY = pointBY - pointAY; + var d2 = dX * dX + dY * dY; + if (d2 > Number.MIN_VALUE * Number.MIN_VALUE) { + var d = Math.sqrt(d2); + this.m_normal.x = dX / d; + this.m_normal.y = dY / d; + } + else { + this.m_normal.x = 1.0; + this.m_normal.y = 0.0; + } + this.m_points[0].x = 0.5 * (pointAX + pointBX); + this.m_points[0].y = 0.5 * (pointAY + pointBY); + this.m_separations[0] = dX * this.m_normal.x + dY * this.m_normal.y - cc.radius; + } + break; + case b2Manifold.e_faceA: + { + tMat = cc.bodyA.m_xf.R; + tVec = cc.localPlaneNormal; + this.m_normal.x = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + this.m_normal.y = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = cc.bodyA.m_xf.R; + tVec = cc.localPoint; + planePointX = cc.bodyA.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + planePointY = cc.bodyA.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = cc.bodyB.m_xf.R; + for (i = 0; + i < cc.pointCount; ++i) { + tVec = cc.points[i].localPoint; + clipPointX = cc.bodyB.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + clipPointY = cc.bodyB.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + this.m_separations[i] = (clipPointX - planePointX) * this.m_normal.x + (clipPointY - planePointY) * this.m_normal.y - cc.radius; + this.m_points[i].x = clipPointX; + this.m_points[i].y = clipPointY; + } + } + break; + case b2Manifold.e_faceB: + { + tMat = cc.bodyB.m_xf.R; + tVec = cc.localPlaneNormal; + this.m_normal.x = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + this.m_normal.y = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = cc.bodyB.m_xf.R; + tVec = cc.localPoint; + planePointX = cc.bodyB.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + planePointY = cc.bodyB.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = cc.bodyA.m_xf.R; + for (i = 0; + i < cc.pointCount; ++i) { + tVec = cc.points[i].localPoint; + clipPointX = cc.bodyA.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + clipPointY = cc.bodyA.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + this.m_separations[i] = (clipPointX - planePointX) * this.m_normal.x + (clipPointY - planePointY) * this.m_normal.y - cc.radius; + this.m_points[i].Set(clipPointX, clipPointY); + } + this.m_normal.x *= (-1); + this.m_normal.y *= (-1); + } + break; + } + } + Box2D.postDefs.push(function () { + Box2D.Dynamics.Contacts.b2PositionSolverManifold.circlePointA = new b2Vec2(); + Box2D.Dynamics.Contacts.b2PositionSolverManifold.circlePointB = new b2Vec2(); + }); +})(); +(function () { + var b2Body = Box2D.Dynamics.b2Body, + b2BodyDef = Box2D.Dynamics.b2BodyDef, + b2ContactFilter = Box2D.Dynamics.b2ContactFilter, + b2ContactImpulse = Box2D.Dynamics.b2ContactImpulse, + b2ContactListener = Box2D.Dynamics.b2ContactListener, + b2ContactManager = Box2D.Dynamics.b2ContactManager, + b2DebugDraw = Box2D.Dynamics.b2DebugDraw, + b2DestructionListener = Box2D.Dynamics.b2DestructionListener, + b2FilterData = Box2D.Dynamics.b2FilterData, + b2Fixture = Box2D.Dynamics.b2Fixture, + b2FixtureDef = Box2D.Dynamics.b2FixtureDef, + b2Island = Box2D.Dynamics.b2Island, + b2TimeStep = Box2D.Dynamics.b2TimeStep, + b2World = Box2D.Dynamics.b2World, + b2Mat22 = Box2D.Common.Math.b2Mat22, + b2Mat33 = Box2D.Common.Math.b2Mat33, + b2Math = Box2D.Common.Math.b2Math, + b2Sweep = Box2D.Common.Math.b2Sweep, + b2Transform = Box2D.Common.Math.b2Transform, + b2Vec2 = Box2D.Common.Math.b2Vec2, + b2Vec3 = Box2D.Common.Math.b2Vec3, + b2Color = Box2D.Common.b2Color, + b2internal = Box2D.Common.b2internal, + b2Settings = Box2D.Common.b2Settings, + b2CircleShape = Box2D.Collision.Shapes.b2CircleShape, + b2EdgeChainDef = Box2D.Collision.Shapes.b2EdgeChainDef, + b2EdgeShape = Box2D.Collision.Shapes.b2EdgeShape, + b2MassData = Box2D.Collision.Shapes.b2MassData, + b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape, + b2Shape = Box2D.Collision.Shapes.b2Shape, + b2BuoyancyController = Box2D.Dynamics.Controllers.b2BuoyancyController, + b2ConstantAccelController = Box2D.Dynamics.Controllers.b2ConstantAccelController, + b2ConstantForceController = Box2D.Dynamics.Controllers.b2ConstantForceController, + b2Controller = Box2D.Dynamics.Controllers.b2Controller, + b2ControllerEdge = Box2D.Dynamics.Controllers.b2ControllerEdge, + b2GravityController = Box2D.Dynamics.Controllers.b2GravityController, + b2TensorDampingController = Box2D.Dynamics.Controllers.b2TensorDampingController; + + Box2D.inherit(b2BuoyancyController, Box2D.Dynamics.Controllers.b2Controller); + b2BuoyancyController.prototype.__super = Box2D.Dynamics.Controllers.b2Controller.prototype; + b2BuoyancyController.b2BuoyancyController = function () { + Box2D.Dynamics.Controllers.b2Controller.b2Controller.apply(this, arguments); + this.normal = new b2Vec2(0, (-1)); + this.offset = 0; + this.density = 0; + this.velocity = new b2Vec2(0, 0); + this.linearDrag = 2; + this.angularDrag = 1; + this.useDensity = false; + this.useWorldGravity = true; + this.gravity = null; + }; + b2BuoyancyController.prototype.Step = function (step) { + if (!this.m_bodyList) return; + if (this.useWorldGravity) { + this.gravity = this.GetWorld().GetGravity().Copy(); + } + for (var i = this.m_bodyList; i; i = i.nextBody) { + var body = i.body; + if (body.IsAwake() == false) { + continue; + } + var areac = new b2Vec2(); + var massc = new b2Vec2(); + var area = 0.0; + var mass = 0.0; + for (var fixture = body.GetFixtureList(); fixture; fixture = fixture.GetNext()) { + var sc = new b2Vec2(); + var sarea = fixture.GetShape().ComputeSubmergedArea(this.normal, this.offset, body.GetTransform(), sc); + area += sarea; + areac.x += sarea * sc.x; + areac.y += sarea * sc.y; + var shapeDensity = 0; + if (this.useDensity) { + shapeDensity = 1; + } + else { + shapeDensity = 1; + } + mass += sarea * shapeDensity; + massc.x += sarea * sc.x * shapeDensity; + massc.y += sarea * sc.y * shapeDensity; + } + areac.x /= area; + areac.y /= area; + massc.x /= mass; + massc.y /= mass; + if (area < Number.MIN_VALUE) continue; + var buoyancyForce = this.gravity.GetNegative(); + buoyancyForce.Multiply(this.density * area); + body.ApplyForce(buoyancyForce, massc); + var dragForce = body.GetLinearVelocityFromWorldPoint(areac); + dragForce.Subtract(this.velocity); + dragForce.Multiply((-this.linearDrag * area)); + body.ApplyForce(dragForce, areac); + body.ApplyTorque((-body.GetInertia() / body.GetMass() * area * body.GetAngularVelocity() * this.angularDrag)); + } + } + b2BuoyancyController.prototype.Draw = function (debugDraw) { + var r = 1000; + var p1 = new b2Vec2(); + var p2 = new b2Vec2(); + p1.x = this.normal.x * this.offset + this.normal.y * r; + p1.y = this.normal.y * this.offset - this.normal.x * r; + p2.x = this.normal.x * this.offset - this.normal.y * r; + p2.y = this.normal.y * this.offset + this.normal.x * r; + var color = new b2Color(0, 0, 1); + debugDraw.DrawSegment(p1, p2, color); + } + Box2D.inherit(b2ConstantAccelController, Box2D.Dynamics.Controllers.b2Controller); + b2ConstantAccelController.prototype.__super = Box2D.Dynamics.Controllers.b2Controller.prototype; + b2ConstantAccelController.b2ConstantAccelController = function () { + Box2D.Dynamics.Controllers.b2Controller.b2Controller.apply(this, arguments); + this.A = new b2Vec2(0, 0); + }; + b2ConstantAccelController.prototype.Step = function (step) { + var smallA = new b2Vec2(this.A.x * step.dt, this.A.y * step.dt); + for (var i = this.m_bodyList; i; i = i.nextBody) { + var body = i.body; + if (!body.IsAwake()) continue; + body.SetLinearVelocity(new b2Vec2(body.GetLinearVelocity().x + smallA.x, body.GetLinearVelocity().y + smallA.y)); + } + } + Box2D.inherit(b2ConstantForceController, Box2D.Dynamics.Controllers.b2Controller); + b2ConstantForceController.prototype.__super = Box2D.Dynamics.Controllers.b2Controller.prototype; + b2ConstantForceController.b2ConstantForceController = function () { + Box2D.Dynamics.Controllers.b2Controller.b2Controller.apply(this, arguments); + this.F = new b2Vec2(0, 0); + }; + b2ConstantForceController.prototype.Step = function (step) { + for (var i = this.m_bodyList; i; i = i.nextBody) { + var body = i.body; + if (!body.IsAwake()) continue; + body.ApplyForce(this.F, body.GetWorldCenter()); + } + } + b2Controller.b2Controller = function () {}; + b2Controller.prototype.Step = function (step) {} + b2Controller.prototype.Draw = function (debugDraw) {} + b2Controller.prototype.AddBody = function (body) { + var edge = new b2ControllerEdge(); + edge.controller = this; + edge.body = body; + edge.nextBody = this.m_bodyList; + edge.prevBody = null; + this.m_bodyList = edge; + if (edge.nextBody) edge.nextBody.prevBody = edge; + this.m_bodyCount++; + edge.nextController = body.m_controllerList; + edge.prevController = null; + body.m_controllerList = edge; + if (edge.nextController) edge.nextController.prevController = edge; + body.m_controllerCount++; + } + b2Controller.prototype.RemoveBody = function (body) { + var edge = body.m_controllerList; + while (edge && edge.controller != this) + edge = edge.nextController; + if (edge.prevBody) edge.prevBody.nextBody = edge.nextBody; + if (edge.nextBody) edge.nextBody.prevBody = edge.prevBody; + if (edge.nextController) edge.nextController.prevController = edge.prevController; + if (edge.prevController) edge.prevController.nextController = edge.nextController; + if (this.m_bodyList == edge) this.m_bodyList = edge.nextBody; + if (body.m_controllerList == edge) body.m_controllerList = edge.nextController; + body.m_controllerCount--; + this.m_bodyCount--; + } + b2Controller.prototype.Clear = function () { + while (this.m_bodyList) + this.RemoveBody(this.m_bodyList.body); + } + b2Controller.prototype.GetNext = function () { + return this.m_next; + } + b2Controller.prototype.GetWorld = function () { + return this.m_world; + } + b2Controller.prototype.GetBodyList = function () { + return this.m_bodyList; + } + b2ControllerEdge.b2ControllerEdge = function () {}; + Box2D.inherit(b2GravityController, Box2D.Dynamics.Controllers.b2Controller); + b2GravityController.prototype.__super = Box2D.Dynamics.Controllers.b2Controller.prototype; + b2GravityController.b2GravityController = function () { + Box2D.Dynamics.Controllers.b2Controller.b2Controller.apply(this, arguments); + this.G = 1; + this.invSqr = true; + }; + b2GravityController.prototype.Step = function (step) { + var i = null; + var body1 = null; + var p1 = null; + var mass1 = 0; + var j = null; + var body2 = null; + var p2 = null; + var dx = 0; + var dy = 0; + var r2 = 0; + var f = null; + if (this.invSqr) { + for (i = this.m_bodyList; + i; i = i.nextBody) { + body1 = i.body; + p1 = body1.GetWorldCenter(); + mass1 = body1.GetMass(); + for (j = this.m_bodyList; + j != i; j = j.nextBody) { + body2 = j.body; + p2 = body2.GetWorldCenter(); + dx = p2.x - p1.x; + dy = p2.y - p1.y; + r2 = dx * dx + dy * dy; + if (r2 < Number.MIN_VALUE) continue; + f = new b2Vec2(dx, dy); + f.Multiply(this.G / r2 / Math.sqrt(r2) * mass1 * body2.GetMass()); + if (body1.IsAwake()) body1.ApplyForce(f, p1); + f.Multiply((-1)); + if (body2.IsAwake()) body2.ApplyForce(f, p2); + } + } + } + else { + for (i = this.m_bodyList; + i; i = i.nextBody) { + body1 = i.body; + p1 = body1.GetWorldCenter(); + mass1 = body1.GetMass(); + for (j = this.m_bodyList; + j != i; j = j.nextBody) { + body2 = j.body; + p2 = body2.GetWorldCenter(); + dx = p2.x - p1.x; + dy = p2.y - p1.y; + r2 = dx * dx + dy * dy; + if (r2 < Number.MIN_VALUE) continue; + f = new b2Vec2(dx, dy); + f.Multiply(this.G / r2 * mass1 * body2.GetMass()); + if (body1.IsAwake()) body1.ApplyForce(f, p1); + f.Multiply((-1)); + if (body2.IsAwake()) body2.ApplyForce(f, p2); + } + } + } + } + Box2D.inherit(b2TensorDampingController, Box2D.Dynamics.Controllers.b2Controller); + b2TensorDampingController.prototype.__super = Box2D.Dynamics.Controllers.b2Controller.prototype; + b2TensorDampingController.b2TensorDampingController = function () { + Box2D.Dynamics.Controllers.b2Controller.b2Controller.apply(this, arguments); + this.T = new b2Mat22(); + this.maxTimestep = 0; + }; + b2TensorDampingController.prototype.SetAxisAligned = function (xDamping, yDamping) { + if (xDamping === undefined) xDamping = 0; + if (yDamping === undefined) yDamping = 0; + this.T.col1.x = (-xDamping); + this.T.col1.y = 0; + this.T.col2.x = 0; + this.T.col2.y = (-yDamping); + if (xDamping > 0 || yDamping > 0) { + this.maxTimestep = 1 / Math.max(xDamping, yDamping); + } + else { + this.maxTimestep = 0; + } + } + b2TensorDampingController.prototype.Step = function (step) { + var timestep = step.dt; + if (timestep <= Number.MIN_VALUE) return; + if (timestep > this.maxTimestep && this.maxTimestep > 0) timestep = this.maxTimestep; + for (var i = this.m_bodyList; i; i = i.nextBody) { + var body = i.body; + if (!body.IsAwake()) { + continue; + } + var damping = body.GetWorldVector(b2Math.MulMV(this.T, body.GetLocalVector(body.GetLinearVelocity()))); + body.SetLinearVelocity(new b2Vec2(body.GetLinearVelocity().x + damping.x * timestep, body.GetLinearVelocity().y + damping.y * timestep)); + } + } +})(); +(function () { + var b2Color = Box2D.Common.b2Color, + b2internal = Box2D.Common.b2internal, + b2Settings = Box2D.Common.b2Settings, + b2Mat22 = Box2D.Common.Math.b2Mat22, + b2Mat33 = Box2D.Common.Math.b2Mat33, + b2Math = Box2D.Common.Math.b2Math, + b2Sweep = Box2D.Common.Math.b2Sweep, + b2Transform = Box2D.Common.Math.b2Transform, + b2Vec2 = Box2D.Common.Math.b2Vec2, + b2Vec3 = Box2D.Common.Math.b2Vec3, + b2DistanceJoint = Box2D.Dynamics.Joints.b2DistanceJoint, + b2DistanceJointDef = Box2D.Dynamics.Joints.b2DistanceJointDef, + b2FrictionJoint = Box2D.Dynamics.Joints.b2FrictionJoint, + b2FrictionJointDef = Box2D.Dynamics.Joints.b2FrictionJointDef, + b2GearJoint = Box2D.Dynamics.Joints.b2GearJoint, + b2GearJointDef = Box2D.Dynamics.Joints.b2GearJointDef, + b2Jacobian = Box2D.Dynamics.Joints.b2Jacobian, + b2Joint = Box2D.Dynamics.Joints.b2Joint, + b2JointDef = Box2D.Dynamics.Joints.b2JointDef, + b2JointEdge = Box2D.Dynamics.Joints.b2JointEdge, + b2LineJoint = Box2D.Dynamics.Joints.b2LineJoint, + b2LineJointDef = Box2D.Dynamics.Joints.b2LineJointDef, + b2MouseJoint = Box2D.Dynamics.Joints.b2MouseJoint, + b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef, + b2PrismaticJoint = Box2D.Dynamics.Joints.b2PrismaticJoint, + b2PrismaticJointDef = Box2D.Dynamics.Joints.b2PrismaticJointDef, + b2PulleyJoint = Box2D.Dynamics.Joints.b2PulleyJoint, + b2PulleyJointDef = Box2D.Dynamics.Joints.b2PulleyJointDef, + b2RevoluteJoint = Box2D.Dynamics.Joints.b2RevoluteJoint, + b2RevoluteJointDef = Box2D.Dynamics.Joints.b2RevoluteJointDef, + b2WeldJoint = Box2D.Dynamics.Joints.b2WeldJoint, + b2WeldJointDef = Box2D.Dynamics.Joints.b2WeldJointDef, + b2Body = Box2D.Dynamics.b2Body, + b2BodyDef = Box2D.Dynamics.b2BodyDef, + b2ContactFilter = Box2D.Dynamics.b2ContactFilter, + b2ContactImpulse = Box2D.Dynamics.b2ContactImpulse, + b2ContactListener = Box2D.Dynamics.b2ContactListener, + b2ContactManager = Box2D.Dynamics.b2ContactManager, + b2DebugDraw = Box2D.Dynamics.b2DebugDraw, + b2DestructionListener = Box2D.Dynamics.b2DestructionListener, + b2FilterData = Box2D.Dynamics.b2FilterData, + b2Fixture = Box2D.Dynamics.b2Fixture, + b2FixtureDef = Box2D.Dynamics.b2FixtureDef, + b2Island = Box2D.Dynamics.b2Island, + b2TimeStep = Box2D.Dynamics.b2TimeStep, + b2World = Box2D.Dynamics.b2World; + + Box2D.inherit(b2DistanceJoint, Box2D.Dynamics.Joints.b2Joint); + b2DistanceJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; + b2DistanceJoint.b2DistanceJoint = function () { + Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); + this.m_localAnchor1 = new b2Vec2(); + this.m_localAnchor2 = new b2Vec2(); + this.m_u = new b2Vec2(); + }; + b2DistanceJoint.prototype.GetAnchorA = function () { + return this.m_bodyA.GetWorldPoint(this.m_localAnchor1); + } + b2DistanceJoint.prototype.GetAnchorB = function () { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor2); + } + b2DistanceJoint.prototype.GetReactionForce = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return new b2Vec2(inv_dt * this.m_impulse * this.m_u.x, inv_dt * this.m_impulse * this.m_u.y); + } + b2DistanceJoint.prototype.GetReactionTorque = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return 0.0; + } + b2DistanceJoint.prototype.GetLength = function () { + return this.m_length; + } + b2DistanceJoint.prototype.SetLength = function (length) { + if (length === undefined) length = 0; + this.m_length = length; + } + b2DistanceJoint.prototype.GetFrequency = function () { + return this.m_frequencyHz; + } + b2DistanceJoint.prototype.SetFrequency = function (hz) { + if (hz === undefined) hz = 0; + this.m_frequencyHz = hz; + } + b2DistanceJoint.prototype.GetDampingRatio = function () { + return this.m_dampingRatio; + } + b2DistanceJoint.prototype.SetDampingRatio = function (ratio) { + if (ratio === undefined) ratio = 0; + this.m_dampingRatio = ratio; + } + b2DistanceJoint.prototype.b2DistanceJoint = function (def) { + this.__super.b2Joint.call(this, def); + var tMat; + var tX = 0; + var tY = 0; + this.m_localAnchor1.SetV(def.localAnchorA); + this.m_localAnchor2.SetV(def.localAnchorB); + this.m_length = def.length; + this.m_frequencyHz = def.frequencyHz; + this.m_dampingRatio = def.dampingRatio; + this.m_impulse = 0.0; + this.m_gamma = 0.0; + this.m_bias = 0.0; + } + b2DistanceJoint.prototype.InitVelocityConstraints = function (step) { + var tMat; + var tX = 0; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + this.m_u.x = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; + this.m_u.y = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; + var length = Math.sqrt(this.m_u.x * this.m_u.x + this.m_u.y * this.m_u.y); + if (length > b2Settings.b2_linearSlop) { + this.m_u.Multiply(1.0 / length); + } + else { + this.m_u.SetZero(); + } + var cr1u = (r1X * this.m_u.y - r1Y * this.m_u.x); + var cr2u = (r2X * this.m_u.y - r2Y * this.m_u.x); + var invMass = bA.m_invMass + bA.m_invI * cr1u * cr1u + bB.m_invMass + bB.m_invI * cr2u * cr2u; + this.m_mass = invMass != 0.0 ? 1.0 / invMass : 0.0; + if (this.m_frequencyHz > 0.0) { + var C = length - this.m_length; + var omega = 2.0 * Math.PI * this.m_frequencyHz; + var d = 2.0 * this.m_mass * this.m_dampingRatio * omega; + var k = this.m_mass * omega * omega; + this.m_gamma = step.dt * (d + step.dt * k); + this.m_gamma = this.m_gamma != 0.0 ? 1 / this.m_gamma : 0.0; + this.m_bias = C * step.dt * k * this.m_gamma; + this.m_mass = invMass + this.m_gamma; + this.m_mass = this.m_mass != 0.0 ? 1.0 / this.m_mass : 0.0; + } + if (step.warmStarting) { + this.m_impulse *= step.dtRatio; + var PX = this.m_impulse * this.m_u.x; + var PY = this.m_impulse * this.m_u.y; + bA.m_linearVelocity.x -= bA.m_invMass * PX; + bA.m_linearVelocity.y -= bA.m_invMass * PY; + bA.m_angularVelocity -= bA.m_invI * (r1X * PY - r1Y * PX); + bB.m_linearVelocity.x += bB.m_invMass * PX; + bB.m_linearVelocity.y += bB.m_invMass * PY; + bB.m_angularVelocity += bB.m_invI * (r2X * PY - r2Y * PX); + } + else { + this.m_impulse = 0.0; + } + } + b2DistanceJoint.prototype.SolveVelocityConstraints = function (step) { + var tMat; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var v1X = bA.m_linearVelocity.x + ((-bA.m_angularVelocity * r1Y)); + var v1Y = bA.m_linearVelocity.y + (bA.m_angularVelocity * r1X); + var v2X = bB.m_linearVelocity.x + ((-bB.m_angularVelocity * r2Y)); + var v2Y = bB.m_linearVelocity.y + (bB.m_angularVelocity * r2X); + var Cdot = (this.m_u.x * (v2X - v1X) + this.m_u.y * (v2Y - v1Y)); + var impulse = (-this.m_mass * (Cdot + this.m_bias + this.m_gamma * this.m_impulse)); + this.m_impulse += impulse; + var PX = impulse * this.m_u.x; + var PY = impulse * this.m_u.y; + bA.m_linearVelocity.x -= bA.m_invMass * PX; + bA.m_linearVelocity.y -= bA.m_invMass * PY; + bA.m_angularVelocity -= bA.m_invI * (r1X * PY - r1Y * PX); + bB.m_linearVelocity.x += bB.m_invMass * PX; + bB.m_linearVelocity.y += bB.m_invMass * PY; + bB.m_angularVelocity += bB.m_invI * (r2X * PY - r2Y * PX); + } + b2DistanceJoint.prototype.SolvePositionConstraints = function (baumgarte) { + if (baumgarte === undefined) baumgarte = 0; + var tMat; + if (this.m_frequencyHz > 0.0) { + return true; + } + var bA = this.m_bodyA; + var bB = this.m_bodyB; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var dX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; + var dY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; + var length = Math.sqrt(dX * dX + dY * dY); + dX /= length; + dY /= length; + var C = length - this.m_length; + C = b2Math.Clamp(C, (-b2Settings.b2_maxLinearCorrection), b2Settings.b2_maxLinearCorrection); + var impulse = (-this.m_mass * C); + this.m_u.Set(dX, dY); + var PX = impulse * this.m_u.x; + var PY = impulse * this.m_u.y; + bA.m_sweep.c.x -= bA.m_invMass * PX; + bA.m_sweep.c.y -= bA.m_invMass * PY; + bA.m_sweep.a -= bA.m_invI * (r1X * PY - r1Y * PX); + bB.m_sweep.c.x += bB.m_invMass * PX; + bB.m_sweep.c.y += bB.m_invMass * PY; + bB.m_sweep.a += bB.m_invI * (r2X * PY - r2Y * PX); + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + return b2Math.Abs(C) < b2Settings.b2_linearSlop; + } + Box2D.inherit(b2DistanceJointDef, Box2D.Dynamics.Joints.b2JointDef); + b2DistanceJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; + b2DistanceJointDef.b2DistanceJointDef = function () { + Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); + this.localAnchorA = new b2Vec2(); + this.localAnchorB = new b2Vec2(); + }; + b2DistanceJointDef.prototype.b2DistanceJointDef = function () { + this.__super.b2JointDef.call(this); + this.type = b2Joint.e_distanceJoint; + this.length = 1.0; + this.frequencyHz = 0.0; + this.dampingRatio = 0.0; + } + b2DistanceJointDef.prototype.Initialize = function (bA, bB, anchorA, anchorB) { + this.bodyA = bA; + this.bodyB = bB; + this.localAnchorA.SetV(this.bodyA.GetLocalPoint(anchorA)); + this.localAnchorB.SetV(this.bodyB.GetLocalPoint(anchorB)); + var dX = anchorB.x - anchorA.x; + var dY = anchorB.y - anchorA.y; + this.length = Math.sqrt(dX * dX + dY * dY); + this.frequencyHz = 0.0; + this.dampingRatio = 0.0; + } + Box2D.inherit(b2FrictionJoint, Box2D.Dynamics.Joints.b2Joint); + b2FrictionJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; + b2FrictionJoint.b2FrictionJoint = function () { + Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); + this.m_localAnchorA = new b2Vec2(); + this.m_localAnchorB = new b2Vec2(); + this.m_linearMass = new b2Mat22(); + this.m_linearImpulse = new b2Vec2(); + }; + b2FrictionJoint.prototype.GetAnchorA = function () { + return this.m_bodyA.GetWorldPoint(this.m_localAnchorA); + } + b2FrictionJoint.prototype.GetAnchorB = function () { + return this.m_bodyB.GetWorldPoint(this.m_localAnchorB); + } + b2FrictionJoint.prototype.GetReactionForce = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return new b2Vec2(inv_dt * this.m_linearImpulse.x, inv_dt * this.m_linearImpulse.y); + } + b2FrictionJoint.prototype.GetReactionTorque = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return inv_dt * this.m_angularImpulse; + } + b2FrictionJoint.prototype.SetMaxForce = function (force) { + if (force === undefined) force = 0; + this.m_maxForce = force; + } + b2FrictionJoint.prototype.GetMaxForce = function () { + return this.m_maxForce; + } + b2FrictionJoint.prototype.SetMaxTorque = function (torque) { + if (torque === undefined) torque = 0; + this.m_maxTorque = torque; + } + b2FrictionJoint.prototype.GetMaxTorque = function () { + return this.m_maxTorque; + } + b2FrictionJoint.prototype.b2FrictionJoint = function (def) { + this.__super.b2Joint.call(this, def); + this.m_localAnchorA.SetV(def.localAnchorA); + this.m_localAnchorB.SetV(def.localAnchorB); + this.m_linearMass.SetZero(); + this.m_angularMass = 0.0; + this.m_linearImpulse.SetZero(); + this.m_angularImpulse = 0.0; + this.m_maxForce = def.maxForce; + this.m_maxTorque = def.maxTorque; + } + b2FrictionJoint.prototype.InitVelocityConstraints = function (step) { + var tMat; + var tX = 0; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + tMat = bA.m_xf.R; + var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; + var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; + tX = (tMat.col1.x * rAX + tMat.col2.x * rAY); + rAY = (tMat.col1.y * rAX + tMat.col2.y * rAY); + rAX = tX; + tMat = bB.m_xf.R; + var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; + var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * rBX + tMat.col2.x * rBY); + rBY = (tMat.col1.y * rBX + tMat.col2.y * rBY); + rBX = tX; + var mA = bA.m_invMass; + var mB = bB.m_invMass; + var iA = bA.m_invI; + var iB = bB.m_invI; + var K = new b2Mat22(); + K.col1.x = mA + mB; + K.col2.x = 0.0; + K.col1.y = 0.0; + K.col2.y = mA + mB; + K.col1.x += iA * rAY * rAY; + K.col2.x += (-iA * rAX * rAY); + K.col1.y += (-iA * rAX * rAY); + K.col2.y += iA * rAX * rAX; + K.col1.x += iB * rBY * rBY; + K.col2.x += (-iB * rBX * rBY); + K.col1.y += (-iB * rBX * rBY); + K.col2.y += iB * rBX * rBX; + K.GetInverse(this.m_linearMass); + this.m_angularMass = iA + iB; + if (this.m_angularMass > 0.0) { + this.m_angularMass = 1.0 / this.m_angularMass; + } + if (step.warmStarting) { + this.m_linearImpulse.x *= step.dtRatio; + this.m_linearImpulse.y *= step.dtRatio; + this.m_angularImpulse *= step.dtRatio; + var P = this.m_linearImpulse; + bA.m_linearVelocity.x -= mA * P.x; + bA.m_linearVelocity.y -= mA * P.y; + bA.m_angularVelocity -= iA * (rAX * P.y - rAY * P.x + this.m_angularImpulse); + bB.m_linearVelocity.x += mB * P.x; + bB.m_linearVelocity.y += mB * P.y; + bB.m_angularVelocity += iB * (rBX * P.y - rBY * P.x + this.m_angularImpulse); + } + else { + this.m_linearImpulse.SetZero(); + this.m_angularImpulse = 0.0; + } + } + b2FrictionJoint.prototype.SolveVelocityConstraints = function (step) { + var tMat; + var tX = 0; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var vA = bA.m_linearVelocity; + var wA = bA.m_angularVelocity; + var vB = bB.m_linearVelocity; + var wB = bB.m_angularVelocity; + var mA = bA.m_invMass; + var mB = bB.m_invMass; + var iA = bA.m_invI; + var iB = bB.m_invI; + tMat = bA.m_xf.R; + var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; + var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; + tX = (tMat.col1.x * rAX + tMat.col2.x * rAY); + rAY = (tMat.col1.y * rAX + tMat.col2.y * rAY); + rAX = tX; + tMat = bB.m_xf.R; + var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; + var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * rBX + tMat.col2.x * rBY); + rBY = (tMat.col1.y * rBX + tMat.col2.y * rBY); + rBX = tX; + var maxImpulse = 0; { + var Cdot = wB - wA; + var impulse = (-this.m_angularMass * Cdot); + var oldImpulse = this.m_angularImpulse; + maxImpulse = step.dt * this.m_maxTorque; + this.m_angularImpulse = b2Math.Clamp(this.m_angularImpulse + impulse, (-maxImpulse), maxImpulse); + impulse = this.m_angularImpulse - oldImpulse; + wA -= iA * impulse; + wB += iB * impulse; + } { + var CdotX = vB.x - wB * rBY - vA.x + wA * rAY; + var CdotY = vB.y + wB * rBX - vA.y - wA * rAX; + var impulseV = b2Math.MulMV(this.m_linearMass, new b2Vec2((-CdotX), (-CdotY))); + var oldImpulseV = this.m_linearImpulse.Copy(); + this.m_linearImpulse.Add(impulseV); + maxImpulse = step.dt * this.m_maxForce; + if (this.m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) { + this.m_linearImpulse.Normalize(); + this.m_linearImpulse.Multiply(maxImpulse); + } + impulseV = b2Math.SubtractVV(this.m_linearImpulse, oldImpulseV); + vA.x -= mA * impulseV.x; + vA.y -= mA * impulseV.y; + wA -= iA * (rAX * impulseV.y - rAY * impulseV.x); + vB.x += mB * impulseV.x; + vB.y += mB * impulseV.y; + wB += iB * (rBX * impulseV.y - rBY * impulseV.x); + } + bA.m_angularVelocity = wA; + bB.m_angularVelocity = wB; + } + b2FrictionJoint.prototype.SolvePositionConstraints = function (baumgarte) { + if (baumgarte === undefined) baumgarte = 0; + return true; + } + Box2D.inherit(b2FrictionJointDef, Box2D.Dynamics.Joints.b2JointDef); + b2FrictionJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; + b2FrictionJointDef.b2FrictionJointDef = function () { + Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); + this.localAnchorA = new b2Vec2(); + this.localAnchorB = new b2Vec2(); + }; + b2FrictionJointDef.prototype.b2FrictionJointDef = function () { + this.__super.b2JointDef.call(this); + this.type = b2Joint.e_frictionJoint; + this.maxForce = 0.0; + this.maxTorque = 0.0; + } + b2FrictionJointDef.prototype.Initialize = function (bA, bB, anchor) { + this.bodyA = bA; + this.bodyB = bB; + this.localAnchorA.SetV(this.bodyA.GetLocalPoint(anchor)); + this.localAnchorB.SetV(this.bodyB.GetLocalPoint(anchor)); + } + Box2D.inherit(b2GearJoint, Box2D.Dynamics.Joints.b2Joint); + b2GearJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; + b2GearJoint.b2GearJoint = function () { + Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); + this.m_groundAnchor1 = new b2Vec2(); + this.m_groundAnchor2 = new b2Vec2(); + this.m_localAnchor1 = new b2Vec2(); + this.m_localAnchor2 = new b2Vec2(); + this.m_J = new b2Jacobian(); + }; + b2GearJoint.prototype.GetAnchorA = function () { + return this.m_bodyA.GetWorldPoint(this.m_localAnchor1); + } + b2GearJoint.prototype.GetAnchorB = function () { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor2); + } + b2GearJoint.prototype.GetReactionForce = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return new b2Vec2(inv_dt * this.m_impulse * this.m_J.linearB.x, inv_dt * this.m_impulse * this.m_J.linearB.y); + } + b2GearJoint.prototype.GetReactionTorque = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + var tMat = this.m_bodyB.m_xf.R; + var rX = this.m_localAnchor1.x - this.m_bodyB.m_sweep.localCenter.x; + var rY = this.m_localAnchor1.y - this.m_bodyB.m_sweep.localCenter.y; + var tX = tMat.col1.x * rX + tMat.col2.x * rY; + rY = tMat.col1.y * rX + tMat.col2.y * rY; + rX = tX; + var PX = this.m_impulse * this.m_J.linearB.x; + var PY = this.m_impulse * this.m_J.linearB.y; + return inv_dt * (this.m_impulse * this.m_J.angularB - rX * PY + rY * PX); + } + b2GearJoint.prototype.GetRatio = function () { + return this.m_ratio; + } + b2GearJoint.prototype.SetRatio = function (ratio) { + if (ratio === undefined) ratio = 0; + this.m_ratio = ratio; + } + b2GearJoint.prototype.b2GearJoint = function (def) { + this.__super.b2Joint.call(this, def); + var type1 = parseInt(def.joint1.m_type); + var type2 = parseInt(def.joint2.m_type); + this.m_revolute1 = null; + this.m_prismatic1 = null; + this.m_revolute2 = null; + this.m_prismatic2 = null; + var coordinate1 = 0; + var coordinate2 = 0; + this.m_ground1 = def.joint1.GetBodyA(); + this.m_bodyA = def.joint1.GetBodyB(); + if (type1 == b2Joint.e_revoluteJoint) { + this.m_revolute1 = (def.joint1 instanceof b2RevoluteJoint ? def.joint1 : null); + this.m_groundAnchor1.SetV(this.m_revolute1.m_localAnchor1); + this.m_localAnchor1.SetV(this.m_revolute1.m_localAnchor2); + coordinate1 = this.m_revolute1.GetJointAngle(); + } + else { + this.m_prismatic1 = (def.joint1 instanceof b2PrismaticJoint ? def.joint1 : null); + this.m_groundAnchor1.SetV(this.m_prismatic1.m_localAnchor1); + this.m_localAnchor1.SetV(this.m_prismatic1.m_localAnchor2); + coordinate1 = this.m_prismatic1.GetJointTranslation(); + } + this.m_ground2 = def.joint2.GetBodyA(); + this.m_bodyB = def.joint2.GetBodyB(); + if (type2 == b2Joint.e_revoluteJoint) { + this.m_revolute2 = (def.joint2 instanceof b2RevoluteJoint ? def.joint2 : null); + this.m_groundAnchor2.SetV(this.m_revolute2.m_localAnchor1); + this.m_localAnchor2.SetV(this.m_revolute2.m_localAnchor2); + coordinate2 = this.m_revolute2.GetJointAngle(); + } + else { + this.m_prismatic2 = (def.joint2 instanceof b2PrismaticJoint ? def.joint2 : null); + this.m_groundAnchor2.SetV(this.m_prismatic2.m_localAnchor1); + this.m_localAnchor2.SetV(this.m_prismatic2.m_localAnchor2); + coordinate2 = this.m_prismatic2.GetJointTranslation(); + } + this.m_ratio = def.ratio; + this.m_constant = coordinate1 + this.m_ratio * coordinate2; + this.m_impulse = 0.0; + } + b2GearJoint.prototype.InitVelocityConstraints = function (step) { + var g1 = this.m_ground1; + var g2 = this.m_ground2; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var ugX = 0; + var ugY = 0; + var rX = 0; + var rY = 0; + var tMat; + var tVec; + var crug = 0; + var tX = 0; + var K = 0.0; + this.m_J.SetZero(); + if (this.m_revolute1) { + this.m_J.angularA = (-1.0); + K += bA.m_invI; + } + else { + tMat = g1.m_xf.R; + tVec = this.m_prismatic1.m_localXAxis1; + ugX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + ugY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = bA.m_xf.R; + rX = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + rY = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * rX + tMat.col2.x * rY; + rY = tMat.col1.y * rX + tMat.col2.y * rY; + rX = tX; + crug = rX * ugY - rY * ugX; + this.m_J.linearA.Set((-ugX), (-ugY)); + this.m_J.angularA = (-crug); + K += bA.m_invMass + bA.m_invI * crug * crug; + } + if (this.m_revolute2) { + this.m_J.angularB = (-this.m_ratio); + K += this.m_ratio * this.m_ratio * bB.m_invI; + } + else { + tMat = g2.m_xf.R; + tVec = this.m_prismatic2.m_localXAxis1; + ugX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + ugY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = bB.m_xf.R; + rX = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + rY = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * rX + tMat.col2.x * rY; + rY = tMat.col1.y * rX + tMat.col2.y * rY; + rX = tX; + crug = rX * ugY - rY * ugX; + this.m_J.linearB.Set((-this.m_ratio * ugX), (-this.m_ratio * ugY)); + this.m_J.angularB = (-this.m_ratio * crug); + K += this.m_ratio * this.m_ratio * (bB.m_invMass + bB.m_invI * crug * crug); + } + this.m_mass = K > 0.0 ? 1.0 / K : 0.0; + if (step.warmStarting) { + bA.m_linearVelocity.x += bA.m_invMass * this.m_impulse * this.m_J.linearA.x; + bA.m_linearVelocity.y += bA.m_invMass * this.m_impulse * this.m_J.linearA.y; + bA.m_angularVelocity += bA.m_invI * this.m_impulse * this.m_J.angularA; + bB.m_linearVelocity.x += bB.m_invMass * this.m_impulse * this.m_J.linearB.x; + bB.m_linearVelocity.y += bB.m_invMass * this.m_impulse * this.m_J.linearB.y; + bB.m_angularVelocity += bB.m_invI * this.m_impulse * this.m_J.angularB; + } + else { + this.m_impulse = 0.0; + } + } + b2GearJoint.prototype.SolveVelocityConstraints = function (step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var Cdot = this.m_J.Compute(bA.m_linearVelocity, bA.m_angularVelocity, bB.m_linearVelocity, bB.m_angularVelocity); + var impulse = (-this.m_mass * Cdot); + this.m_impulse += impulse; + bA.m_linearVelocity.x += bA.m_invMass * impulse * this.m_J.linearA.x; + bA.m_linearVelocity.y += bA.m_invMass * impulse * this.m_J.linearA.y; + bA.m_angularVelocity += bA.m_invI * impulse * this.m_J.angularA; + bB.m_linearVelocity.x += bB.m_invMass * impulse * this.m_J.linearB.x; + bB.m_linearVelocity.y += bB.m_invMass * impulse * this.m_J.linearB.y; + bB.m_angularVelocity += bB.m_invI * impulse * this.m_J.angularB; + } + b2GearJoint.prototype.SolvePositionConstraints = function (baumgarte) { + if (baumgarte === undefined) baumgarte = 0; + var linearError = 0.0; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var coordinate1 = 0; + var coordinate2 = 0; + if (this.m_revolute1) { + coordinate1 = this.m_revolute1.GetJointAngle(); + } + else { + coordinate1 = this.m_prismatic1.GetJointTranslation(); + } + if (this.m_revolute2) { + coordinate2 = this.m_revolute2.GetJointAngle(); + } + else { + coordinate2 = this.m_prismatic2.GetJointTranslation(); + } + var C = this.m_constant - (coordinate1 + this.m_ratio * coordinate2); + var impulse = (-this.m_mass * C); + bA.m_sweep.c.x += bA.m_invMass * impulse * this.m_J.linearA.x; + bA.m_sweep.c.y += bA.m_invMass * impulse * this.m_J.linearA.y; + bA.m_sweep.a += bA.m_invI * impulse * this.m_J.angularA; + bB.m_sweep.c.x += bB.m_invMass * impulse * this.m_J.linearB.x; + bB.m_sweep.c.y += bB.m_invMass * impulse * this.m_J.linearB.y; + bB.m_sweep.a += bB.m_invI * impulse * this.m_J.angularB; + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + return linearError < b2Settings.b2_linearSlop; + } + Box2D.inherit(b2GearJointDef, Box2D.Dynamics.Joints.b2JointDef); + b2GearJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; + b2GearJointDef.b2GearJointDef = function () { + Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); + }; + b2GearJointDef.prototype.b2GearJointDef = function () { + this.__super.b2JointDef.call(this); + this.type = b2Joint.e_gearJoint; + this.joint1 = null; + this.joint2 = null; + this.ratio = 1.0; + } + b2Jacobian.b2Jacobian = function () { + this.linearA = new b2Vec2(); + this.linearB = new b2Vec2(); + }; + b2Jacobian.prototype.SetZero = function () { + this.linearA.SetZero(); + this.angularA = 0.0; + this.linearB.SetZero(); + this.angularB = 0.0; + } + b2Jacobian.prototype.Set = function (x1, a1, x2, a2) { + if (a1 === undefined) a1 = 0; + if (a2 === undefined) a2 = 0; + this.linearA.SetV(x1); + this.angularA = a1; + this.linearB.SetV(x2); + this.angularB = a2; + } + b2Jacobian.prototype.Compute = function (x1, a1, x2, a2) { + if (a1 === undefined) a1 = 0; + if (a2 === undefined) a2 = 0; + return (this.linearA.x * x1.x + this.linearA.y * x1.y) + this.angularA * a1 + (this.linearB.x * x2.x + this.linearB.y * x2.y) + this.angularB * a2; + } + b2Joint.b2Joint = function () { + this.m_edgeA = new b2JointEdge(); + this.m_edgeB = new b2JointEdge(); + this.m_localCenterA = new b2Vec2(); + this.m_localCenterB = new b2Vec2(); + }; + b2Joint.prototype.GetType = function () { + return this.m_type; + } + b2Joint.prototype.GetAnchorA = function () { + return null; + } + b2Joint.prototype.GetAnchorB = function () { + return null; + } + b2Joint.prototype.GetReactionForce = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return null; + } + b2Joint.prototype.GetReactionTorque = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return 0.0; + } + b2Joint.prototype.GetBodyA = function () { + return this.m_bodyA; + } + b2Joint.prototype.GetBodyB = function () { + return this.m_bodyB; + } + b2Joint.prototype.GetNext = function () { + return this.m_next; + } + b2Joint.prototype.GetUserData = function () { + return this.m_userData; + } + b2Joint.prototype.SetUserData = function (data) { + this.m_userData = data; + } + b2Joint.prototype.IsActive = function () { + return this.m_bodyA.IsActive() && this.m_bodyB.IsActive(); + } + b2Joint.Create = function (def, allocator) { + var joint = null; + switch (def.type) { + case b2Joint.e_distanceJoint: + { + joint = new b2DistanceJoint((def instanceof b2DistanceJointDef ? def : null)); + } + break; + case b2Joint.e_mouseJoint: + { + joint = new b2MouseJoint((def instanceof b2MouseJointDef ? def : null)); + } + break; + case b2Joint.e_prismaticJoint: + { + joint = new b2PrismaticJoint((def instanceof b2PrismaticJointDef ? def : null)); + } + break; + case b2Joint.e_revoluteJoint: + { + joint = new b2RevoluteJoint((def instanceof b2RevoluteJointDef ? def : null)); + } + break; + case b2Joint.e_pulleyJoint: + { + joint = new b2PulleyJoint((def instanceof b2PulleyJointDef ? def : null)); + } + break; + case b2Joint.e_gearJoint: + { + joint = new b2GearJoint((def instanceof b2GearJointDef ? def : null)); + } + break; + case b2Joint.e_lineJoint: + { + joint = new b2LineJoint((def instanceof b2LineJointDef ? def : null)); + } + break; + case b2Joint.e_weldJoint: + { + joint = new b2WeldJoint((def instanceof b2WeldJointDef ? def : null)); + } + break; + case b2Joint.e_frictionJoint: + { + joint = new b2FrictionJoint((def instanceof b2FrictionJointDef ? def : null)); + } + break; + default: + break; + } + return joint; + } + b2Joint.Destroy = function (joint, allocator) {} + b2Joint.prototype.b2Joint = function (def) { + b2Settings.b2Assert(def.bodyA != def.bodyB); + this.m_type = def.type; + this.m_prev = null; + this.m_next = null; + this.m_bodyA = def.bodyA; + this.m_bodyB = def.bodyB; + this.m_collideConnected = def.collideConnected; + this.m_islandFlag = false; + this.m_userData = def.userData; + } + b2Joint.prototype.InitVelocityConstraints = function (step) {} + b2Joint.prototype.SolveVelocityConstraints = function (step) {} + b2Joint.prototype.FinalizeVelocityConstraints = function () {} + b2Joint.prototype.SolvePositionConstraints = function (baumgarte) { + if (baumgarte === undefined) baumgarte = 0; + return false; + } + Box2D.postDefs.push(function () { + Box2D.Dynamics.Joints.b2Joint.e_unknownJoint = 0; + Box2D.Dynamics.Joints.b2Joint.e_revoluteJoint = 1; + Box2D.Dynamics.Joints.b2Joint.e_prismaticJoint = 2; + Box2D.Dynamics.Joints.b2Joint.e_distanceJoint = 3; + Box2D.Dynamics.Joints.b2Joint.e_pulleyJoint = 4; + Box2D.Dynamics.Joints.b2Joint.e_mouseJoint = 5; + Box2D.Dynamics.Joints.b2Joint.e_gearJoint = 6; + Box2D.Dynamics.Joints.b2Joint.e_lineJoint = 7; + Box2D.Dynamics.Joints.b2Joint.e_weldJoint = 8; + Box2D.Dynamics.Joints.b2Joint.e_frictionJoint = 9; + Box2D.Dynamics.Joints.b2Joint.e_inactiveLimit = 0; + Box2D.Dynamics.Joints.b2Joint.e_atLowerLimit = 1; + Box2D.Dynamics.Joints.b2Joint.e_atUpperLimit = 2; + Box2D.Dynamics.Joints.b2Joint.e_equalLimits = 3; + }); + b2JointDef.b2JointDef = function () {}; + b2JointDef.prototype.b2JointDef = function () { + this.type = b2Joint.e_unknownJoint; + this.userData = null; + this.bodyA = null; + this.bodyB = null; + this.collideConnected = false; + } + b2JointEdge.b2JointEdge = function () {}; + Box2D.inherit(b2LineJoint, Box2D.Dynamics.Joints.b2Joint); + b2LineJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; + b2LineJoint.b2LineJoint = function () { + Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); + this.m_localAnchor1 = new b2Vec2(); + this.m_localAnchor2 = new b2Vec2(); + this.m_localXAxis1 = new b2Vec2(); + this.m_localYAxis1 = new b2Vec2(); + this.m_axis = new b2Vec2(); + this.m_perp = new b2Vec2(); + this.m_K = new b2Mat22(); + this.m_impulse = new b2Vec2(); + }; + b2LineJoint.prototype.GetAnchorA = function () { + return this.m_bodyA.GetWorldPoint(this.m_localAnchor1); + } + b2LineJoint.prototype.GetAnchorB = function () { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor2); + } + b2LineJoint.prototype.GetReactionForce = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return new b2Vec2(inv_dt * (this.m_impulse.x * this.m_perp.x + (this.m_motorImpulse + this.m_impulse.y) * this.m_axis.x), inv_dt * (this.m_impulse.x * this.m_perp.y + (this.m_motorImpulse + this.m_impulse.y) * this.m_axis.y)); + } + b2LineJoint.prototype.GetReactionTorque = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return inv_dt * this.m_impulse.y; + } + b2LineJoint.prototype.GetJointTranslation = function () { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var p1 = bA.GetWorldPoint(this.m_localAnchor1); + var p2 = bB.GetWorldPoint(this.m_localAnchor2); + var dX = p2.x - p1.x; + var dY = p2.y - p1.y; + var axis = bA.GetWorldVector(this.m_localXAxis1); + var translation = axis.x * dX + axis.y * dY; + return translation; + } + b2LineJoint.prototype.GetJointSpeed = function () { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var p1X = bA.m_sweep.c.x + r1X; + var p1Y = bA.m_sweep.c.y + r1Y; + var p2X = bB.m_sweep.c.x + r2X; + var p2Y = bB.m_sweep.c.y + r2Y; + var dX = p2X - p1X; + var dY = p2Y - p1Y; + var axis = bA.GetWorldVector(this.m_localXAxis1); + var v1 = bA.m_linearVelocity; + var v2 = bB.m_linearVelocity; + var w1 = bA.m_angularVelocity; + var w2 = bB.m_angularVelocity; + var speed = (dX * ((-w1 * axis.y)) + dY * (w1 * axis.x)) + (axis.x * (((v2.x + ((-w2 * r2Y))) - v1.x) - ((-w1 * r1Y))) + axis.y * (((v2.y + (w2 * r2X)) - v1.y) - (w1 * r1X))); + return speed; + } + b2LineJoint.prototype.IsLimitEnabled = function () { + return this.m_enableLimit; + } + b2LineJoint.prototype.EnableLimit = function (flag) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_enableLimit = flag; + } + b2LineJoint.prototype.GetLowerLimit = function () { + return this.m_lowerTranslation; + } + b2LineJoint.prototype.GetUpperLimit = function () { + return this.m_upperTranslation; + } + b2LineJoint.prototype.SetLimits = function (lower, upper) { + if (lower === undefined) lower = 0; + if (upper === undefined) upper = 0; + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_lowerTranslation = lower; + this.m_upperTranslation = upper; + } + b2LineJoint.prototype.IsMotorEnabled = function () { + return this.m_enableMotor; + } + b2LineJoint.prototype.EnableMotor = function (flag) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_enableMotor = flag; + } + b2LineJoint.prototype.SetMotorSpeed = function (speed) { + if (speed === undefined) speed = 0; + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_motorSpeed = speed; + } + b2LineJoint.prototype.GetMotorSpeed = function () { + return this.m_motorSpeed; + } + b2LineJoint.prototype.SetMaxMotorForce = function (force) { + if (force === undefined) force = 0; + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_maxMotorForce = force; + } + b2LineJoint.prototype.GetMaxMotorForce = function () { + return this.m_maxMotorForce; + } + b2LineJoint.prototype.GetMotorForce = function () { + return this.m_motorImpulse; + } + b2LineJoint.prototype.b2LineJoint = function (def) { + this.__super.b2Joint.call(this, def); + var tMat; + var tX = 0; + var tY = 0; + this.m_localAnchor1.SetV(def.localAnchorA); + this.m_localAnchor2.SetV(def.localAnchorB); + this.m_localXAxis1.SetV(def.localAxisA); + this.m_localYAxis1.x = (-this.m_localXAxis1.y); + this.m_localYAxis1.y = this.m_localXAxis1.x; + this.m_impulse.SetZero(); + this.m_motorMass = 0.0; + this.m_motorImpulse = 0.0; + this.m_lowerTranslation = def.lowerTranslation; + this.m_upperTranslation = def.upperTranslation; + this.m_maxMotorForce = def.maxMotorForce; + this.m_motorSpeed = def.motorSpeed; + this.m_enableLimit = def.enableLimit; + this.m_enableMotor = def.enableMotor; + this.m_limitState = b2Joint.e_inactiveLimit; + this.m_axis.SetZero(); + this.m_perp.SetZero(); + } + b2LineJoint.prototype.InitVelocityConstraints = function (step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var tX = 0; + this.m_localCenterA.SetV(bA.GetLocalCenter()); + this.m_localCenterB.SetV(bB.GetLocalCenter()); + var xf1 = bA.GetTransform(); + var xf2 = bB.GetTransform(); + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - this.m_localCenterA.x; + var r1Y = this.m_localAnchor1.y - this.m_localCenterA.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - this.m_localCenterB.x; + var r2Y = this.m_localAnchor2.y - this.m_localCenterB.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var dX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; + var dY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; + this.m_invMassA = bA.m_invMass; + this.m_invMassB = bB.m_invMass; + this.m_invIA = bA.m_invI; + this.m_invIB = bB.m_invI; { + this.m_axis.SetV(b2Math.MulMV(xf1.R, this.m_localXAxis1)); + this.m_a1 = (dX + r1X) * this.m_axis.y - (dY + r1Y) * this.m_axis.x; + this.m_a2 = r2X * this.m_axis.y - r2Y * this.m_axis.x; + this.m_motorMass = this.m_invMassA + this.m_invMassB + this.m_invIA * this.m_a1 * this.m_a1 + this.m_invIB * this.m_a2 * this.m_a2; + this.m_motorMass = this.m_motorMass > Number.MIN_VALUE ? 1.0 / this.m_motorMass : 0.0; + } { + this.m_perp.SetV(b2Math.MulMV(xf1.R, this.m_localYAxis1)); + this.m_s1 = (dX + r1X) * this.m_perp.y - (dY + r1Y) * this.m_perp.x; + this.m_s2 = r2X * this.m_perp.y - r2Y * this.m_perp.x; + var m1 = this.m_invMassA; + var m2 = this.m_invMassB; + var i1 = this.m_invIA; + var i2 = this.m_invIB; + this.m_K.col1.x = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; + this.m_K.col1.y = i1 * this.m_s1 * this.m_a1 + i2 * this.m_s2 * this.m_a2; + this.m_K.col2.x = this.m_K.col1.y; + this.m_K.col2.y = m1 + m2 + i1 * this.m_a1 * this.m_a1 + i2 * this.m_a2 * this.m_a2; + } + if (this.m_enableLimit) { + var jointTransition = this.m_axis.x * dX + this.m_axis.y * dY; + if (b2Math.Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2.0 * b2Settings.b2_linearSlop) { + this.m_limitState = b2Joint.e_equalLimits; + } + else if (jointTransition <= this.m_lowerTranslation) { + if (this.m_limitState != b2Joint.e_atLowerLimit) { + this.m_limitState = b2Joint.e_atLowerLimit; + this.m_impulse.y = 0.0; + } + } + else if (jointTransition >= this.m_upperTranslation) { + if (this.m_limitState != b2Joint.e_atUpperLimit) { + this.m_limitState = b2Joint.e_atUpperLimit; + this.m_impulse.y = 0.0; + } + } + else { + this.m_limitState = b2Joint.e_inactiveLimit; + this.m_impulse.y = 0.0; + } + } + else { + this.m_limitState = b2Joint.e_inactiveLimit; + } + if (this.m_enableMotor == false) { + this.m_motorImpulse = 0.0; + } + if (step.warmStarting) { + this.m_impulse.x *= step.dtRatio; + this.m_impulse.y *= step.dtRatio; + this.m_motorImpulse *= step.dtRatio; + var PX = this.m_impulse.x * this.m_perp.x + (this.m_motorImpulse + this.m_impulse.y) * this.m_axis.x; + var PY = this.m_impulse.x * this.m_perp.y + (this.m_motorImpulse + this.m_impulse.y) * this.m_axis.y; + var L1 = this.m_impulse.x * this.m_s1 + (this.m_motorImpulse + this.m_impulse.y) * this.m_a1; + var L2 = this.m_impulse.x * this.m_s2 + (this.m_motorImpulse + this.m_impulse.y) * this.m_a2; + bA.m_linearVelocity.x -= this.m_invMassA * PX; + bA.m_linearVelocity.y -= this.m_invMassA * PY; + bA.m_angularVelocity -= this.m_invIA * L1; + bB.m_linearVelocity.x += this.m_invMassB * PX; + bB.m_linearVelocity.y += this.m_invMassB * PY; + bB.m_angularVelocity += this.m_invIB * L2; + } + else { + this.m_impulse.SetZero(); + this.m_motorImpulse = 0.0; + } + } + b2LineJoint.prototype.SolveVelocityConstraints = function (step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var v1 = bA.m_linearVelocity; + var w1 = bA.m_angularVelocity; + var v2 = bB.m_linearVelocity; + var w2 = bB.m_angularVelocity; + var PX = 0; + var PY = 0; + var L1 = 0; + var L2 = 0; + if (this.m_enableMotor && this.m_limitState != b2Joint.e_equalLimits) { + var Cdot = this.m_axis.x * (v2.x - v1.x) + this.m_axis.y * (v2.y - v1.y) + this.m_a2 * w2 - this.m_a1 * w1; + var impulse = this.m_motorMass * (this.m_motorSpeed - Cdot); + var oldImpulse = this.m_motorImpulse; + var maxImpulse = step.dt * this.m_maxMotorForce; + this.m_motorImpulse = b2Math.Clamp(this.m_motorImpulse + impulse, (-maxImpulse), maxImpulse); + impulse = this.m_motorImpulse - oldImpulse; + PX = impulse * this.m_axis.x; + PY = impulse * this.m_axis.y; + L1 = impulse * this.m_a1; + L2 = impulse * this.m_a2; + v1.x -= this.m_invMassA * PX; + v1.y -= this.m_invMassA * PY; + w1 -= this.m_invIA * L1; + v2.x += this.m_invMassB * PX; + v2.y += this.m_invMassB * PY; + w2 += this.m_invIB * L2; + } + var Cdot1 = this.m_perp.x * (v2.x - v1.x) + this.m_perp.y * (v2.y - v1.y) + this.m_s2 * w2 - this.m_s1 * w1; + if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) { + var Cdot2 = this.m_axis.x * (v2.x - v1.x) + this.m_axis.y * (v2.y - v1.y) + this.m_a2 * w2 - this.m_a1 * w1; + var f1 = this.m_impulse.Copy(); + var df = this.m_K.Solve(new b2Vec2(), (-Cdot1), (-Cdot2)); + this.m_impulse.Add(df); + if (this.m_limitState == b2Joint.e_atLowerLimit) { + this.m_impulse.y = b2Math.Max(this.m_impulse.y, 0.0); + } + else if (this.m_limitState == b2Joint.e_atUpperLimit) { + this.m_impulse.y = b2Math.Min(this.m_impulse.y, 0.0); + } + var b = (-Cdot1) - (this.m_impulse.y - f1.y) * this.m_K.col2.x; + var f2r = 0; + if (this.m_K.col1.x != 0.0) { + f2r = b / this.m_K.col1.x + f1.x; + } + else { + f2r = f1.x; + } + this.m_impulse.x = f2r; + df.x = this.m_impulse.x - f1.x; + df.y = this.m_impulse.y - f1.y; + PX = df.x * this.m_perp.x + df.y * this.m_axis.x; + PY = df.x * this.m_perp.y + df.y * this.m_axis.y; + L1 = df.x * this.m_s1 + df.y * this.m_a1; + L2 = df.x * this.m_s2 + df.y * this.m_a2; + v1.x -= this.m_invMassA * PX; + v1.y -= this.m_invMassA * PY; + w1 -= this.m_invIA * L1; + v2.x += this.m_invMassB * PX; + v2.y += this.m_invMassB * PY; + w2 += this.m_invIB * L2; + } + else { + var df2 = 0; + if (this.m_K.col1.x != 0.0) { + df2 = ((-Cdot1)) / this.m_K.col1.x; + } + else { + df2 = 0.0; + } + this.m_impulse.x += df2; + PX = df2 * this.m_perp.x; + PY = df2 * this.m_perp.y; + L1 = df2 * this.m_s1; + L2 = df2 * this.m_s2; + v1.x -= this.m_invMassA * PX; + v1.y -= this.m_invMassA * PY; + w1 -= this.m_invIA * L1; + v2.x += this.m_invMassB * PX; + v2.y += this.m_invMassB * PY; + w2 += this.m_invIB * L2; + } + bA.m_linearVelocity.SetV(v1); + bA.m_angularVelocity = w1; + bB.m_linearVelocity.SetV(v2); + bB.m_angularVelocity = w2; + } + b2LineJoint.prototype.SolvePositionConstraints = function (baumgarte) { + if (baumgarte === undefined) baumgarte = 0; + var limitC = 0; + var oldLimitImpulse = 0; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var c1 = bA.m_sweep.c; + var a1 = bA.m_sweep.a; + var c2 = bB.m_sweep.c; + var a2 = bB.m_sweep.a; + var tMat; + var tX = 0; + var m1 = 0; + var m2 = 0; + var i1 = 0; + var i2 = 0; + var linearError = 0.0; + var angularError = 0.0; + var active = false; + var C2 = 0.0; + var R1 = b2Mat22.FromAngle(a1); + var R2 = b2Mat22.FromAngle(a2); + tMat = R1; + var r1X = this.m_localAnchor1.x - this.m_localCenterA.x; + var r1Y = this.m_localAnchor1.y - this.m_localCenterA.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = R2; + var r2X = this.m_localAnchor2.x - this.m_localCenterB.x; + var r2Y = this.m_localAnchor2.y - this.m_localCenterB.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var dX = c2.x + r2X - c1.x - r1X; + var dY = c2.y + r2Y - c1.y - r1Y; + if (this.m_enableLimit) { + this.m_axis = b2Math.MulMV(R1, this.m_localXAxis1); + this.m_a1 = (dX + r1X) * this.m_axis.y - (dY + r1Y) * this.m_axis.x; + this.m_a2 = r2X * this.m_axis.y - r2Y * this.m_axis.x; + var translation = this.m_axis.x * dX + this.m_axis.y * dY; + if (b2Math.Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2.0 * b2Settings.b2_linearSlop) { + C2 = b2Math.Clamp(translation, (-b2Settings.b2_maxLinearCorrection), b2Settings.b2_maxLinearCorrection); + linearError = b2Math.Abs(translation); + active = true; + } + else if (translation <= this.m_lowerTranslation) { + C2 = b2Math.Clamp(translation - this.m_lowerTranslation + b2Settings.b2_linearSlop, (-b2Settings.b2_maxLinearCorrection), 0.0); + linearError = this.m_lowerTranslation - translation; + active = true; + } + else if (translation >= this.m_upperTranslation) { + C2 = b2Math.Clamp(translation - this.m_upperTranslation + b2Settings.b2_linearSlop, 0.0, b2Settings.b2_maxLinearCorrection); + linearError = translation - this.m_upperTranslation; + active = true; + } + } + this.m_perp = b2Math.MulMV(R1, this.m_localYAxis1); + this.m_s1 = (dX + r1X) * this.m_perp.y - (dY + r1Y) * this.m_perp.x; + this.m_s2 = r2X * this.m_perp.y - r2Y * this.m_perp.x; + var impulse = new b2Vec2(); + var C1 = this.m_perp.x * dX + this.m_perp.y * dY; + linearError = b2Math.Max(linearError, b2Math.Abs(C1)); + angularError = 0.0; + if (active) { + m1 = this.m_invMassA; + m2 = this.m_invMassB; + i1 = this.m_invIA; + i2 = this.m_invIB; + this.m_K.col1.x = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; + this.m_K.col1.y = i1 * this.m_s1 * this.m_a1 + i2 * this.m_s2 * this.m_a2; + this.m_K.col2.x = this.m_K.col1.y; + this.m_K.col2.y = m1 + m2 + i1 * this.m_a1 * this.m_a1 + i2 * this.m_a2 * this.m_a2; + this.m_K.Solve(impulse, (-C1), (-C2)); + } + else { + m1 = this.m_invMassA; + m2 = this.m_invMassB; + i1 = this.m_invIA; + i2 = this.m_invIB; + var k11 = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; + var impulse1 = 0; + if (k11 != 0.0) { + impulse1 = ((-C1)) / k11; + } + else { + impulse1 = 0.0; + } + impulse.x = impulse1; + impulse.y = 0.0; + } + var PX = impulse.x * this.m_perp.x + impulse.y * this.m_axis.x; + var PY = impulse.x * this.m_perp.y + impulse.y * this.m_axis.y; + var L1 = impulse.x * this.m_s1 + impulse.y * this.m_a1; + var L2 = impulse.x * this.m_s2 + impulse.y * this.m_a2; + c1.x -= this.m_invMassA * PX; + c1.y -= this.m_invMassA * PY; + a1 -= this.m_invIA * L1; + c2.x += this.m_invMassB * PX; + c2.y += this.m_invMassB * PY; + a2 += this.m_invIB * L2; + bA.m_sweep.a = a1; + bB.m_sweep.a = a2; + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + + return linearError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop; + } + Box2D.inherit(b2LineJointDef, Box2D.Dynamics.Joints.b2JointDef); + b2LineJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; + b2LineJointDef.b2LineJointDef = function () { + Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); + this.localAnchorA = new b2Vec2(); + this.localAnchorB = new b2Vec2(); + this.localAxisA = new b2Vec2(); + }; + b2LineJointDef.prototype.b2LineJointDef = function () { + this.__super.b2JointDef.call(this); + this.type = b2Joint.e_lineJoint; + this.localAxisA.Set(1.0, 0.0); + this.enableLimit = false; + this.lowerTranslation = 0.0; + this.upperTranslation = 0.0; + this.enableMotor = false; + this.maxMotorForce = 0.0; + this.motorSpeed = 0.0; + } + b2LineJointDef.prototype.Initialize = function (bA, bB, anchor, axis) { + this.bodyA = bA; + this.bodyB = bB; + this.localAnchorA = this.bodyA.GetLocalPoint(anchor); + this.localAnchorB = this.bodyB.GetLocalPoint(anchor); + this.localAxisA = this.bodyA.GetLocalVector(axis); + } + Box2D.inherit(b2MouseJoint, Box2D.Dynamics.Joints.b2Joint); + b2MouseJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; + b2MouseJoint.b2MouseJoint = function () { + Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); + this.K = new b2Mat22(); + this.K1 = new b2Mat22(); + this.K2 = new b2Mat22(); + this.m_localAnchor = new b2Vec2(); + this.m_target = new b2Vec2(); + this.m_impulse = new b2Vec2(); + this.m_mass = new b2Mat22(); + this.m_C = new b2Vec2(); + }; + b2MouseJoint.prototype.GetAnchorA = function () { + return this.m_target; + } + b2MouseJoint.prototype.GetAnchorB = function () { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor); + } + b2MouseJoint.prototype.GetReactionForce = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return new b2Vec2(inv_dt * this.m_impulse.x, inv_dt * this.m_impulse.y); + } + b2MouseJoint.prototype.GetReactionTorque = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return 0.0; + } + b2MouseJoint.prototype.GetTarget = function () { + return this.m_target; + } + b2MouseJoint.prototype.SetTarget = function (target) { + if (this.m_bodyB.IsAwake() == false) { + this.m_bodyB.SetAwake(true); + } + this.m_target = target; + } + b2MouseJoint.prototype.GetMaxForce = function () { + return this.m_maxForce; + } + b2MouseJoint.prototype.SetMaxForce = function (maxForce) { + if (maxForce === undefined) maxForce = 0; + this.m_maxForce = maxForce; + } + b2MouseJoint.prototype.GetFrequency = function () { + return this.m_frequencyHz; + } + b2MouseJoint.prototype.SetFrequency = function (hz) { + if (hz === undefined) hz = 0; + this.m_frequencyHz = hz; + } + b2MouseJoint.prototype.GetDampingRatio = function () { + return this.m_dampingRatio; + } + b2MouseJoint.prototype.SetDampingRatio = function (ratio) { + if (ratio === undefined) ratio = 0; + this.m_dampingRatio = ratio; + } + b2MouseJoint.prototype.b2MouseJoint = function (def) { + this.__super.b2Joint.call(this, def); + this.m_target.SetV(def.target); + var tX = this.m_target.x - this.m_bodyB.m_xf.position.x; + var tY = this.m_target.y - this.m_bodyB.m_xf.position.y; + var tMat = this.m_bodyB.m_xf.R; + this.m_localAnchor.x = (tX * tMat.col1.x + tY * tMat.col1.y); + this.m_localAnchor.y = (tX * tMat.col2.x + tY * tMat.col2.y); + this.m_maxForce = def.maxForce; + this.m_impulse.SetZero(); + this.m_frequencyHz = def.frequencyHz; + this.m_dampingRatio = def.dampingRatio; + this.m_beta = 0.0; + this.m_gamma = 0.0; + } + b2MouseJoint.prototype.InitVelocityConstraints = function (step) { + var b = this.m_bodyB; + var mass = b.GetMass(); + var omega = 2.0 * Math.PI * this.m_frequencyHz; + var d = 2.0 * mass * this.m_dampingRatio * omega; + var k = mass * omega * omega; + this.m_gamma = step.dt * (d + step.dt * k); + this.m_gamma = this.m_gamma != 0 ? 1 / this.m_gamma : 0.0; + this.m_beta = step.dt * k * this.m_gamma; + var tMat;tMat = b.m_xf.R; + var rX = this.m_localAnchor.x - b.m_sweep.localCenter.x; + var rY = this.m_localAnchor.y - b.m_sweep.localCenter.y; + var tX = (tMat.col1.x * rX + tMat.col2.x * rY);rY = (tMat.col1.y * rX + tMat.col2.y * rY); + rX = tX; + var invMass = b.m_invMass; + var invI = b.m_invI;this.K1.col1.x = invMass; + this.K1.col2.x = 0.0; + this.K1.col1.y = 0.0; + this.K1.col2.y = invMass; + this.K2.col1.x = invI * rY * rY; + this.K2.col2.x = (-invI * rX * rY); + this.K2.col1.y = (-invI * rX * rY); + this.K2.col2.y = invI * rX * rX; + this.K.SetM(this.K1); + this.K.AddM(this.K2); + this.K.col1.x += this.m_gamma; + this.K.col2.y += this.m_gamma; + this.K.GetInverse(this.m_mass); + this.m_C.x = b.m_sweep.c.x + rX - this.m_target.x; + this.m_C.y = b.m_sweep.c.y + rY - this.m_target.y; + b.m_angularVelocity *= 0.98; + this.m_impulse.x *= step.dtRatio; + this.m_impulse.y *= step.dtRatio; + b.m_linearVelocity.x += invMass * this.m_impulse.x; + b.m_linearVelocity.y += invMass * this.m_impulse.y; + b.m_angularVelocity += invI * (rX * this.m_impulse.y - rY * this.m_impulse.x); + } + b2MouseJoint.prototype.SolveVelocityConstraints = function (step) { + var b = this.m_bodyB; + var tMat; + var tX = 0; + var tY = 0; + tMat = b.m_xf.R; + var rX = this.m_localAnchor.x - b.m_sweep.localCenter.x; + var rY = this.m_localAnchor.y - b.m_sweep.localCenter.y; + tX = (tMat.col1.x * rX + tMat.col2.x * rY); + rY = (tMat.col1.y * rX + tMat.col2.y * rY); + rX = tX; + var CdotX = b.m_linearVelocity.x + ((-b.m_angularVelocity * rY)); + var CdotY = b.m_linearVelocity.y + (b.m_angularVelocity * rX); + tMat = this.m_mass; + tX = CdotX + this.m_beta * this.m_C.x + this.m_gamma * this.m_impulse.x; + tY = CdotY + this.m_beta * this.m_C.y + this.m_gamma * this.m_impulse.y; + var impulseX = (-(tMat.col1.x * tX + tMat.col2.x * tY)); + var impulseY = (-(tMat.col1.y * tX + tMat.col2.y * tY)); + var oldImpulseX = this.m_impulse.x; + var oldImpulseY = this.m_impulse.y; + this.m_impulse.x += impulseX; + this.m_impulse.y += impulseY; + var maxImpulse = step.dt * this.m_maxForce; + if (this.m_impulse.LengthSquared() > maxImpulse * maxImpulse) { + this.m_impulse.Multiply(maxImpulse / this.m_impulse.Length()); + } + impulseX = this.m_impulse.x - oldImpulseX; + impulseY = this.m_impulse.y - oldImpulseY; + b.m_linearVelocity.x += b.m_invMass * impulseX; + b.m_linearVelocity.y += b.m_invMass * impulseY; + b.m_angularVelocity += b.m_invI * (rX * impulseY - rY * impulseX); + } + b2MouseJoint.prototype.SolvePositionConstraints = function (baumgarte) { + if (baumgarte === undefined) baumgarte = 0; + return true; + } + Box2D.inherit(b2MouseJointDef, Box2D.Dynamics.Joints.b2JointDef); + b2MouseJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; + b2MouseJointDef.b2MouseJointDef = function () { + Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); + this.target = new b2Vec2(); + }; + b2MouseJointDef.prototype.b2MouseJointDef = function () { + this.__super.b2JointDef.call(this); + this.type = b2Joint.e_mouseJoint; + this.maxForce = 0.0; + this.frequencyHz = 5.0; + this.dampingRatio = 0.7; + } + Box2D.inherit(b2PrismaticJoint, Box2D.Dynamics.Joints.b2Joint); + b2PrismaticJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; + b2PrismaticJoint.b2PrismaticJoint = function () { + Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); + this.m_localAnchor1 = new b2Vec2(); + this.m_localAnchor2 = new b2Vec2(); + this.m_localXAxis1 = new b2Vec2(); + this.m_localYAxis1 = new b2Vec2(); + this.m_axis = new b2Vec2(); + this.m_perp = new b2Vec2(); + this.m_K = new b2Mat33(); + this.m_impulse = new b2Vec3(); + }; + b2PrismaticJoint.prototype.GetAnchorA = function () { + return this.m_bodyA.GetWorldPoint(this.m_localAnchor1); + } + b2PrismaticJoint.prototype.GetAnchorB = function () { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor2); + } + b2PrismaticJoint.prototype.GetReactionForce = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return new b2Vec2(inv_dt * (this.m_impulse.x * this.m_perp.x + (this.m_motorImpulse + this.m_impulse.z) * this.m_axis.x), inv_dt * (this.m_impulse.x * this.m_perp.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_axis.y)); + } + b2PrismaticJoint.prototype.GetReactionTorque = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return inv_dt * this.m_impulse.y; + } + b2PrismaticJoint.prototype.GetJointTranslation = function () { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var p1 = bA.GetWorldPoint(this.m_localAnchor1); + var p2 = bB.GetWorldPoint(this.m_localAnchor2); + var dX = p2.x - p1.x; + var dY = p2.y - p1.y; + var axis = bA.GetWorldVector(this.m_localXAxis1); + var translation = axis.x * dX + axis.y * dY; + return translation; + } + b2PrismaticJoint.prototype.GetJointSpeed = function () { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var p1X = bA.m_sweep.c.x + r1X; + var p1Y = bA.m_sweep.c.y + r1Y; + var p2X = bB.m_sweep.c.x + r2X; + var p2Y = bB.m_sweep.c.y + r2Y; + var dX = p2X - p1X; + var dY = p2Y - p1Y; + var axis = bA.GetWorldVector(this.m_localXAxis1); + var v1 = bA.m_linearVelocity; + var v2 = bB.m_linearVelocity; + var w1 = bA.m_angularVelocity; + var w2 = bB.m_angularVelocity; + var speed = (dX * ((-w1 * axis.y)) + dY * (w1 * axis.x)) + (axis.x * (((v2.x + ((-w2 * r2Y))) - v1.x) - ((-w1 * r1Y))) + axis.y * (((v2.y + (w2 * r2X)) - v1.y) - (w1 * r1X))); + return speed; + } + b2PrismaticJoint.prototype.IsLimitEnabled = function () { + return this.m_enableLimit; + } + b2PrismaticJoint.prototype.EnableLimit = function (flag) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_enableLimit = flag; + } + b2PrismaticJoint.prototype.GetLowerLimit = function () { + return this.m_lowerTranslation; + } + b2PrismaticJoint.prototype.GetUpperLimit = function () { + return this.m_upperTranslation; + } + b2PrismaticJoint.prototype.SetLimits = function (lower, upper) { + if (lower === undefined) lower = 0; + if (upper === undefined) upper = 0; + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_lowerTranslation = lower; + this.m_upperTranslation = upper; + } + b2PrismaticJoint.prototype.IsMotorEnabled = function () { + return this.m_enableMotor; + } + b2PrismaticJoint.prototype.EnableMotor = function (flag) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_enableMotor = flag; + } + b2PrismaticJoint.prototype.SetMotorSpeed = function (speed) { + if (speed === undefined) speed = 0; + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_motorSpeed = speed; + } + b2PrismaticJoint.prototype.GetMotorSpeed = function () { + return this.m_motorSpeed; + } + b2PrismaticJoint.prototype.SetMaxMotorForce = function (force) { + if (force === undefined) force = 0; + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_maxMotorForce = force; + } + b2PrismaticJoint.prototype.GetMotorForce = function () { + return this.m_motorImpulse; + } + b2PrismaticJoint.prototype.b2PrismaticJoint = function (def) { + this.__super.b2Joint.call(this, def); + var tMat; + var tX = 0; + var tY = 0; + this.m_localAnchor1.SetV(def.localAnchorA); + this.m_localAnchor2.SetV(def.localAnchorB); + this.m_localXAxis1.SetV(def.localAxisA); + this.m_localYAxis1.x = (-this.m_localXAxis1.y); + this.m_localYAxis1.y = this.m_localXAxis1.x; + this.m_refAngle = def.referenceAngle; + this.m_impulse.SetZero(); + this.m_motorMass = 0.0; + this.m_motorImpulse = 0.0; + this.m_lowerTranslation = def.lowerTranslation; + this.m_upperTranslation = def.upperTranslation; + this.m_maxMotorForce = def.maxMotorForce; + this.m_motorSpeed = def.motorSpeed; + this.m_enableLimit = def.enableLimit; + this.m_enableMotor = def.enableMotor; + this.m_limitState = b2Joint.e_inactiveLimit; + this.m_axis.SetZero(); + this.m_perp.SetZero(); + } + b2PrismaticJoint.prototype.InitVelocityConstraints = function (step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var tX = 0; + this.m_localCenterA.SetV(bA.GetLocalCenter()); + this.m_localCenterB.SetV(bB.GetLocalCenter()); + var xf1 = bA.GetTransform(); + var xf2 = bB.GetTransform(); + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - this.m_localCenterA.x; + var r1Y = this.m_localAnchor1.y - this.m_localCenterA.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - this.m_localCenterB.x; + var r2Y = this.m_localAnchor2.y - this.m_localCenterB.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var dX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; + var dY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; + this.m_invMassA = bA.m_invMass; + this.m_invMassB = bB.m_invMass; + this.m_invIA = bA.m_invI; + this.m_invIB = bB.m_invI; { + this.m_axis.SetV(b2Math.MulMV(xf1.R, this.m_localXAxis1)); + this.m_a1 = (dX + r1X) * this.m_axis.y - (dY + r1Y) * this.m_axis.x; + this.m_a2 = r2X * this.m_axis.y - r2Y * this.m_axis.x; + this.m_motorMass = this.m_invMassA + this.m_invMassB + this.m_invIA * this.m_a1 * this.m_a1 + this.m_invIB * this.m_a2 * this.m_a2; + if (this.m_motorMass > Number.MIN_VALUE) this.m_motorMass = 1.0 / this.m_motorMass; + } { + this.m_perp.SetV(b2Math.MulMV(xf1.R, this.m_localYAxis1)); + this.m_s1 = (dX + r1X) * this.m_perp.y - (dY + r1Y) * this.m_perp.x; + this.m_s2 = r2X * this.m_perp.y - r2Y * this.m_perp.x; + var m1 = this.m_invMassA; + var m2 = this.m_invMassB; + var i1 = this.m_invIA; + var i2 = this.m_invIB; + this.m_K.col1.x = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; + this.m_K.col1.y = i1 * this.m_s1 + i2 * this.m_s2; + this.m_K.col1.z = i1 * this.m_s1 * this.m_a1 + i2 * this.m_s2 * this.m_a2; + this.m_K.col2.x = this.m_K.col1.y; + this.m_K.col2.y = i1 + i2; + this.m_K.col2.z = i1 * this.m_a1 + i2 * this.m_a2; + this.m_K.col3.x = this.m_K.col1.z; + this.m_K.col3.y = this.m_K.col2.z; + this.m_K.col3.z = m1 + m2 + i1 * this.m_a1 * this.m_a1 + i2 * this.m_a2 * this.m_a2; + } + if (this.m_enableLimit) { + var jointTransition = this.m_axis.x * dX + this.m_axis.y * dY; + if (b2Math.Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2.0 * b2Settings.b2_linearSlop) { + this.m_limitState = b2Joint.e_equalLimits; + } + else if (jointTransition <= this.m_lowerTranslation) { + if (this.m_limitState != b2Joint.e_atLowerLimit) { + this.m_limitState = b2Joint.e_atLowerLimit; + this.m_impulse.z = 0.0; + } + } + else if (jointTransition >= this.m_upperTranslation) { + if (this.m_limitState != b2Joint.e_atUpperLimit) { + this.m_limitState = b2Joint.e_atUpperLimit; + this.m_impulse.z = 0.0; + } + } + else { + this.m_limitState = b2Joint.e_inactiveLimit; + this.m_impulse.z = 0.0; + } + } + else { + this.m_limitState = b2Joint.e_inactiveLimit; + } + if (this.m_enableMotor == false) { + this.m_motorImpulse = 0.0; + } + if (step.warmStarting) { + this.m_impulse.x *= step.dtRatio; + this.m_impulse.y *= step.dtRatio; + this.m_motorImpulse *= step.dtRatio; + var PX = this.m_impulse.x * this.m_perp.x + (this.m_motorImpulse + this.m_impulse.z) * this.m_axis.x; + var PY = this.m_impulse.x * this.m_perp.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_axis.y; + var L1 = this.m_impulse.x * this.m_s1 + this.m_impulse.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_a1; + var L2 = this.m_impulse.x * this.m_s2 + this.m_impulse.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_a2; + bA.m_linearVelocity.x -= this.m_invMassA * PX; + bA.m_linearVelocity.y -= this.m_invMassA * PY; + bA.m_angularVelocity -= this.m_invIA * L1; + bB.m_linearVelocity.x += this.m_invMassB * PX; + bB.m_linearVelocity.y += this.m_invMassB * PY; + bB.m_angularVelocity += this.m_invIB * L2; + } + else { + this.m_impulse.SetZero(); + this.m_motorImpulse = 0.0; + } + } + b2PrismaticJoint.prototype.SolveVelocityConstraints = function (step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var v1 = bA.m_linearVelocity; + var w1 = bA.m_angularVelocity; + var v2 = bB.m_linearVelocity; + var w2 = bB.m_angularVelocity; + var PX = 0; + var PY = 0; + var L1 = 0; + var L2 = 0; + if (this.m_enableMotor && this.m_limitState != b2Joint.e_equalLimits) { + var Cdot = this.m_axis.x * (v2.x - v1.x) + this.m_axis.y * (v2.y - v1.y) + this.m_a2 * w2 - this.m_a1 * w1; + var impulse = this.m_motorMass * (this.m_motorSpeed - Cdot); + var oldImpulse = this.m_motorImpulse; + var maxImpulse = step.dt * this.m_maxMotorForce; + this.m_motorImpulse = b2Math.Clamp(this.m_motorImpulse + impulse, (-maxImpulse), maxImpulse); + impulse = this.m_motorImpulse - oldImpulse; + PX = impulse * this.m_axis.x; + PY = impulse * this.m_axis.y; + L1 = impulse * this.m_a1; + L2 = impulse * this.m_a2; + v1.x -= this.m_invMassA * PX; + v1.y -= this.m_invMassA * PY; + w1 -= this.m_invIA * L1; + v2.x += this.m_invMassB * PX; + v2.y += this.m_invMassB * PY; + w2 += this.m_invIB * L2; + } + var Cdot1X = this.m_perp.x * (v2.x - v1.x) + this.m_perp.y * (v2.y - v1.y) + this.m_s2 * w2 - this.m_s1 * w1; + var Cdot1Y = w2 - w1; + if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) { + var Cdot2 = this.m_axis.x * (v2.x - v1.x) + this.m_axis.y * (v2.y - v1.y) + this.m_a2 * w2 - this.m_a1 * w1; + var f1 = this.m_impulse.Copy(); + var df = this.m_K.Solve33(new b2Vec3(), (-Cdot1X), (-Cdot1Y), (-Cdot2)); + this.m_impulse.Add(df); + if (this.m_limitState == b2Joint.e_atLowerLimit) { + this.m_impulse.z = b2Math.Max(this.m_impulse.z, 0.0); + } + else if (this.m_limitState == b2Joint.e_atUpperLimit) { + this.m_impulse.z = b2Math.Min(this.m_impulse.z, 0.0); + } + var bX = (-Cdot1X) - (this.m_impulse.z - f1.z) * this.m_K.col3.x; + var bY = (-Cdot1Y) - (this.m_impulse.z - f1.z) * this.m_K.col3.y; + var f2r = this.m_K.Solve22(new b2Vec2(), bX, bY); + f2r.x += f1.x; + f2r.y += f1.y; + this.m_impulse.x = f2r.x; + this.m_impulse.y = f2r.y; + df.x = this.m_impulse.x - f1.x; + df.y = this.m_impulse.y - f1.y; + df.z = this.m_impulse.z - f1.z; + PX = df.x * this.m_perp.x + df.z * this.m_axis.x; + PY = df.x * this.m_perp.y + df.z * this.m_axis.y; + L1 = df.x * this.m_s1 + df.y + df.z * this.m_a1; + L2 = df.x * this.m_s2 + df.y + df.z * this.m_a2; + v1.x -= this.m_invMassA * PX; + v1.y -= this.m_invMassA * PY; + w1 -= this.m_invIA * L1; + v2.x += this.m_invMassB * PX; + v2.y += this.m_invMassB * PY; + w2 += this.m_invIB * L2; + } + else { + var df2 = this.m_K.Solve22(new b2Vec2(), (-Cdot1X), (-Cdot1Y)); + this.m_impulse.x += df2.x; + this.m_impulse.y += df2.y; + PX = df2.x * this.m_perp.x; + PY = df2.x * this.m_perp.y; + L1 = df2.x * this.m_s1 + df2.y; + L2 = df2.x * this.m_s2 + df2.y; + v1.x -= this.m_invMassA * PX; + v1.y -= this.m_invMassA * PY; + w1 -= this.m_invIA * L1; + v2.x += this.m_invMassB * PX; + v2.y += this.m_invMassB * PY; + w2 += this.m_invIB * L2; + } + bA.m_linearVelocity.SetV(v1); + bA.m_angularVelocity = w1; + bB.m_linearVelocity.SetV(v2); + bB.m_angularVelocity = w2; + } + b2PrismaticJoint.prototype.SolvePositionConstraints = function (baumgarte) { + if (baumgarte === undefined) baumgarte = 0; + var limitC = 0; + var oldLimitImpulse = 0; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var c1 = bA.m_sweep.c; + var a1 = bA.m_sweep.a; + var c2 = bB.m_sweep.c; + var a2 = bB.m_sweep.a; + var tMat; + var tX = 0; + var m1 = 0; + var m2 = 0; + var i1 = 0; + var i2 = 0; + var linearError = 0.0; + var angularError = 0.0; + var active = false; + var C2 = 0.0; + var R1 = b2Mat22.FromAngle(a1); + var R2 = b2Mat22.FromAngle(a2); + tMat = R1; + var r1X = this.m_localAnchor1.x - this.m_localCenterA.x; + var r1Y = this.m_localAnchor1.y - this.m_localCenterA.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = R2; + var r2X = this.m_localAnchor2.x - this.m_localCenterB.x; + var r2Y = this.m_localAnchor2.y - this.m_localCenterB.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var dX = c2.x + r2X - c1.x - r1X; + var dY = c2.y + r2Y - c1.y - r1Y; + if (this.m_enableLimit) { + this.m_axis = b2Math.MulMV(R1, this.m_localXAxis1); + this.m_a1 = (dX + r1X) * this.m_axis.y - (dY + r1Y) * this.m_axis.x; + this.m_a2 = r2X * this.m_axis.y - r2Y * this.m_axis.x; + var translation = this.m_axis.x * dX + this.m_axis.y * dY; + if (b2Math.Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2.0 * b2Settings.b2_linearSlop) { + C2 = b2Math.Clamp(translation, (-b2Settings.b2_maxLinearCorrection), b2Settings.b2_maxLinearCorrection); + linearError = b2Math.Abs(translation); + active = true; + } + else if (translation <= this.m_lowerTranslation) { + C2 = b2Math.Clamp(translation - this.m_lowerTranslation + b2Settings.b2_linearSlop, (-b2Settings.b2_maxLinearCorrection), 0.0); + linearError = this.m_lowerTranslation - translation; + active = true; + } + else if (translation >= this.m_upperTranslation) { + C2 = b2Math.Clamp(translation - this.m_upperTranslation + b2Settings.b2_linearSlop, 0.0, b2Settings.b2_maxLinearCorrection); + linearError = translation - this.m_upperTranslation; + active = true; + } + } + this.m_perp = b2Math.MulMV(R1, this.m_localYAxis1); + this.m_s1 = (dX + r1X) * this.m_perp.y - (dY + r1Y) * this.m_perp.x; + this.m_s2 = r2X * this.m_perp.y - r2Y * this.m_perp.x; + var impulse = new b2Vec3(); + var C1X = this.m_perp.x * dX + this.m_perp.y * dY; + var C1Y = a2 - a1 - this.m_refAngle; + linearError = b2Math.Max(linearError, b2Math.Abs(C1X)); + angularError = b2Math.Abs(C1Y); + if (active) { + m1 = this.m_invMassA; + m2 = this.m_invMassB; + i1 = this.m_invIA; + i2 = this.m_invIB; + this.m_K.col1.x = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; + this.m_K.col1.y = i1 * this.m_s1 + i2 * this.m_s2; + this.m_K.col1.z = i1 * this.m_s1 * this.m_a1 + i2 * this.m_s2 * this.m_a2; + this.m_K.col2.x = this.m_K.col1.y; + this.m_K.col2.y = i1 + i2; + this.m_K.col2.z = i1 * this.m_a1 + i2 * this.m_a2; + this.m_K.col3.x = this.m_K.col1.z; + this.m_K.col3.y = this.m_K.col2.z; + this.m_K.col3.z = m1 + m2 + i1 * this.m_a1 * this.m_a1 + i2 * this.m_a2 * this.m_a2; + this.m_K.Solve33(impulse, (-C1X), (-C1Y), (-C2)); + } + else { + m1 = this.m_invMassA; + m2 = this.m_invMassB; + i1 = this.m_invIA; + i2 = this.m_invIB; + var k11 = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; + var k12 = i1 * this.m_s1 + i2 * this.m_s2; + var k22 = i1 + i2; + this.m_K.col1.Set(k11, k12, 0.0); + this.m_K.col2.Set(k12, k22, 0.0); + var impulse1 = this.m_K.Solve22(new b2Vec2(), (-C1X), (-C1Y)); + impulse.x = impulse1.x; + impulse.y = impulse1.y; + impulse.z = 0.0; + } + var PX = impulse.x * this.m_perp.x + impulse.z * this.m_axis.x; + var PY = impulse.x * this.m_perp.y + impulse.z * this.m_axis.y; + var L1 = impulse.x * this.m_s1 + impulse.y + impulse.z * this.m_a1; + var L2 = impulse.x * this.m_s2 + impulse.y + impulse.z * this.m_a2; + c1.x -= this.m_invMassA * PX; + c1.y -= this.m_invMassA * PY; + a1 -= this.m_invIA * L1; + c2.x += this.m_invMassB * PX; + c2.y += this.m_invMassB * PY; + a2 += this.m_invIB * L2; + bA.m_sweep.a = a1; + bB.m_sweep.a = a2; + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + return linearError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop; + } + Box2D.inherit(b2PrismaticJointDef, Box2D.Dynamics.Joints.b2JointDef); + b2PrismaticJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; + b2PrismaticJointDef.b2PrismaticJointDef = function () { + Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); + this.localAnchorA = new b2Vec2(); + this.localAnchorB = new b2Vec2(); + this.localAxisA = new b2Vec2(); + }; + b2PrismaticJointDef.prototype.b2PrismaticJointDef = function () { + this.__super.b2JointDef.call(this); + this.type = b2Joint.e_prismaticJoint; + this.localAxisA.Set(1.0, 0.0); + this.referenceAngle = 0.0; + this.enableLimit = false; + this.lowerTranslation = 0.0; + this.upperTranslation = 0.0; + this.enableMotor = false; + this.maxMotorForce = 0.0; + this.motorSpeed = 0.0; + } + b2PrismaticJointDef.prototype.Initialize = function (bA, bB, anchor, axis) { + this.bodyA = bA; + this.bodyB = bB; + this.localAnchorA = this.bodyA.GetLocalPoint(anchor); + this.localAnchorB = this.bodyB.GetLocalPoint(anchor); + this.localAxisA = this.bodyA.GetLocalVector(axis); + this.referenceAngle = this.bodyB.GetAngle() - this.bodyA.GetAngle(); + } + Box2D.inherit(b2PulleyJoint, Box2D.Dynamics.Joints.b2Joint); + b2PulleyJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; + b2PulleyJoint.b2PulleyJoint = function () { + Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); + this.m_groundAnchor1 = new b2Vec2(); + this.m_groundAnchor2 = new b2Vec2(); + this.m_localAnchor1 = new b2Vec2(); + this.m_localAnchor2 = new b2Vec2(); + this.m_u1 = new b2Vec2(); + this.m_u2 = new b2Vec2(); + }; + b2PulleyJoint.prototype.GetAnchorA = function () { + return this.m_bodyA.GetWorldPoint(this.m_localAnchor1); + } + b2PulleyJoint.prototype.GetAnchorB = function () { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor2); + } + b2PulleyJoint.prototype.GetReactionForce = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return new b2Vec2(inv_dt * this.m_impulse * this.m_u2.x, inv_dt * this.m_impulse * this.m_u2.y); + } + b2PulleyJoint.prototype.GetReactionTorque = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return 0.0; + } + b2PulleyJoint.prototype.GetGroundAnchorA = function () { + var a = this.m_ground.m_xf.position.Copy(); + a.Add(this.m_groundAnchor1); + return a; + } + b2PulleyJoint.prototype.GetGroundAnchorB = function () { + var a = this.m_ground.m_xf.position.Copy(); + a.Add(this.m_groundAnchor2); + return a; + } + b2PulleyJoint.prototype.GetLength1 = function () { + var p = this.m_bodyA.GetWorldPoint(this.m_localAnchor1); + var sX = this.m_ground.m_xf.position.x + this.m_groundAnchor1.x; + var sY = this.m_ground.m_xf.position.y + this.m_groundAnchor1.y; + var dX = p.x - sX; + var dY = p.y - sY; + return Math.sqrt(dX * dX + dY * dY); + } + b2PulleyJoint.prototype.GetLength2 = function () { + var p = this.m_bodyB.GetWorldPoint(this.m_localAnchor2); + var sX = this.m_ground.m_xf.position.x + this.m_groundAnchor2.x; + var sY = this.m_ground.m_xf.position.y + this.m_groundAnchor2.y; + var dX = p.x - sX; + var dY = p.y - sY; + return Math.sqrt(dX * dX + dY * dY); + } + b2PulleyJoint.prototype.GetRatio = function () { + return this.m_ratio; + } + b2PulleyJoint.prototype.b2PulleyJoint = function (def) { + this.__super.b2Joint.call(this, def); + var tMat; + var tX = 0; + var tY = 0; + this.m_ground = this.m_bodyA.m_world.m_groundBody; + this.m_groundAnchor1.x = def.groundAnchorA.x - this.m_ground.m_xf.position.x; + this.m_groundAnchor1.y = def.groundAnchorA.y - this.m_ground.m_xf.position.y; + this.m_groundAnchor2.x = def.groundAnchorB.x - this.m_ground.m_xf.position.x; + this.m_groundAnchor2.y = def.groundAnchorB.y - this.m_ground.m_xf.position.y; + this.m_localAnchor1.SetV(def.localAnchorA); + this.m_localAnchor2.SetV(def.localAnchorB); + this.m_ratio = def.ratio; + this.m_constant = def.lengthA + this.m_ratio * def.lengthB; + this.m_maxLength1 = b2Math.Min(def.maxLengthA, this.m_constant - this.m_ratio * b2PulleyJoint.b2_minPulleyLength); + this.m_maxLength2 = b2Math.Min(def.maxLengthB, (this.m_constant - b2PulleyJoint.b2_minPulleyLength) / this.m_ratio); + this.m_impulse = 0.0; + this.m_limitImpulse1 = 0.0; + this.m_limitImpulse2 = 0.0; + } + b2PulleyJoint.prototype.InitVelocityConstraints = function (step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var p1X = bA.m_sweep.c.x + r1X; + var p1Y = bA.m_sweep.c.y + r1Y; + var p2X = bB.m_sweep.c.x + r2X; + var p2Y = bB.m_sweep.c.y + r2Y; + var s1X = this.m_ground.m_xf.position.x + this.m_groundAnchor1.x; + var s1Y = this.m_ground.m_xf.position.y + this.m_groundAnchor1.y; + var s2X = this.m_ground.m_xf.position.x + this.m_groundAnchor2.x; + var s2Y = this.m_ground.m_xf.position.y + this.m_groundAnchor2.y; + this.m_u1.Set(p1X - s1X, p1Y - s1Y); + this.m_u2.Set(p2X - s2X, p2Y - s2Y); + var length1 = this.m_u1.Length(); + var length2 = this.m_u2.Length(); + if (length1 > b2Settings.b2_linearSlop) { + this.m_u1.Multiply(1.0 / length1); + } + else { + this.m_u1.SetZero(); + } + if (length2 > b2Settings.b2_linearSlop) { + this.m_u2.Multiply(1.0 / length2); + } + else { + this.m_u2.SetZero(); + } + var C = this.m_constant - length1 - this.m_ratio * length2; + if (C > 0.0) { + this.m_state = b2Joint.e_inactiveLimit; + this.m_impulse = 0.0; + } + else { + this.m_state = b2Joint.e_atUpperLimit; + } + if (length1 < this.m_maxLength1) { + this.m_limitState1 = b2Joint.e_inactiveLimit; + this.m_limitImpulse1 = 0.0; + } + else { + this.m_limitState1 = b2Joint.e_atUpperLimit; + } + if (length2 < this.m_maxLength2) { + this.m_limitState2 = b2Joint.e_inactiveLimit; + this.m_limitImpulse2 = 0.0; + } + else { + this.m_limitState2 = b2Joint.e_atUpperLimit; + } + var cr1u1 = r1X * this.m_u1.y - r1Y * this.m_u1.x; + var cr2u2 = r2X * this.m_u2.y - r2Y * this.m_u2.x; + this.m_limitMass1 = bA.m_invMass + bA.m_invI * cr1u1 * cr1u1; + this.m_limitMass2 = bB.m_invMass + bB.m_invI * cr2u2 * cr2u2; + this.m_pulleyMass = this.m_limitMass1 + this.m_ratio * this.m_ratio * this.m_limitMass2; + this.m_limitMass1 = 1.0 / this.m_limitMass1; + this.m_limitMass2 = 1.0 / this.m_limitMass2; + this.m_pulleyMass = 1.0 / this.m_pulleyMass; + if (step.warmStarting) { + this.m_impulse *= step.dtRatio; + this.m_limitImpulse1 *= step.dtRatio; + this.m_limitImpulse2 *= step.dtRatio; + var P1X = ((-this.m_impulse) - this.m_limitImpulse1) * this.m_u1.x; + var P1Y = ((-this.m_impulse) - this.m_limitImpulse1) * this.m_u1.y; + var P2X = ((-this.m_ratio * this.m_impulse) - this.m_limitImpulse2) * this.m_u2.x; + var P2Y = ((-this.m_ratio * this.m_impulse) - this.m_limitImpulse2) * this.m_u2.y; + bA.m_linearVelocity.x += bA.m_invMass * P1X; + bA.m_linearVelocity.y += bA.m_invMass * P1Y; + bA.m_angularVelocity += bA.m_invI * (r1X * P1Y - r1Y * P1X); + bB.m_linearVelocity.x += bB.m_invMass * P2X; + bB.m_linearVelocity.y += bB.m_invMass * P2Y; + bB.m_angularVelocity += bB.m_invI * (r2X * P2Y - r2Y * P2X); + } + else { + this.m_impulse = 0.0; + this.m_limitImpulse1 = 0.0; + this.m_limitImpulse2 = 0.0; + } + } + b2PulleyJoint.prototype.SolveVelocityConstraints = function (step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var v1X = 0; + var v1Y = 0; + var v2X = 0; + var v2Y = 0; + var P1X = 0; + var P1Y = 0; + var P2X = 0; + var P2Y = 0; + var Cdot = 0; + var impulse = 0; + var oldImpulse = 0; + if (this.m_state == b2Joint.e_atUpperLimit) { + v1X = bA.m_linearVelocity.x + ((-bA.m_angularVelocity * r1Y)); + v1Y = bA.m_linearVelocity.y + (bA.m_angularVelocity * r1X); + v2X = bB.m_linearVelocity.x + ((-bB.m_angularVelocity * r2Y)); + v2Y = bB.m_linearVelocity.y + (bB.m_angularVelocity * r2X); + Cdot = (-(this.m_u1.x * v1X + this.m_u1.y * v1Y)) - this.m_ratio * (this.m_u2.x * v2X + this.m_u2.y * v2Y); + impulse = this.m_pulleyMass * ((-Cdot)); + oldImpulse = this.m_impulse; + this.m_impulse = b2Math.Max(0.0, this.m_impulse + impulse); + impulse = this.m_impulse - oldImpulse; + P1X = (-impulse * this.m_u1.x); + P1Y = (-impulse * this.m_u1.y); + P2X = (-this.m_ratio * impulse * this.m_u2.x); + P2Y = (-this.m_ratio * impulse * this.m_u2.y); + bA.m_linearVelocity.x += bA.m_invMass * P1X; + bA.m_linearVelocity.y += bA.m_invMass * P1Y; + bA.m_angularVelocity += bA.m_invI * (r1X * P1Y - r1Y * P1X); + bB.m_linearVelocity.x += bB.m_invMass * P2X; + bB.m_linearVelocity.y += bB.m_invMass * P2Y; + bB.m_angularVelocity += bB.m_invI * (r2X * P2Y - r2Y * P2X); + } + if (this.m_limitState1 == b2Joint.e_atUpperLimit) { + v1X = bA.m_linearVelocity.x + ((-bA.m_angularVelocity * r1Y)); + v1Y = bA.m_linearVelocity.y + (bA.m_angularVelocity * r1X); + Cdot = (-(this.m_u1.x * v1X + this.m_u1.y * v1Y)); + impulse = (-this.m_limitMass1 * Cdot); + oldImpulse = this.m_limitImpulse1; + this.m_limitImpulse1 = b2Math.Max(0.0, this.m_limitImpulse1 + impulse); + impulse = this.m_limitImpulse1 - oldImpulse; + P1X = (-impulse * this.m_u1.x); + P1Y = (-impulse * this.m_u1.y); + bA.m_linearVelocity.x += bA.m_invMass * P1X; + bA.m_linearVelocity.y += bA.m_invMass * P1Y; + bA.m_angularVelocity += bA.m_invI * (r1X * P1Y - r1Y * P1X); + } + if (this.m_limitState2 == b2Joint.e_atUpperLimit) { + v2X = bB.m_linearVelocity.x + ((-bB.m_angularVelocity * r2Y)); + v2Y = bB.m_linearVelocity.y + (bB.m_angularVelocity * r2X); + Cdot = (-(this.m_u2.x * v2X + this.m_u2.y * v2Y)); + impulse = (-this.m_limitMass2 * Cdot); + oldImpulse = this.m_limitImpulse2; + this.m_limitImpulse2 = b2Math.Max(0.0, this.m_limitImpulse2 + impulse); + impulse = this.m_limitImpulse2 - oldImpulse; + P2X = (-impulse * this.m_u2.x); + P2Y = (-impulse * this.m_u2.y); + bB.m_linearVelocity.x += bB.m_invMass * P2X; + bB.m_linearVelocity.y += bB.m_invMass * P2Y; + bB.m_angularVelocity += bB.m_invI * (r2X * P2Y - r2Y * P2X); + } + } + b2PulleyJoint.prototype.SolvePositionConstraints = function (baumgarte) { + if (baumgarte === undefined) baumgarte = 0; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var s1X = this.m_ground.m_xf.position.x + this.m_groundAnchor1.x; + var s1Y = this.m_ground.m_xf.position.y + this.m_groundAnchor1.y; + var s2X = this.m_ground.m_xf.position.x + this.m_groundAnchor2.x; + var s2Y = this.m_ground.m_xf.position.y + this.m_groundAnchor2.y; + var r1X = 0; + var r1Y = 0; + var r2X = 0; + var r2Y = 0; + var p1X = 0; + var p1Y = 0; + var p2X = 0; + var p2Y = 0; + var length1 = 0; + var length2 = 0; + var C = 0; + var impulse = 0; + var oldImpulse = 0; + var oldLimitPositionImpulse = 0; + var tX = 0; + var linearError = 0.0; + if (this.m_state == b2Joint.e_atUpperLimit) { + tMat = bA.m_xf.R; + r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + p1X = bA.m_sweep.c.x + r1X; + p1Y = bA.m_sweep.c.y + r1Y; + p2X = bB.m_sweep.c.x + r2X; + p2Y = bB.m_sweep.c.y + r2Y; + this.m_u1.Set(p1X - s1X, p1Y - s1Y); + this.m_u2.Set(p2X - s2X, p2Y - s2Y); + length1 = this.m_u1.Length(); + length2 = this.m_u2.Length(); + if (length1 > b2Settings.b2_linearSlop) { + this.m_u1.Multiply(1.0 / length1); + } + else { + this.m_u1.SetZero(); + } + if (length2 > b2Settings.b2_linearSlop) { + this.m_u2.Multiply(1.0 / length2); + } + else { + this.m_u2.SetZero(); + } + C = this.m_constant - length1 - this.m_ratio * length2; + linearError = b2Math.Max(linearError, (-C)); + C = b2Math.Clamp(C + b2Settings.b2_linearSlop, (-b2Settings.b2_maxLinearCorrection), 0.0); + impulse = (-this.m_pulleyMass * C); + p1X = (-impulse * this.m_u1.x); + p1Y = (-impulse * this.m_u1.y); + p2X = (-this.m_ratio * impulse * this.m_u2.x); + p2Y = (-this.m_ratio * impulse * this.m_u2.y); + bA.m_sweep.c.x += bA.m_invMass * p1X; + bA.m_sweep.c.y += bA.m_invMass * p1Y; + bA.m_sweep.a += bA.m_invI * (r1X * p1Y - r1Y * p1X); + bB.m_sweep.c.x += bB.m_invMass * p2X; + bB.m_sweep.c.y += bB.m_invMass * p2Y; + bB.m_sweep.a += bB.m_invI * (r2X * p2Y - r2Y * p2X); + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + } + if (this.m_limitState1 == b2Joint.e_atUpperLimit) { + tMat = bA.m_xf.R; + r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + p1X = bA.m_sweep.c.x + r1X; + p1Y = bA.m_sweep.c.y + r1Y; + this.m_u1.Set(p1X - s1X, p1Y - s1Y); + length1 = this.m_u1.Length(); + if (length1 > b2Settings.b2_linearSlop) { + this.m_u1.x *= 1.0 / length1; + this.m_u1.y *= 1.0 / length1; + } + else { + this.m_u1.SetZero(); + } + C = this.m_maxLength1 - length1; + linearError = b2Math.Max(linearError, (-C)); + C = b2Math.Clamp(C + b2Settings.b2_linearSlop, (-b2Settings.b2_maxLinearCorrection), 0.0); + impulse = (-this.m_limitMass1 * C); + p1X = (-impulse * this.m_u1.x); + p1Y = (-impulse * this.m_u1.y); + bA.m_sweep.c.x += bA.m_invMass * p1X; + bA.m_sweep.c.y += bA.m_invMass * p1Y; + bA.m_sweep.a += bA.m_invI * (r1X * p1Y - r1Y * p1X); + bA.SynchronizeTransform(); + } + if (this.m_limitState2 == b2Joint.e_atUpperLimit) { + tMat = bB.m_xf.R; + r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + p2X = bB.m_sweep.c.x + r2X; + p2Y = bB.m_sweep.c.y + r2Y; + this.m_u2.Set(p2X - s2X, p2Y - s2Y); + length2 = this.m_u2.Length(); + if (length2 > b2Settings.b2_linearSlop) { + this.m_u2.x *= 1.0 / length2; + this.m_u2.y *= 1.0 / length2; + } + else { + this.m_u2.SetZero(); + } + C = this.m_maxLength2 - length2; + linearError = b2Math.Max(linearError, (-C)); + C = b2Math.Clamp(C + b2Settings.b2_linearSlop, (-b2Settings.b2_maxLinearCorrection), 0.0); + impulse = (-this.m_limitMass2 * C); + p2X = (-impulse * this.m_u2.x); + p2Y = (-impulse * this.m_u2.y); + bB.m_sweep.c.x += bB.m_invMass * p2X; + bB.m_sweep.c.y += bB.m_invMass * p2Y; + bB.m_sweep.a += bB.m_invI * (r2X * p2Y - r2Y * p2X); + bB.SynchronizeTransform(); + } + return linearError < b2Settings.b2_linearSlop; + } + Box2D.postDefs.push(function () { + Box2D.Dynamics.Joints.b2PulleyJoint.b2_minPulleyLength = 2.0; + }); + Box2D.inherit(b2PulleyJointDef, Box2D.Dynamics.Joints.b2JointDef); + b2PulleyJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; + b2PulleyJointDef.b2PulleyJointDef = function () { + Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); + this.groundAnchorA = new b2Vec2(); + this.groundAnchorB = new b2Vec2(); + this.localAnchorA = new b2Vec2(); + this.localAnchorB = new b2Vec2(); + }; + b2PulleyJointDef.prototype.b2PulleyJointDef = function () { + this.__super.b2JointDef.call(this); + this.type = b2Joint.e_pulleyJoint; + this.groundAnchorA.Set((-1.0), 1.0); + this.groundAnchorB.Set(1.0, 1.0); + this.localAnchorA.Set((-1.0), 0.0); + this.localAnchorB.Set(1.0, 0.0); + this.lengthA = 0.0; + this.maxLengthA = 0.0; + this.lengthB = 0.0; + this.maxLengthB = 0.0; + this.ratio = 1.0; + this.collideConnected = true; + } + b2PulleyJointDef.prototype.Initialize = function (bA, bB, gaA, gaB, anchorA, anchorB, r) { + if (r === undefined) r = 0; + this.bodyA = bA; + this.bodyB = bB; + this.groundAnchorA.SetV(gaA); + this.groundAnchorB.SetV(gaB); + this.localAnchorA = this.bodyA.GetLocalPoint(anchorA); + this.localAnchorB = this.bodyB.GetLocalPoint(anchorB); + var d1X = anchorA.x - gaA.x; + var d1Y = anchorA.y - gaA.y; + this.lengthA = Math.sqrt(d1X * d1X + d1Y * d1Y); + var d2X = anchorB.x - gaB.x; + var d2Y = anchorB.y - gaB.y; + this.lengthB = Math.sqrt(d2X * d2X + d2Y * d2Y); + this.ratio = r; + var C = this.lengthA + this.ratio * this.lengthB; + this.maxLengthA = C - this.ratio * b2PulleyJoint.b2_minPulleyLength; + this.maxLengthB = (C - b2PulleyJoint.b2_minPulleyLength) / this.ratio; + } + Box2D.inherit(b2RevoluteJoint, Box2D.Dynamics.Joints.b2Joint); + b2RevoluteJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; + b2RevoluteJoint.b2RevoluteJoint = function () { + Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); + this.K = new b2Mat22(); + this.K1 = new b2Mat22(); + this.K2 = new b2Mat22(); + this.K3 = new b2Mat22(); + this.impulse3 = new b2Vec3(); + this.impulse2 = new b2Vec2(); + this.reduced = new b2Vec2(); + this.m_localAnchor1 = new b2Vec2(); + this.m_localAnchor2 = new b2Vec2(); + this.m_impulse = new b2Vec3(); + this.m_mass = new b2Mat33(); + }; + b2RevoluteJoint.prototype.GetAnchorA = function () { + return this.m_bodyA.GetWorldPoint(this.m_localAnchor1); + } + b2RevoluteJoint.prototype.GetAnchorB = function () { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor2); + } + b2RevoluteJoint.prototype.GetReactionForce = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return new b2Vec2(inv_dt * this.m_impulse.x, inv_dt * this.m_impulse.y); + } + b2RevoluteJoint.prototype.GetReactionTorque = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return inv_dt * this.m_impulse.z; + } + b2RevoluteJoint.prototype.GetJointAngle = function () { + return this.m_bodyB.m_sweep.a - this.m_bodyA.m_sweep.a - this.m_referenceAngle; + } + b2RevoluteJoint.prototype.GetJointSpeed = function () { + return this.m_bodyB.m_angularVelocity - this.m_bodyA.m_angularVelocity; + } + b2RevoluteJoint.prototype.IsLimitEnabled = function () { + return this.m_enableLimit; + } + b2RevoluteJoint.prototype.EnableLimit = function (flag) { + this.m_enableLimit = flag; + } + b2RevoluteJoint.prototype.GetLowerLimit = function () { + return this.m_lowerAngle; + } + b2RevoluteJoint.prototype.GetUpperLimit = function () { + return this.m_upperAngle; + } + b2RevoluteJoint.prototype.SetLimits = function (lower, upper) { + + if (lower === undefined) lower = 0; + if (upper === undefined) upper = 0; + this.m_lowerAngle = lower; + this.m_upperAngle = upper; + } + b2RevoluteJoint.prototype.IsMotorEnabled = function () { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + return this.m_enableMotor; + } + b2RevoluteJoint.prototype.EnableMotor = function (flag) { + this.m_enableMotor = flag; + } + b2RevoluteJoint.prototype.SetMotorSpeed = function (speed) { + if (speed === undefined) speed = 0; + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_motorSpeed = speed; + } + b2RevoluteJoint.prototype.GetMotorSpeed = function () { + return this.m_motorSpeed; + } + b2RevoluteJoint.prototype.SetMaxMotorTorque = function (torque) { + if (torque === undefined) torque = 0; + this.m_maxMotorTorque = torque; + } + b2RevoluteJoint.prototype.GetMotorTorque = function () { + return this.m_maxMotorTorque; + } + b2RevoluteJoint.prototype.b2RevoluteJoint = function (def) { + this.__super.b2Joint.call(this, def); + this.m_localAnchor1.SetV(def.localAnchorA); + this.m_localAnchor2.SetV(def.localAnchorB); + this.m_referenceAngle = def.referenceAngle; + this.m_impulse.SetZero(); + this.m_motorImpulse = 0.0; + this.m_lowerAngle = def.lowerAngle; + this.m_upperAngle = def.upperAngle; + this.m_maxMotorTorque = def.maxMotorTorque; + this.m_motorSpeed = def.motorSpeed; + this.m_enableLimit = def.enableLimit; + this.m_enableMotor = def.enableMotor; + this.m_limitState = b2Joint.e_inactiveLimit; + } + b2RevoluteJoint.prototype.InitVelocityConstraints = function (step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var tX = 0; + if (this.m_enableMotor || this.m_enableLimit) {} + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var m1 = bA.m_invMass; + var m2 = bB.m_invMass; + var i1 = bA.m_invI; + var i2 = bB.m_invI; + this.m_mass.col1.x = m1 + m2 + r1Y * r1Y * i1 + r2Y * r2Y * i2; + this.m_mass.col2.x = (-r1Y * r1X * i1) - r2Y * r2X * i2; + this.m_mass.col3.x = (-r1Y * i1) - r2Y * i2; + this.m_mass.col1.y = this.m_mass.col2.x; + this.m_mass.col2.y = m1 + m2 + r1X * r1X * i1 + r2X * r2X * i2; + this.m_mass.col3.y = r1X * i1 + r2X * i2; + this.m_mass.col1.z = this.m_mass.col3.x; + this.m_mass.col2.z = this.m_mass.col3.y; + this.m_mass.col3.z = i1 + i2; + this.m_motorMass = 1.0 / (i1 + i2); + if (this.m_enableMotor == false) { + this.m_motorImpulse = 0.0; + } + if (this.m_enableLimit) { + var jointAngle = bB.m_sweep.a - bA.m_sweep.a - this.m_referenceAngle; + if (b2Math.Abs(this.m_upperAngle - this.m_lowerAngle) < 2.0 * b2Settings.b2_angularSlop) { + this.m_limitState = b2Joint.e_equalLimits; + } + else if (jointAngle <= this.m_lowerAngle) { + if (this.m_limitState != b2Joint.e_atLowerLimit) { + this.m_impulse.z = 0.0; + } + this.m_limitState = b2Joint.e_atLowerLimit; + } + else if (jointAngle >= this.m_upperAngle) { + if (this.m_limitState != b2Joint.e_atUpperLimit) { + this.m_impulse.z = 0.0; + } + this.m_limitState = b2Joint.e_atUpperLimit; + } + else { + this.m_limitState = b2Joint.e_inactiveLimit; + this.m_impulse.z = 0.0; + } + } + else { + this.m_limitState = b2Joint.e_inactiveLimit; + } + if (step.warmStarting) { + this.m_impulse.x *= step.dtRatio; + this.m_impulse.y *= step.dtRatio; + this.m_motorImpulse *= step.dtRatio; + var PX = this.m_impulse.x; + var PY = this.m_impulse.y; + bA.m_linearVelocity.x -= m1 * PX; + bA.m_linearVelocity.y -= m1 * PY; + bA.m_angularVelocity -= i1 * ((r1X * PY - r1Y * PX) + this.m_motorImpulse + this.m_impulse.z); + bB.m_linearVelocity.x += m2 * PX; + bB.m_linearVelocity.y += m2 * PY; + bB.m_angularVelocity += i2 * ((r2X * PY - r2Y * PX) + this.m_motorImpulse + this.m_impulse.z); + } + else { + this.m_impulse.SetZero(); + this.m_motorImpulse = 0.0; + } + } + b2RevoluteJoint.prototype.SolveVelocityConstraints = function (step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var tX = 0; + var newImpulse = 0; + var r1X = 0; + var r1Y = 0; + var r2X = 0; + var r2Y = 0; + var v1 = bA.m_linearVelocity; + var w1 = bA.m_angularVelocity; + var v2 = bB.m_linearVelocity; + var w2 = bB.m_angularVelocity; + var m1 = bA.m_invMass; + var m2 = bB.m_invMass; + var i1 = bA.m_invI; + var i2 = bB.m_invI; + if (this.m_enableMotor && this.m_limitState != b2Joint.e_equalLimits) { + var Cdot = w2 - w1 - this.m_motorSpeed; + var impulse = this.m_motorMass * ((-Cdot)); + var oldImpulse = this.m_motorImpulse; + var maxImpulse = step.dt * this.m_maxMotorTorque; + this.m_motorImpulse = b2Math.Clamp(this.m_motorImpulse + impulse, (-maxImpulse), maxImpulse); + impulse = this.m_motorImpulse - oldImpulse; + w1 -= i1 * impulse; + w2 += i2 * impulse; + } + if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) { + tMat = bA.m_xf.R; + r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var Cdot1X = v2.x + ((-w2 * r2Y)) - v1.x - ((-w1 * r1Y)); + var Cdot1Y = v2.y + (w2 * r2X) - v1.y - (w1 * r1X); + var Cdot2 = w2 - w1; + this.m_mass.Solve33(this.impulse3, (-Cdot1X), (-Cdot1Y), (-Cdot2)); + if (this.m_limitState == b2Joint.e_equalLimits) { + this.m_impulse.Add(this.impulse3); + } + else if (this.m_limitState == b2Joint.e_atLowerLimit) { + newImpulse = this.m_impulse.z + this.impulse3.z; + if (newImpulse < 0.0) { + this.m_mass.Solve22(this.reduced, (-Cdot1X), (-Cdot1Y)); + this.impulse3.x = this.reduced.x; + this.impulse3.y = this.reduced.y; + this.impulse3.z = (-this.m_impulse.z); + this.m_impulse.x += this.reduced.x; + this.m_impulse.y += this.reduced.y; + this.m_impulse.z = 0.0; + } + } + else if (this.m_limitState == b2Joint.e_atUpperLimit) { + newImpulse = this.m_impulse.z + this.impulse3.z; + if (newImpulse > 0.0) { + this.m_mass.Solve22(this.reduced, (-Cdot1X), (-Cdot1Y)); + this.impulse3.x = this.reduced.x; + this.impulse3.y = this.reduced.y; + this.impulse3.z = (-this.m_impulse.z); + this.m_impulse.x += this.reduced.x; + this.m_impulse.y += this.reduced.y; + this.m_impulse.z = 0.0; + } + } + v1.x -= m1 * this.impulse3.x; + v1.y -= m1 * this.impulse3.y; + w1 -= i1 * (r1X * this.impulse3.y - r1Y * this.impulse3.x + this.impulse3.z); + v2.x += m2 * this.impulse3.x; + v2.y += m2 * this.impulse3.y; + w2 += i2 * (r2X * this.impulse3.y - r2Y * this.impulse3.x + this.impulse3.z); + } + else { + tMat = bA.m_xf.R; + r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var CdotX = v2.x + ((-w2 * r2Y)) - v1.x - ((-w1 * r1Y)); + var CdotY = v2.y + (w2 * r2X) - v1.y - (w1 * r1X); + this.m_mass.Solve22(this.impulse2, (-CdotX), (-CdotY)); + this.m_impulse.x += this.impulse2.x; + this.m_impulse.y += this.impulse2.y; + v1.x -= m1 * this.impulse2.x; + v1.y -= m1 * this.impulse2.y; + w1 -= i1 * (r1X * this.impulse2.y - r1Y * this.impulse2.x); + v2.x += m2 * this.impulse2.x; + v2.y += m2 * this.impulse2.y; + w2 += i2 * (r2X * this.impulse2.y - r2Y * this.impulse2.x); + } + bA.m_linearVelocity.SetV(v1); + bA.m_angularVelocity = w1; + bB.m_linearVelocity.SetV(v2); + bB.m_angularVelocity = w2; + } + b2RevoluteJoint.prototype.SolvePositionConstraints = function (baumgarte) { + if (baumgarte === undefined) baumgarte = 0; + var oldLimitImpulse = 0; + var C = 0; + var tMat; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var angularError = 0.0; + var positionError = 0.0; + var tX = 0; + var impulseX = 0; + var impulseY = 0; + if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) { + var angle = bB.m_sweep.a - bA.m_sweep.a - this.m_referenceAngle; + var limitImpulse = 0.0; + if (this.m_limitState == b2Joint.e_equalLimits) { + C = b2Math.Clamp(angle - this.m_lowerAngle, (-b2Settings.b2_maxAngularCorrection), b2Settings.b2_maxAngularCorrection); + limitImpulse = (-this.m_motorMass * C); + angularError = b2Math.Abs(C); + } + else if (this.m_limitState == b2Joint.e_atLowerLimit) { + C = angle - this.m_lowerAngle; + angularError = (-C); + C = b2Math.Clamp(C + b2Settings.b2_angularSlop, (-b2Settings.b2_maxAngularCorrection), 0.0); + limitImpulse = (-this.m_motorMass * C); + } + else if (this.m_limitState == b2Joint.e_atUpperLimit) { + C = angle - this.m_upperAngle; + angularError = C; + C = b2Math.Clamp(C - b2Settings.b2_angularSlop, 0.0, b2Settings.b2_maxAngularCorrection); + limitImpulse = (-this.m_motorMass * C); + } + bA.m_sweep.a -= bA.m_invI * limitImpulse; + bB.m_sweep.a += bB.m_invI * limitImpulse; + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + } { + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + var CX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; + var CY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; + var CLengthSquared = CX * CX + CY * CY; + var CLength = Math.sqrt(CLengthSquared); + positionError = CLength; + var invMass1 = bA.m_invMass; + var invMass2 = bB.m_invMass; + var invI1 = bA.m_invI; + var invI2 = bB.m_invI; + var k_allowedStretch = 10.0 * b2Settings.b2_linearSlop; + if (CLengthSquared > k_allowedStretch * k_allowedStretch) { + var uX = CX / CLength; + var uY = CY / CLength; + var k = invMass1 + invMass2; + var m = 1.0 / k; + impulseX = m * ((-CX)); + impulseY = m * ((-CY)); + var k_beta = 0.5; + bA.m_sweep.c.x -= k_beta * invMass1 * impulseX; + bA.m_sweep.c.y -= k_beta * invMass1 * impulseY; + bB.m_sweep.c.x += k_beta * invMass2 * impulseX; + bB.m_sweep.c.y += k_beta * invMass2 * impulseY; + CX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; + CY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; + } + this.K1.col1.x = invMass1 + invMass2; + this.K1.col2.x = 0.0; + this.K1.col1.y = 0.0; + this.K1.col2.y = invMass1 + invMass2; + this.K2.col1.x = invI1 * r1Y * r1Y; + this.K2.col2.x = (-invI1 * r1X * r1Y); + this.K2.col1.y = (-invI1 * r1X * r1Y); + this.K2.col2.y = invI1 * r1X * r1X; + this.K3.col1.x = invI2 * r2Y * r2Y; + this.K3.col2.x = (-invI2 * r2X * r2Y); + this.K3.col1.y = (-invI2 * r2X * r2Y); + this.K3.col2.y = invI2 * r2X * r2X; + this.K.SetM(this.K1); + this.K.AddM(this.K2); + this.K.AddM(this.K3); + this.K.Solve(b2RevoluteJoint.tImpulse, (-CX), (-CY)); + impulseX = b2RevoluteJoint.tImpulse.x; + impulseY = b2RevoluteJoint.tImpulse.y; + bA.m_sweep.c.x -= bA.m_invMass * impulseX; + bA.m_sweep.c.y -= bA.m_invMass * impulseY; + bA.m_sweep.a -= bA.m_invI * (r1X * impulseY - r1Y * impulseX); + bB.m_sweep.c.x += bB.m_invMass * impulseX; + bB.m_sweep.c.y += bB.m_invMass * impulseY; + bB.m_sweep.a += bB.m_invI * (r2X * impulseY - r2Y * impulseX); + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + } + return positionError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop; + } + Box2D.postDefs.push(function () { + Box2D.Dynamics.Joints.b2RevoluteJoint.tImpulse = new b2Vec2(); + }); + Box2D.inherit(b2RevoluteJointDef, Box2D.Dynamics.Joints.b2JointDef); + b2RevoluteJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; + b2RevoluteJointDef.b2RevoluteJointDef = function () { + Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); + this.localAnchorA = new b2Vec2(); + this.localAnchorB = new b2Vec2(); + }; + b2RevoluteJointDef.prototype.b2RevoluteJointDef = function () { + this.__super.b2JointDef.call(this); + this.type = b2Joint.e_revoluteJoint; + this.localAnchorA.Set(0.0, 0.0); + this.localAnchorB.Set(0.0, 0.0); + this.referenceAngle = 0.0; + this.lowerAngle = 0.0; + this.upperAngle = 0.0; + this.maxMotorTorque = 0.0; + this.motorSpeed = 0.0; + this.enableLimit = false; + this.enableMotor = false; + } + b2RevoluteJointDef.prototype.Initialize = function (bA, bB, anchor) { + this.bodyA = bA; + this.bodyB = bB; + this.localAnchorA = this.bodyA.GetLocalPoint(anchor); + this.localAnchorB = this.bodyB.GetLocalPoint(anchor); + this.referenceAngle = this.bodyB.GetAngle() - this.bodyA.GetAngle(); + } + Box2D.inherit(b2WeldJoint, Box2D.Dynamics.Joints.b2Joint); + b2WeldJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; + b2WeldJoint.b2WeldJoint = function () { + Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); + this.m_localAnchorA = new b2Vec2(); + this.m_localAnchorB = new b2Vec2(); + this.m_impulse = new b2Vec3(); + this.m_mass = new b2Mat33(); + }; + b2WeldJoint.prototype.GetAnchorA = function () { + return this.m_bodyA.GetWorldPoint(this.m_localAnchorA); + } + b2WeldJoint.prototype.GetAnchorB = function () { + return this.m_bodyB.GetWorldPoint(this.m_localAnchorB); + } + b2WeldJoint.prototype.GetReactionForce = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return new b2Vec2(inv_dt * this.m_impulse.x, inv_dt * this.m_impulse.y); + } + b2WeldJoint.prototype.GetReactionTorque = function (inv_dt) { + if (inv_dt === undefined) inv_dt = 0; + return inv_dt * this.m_impulse.z; + } + b2WeldJoint.prototype.b2WeldJoint = function (def) { + this.__super.b2Joint.call(this, def); + this.m_localAnchorA.SetV(def.localAnchorA); + this.m_localAnchorB.SetV(def.localAnchorB); + this.m_referenceAngle = def.referenceAngle; + this.m_impulse.SetZero(); + this.m_mass = new b2Mat33(); + } + b2WeldJoint.prototype.InitVelocityConstraints = function (step) { + var tMat; + var tX = 0; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + tMat = bA.m_xf.R; + var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; + var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; + tX = (tMat.col1.x * rAX + tMat.col2.x * rAY); + rAY = (tMat.col1.y * rAX + tMat.col2.y * rAY); + rAX = tX; + tMat = bB.m_xf.R; + var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; + var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * rBX + tMat.col2.x * rBY); + rBY = (tMat.col1.y * rBX + tMat.col2.y * rBY); + rBX = tX; + var mA = bA.m_invMass; + var mB = bB.m_invMass; + var iA = bA.m_invI; + var iB = bB.m_invI; + this.m_mass.col1.x = mA + mB + rAY * rAY * iA + rBY * rBY * iB; + this.m_mass.col2.x = (-rAY * rAX * iA) - rBY * rBX * iB; + this.m_mass.col3.x = (-rAY * iA) - rBY * iB; + this.m_mass.col1.y = this.m_mass.col2.x; + this.m_mass.col2.y = mA + mB + rAX * rAX * iA + rBX * rBX * iB; + this.m_mass.col3.y = rAX * iA + rBX * iB; + this.m_mass.col1.z = this.m_mass.col3.x; + this.m_mass.col2.z = this.m_mass.col3.y; + this.m_mass.col3.z = iA + iB; + if (step.warmStarting) { + this.m_impulse.x *= step.dtRatio; + this.m_impulse.y *= step.dtRatio; + this.m_impulse.z *= step.dtRatio; + bA.m_linearVelocity.x -= mA * this.m_impulse.x; + bA.m_linearVelocity.y -= mA * this.m_impulse.y; + bA.m_angularVelocity -= iA * (rAX * this.m_impulse.y - rAY * this.m_impulse.x + this.m_impulse.z); + bB.m_linearVelocity.x += mB * this.m_impulse.x; + bB.m_linearVelocity.y += mB * this.m_impulse.y; + bB.m_angularVelocity += iB * (rBX * this.m_impulse.y - rBY * this.m_impulse.x + this.m_impulse.z); + } + else { + this.m_impulse.SetZero(); + } + } + b2WeldJoint.prototype.SolveVelocityConstraints = function (step) { + var tMat; + var tX = 0; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var vA = bA.m_linearVelocity; + var wA = bA.m_angularVelocity; + var vB = bB.m_linearVelocity; + var wB = bB.m_angularVelocity; + var mA = bA.m_invMass; + var mB = bB.m_invMass; + var iA = bA.m_invI; + var iB = bB.m_invI; + tMat = bA.m_xf.R; + var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; + var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; + tX = (tMat.col1.x * rAX + tMat.col2.x * rAY); + rAY = (tMat.col1.y * rAX + tMat.col2.y * rAY); + rAX = tX; + tMat = bB.m_xf.R; + var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; + var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * rBX + tMat.col2.x * rBY); + rBY = (tMat.col1.y * rBX + tMat.col2.y * rBY); + rBX = tX; + var Cdot1X = vB.x - wB * rBY - vA.x + wA * rAY; + var Cdot1Y = vB.y + wB * rBX - vA.y - wA * rAX; + var Cdot2 = wB - wA; + var impulse = new b2Vec3(); + this.m_mass.Solve33(impulse, (-Cdot1X), (-Cdot1Y), (-Cdot2)); + this.m_impulse.Add(impulse); + vA.x -= mA * impulse.x; + vA.y -= mA * impulse.y; + wA -= iA * (rAX * impulse.y - rAY * impulse.x + impulse.z); + vB.x += mB * impulse.x; + vB.y += mB * impulse.y; + wB += iB * (rBX * impulse.y - rBY * impulse.x + impulse.z); + bA.m_angularVelocity = wA; + bB.m_angularVelocity = wB; + } + b2WeldJoint.prototype.SolvePositionConstraints = function (baumgarte) { + if (baumgarte === undefined) baumgarte = 0; + var tMat; + var tX = 0; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + tMat = bA.m_xf.R; + var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; + var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; + tX = (tMat.col1.x * rAX + tMat.col2.x * rAY); + rAY = (tMat.col1.y * rAX + tMat.col2.y * rAY); + rAX = tX; + tMat = bB.m_xf.R; + var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; + var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; + tX = (tMat.col1.x * rBX + tMat.col2.x * rBY); + rBY = (tMat.col1.y * rBX + tMat.col2.y * rBY); + rBX = tX; + var mA = bA.m_invMass; + var mB = bB.m_invMass; + var iA = bA.m_invI; + var iB = bB.m_invI; + var C1X = bB.m_sweep.c.x + rBX - bA.m_sweep.c.x - rAX; + var C1Y = bB.m_sweep.c.y + rBY - bA.m_sweep.c.y - rAY; + var C2 = bB.m_sweep.a - bA.m_sweep.a - this.m_referenceAngle; + var k_allowedStretch = 10.0 * b2Settings.b2_linearSlop; + var positionError = Math.sqrt(C1X * C1X + C1Y * C1Y); + var angularError = b2Math.Abs(C2); + if (positionError > k_allowedStretch) { + iA *= 1.0; + iB *= 1.0; + } + this.m_mass.col1.x = mA + mB + rAY * rAY * iA + rBY * rBY * iB; + this.m_mass.col2.x = (-rAY * rAX * iA) - rBY * rBX * iB; + this.m_mass.col3.x = (-rAY * iA) - rBY * iB; + this.m_mass.col1.y = this.m_mass.col2.x; + this.m_mass.col2.y = mA + mB + rAX * rAX * iA + rBX * rBX * iB; + this.m_mass.col3.y = rAX * iA + rBX * iB; + this.m_mass.col1.z = this.m_mass.col3.x; + this.m_mass.col2.z = this.m_mass.col3.y; + this.m_mass.col3.z = iA + iB; + var impulse = new b2Vec3(); + this.m_mass.Solve33(impulse, (-C1X), (-C1Y), (-C2)); + bA.m_sweep.c.x -= mA * impulse.x; + bA.m_sweep.c.y -= mA * impulse.y; + bA.m_sweep.a -= iA * (rAX * impulse.y - rAY * impulse.x + impulse.z); + bB.m_sweep.c.x += mB * impulse.x; + bB.m_sweep.c.y += mB * impulse.y; + bB.m_sweep.a += iB * (rBX * impulse.y - rBY * impulse.x + impulse.z); + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + return positionError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop; + } + Box2D.inherit(b2WeldJointDef, Box2D.Dynamics.Joints.b2JointDef); + b2WeldJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; + b2WeldJointDef.b2WeldJointDef = function () { + Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); + this.localAnchorA = new b2Vec2(); + this.localAnchorB = new b2Vec2(); + }; + b2WeldJointDef.prototype.b2WeldJointDef = function () { + this.__super.b2JointDef.call(this); + this.type = b2Joint.e_weldJoint; + this.referenceAngle = 0.0; + } + b2WeldJointDef.prototype.Initialize = function (bA, bB, anchor) { + this.bodyA = bA; + this.bodyB = bB; + this.localAnchorA.SetV(this.bodyA.GetLocalPoint(anchor)); + this.localAnchorB.SetV(this.bodyB.GetLocalPoint(anchor)); + this.referenceAngle = this.bodyB.GetAngle() - this.bodyA.GetAngle(); + } +})(); +(function () { + var b2DebugDraw = Box2D.Dynamics.b2DebugDraw; + b2DebugDraw.b2DebugDraw = function () { + this.m_drawScale = 1.0; + this.m_lineThickness = 1.0; + this.m_alpha = 1.0; + this.m_fillAlpha = 1.0; + this.m_xformScale = 1.0; + var __this = this; + //#WORKAROUND + this.m_sprite = { + graphics: { + clear: function () { + __this.m_ctx.clearRect(0, 0, __this.m_ctx.canvas.width, __this.m_ctx.canvas.height) + } + } + }; + }; + b2DebugDraw.prototype._color = function (color, alpha) { + return "rgba(" + ((color & 0xFF0000) >> 16) + "," + ((color & 0xFF00) >> 8) + "," + (color & 0xFF) + "," + alpha + ")"; + }; + b2DebugDraw.prototype.b2DebugDraw = function () { + this.m_drawFlags = 0; + }; + b2DebugDraw.prototype.SetFlags = function (flags) { + if (flags === undefined) flags = 0; + this.m_drawFlags = flags; + }; + b2DebugDraw.prototype.GetFlags = function () { + return this.m_drawFlags; + }; + b2DebugDraw.prototype.AppendFlags = function (flags) { + if (flags === undefined) flags = 0; + this.m_drawFlags |= flags; + }; + b2DebugDraw.prototype.ClearFlags = function (flags) { + if (flags === undefined) flags = 0; + this.m_drawFlags &= ~flags; + }; + b2DebugDraw.prototype.SetSprite = function (sprite) { + this.m_ctx = sprite; + }; + b2DebugDraw.prototype.GetSprite = function () { + return this.m_ctx; + }; + b2DebugDraw.prototype.SetDrawScale = function (drawScale) { + if (drawScale === undefined) drawScale = 0; + this.m_drawScale = drawScale; + }; + b2DebugDraw.prototype.GetDrawScale = function () { + return this.m_drawScale; + }; + b2DebugDraw.prototype.SetLineThickness = function (lineThickness) { + if (lineThickness === undefined) lineThickness = 0; + this.m_lineThickness = lineThickness; + this.m_ctx.strokeWidth = lineThickness; + }; + b2DebugDraw.prototype.GetLineThickness = function () { + return this.m_lineThickness; + }; + b2DebugDraw.prototype.SetAlpha = function (alpha) { + if (alpha === undefined) alpha = 0; + this.m_alpha = alpha; + }; + b2DebugDraw.prototype.GetAlpha = function () { + return this.m_alpha; + }; + b2DebugDraw.prototype.SetFillAlpha = function (alpha) { + if (alpha === undefined) alpha = 0; + this.m_fillAlpha = alpha; + }; + b2DebugDraw.prototype.GetFillAlpha = function () { + return this.m_fillAlpha; + }; + b2DebugDraw.prototype.SetXFormScale = function (xformScale) { + if (xformScale === undefined) xformScale = 0; + this.m_xformScale = xformScale; + }; + b2DebugDraw.prototype.GetXFormScale = function () { + return this.m_xformScale; + }; + b2DebugDraw.prototype.DrawPolygon = function (vertices, vertexCount, color) { + if (!vertexCount) return; + var s = this.m_ctx; + var drawScale = this.m_drawScale; + s.beginPath(); + s.strokeStyle = this._color(color.color, this.m_alpha); + s.moveTo(vertices[0].x * drawScale, vertices[0].y * drawScale); + for (var i = 1; i < vertexCount; i++) { + s.lineTo(vertices[i].x * drawScale, vertices[i].y * drawScale); + } + s.lineTo(vertices[0].x * drawScale, vertices[0].y * drawScale); + s.closePath(); + s.stroke(); + }; + b2DebugDraw.prototype.DrawSolidPolygon = function (vertices, vertexCount, color) { + if (!vertexCount) return; + var s = this.m_ctx; + var drawScale = this.m_drawScale; + s.beginPath(); + s.strokeStyle = this._color(color.color, this.m_alpha); + s.fillStyle = this._color(color.color, this.m_fillAlpha); + s.moveTo(vertices[0].x * drawScale, vertices[0].y * drawScale); + for (var i = 1; i < vertexCount; i++) { + s.lineTo(vertices[i].x * drawScale, vertices[i].y * drawScale); + } + s.lineTo(vertices[0].x * drawScale, vertices[0].y * drawScale); + s.closePath(); + s.fill(); + s.stroke(); + }; + b2DebugDraw.prototype.DrawCircle = function (center, radius, color) { + if (!radius) return; + var s = this.m_ctx; + var drawScale = this.m_drawScale; + s.beginPath(); + s.strokeStyle = this._color(color.color, this.m_alpha); + s.arc(center.x * drawScale, center.y * drawScale, radius * drawScale, 0, Math.PI * 2, true); + s.closePath(); + s.stroke(); + }; + b2DebugDraw.prototype.DrawSolidCircle = function (center, radius, axis, color) { + if (!radius) return; + var s = this.m_ctx, + drawScale = this.m_drawScale, + cx = center.x * drawScale, + cy = center.y * drawScale; + s.moveTo(0, 0); + s.beginPath(); + s.strokeStyle = this._color(color.color, this.m_alpha); + s.fillStyle = this._color(color.color, this.m_fillAlpha); + s.arc(cx, cy, radius * drawScale, 0, Math.PI * 2, true); + s.moveTo(cx, cy); + s.lineTo((center.x + axis.x * radius) * drawScale, (center.y + axis.y * radius) * drawScale); + s.closePath(); + s.fill(); + s.stroke(); + }; + b2DebugDraw.prototype.DrawSegment = function (p1, p2, color) { + var s = this.m_ctx, + drawScale = this.m_drawScale; + s.strokeStyle = this._color(color.color, this.m_alpha); + s.beginPath(); + s.moveTo(p1.x * drawScale, p1.y * drawScale); + s.lineTo(p2.x * drawScale, p2.y * drawScale); + s.closePath(); + s.stroke(); + }; + b2DebugDraw.prototype.DrawTransform = function (xf) { + var s = this.m_ctx, + drawScale = this.m_drawScale; + s.beginPath(); + s.strokeStyle = this._color(0xff0000, this.m_alpha); + s.moveTo(xf.position.x * drawScale, xf.position.y * drawScale); + s.lineTo((xf.position.x + this.m_xformScale * xf.R.col1.x) * drawScale, (xf.position.y + this.m_xformScale * xf.R.col1.y) * drawScale); + + s.strokeStyle = this._color(0xff00, this.m_alpha); + s.moveTo(xf.position.x * drawScale, xf.position.y * drawScale); + s.lineTo((xf.position.x + this.m_xformScale * xf.R.col2.x) * drawScale, (xf.position.y + this.m_xformScale * xf.R.col2.y) * drawScale); + s.closePath(); + s.stroke(); + }; +})(); //post-definitions +var i; +for (i = 0; i < Box2D.postDefs.length; ++i) Box2D.postDefs[i](); +delete Box2D.postDefs; + +// for node.js +if (typeof window === 'undefined') module.exports = Box2D; diff --git a/networking/client.js b/networking/client.js new file mode 100644 index 0000000..61c5997 --- /dev/null +++ b/networking/client.js @@ -0,0 +1,107 @@ +var id = null; + +function setupCanvas() { + var debugDraw = new b2DebugDraw(); + + debugDraw.SetSprite(document.getElementById("canvas").getContext("2d")); + debugDraw.SetDrawScale(30.0); + debugDraw.SetFillAlpha(0.5); + debugDraw.SetLineThickness(1.0); + debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit); + + world.SetDebugDraw(debugDraw); +} + +function _jump() { + jump(); + + var data = { + m: 'jump' + }; + socket.send(JSON.stringify(data)); +} + +function init() { + setupWorld(); + setupCanvas(); + + window.setInterval(update, 1000 / 60); + + var body; + + //update + function update() { + world.Step(1 / 60, 10, 10); + world.DrawDebugData(); + world.ClearForces(); + } +} + +//helpers + +//http://js-tut.aardon.de/js-tut/tutorial/position.html +function getElementPosition(element) { + var elem = element, tagname = "", x = 0, y = 0; + + while((typeof(elem) == "object") && (typeof(elem.tagName) != "undefined")) { + y += elem.offsetTop; + x += elem.offsetLeft; + + tagname = elem.tagName.toUpperCase(); + + if(tagname == "BODY") elem = 0; + + if(typeof(elem) == "object") { + if(typeof(elem.offsetParent) == "object") elem = elem.offsetParent; + } + + return {x: x, y: y}; + } +} + +function updateWorld(data) { + var body = world.GetBodyList(); + do { + var userData = body.GetUserData(); + if(userData && userData.bodyId){ + var update = data[userData.bodyId]; + body.SetPosition(update.p); + body.SetAngle(update.a); + body.SetLinearVelocity(update.v); + } + } while (body = body.GetNext()); +} + + + + +var socket = io.connect(xhost + ':' + xport); + +socket.on('connect',function() { + console.log('Client has connected to the server!'); + connected = true; +}); + +socket.on('message', function(packet) { + packet = JSON.parse(packet); + //console.log(packet); + + if (packet && packet.m) { + switch(packet.m) { + case 'world-update': + updateWorld(packet.d); + break; + default: + break; + } + + } +}); + +socket.on('disconnect',function() { + console.log('The client has disconnected!'); + connected = false; +}); + + +window.onload = init; \ No newline at end of file diff --git a/networking/client.js~ b/networking/client.js~ new file mode 100644 index 0000000..efbf1f1 --- /dev/null +++ b/networking/client.js~ @@ -0,0 +1,107 @@ +var id = null; + +function setupCanvas() { + var debugDraw = new b2DebugDraw(); + + debugDraw.SetSprite(document.getElementById("canvas").getContext("2d")); + debugDraw.SetDrawScale(30.0); + debugDraw.SetFillAlpha(0.5); + debugDraw.SetLineThickness(1.0); + debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit); + + world.SetDebugDraw(debugDraw); +} + +function _jump() { + + var data = { + m: 'jump' + }; + + socket.send(JSON.stringify(data)); +} + +function init() { + setupWorld(); + setupCanvas(); + + window.setInterval(update, 1000 / 60); + + var body; + + //update + function update() { + world.Step(1 / 60, 10, 10); + world.DrawDebugData(); + world.ClearForces(); + } +} + +//helpers + +//http://js-tut.aardon.de/js-tut/tutorial/position.html +function getElementPosition(element) { + var elem = element, tagname = "", x = 0, y = 0; + + while((typeof(elem) == "object") && (typeof(elem.tagName) != "undefined")) { + y += elem.offsetTop; + x += elem.offsetLeft; + + tagname = elem.tagName.toUpperCase(); + + if(tagname == "BODY") elem = 0; + + if(typeof(elem) == "object") { + if(typeof(elem.offsetParent) == "object") elem = elem.offsetParent; + } + + return {x: x, y: y}; + } +} + +function updateWorld(data) { + var body = world.GetBodyList(); + do { + var userData = body.GetUserData(); + if(userData && userData.bodyId){ + var update = data[userData.bodyId]; + body.SetPosition(update.p); + body.SetAngle(update.a); + body.SetLinearVelocity(update.v); + } + } while (body = body.GetNext()); +} + + + + +var socket = io.connect(xhost + ':' + xport); + +socket.on('connect',function() { + console.log('Client has connected to the server!'); + connected = true; +}); + +socket.on('message', function(packet) { + packet = JSON.parse(packet); + //console.log(packet); + + if (packet && packet.m) { + switch(packet.m) { + case 'world-update': + updateWorld(packet.d); + break; + default: + break; + } + + } +}); + +socket.on('disconnect',function() { + console.log('The client has disconnected!'); + connected = false; +}); + + +window.onload = init; \ No newline at end of file diff --git a/networking/common.js b/networking/common.js new file mode 100644 index 0000000..1f6c28c --- /dev/null +++ b/networking/common.js @@ -0,0 +1,82 @@ +var bodiesNum = 3; +var world; + +var xport = 8003; +var xhost = '127.0.0.1'; + +var b2Vec2 = Box2D.Common.Math.b2Vec2, + b2AABB = Box2D.Collision.b2AABB, + b2BodyDef = Box2D.Dynamics.b2BodyDef, + b2Body = Box2D.Dynamics.b2Body, + b2FixtureDef = Box2D.Dynamics.b2FixtureDef, + b2Fixture = Box2D.Dynamics.b2Fixture, + b2World = Box2D.Dynamics.b2World, + b2MassData = Box2D.Collision.Shapes.b2MassData, + b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape, + b2CircleShape = Box2D.Collision.Shapes.b2CircleShape, + b2DebugDraw = Box2D.Dynamics.b2DebugDraw, + b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef; + +function setupWorld() { + world = new b2World(new b2Vec2(0, 10), true); + + var fixDef = new b2FixtureDef; + fixDef.density = 1.0; + fixDef.friction = 0.5; + fixDef.restitution = 0.2; + + var bodyDef = new b2BodyDef; + + // create ground + bodyDef.type = b2Body.b2_staticBody; + fixDef.shape = new b2PolygonShape; + fixDef.shape.SetAsBox(20, 2); + + bodyDef.position.Set(10, 400 / 30 + 1.8); + + world.CreateBody(bodyDef).CreateFixture(fixDef); + bodyDef.position.Set(10, -1.8); + + world.CreateBody(bodyDef).CreateFixture(fixDef); + fixDef.shape.SetAsBox(2, 14); + + bodyDef.position.Set(-1.8, 13); + world.CreateBody(bodyDef).CreateFixture(fixDef); + + bodyDef.position.Set(21.8, 13); + world.CreateBody(bodyDef).CreateFixture(fixDef); + + // create some objects + bodyDef.type = b2Body.b2_dynamicBody; + + for(var i = 0; i < bodiesNum; i++) { + fixDef.shape = new b2PolygonShape; + fixDef.shape.SetAsBox(0.5, 0.5); + + bodyDef.position.x = (i + 1) * 4; + bodyDef.position.y = 3; + + bodyDef.userData = {"bodyId" : parseInt(i) }; + + world.CreateBody(bodyDef).CreateFixture(fixDef); + } +} + +function jump() { + var body = findBody(1); + body.SetAwake(true); + body.ApplyImpulse(new b2Vec2(0, -9), body.GetPosition()); +} + +function findBody(index) { + var body = null; + + var nextBody = world.GetBodyList(); + for (var i = 0; i < bodiesNum; i++) { + if (nextBody.GetUserData().bodyId == index) { body = nextBody; break; } + nextBody = nextBody.GetNext(); + } + + return body; +} + diff --git a/networking/common.js~ b/networking/common.js~ new file mode 100644 index 0000000..9793e9c --- /dev/null +++ b/networking/common.js~ @@ -0,0 +1,82 @@ +var bodiesNum = 3; +var world; + +var xport = 8003; +var xhost = '127.0.0.1'; + +var b2Vec2 = Box2D.Common.Math.b2Vec2, + b2AABB = Box2D.Collision.b2AABB, + b2BodyDef = Box2D.Dynamics.b2BodyDef, + b2Body = Box2D.Dynamics.b2Body, + b2FixtureDef = Box2D.Dynamics.b2FixtureDef, + b2Fixture = Box2D.Dynamics.b2Fixture, + b2World = Box2D.Dynamics.b2World, + b2MassData = Box2D.Collision.Shapes.b2MassData, + b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape, + b2CircleShape = Box2D.Collision.Shapes.b2CircleShape, + b2DebugDraw = Box2D.Dynamics.b2DebugDraw, + b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef; + +function setupWorld() { + world = new b2World(new b2Vec2(0, 10), true); + + var fixDef = new b2FixtureDef; + fixDef.density = 1.0; + fixDef.friction = 0.5; + fixDef.restitution = 0.2; + + var bodyDef = new b2BodyDef; + + // create ground + bodyDef.type = b2Body.b2_staticBody; + fixDef.shape = new b2PolygonShape; + fixDef.shape.SetAsBox(20, 2); + + bodyDef.position.Set(10, 400 / 30 + 1.8); + + world.CreateBody(bodyDef).CreateFixture(fixDef); + bodyDef.position.Set(10, -1.8); + + world.CreateBody(bodyDef).CreateFixture(fixDef); + fixDef.shape.SetAsBox(2, 14); + + bodyDef.position.Set(-1.8, 13); + world.CreateBody(bodyDef).CreateFixture(fixDef); + + bodyDef.position.Set(21.8, 13); + world.CreateBody(bodyDef).CreateFixture(fixDef); + + // create some objects + bodyDef.type = b2Body.b2_dynamicBody; + + for(var i = 0; i < bodiesNum; i++) { + fixDef.shape = new b2PolygonShape; + fixDef.shape.SetAsBox(0.5, 0.5); + + bodyDef.position.x = (i + 1) * 4; + bodyDef.position.y = 3; + + bodyDef.userData = {"bodyId" : parseInt(i) }; + + world.CreateBody(bodyDef).CreateFixture(fixDef); + } +} + +function jump() { + var body = findBody(1); + body.SetAwake(true); + body.ApplyImpulse(new b2Vec2(0, -5), body.GetPosition()); +} + +function findBody(index) { + var body = null; + + var nextBody = world.GetBodyList(); + for (var i = 0; i < bodiesNum; i++) { + if (nextBody.GetUserData().bodyId == index) { body = nextBody; break; } + nextBody = nextBody.GetNext(); + } + + return body; +} + diff --git a/networking/index.html b/networking/index.html new file mode 100644 index 0000000..635dffd --- /dev/null +++ b/networking/index.html @@ -0,0 +1,15 @@ + + + + Box2dWeb Demo + + + + + + + + + + + diff --git a/networking/index.html~ b/networking/index.html~ new file mode 100644 index 0000000..b35a31c --- /dev/null +++ b/networking/index.html~ @@ -0,0 +1,15 @@ + + + + Box2dWeb Demo + + + + + + + + + + + diff --git a/networking/node_modules/box2d/README b/networking/node_modules/box2d/README new file mode 100644 index 0000000..57da8a6 --- /dev/null +++ b/networking/node_modules/box2d/README @@ -0,0 +1,58 @@ +@author Josh Adell + +A port of the box2djs library into a node module. + +Here is the box2d "Hello World" program from http://www.box2d.org/ written for node: + +--- BEGIN CODE EXAMPLE --- + +var sys = require("sys"), + b2d = require("./box2dnode"); + +// Define world +var worldAABB = new b2d.b2AABB(); +worldAABB.lowerBound.Set(-100.0, -100.0); +worldAABB.upperBound.Set(100.0, 100.0); + +var gravity = new b2d.b2Vec2(0.0, -10.0); +var doSleep = true; + +var world = new b2d.b2World(worldAABB, gravity, doSleep); + +// Ground Box +var groundBodyDef = new b2d.b2BodyDef(); +groundBodyDef.position.Set(0.0, -10.0); + +var groundBody = world.CreateBody(groundBodyDef); + +var groundShapeDef = new b2d.b2PolygonDef(); +groundShapeDef.SetAsBox(50.0, 10.0); + +groundBody.CreateShape(groundShapeDef); + +// Dynamic Body +var bodyDef = new b2d.b2BodyDef(); +bodyDef.position.Set(0.0, 4.0); + +var body = world.CreateBody(bodyDef); + +var shapeDef = new b2d.b2PolygonDef(); +shapeDef.SetAsBox(1.0, 1.0); +shapeDef.density = 1.0; +shapeDef.friction = 0.3; +body.CreateShape(shapeDef); +body.SetMassFromShapes(); + +// Run Simulation! +var timeStep = 1.0 / 60.0; + +var iterations = 10; + +for (var i=0; i < 60; i++) { + world.Step(timeStep, iterations); + var position = body.GetPosition(); + var angle = body.GetAngle(); + sys.puts(i+": <"+position.x+", "+position.y+"> @"+angle); +} + +--- END CODE EXAMPLE --- diff --git a/networking/node_modules/box2d/box2dnode.js b/networking/node_modules/box2d/box2dnode.js new file mode 100644 index 0000000..4d3225c --- /dev/null +++ b/networking/node_modules/box2d/box2dnode.js @@ -0,0 +1,11132 @@ +/** + * Copyright 2010 Josh Adell. All rights reserved. + * + * Based on Box2d2 - Jonas Wagner + * http://29a.ch/2010/4/17/box2d-2-flash-ported-javascript + * + * This software is provided 'as-is', without any express or + * implied warranty. In no event will the authors be held liable + * for any damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you + * use this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +function extend(a, b) { + for(var c in b) { + a[c] = b[c]; + } +} + + +var b2Settings = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Settings.prototype.__constructor = function(){} +b2Settings.prototype.__varz = function(){ +} +b2Settings.USHRT_MAX = 0x0000ffff; +b2Settings.b2_pi = Math.PI; +b2Settings.b2_maxManifoldPoints = 2; +b2Settings.b2_maxPolygonVertices = 8; +b2Settings.b2_maxProxies = 512; +b2Settings.b2_maxPairs = 8 * b2Settings.b2_maxProxies; +b2Settings.b2_linearSlop = 0.005; +b2Settings.b2_angularSlop = 2.0 / 180.0 * b2Settings.b2_pi; +b2Settings.b2_toiSlop = 8.0 * b2Settings.b2_linearSlop; +b2Settings.b2_maxTOIContactsPerIsland = 32; +b2Settings.b2_velocityThreshold = 1.0; +b2Settings.b2_maxLinearCorrection = 0.2; +b2Settings.b2_maxAngularCorrection = 8.0 / 180.0 * b2Settings.b2_pi; +b2Settings.b2_maxLinearVelocity = 200.0; +b2Settings.b2_maxLinearVelocitySquared = b2Settings.b2_maxLinearVelocity * b2Settings.b2_maxLinearVelocity; +b2Settings.b2_maxAngularVelocity = 250.0; +b2Settings.b2_maxAngularVelocitySquared = b2Settings.b2_maxAngularVelocity * b2Settings.b2_maxAngularVelocity; +b2Settings.b2_contactBaumgarte = 0.2; +b2Settings.b2_timeToSleep = 0.5; +b2Settings.b2_linearSleepTolerance = 0.01; +b2Settings.b2_angularSleepTolerance = 2.0 / 180.0; +b2Settings.b2Assert = function (a) { + if (!a){ + var nullVec; + nullVec.x++; + } + } +exports.b2Settings = b2Settings; + + +var b2Color = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Color.prototype.__constructor = function (rr, gg, bb) { + this._r = parseInt(255 * b2Math.b2Clamp(rr, 0.0, 1.0)); + this._g = parseInt(255 * b2Math.b2Clamp(gg, 0.0, 1.0)); + this._b = parseInt(255 * b2Math.b2Clamp(bb, 0.0, 1.0)); + } +b2Color.prototype.__varz = function(){ +} +b2Color.prototype._r = 0; +b2Color.prototype._g = 0; +b2Color.prototype._b = 0; +b2Color.prototype.Set = function (rr, gg, bb) { + this._r = parseInt(255 * b2Math.b2Clamp(rr, 0.0, 1.0)); + this._g = parseInt(255 * b2Math.b2Clamp(gg, 0.0, 1.0)); + this._b = parseInt(255 * b2Math.b2Clamp(bb, 0.0, 1.0)); + } +b2Color.prototype.set = function (rr) { + this._r = parseInt(255 * b2Math.b2Clamp(rr, 0.0, 1.0)); + } +b2Color.prototype.set = function (gg) { + this._g = parseInt(255 * b2Math.b2Clamp(gg, 0.0, 1.0)); + } +b2Color.prototype.set = function (bb) { + this._b = parseInt(255 * b2Math.b2Clamp(bb, 0.0, 1.0)); + } +b2Color.prototype.get = function () { + return (this._r) | (this._g << 8) | (this._b << 16); + } +exports.b2Color = b2Color; + + +var b2Vec2 = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Vec2.prototype.__constructor = function (x_, y_) { + if(arguments.length == 2) { + this.x=x_; this.y=y_; + } +} +b2Vec2.prototype.__varz = function(){ +} +b2Vec2.Make = function (x_, y_) { + return new b2Vec2(x_, y_); + } +b2Vec2.prototype.x = 0; +b2Vec2.prototype.y = 0; +b2Vec2.prototype.SetZero = function () { this.x = 0.0; this.y = 0.0; } +b2Vec2.prototype.Set = function (x_, y_) {this.x=x_; this.y=y_;} +b2Vec2.prototype.SetV = function (v) {this.x=v.x; this.y=v.y;} +b2Vec2.prototype.Negative = function () { return new b2Vec2(-this.x, -this.y); } +b2Vec2.prototype.Copy = function () { + return new b2Vec2(this.x,this.y); + } +b2Vec2.prototype.Add = function (v) { + this.x += v.x; this.y += v.y; + } +b2Vec2.prototype.Subtract = function (v) { + this.x -= v.x; this.y -= v.y; + } +b2Vec2.prototype.Multiply = function (a) { + this.x *= a; this.y *= a; + } +b2Vec2.prototype.MulM = function (A) { + var tX = this.x; + this.x = A.col1.x * tX + A.col2.x * this.y; + this.y = A.col1.y * tX + A.col2.y * this.y; + } +b2Vec2.prototype.MulTM = function (A) { + var tX = b2Math.b2Dot(this, A.col1); + this.y = b2Math.b2Dot(this, A.col2); + this.x = tX; + } +b2Vec2.prototype.CrossVF = function (s) { + var tX = this.x; + this.x = s * this.y; + this.y = -s * tX; + } +b2Vec2.prototype.CrossFV = function (s) { + var tX = this.x; + this.x = -s * this.y; + this.y = s * tX; + } +b2Vec2.prototype.MinV = function (b) { + this.x = this.x < b.x ? this.x : b.x; + this.y = this.y < b.y ? this.y : b.y; + } +b2Vec2.prototype.MaxV = function (b) { + this.x = this.x > b.x ? this.x : b.x; + this.y = this.y > b.y ? this.y : b.y; + } +b2Vec2.prototype.Abs = function () { + if (this.x < 0) this.x = -this.x; + if (this.y < 0) this.y = -this.y; + } +b2Vec2.prototype.Length = function () { + return Math.sqrt(this.x * this.x + this.y * this.y); + } +b2Vec2.prototype.LengthSquared = function () { + return (this.x * this.x + this.y * this.y); + } +b2Vec2.prototype.Normalize = function () { + var length = Math.sqrt(this.x * this.x + this.y * this.y); + if (length < Number.MIN_VALUE) + { + return 0.0; + } + var invLength = 1.0 / length; + this.x *= invLength; + this.y *= invLength; + + return length; + } +b2Vec2.prototype.IsValid = function () { + return b2Math.b2IsValid(this.x) && b2Math.b2IsValid(this.y); + } +exports.b2Vec2 = b2Vec2; + + +var b2Mat22 = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Mat22.prototype.__constructor = function (angle, c1, c2) { + if (c1!=null && c2!=null){ + this.col1.SetV(c1); + this.col2.SetV(c2); + } + else{ + var c = Math.cos(angle); + var s = Math.sin(angle); + this.col1.x = c; this.col2.x = -s; + this.col1.y = s; this.col2.y = c; + } + } +b2Mat22.prototype.__varz = function(){ +this.col1 = new b2Vec2(); +this.col2 = new b2Vec2(); +} +b2Mat22.prototype.col1 = new b2Vec2(); +b2Mat22.prototype.col2 = new b2Vec2(); +b2Mat22.prototype.Set = function (angle) { + var c = Math.cos(angle); + var s = Math.sin(angle); + this.col1.x = c; this.col2.x = -s; + this.col1.y = s; this.col2.y = c; + } +b2Mat22.prototype.SetVV = function (c1, c2) { + this.col1.SetV(c1); + this.col2.SetV(c2); + } +b2Mat22.prototype.Copy = function () { + return new b2Mat22(0, this.col1, this.col2); + } +b2Mat22.prototype.SetM = function (m) { + this.col1.SetV(m.col1); + this.col2.SetV(m.col2); + } +b2Mat22.prototype.AddM = function (m) { + this.col1.x += m.col1.x; + this.col1.y += m.col1.y; + this.col2.x += m.col2.x; + this.col2.y += m.col2.y; + } +b2Mat22.prototype.SetIdentity = function () { + this.col1.x = 1.0; this.col2.x = 0.0; + this.col1.y = 0.0; this.col2.y = 1.0; + } +b2Mat22.prototype.SetZero = function () { + this.col1.x = 0.0; this.col2.x = 0.0; + this.col1.y = 0.0; this.col2.y = 0.0; + } +b2Mat22.prototype.GetAngle = function () { + return Math.atan2(this.col1.y, this.col1.x); + } +b2Mat22.prototype.Invert = function (out) { + var a = this.col1.x; + var b = this.col2.x; + var c = this.col1.y; + var d = this.col2.y; + + var det = a * d - b * c; + + det = 1.0 / det; + out.col1.x = det * d; out.col2.x = -det * b; + out.col1.y = -det * c; out.col2.y = det * a; + return out; + } +b2Mat22.prototype.Solve = function (out, bX, bY) { + + var a11 = this.col1.x; + var a12 = this.col2.x; + var a21 = this.col1.y; + var a22 = this.col2.y; + + var det = a11 * a22 - a12 * a21; + + det = 1.0 / det; + out.x = det * (a22 * bX - a12 * bY); + out.y = det * (a11 * bY - a21 * bX); + + return out; + } +b2Mat22.prototype.Abs = function () { + this.col1.Abs(); + this.col2.Abs(); + } +exports.b2Mat22 = b2Mat22; + + +var b2XForm = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2XForm.prototype.__constructor = function (pos, r) { + if (pos){ + this.position.SetV(pos); + this.R.SetM(r); + + } + } +b2XForm.prototype.__varz = function(){ +this.position = new b2Vec2; +this.R = new b2Mat22(); +} +b2XForm.prototype.position = new b2Vec2; +b2XForm.prototype.R = new b2Mat22(); +b2XForm.prototype.Initialize = function (pos, r) { + this.position.SetV(pos); + this.R.SetM(r); + } +b2XForm.prototype.SetIdentity = function () { + this.position.SetZero(); + this.R.SetIdentity(); + } +b2XForm.prototype.Set = function (x) { + + this.position.SetV(x.position); + + this.R.SetM(x.R); + + } +exports.b2XForm = b2XForm; + + +var b2Math = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Math.prototype.__constructor = function(){} +b2Math.prototype.__varz = function(){ +} +b2Math.b2Vec2_zero = new b2Vec2(0.0, 0.0); +b2Math.b2Mat22_identity = new b2Mat22(0, new b2Vec2(1.0, 0.0), new b2Vec2(0.0, 1.0)); +b2Math.b2XForm_identity = new b2XForm(b2Math.b2Vec2_zero, b2Math.b2Mat22_identity); +b2Math.b2IsValid = function (x) { + return isFinite(x); + } +b2Math.b2Dot = function (a, b) { + return a.x * b.x + a.y * b.y; + } +b2Math.b2CrossVV = function (a, b) { + return a.x * b.y - a.y * b.x; + } +b2Math.b2CrossVF = function (a, s) { + var v = new b2Vec2(s * a.y, -s * a.x); + return v; + } +b2Math.b2CrossFV = function (s, a) { + var v = new b2Vec2(-s * a.y, s * a.x); + return v; + } +b2Math.b2MulMV = function (A, v) { + + + var u = new b2Vec2(A.col1.x * v.x + A.col2.x * v.y, A.col1.y * v.x + A.col2.y * v.y); + return u; + } +b2Math.b2MulTMV = function (A, v) { + + + var u = new b2Vec2(b2Math.b2Dot(v, A.col1), b2Math.b2Dot(v, A.col2)); + return u; + } +b2Math.b2MulX = function (T, v) { + var a = b2Math.b2MulMV(T.R, v); + a.x += T.position.x; + a.y += T.position.y; + + return a; + } +b2Math.b2MulXT = function (T, v) { + var a = b2Math.SubtractVV(v, T.position); + + var tX = (a.x * T.R.col1.x + a.y * T.R.col1.y ); + a.y = (a.x * T.R.col2.x + a.y * T.R.col2.y ); + a.x = tX; + return a; + } +b2Math.AddVV = function (a, b) { + var v = new b2Vec2(a.x + b.x, a.y + b.y); + return v; + } +b2Math.SubtractVV = function (a, b) { + var v = new b2Vec2(a.x - b.x, a.y - b.y); + return v; + } +b2Math.b2Distance = function (a, b) { + var cX = a.x-b.x; + var cY = a.y-b.y; + return Math.sqrt(cX*cX + cY*cY); + } +b2Math.b2DistanceSquared = function (a, b) { + var cX = a.x-b.x; + var cY = a.y-b.y; + return (cX*cX + cY*cY); + } +b2Math.MulFV = function (s, a) { + var v = new b2Vec2(s * a.x, s * a.y); + return v; + } +b2Math.AddMM = function (A, B) { + var C = new b2Mat22(0, b2Math.AddVV(A.col1, B.col1), b2Math.AddVV(A.col2, B.col2)); + return C; + } +b2Math.b2MulMM = function (A, B) { + var C = new b2Mat22(0, b2Math.b2MulMV(A, B.col1), b2Math.b2MulMV(A, B.col2)); + return C; + } +b2Math.b2MulTMM = function (A, B) { + var c1 = new b2Vec2(b2Math.b2Dot(A.col1, B.col1), b2Math.b2Dot(A.col2, B.col1)); + var c2 = new b2Vec2(b2Math.b2Dot(A.col1, B.col2), b2Math.b2Dot(A.col2, B.col2)); + var C = new b2Mat22(0, c1, c2); + return C; + } +b2Math.b2Abs = function (a) { + return a > 0.0 ? a : -a; + } +b2Math.b2AbsV = function (a) { + var b = new b2Vec2(b2Math.b2Abs(a.x), b2Math.b2Abs(a.y)); + return b; + } +b2Math.b2AbsM = function (A) { + var B = new b2Mat22(0, b2Math.b2AbsV(A.col1), b2Math.b2AbsV(A.col2)); + return B; + } +b2Math.b2Min = function (a, b) { + return a < b ? a : b; + } +b2Math.b2MinV = function (a, b) { + var c = new b2Vec2(b2Math.b2Min(a.x, b.x), b2Math.b2Min(a.y, b.y)); + return c; + } +b2Math.b2Max = function (a, b) { + return a > b ? a : b; + } +b2Math.b2MaxV = function (a, b) { + var c = new b2Vec2(b2Math.b2Max(a.x, b.x), b2Math.b2Max(a.y, b.y)); + return c; + } +b2Math.b2Clamp = function (a, low, high) { + return b2Math.b2Max(low, b2Math.b2Min(a, high)); + } +b2Math.b2ClampV = function (a, low, high) { + return b2Math.b2MaxV(low, b2Math.b2MinV(a, high)); + } +b2Math.b2Swap = function (a, b) { + var tmp = a[0]; + a[0] = b[0]; + b[0] = tmp; + } +b2Math.b2Random = function () { + return Math.random() * 2 - 1; + } +b2Math.b2RandomRange = function (lo, hi) { + var r = Math.random(); + r = (hi - lo) * r + lo; + return r; + } +b2Math.b2NextPowerOfTwo = function (x) { + x |= (x >> 1) & 0x7FFFFFFF; + x |= (x >> 2) & 0x3FFFFFFF; + x |= (x >> 4) & 0x0FFFFFFF; + x |= (x >> 8) & 0x00FFFFFF; + x |= (x >> 16)& 0x0000FFFF; + return x + 1; + } +b2Math.b2IsPowerOfTwo = function (x) { + var result = x > 0 && (x & (x - 1)) == 0; + return result; + } +exports.b2Math = b2Math; + + +var b2Sweep = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Sweep.prototype.__constructor = function(){} +b2Sweep.prototype.__varz = function(){ +this.localCenter = new b2Vec2(); +this.c0 = new b2Vec2; +this.c = new b2Vec2(); +} +b2Sweep.prototype.localCenter = new b2Vec2(); +b2Sweep.prototype.c0 = new b2Vec2; +b2Sweep.prototype.c = new b2Vec2(); +b2Sweep.prototype.a0 = null; +b2Sweep.prototype.a = null; +b2Sweep.prototype.t0 = null; +b2Sweep.prototype.GetXForm = function (xf, t) { + + + if (1.0 - this.t0 > Number.MIN_VALUE) + { + var alpha = (t - this.t0) / (1.0 - this.t0); + xf.position.x = (1.0 - alpha) * this.c0.x + alpha * this.c.x; + xf.position.y = (1.0 - alpha) * this.c0.y + alpha * this.c.y; + var angle = (1.0 - alpha) * this.a0 + alpha * this.a; + xf.R.Set(angle); + } + else + { + xf.position.SetV(this.c); + xf.R.Set(this.a); + } + + + + var tMat = xf.R; + xf.position.x -= (tMat.col1.x * this.localCenter.x + tMat.col2.x * this.localCenter.y); + xf.position.y -= (tMat.col1.y * this.localCenter.x + tMat.col2.y * this.localCenter.y); + + } +b2Sweep.prototype.Advance = function (t) { + if (this.t0 < t && 1.0 - this.t0 > Number.MIN_VALUE) + { + var alpha = (t - this.t0) / (1.0 - this.t0); + + this.c0.x = (1.0 - alpha) * this.c0.x + alpha * this.c.x; + this.c0.y = (1.0 - alpha) * this.c0.y + alpha * this.c.y; + this.a0 = (1.0 - alpha) * this.a0 + alpha * this.a; + this.t0 = t; + } + } +exports.b2Sweep = b2Sweep; + + +var b2Pair = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Pair.prototype.__constructor = function(){} +b2Pair.prototype.__varz = function(){ +} +b2Pair.b2_nullPair = b2Settings.USHRT_MAX; +b2Pair.b2_nullProxy = b2Settings.USHRT_MAX; +b2Pair.b2_tableCapacity = b2Settings.b2_maxPairs; +b2Pair.b2_tableMask = b2Pair.b2_tableCapacity - 1; +b2Pair.e_pairBuffered = 0x0001; +b2Pair.e_pairRemoved = 0x0002; +b2Pair.e_pairFinal = 0x0004; +b2Pair.prototype.userData = null; +b2Pair.prototype.proxyId1 = 0; +b2Pair.prototype.proxyId2 = 0; +b2Pair.prototype.next = 0; +b2Pair.prototype.status = 0; +b2Pair.prototype.SetBuffered = function () { this.status |= b2Pair.e_pairBuffered; } +b2Pair.prototype.ClearBuffered = function () { this.status &= ~b2Pair.e_pairBuffered; } +b2Pair.prototype.IsBuffered = function () { return (this.status & b2Pair.e_pairBuffered) == b2Pair.e_pairBuffered; } +b2Pair.prototype.SetRemoved = function () { this.status |= b2Pair.e_pairRemoved; } +b2Pair.prototype.ClearRemoved = function () { this.status &= ~b2Pair.e_pairRemoved; } +b2Pair.prototype.IsRemoved = function () { return (this.status & b2Pair.e_pairRemoved) == b2Pair.e_pairRemoved; } +b2Pair.prototype.SetFinal = function () { this.status |= b2Pair.e_pairFinal; } +b2Pair.prototype.IsFinal = function () { return (this.status & b2Pair.e_pairFinal) == b2Pair.e_pairFinal; } +exports.b2Pair = b2Pair; + + +var b2PairCallback = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2PairCallback.prototype.__constructor = function(){} +b2PairCallback.prototype.__varz = function(){ +} +b2PairCallback.prototype.PairAdded = function (proxyUserData1, proxyUserData2) {return null} +b2PairCallback.prototype.PairRemoved = function (proxyUserData1, proxyUserData2, pairUserData) {} +exports.b2PairCallback = b2PairCallback; + + +var b2PairManager = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2PairManager.prototype.__constructor = function () { + var i = 0; + + + this.m_hashTable = new Array(b2Pair.b2_tableCapacity); + for (i = 0; i < b2Pair.b2_tableCapacity; ++i) + { + this.m_hashTable[i] = b2Pair.b2_nullPair; + } + this.m_pairs = new Array(b2Settings.b2_maxPairs); + for (i = 0; i < b2Settings.b2_maxPairs; ++i) + { + this.m_pairs[i] = new b2Pair(); + } + this.m_pairBuffer = new Array(b2Settings.b2_maxPairs); + for (i = 0; i < b2Settings.b2_maxPairs; ++i) + { + this.m_pairBuffer[i] = new b2BufferedPair(); + } + + for (i = 0; i < b2Settings.b2_maxPairs; ++i) + { + this.m_pairs[i].proxyId1 = b2Pair.b2_nullProxy; + this.m_pairs[i].proxyId2 = b2Pair.b2_nullProxy; + this.m_pairs[i].userData = null; + this.m_pairs[i].status = 0; + this.m_pairs[i].next = (i + 1); + } + this.m_pairs[parseInt(b2Settings.b2_maxPairs-1)].next = b2Pair.b2_nullPair; + this.m_pairCount = 0; + this.m_pairBufferCount = 0; + } +b2PairManager.prototype.__varz = function(){ +} +b2PairManager.Hash = function (proxyId1, proxyId2) { + var key = ((proxyId2 << 16) & 0xffff0000) | proxyId1; + key = ~key + ((key << 15) & 0xFFFF8000); + key = key ^ ((key >> 12) & 0x000fffff); + key = key + ((key << 2) & 0xFFFFFFFC); + key = key ^ ((key >> 4) & 0x0fffffff); + key = key * 2057; + key = key ^ ((key >> 16) % 65535); + return key; + } +b2PairManager.Equals = function (pair, proxyId1, proxyId2) { + return (pair.proxyId1 == proxyId1 && pair.proxyId2 == proxyId2); + } +b2PairManager.EqualsPair = function (pair1, pair2) { + return pair1.proxyId1 == pair2.proxyId1 && pair1.proxyId2 == pair2.proxyId2; + } +b2PairManager.prototype.m_broadPhase = null; +b2PairManager.prototype.m_callback = null; +b2PairManager.prototype.m_pairs = null; +b2PairManager.prototype.m_freePair = 0; +b2PairManager.prototype.m_pairCount = 0; +b2PairManager.prototype.m_pairBuffer = null; +b2PairManager.prototype.m_pairBufferCount = 0; +b2PairManager.prototype.m_hashTable = null; +b2PairManager.prototype.AddPair = function (proxyId1, proxyId2) { + + if (proxyId1 > proxyId2){ + var temp = proxyId1; + proxyId1 = proxyId2; + proxyId2 = temp; + + } + + var hash = b2PairManager.Hash(proxyId1, proxyId2) & b2Pair.b2_tableMask; + + + var pair = pair = this.FindHash(proxyId1, proxyId2, hash); + + if (pair != null) + { + return pair; + } + + + + var pIndex = this.m_freePair; + pair = this.m_pairs[pIndex]; + this.m_freePair = pair.next; + + pair.proxyId1 = proxyId1; + pair.proxyId2 = proxyId2; + pair.status = 0; + pair.userData = null; + pair.next = this.m_hashTable[hash]; + + this.m_hashTable[hash] = pIndex; + + ++this.m_pairCount; + + return pair; + } +b2PairManager.prototype.RemovePair = function (proxyId1, proxyId2) { + var pair; + + + + if (proxyId1 > proxyId2){ + var temp = proxyId1; + proxyId1 = proxyId2; + proxyId2 = temp; + + } + + var hash = b2PairManager.Hash(proxyId1, proxyId2) & b2Pair.b2_tableMask; + + var node = this.m_hashTable[hash]; + var pNode = null; + + while (node != b2Pair.b2_nullPair) + { + if (b2PairManager.Equals(this.m_pairs[node], proxyId1, proxyId2)) + { + var index = node; + + + pair = this.m_pairs[node]; + if (pNode){ + pNode.next = pair.next; + } + else{ + this.m_hashTable[hash] = pair.next; + } + + pair = this.m_pairs[ index ]; + var userData = pair.userData; + + + pair.next = this.m_freePair; + pair.proxyId1 = b2Pair.b2_nullProxy; + pair.proxyId2 = b2Pair.b2_nullProxy; + pair.userData = null; + pair.status = 0; + + this.m_freePair = index; + --this.m_pairCount; + return userData; + } + else + { + + pNode = this.m_pairs[node]; + node = pNode.next; + } + } + + + return null; + } +b2PairManager.prototype.Find = function (proxyId1, proxyId2) { + + if (proxyId1 > proxyId2){ + var temp = proxyId1; + proxyId1 = proxyId2; + proxyId2 = temp; + + } + + var hash = b2PairManager.Hash(proxyId1, proxyId2) & b2Pair.b2_tableMask; + + return this.FindHash(proxyId1, proxyId2, hash); + } +b2PairManager.prototype.FindHash = function (proxyId1, proxyId2, hash) { + var pair; + var index = this.m_hashTable[hash]; + + pair = this.m_pairs[index]; + while( index != b2Pair.b2_nullPair && b2PairManager.Equals(pair, proxyId1, proxyId2) == false) + { + index = pair.next; + pair = this.m_pairs[index]; + } + + if ( index == b2Pair.b2_nullPair ) + { + return null; + } + + + + return pair; + } +b2PairManager.prototype.ValidateBuffer = function () { + + } +b2PairManager.prototype.ValidateTable = function () { + + } +b2PairManager.prototype.Initialize = function (broadPhase, callback) { + this.m_broadPhase = broadPhase; + this.m_callback = callback; + } +b2PairManager.prototype.AddBufferedPair = function (proxyId1, proxyId2) { + var bufferedPair; + + + + var pair = this.AddPair(proxyId1, proxyId2); + + + if (pair.IsBuffered() == false) + { + + + + + pair.SetBuffered(); + bufferedPair = this.m_pairBuffer[this.m_pairBufferCount]; + bufferedPair.proxyId1 = pair.proxyId1; + bufferedPair.proxyId2 = pair.proxyId2; + ++this.m_pairBufferCount; + + + } + + + pair.ClearRemoved(); + + if (b2BroadPhase.s_validate) + { + this.ValidateBuffer(); + } + } +b2PairManager.prototype.RemoveBufferedPair = function (proxyId1, proxyId2) { + var bufferedPair; + + + + + var pair = this.Find(proxyId1, proxyId2); + + if (pair == null) + { + + return; + } + + + if (pair.IsBuffered() == false) + { + + + + pair.SetBuffered(); + bufferedPair = this.m_pairBuffer[this.m_pairBufferCount]; + bufferedPair.proxyId1 = pair.proxyId1; + bufferedPair.proxyId2 = pair.proxyId2; + ++this.m_pairBufferCount; + + + } + + pair.SetRemoved(); + + if (b2BroadPhase.s_validate) + { + this.ValidateBuffer(); + } + } +b2PairManager.prototype.Commit = function () { + var bufferedPair; + var i = 0; + + var removeCount = 0; + + var proxies = this.m_broadPhase.m_proxyPool; + + for (i = 0; i < this.m_pairBufferCount; ++i) + { + bufferedPair = this.m_pairBuffer[i]; + var pair = this.Find(bufferedPair.proxyId1, bufferedPair.proxyId2); + + pair.ClearBuffered(); + + + + var proxy1 = proxies[ pair.proxyId1 ]; + var proxy2 = proxies[ pair.proxyId2 ]; + + + + + if (pair.IsRemoved()) + { + + + + if (pair.IsFinal() == true) + { + this.m_callback.PairRemoved(proxy1.userData, proxy2.userData, pair.userData); + } + + + bufferedPair = this.m_pairBuffer[removeCount]; + bufferedPair.proxyId1 = pair.proxyId1; + bufferedPair.proxyId2 = pair.proxyId2; + ++removeCount; + } + else + { + + + if (pair.IsFinal() == false) + { + pair.userData = this.m_callback.PairAdded(proxy1.userData, proxy2.userData); + pair.SetFinal(); + } + } + } + + for (i = 0; i < removeCount; ++i) + { + bufferedPair = this.m_pairBuffer[i] + this.RemovePair(bufferedPair.proxyId1, bufferedPair.proxyId2); + } + + this.m_pairBufferCount = 0; + + if (b2BroadPhase.s_validate) + { + this.ValidateTable(); + } + } +exports.b2PairManager = b2PairManager; + + +var b2BufferedPair = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2BufferedPair.prototype.__constructor = function(){} +b2BufferedPair.prototype.__varz = function(){ +} +b2BufferedPair.prototype.proxyId1 = 0; +b2BufferedPair.prototype.proxyId2 = 0; +exports.b2BufferedPair = b2BufferedPair; + + +var b2AABB = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2AABB.prototype.__constructor = function(){} +b2AABB.prototype.__varz = function(){ +this.lowerBound = new b2Vec2(); +this.upperBound = new b2Vec2(); +} +b2AABB.prototype.lowerBound = new b2Vec2(); +b2AABB.prototype.upperBound = new b2Vec2(); +b2AABB.prototype.IsValid = function () { + + var dX = this.upperBound.x - this.lowerBound.x; + var dY = this.upperBound.y - this.lowerBound.y; + var valid = dX >= 0.0 && dY >= 0.0; + valid = valid && this.lowerBound.IsValid() && this.upperBound.IsValid(); + return valid; + } +exports.b2AABB = b2AABB; + + +var b2Manifold = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Manifold.prototype.__constructor = function () { + this.points = new Array(b2Settings.b2_maxManifoldPoints); + for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++){ + this.points[i] = new b2ManifoldPoint(); + } + this.normal = new b2Vec2(); + } +b2Manifold.prototype.__varz = function(){ +} +b2Manifold.prototype.points = null; +b2Manifold.prototype.normal = null; +b2Manifold.prototype.pointCount = 0; +b2Manifold.prototype.Reset = function () { + for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++){ + (this.points[i]).Reset(); + } + this.normal.SetZero(); + this.pointCount = 0; + } +b2Manifold.prototype.Set = function (m) { + this.pointCount = m.pointCount; + for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++){ + (this.points[i]).Set(m.points[i]); + } + this.normal.SetV(m.normal); + } +exports.b2Manifold = b2Manifold; + + +var Features = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +Features.prototype = { + get referenceEdge() { + return this._referenceEdge; + }, + set referenceEdge(value) { + this._referenceEdge = value; + this._m_id._key = (this._m_id._key & 0xffffff00) | (this._referenceEdge & 0x000000ff); + }, + get incidentEdge() { + return this._incidentEdge; + }, + set incidentEdge(value) { + this._incidentEdge = value; + this._m_id._key = (this._m_id._key & 0xffff00ff) | ((this._incidentEdge << 8) & 0x0000ff00); + }, + set incidentVertex(value) { + this._incidentVertex = value; + this._m_id._key = (this._m_id._key & 0xff00ffff) | ((this._incidentVertex << 16) & 0x00ff0000); + }, + get incidentVertex() { + return this._incidentVertex; + }, + set flip(value) { + this._flip = value; + this._m_id._key = (this._m_id._key & 0x00ffffff) | ((this._flip << 24) & 0xff000000); + }, + get flip() { + return this._flip; + } +} +Features.prototype.__constructor = function(){} +Features.prototype.__varz = function(){ +} +Features.prototype._referenceEdge = 0; +Features.prototype._incidentEdge = 0; +Features.prototype._incidentVertex = 0; +Features.prototype._flip = 0; +Features.prototype._m_id = null; +exports.Features = Features; + + +var b2ContactID = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2ContactID.prototype = { + get key() { + return this._key; + }, + set key(value) { + this._key = value; + this.features._referenceEdge = this._key & 0x000000ff; + this.features._incidentEdge = ((this._key & 0x0000ff00) >> 8) & 0x000000ff; + this.features._incidentVertex = ((this._key & 0x00ff0000) >> 16) & 0x000000ff; + this.features._flip = ((this._key & 0xff000000) >> 24) & 0x000000ff; + } +} +b2ContactID.prototype.__constructor = function () { + this.features._m_id = this; +} +b2ContactID.prototype.__varz = function(){ + this.features = new Features(); +} +b2ContactID.prototype.features = new Features(); +b2ContactID.prototype._key = 0; +b2ContactID.prototype.Set = function (id) { + this.key = id._key; +} +b2ContactID.prototype.Copy = function () { + var id = new b2ContactID(); + id.key = this._key; + return id; +} +exports.b2ContactID = b2ContactID; + + +var b2ManifoldPoint = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2ManifoldPoint.prototype.__constructor = function(){} +b2ManifoldPoint.prototype.__varz = function(){ +this.localPoint1 = new b2Vec2(); +this.localPoint2 = new b2Vec2(); +this.id = new b2ContactID(); +} +b2ManifoldPoint.prototype.localPoint1 = new b2Vec2(); +b2ManifoldPoint.prototype.localPoint2 = new b2Vec2(); +b2ManifoldPoint.prototype.separation = null; +b2ManifoldPoint.prototype.normalImpulse = null; +b2ManifoldPoint.prototype.tangentImpulse = null; +b2ManifoldPoint.prototype.id = new b2ContactID(); +b2ManifoldPoint.prototype.Reset = function () { + this.localPoint1.SetZero(); + this.localPoint2.SetZero(); + this.separation = 0.0; + this.normalImpulse = 0.0; + this.tangentImpulse = 0.0; + this.id.key = 0; + } +b2ManifoldPoint.prototype.Set = function (m) { + this.localPoint1.SetV(m.localPoint1); + this.localPoint2.SetV(m.localPoint2); + this.separation = m.separation; + this.normalImpulse = m.normalImpulse; + this.tangentImpulse = m.tangentImpulse; + this.id.key = m.id.key; + } +exports.b2ManifoldPoint = b2ManifoldPoint; + + +var b2Point = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Point.prototype.__constructor = function(){} +b2Point.prototype.__varz = function(){ +this.p = new b2Vec2(); +} +b2Point.prototype.p = new b2Vec2(); +b2Point.prototype.Support = function (xf, vX, vY) { + return this.p; + } +b2Point.prototype.GetFirstVertex = function (xf) { + return this.p; + } +exports.b2Point = b2Point; + + +var b2Bound = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Bound.prototype.__constructor = function(){} +b2Bound.prototype.__varz = function(){ +} +b2Bound.prototype.value = 0; +b2Bound.prototype.proxyId = 0; +b2Bound.prototype.stabbingCount = 0; +b2Bound.prototype.IsLower = function () { return (this.value & 1) == 0; } +b2Bound.prototype.IsUpper = function () { return (this.value & 1) == 1; } +b2Bound.prototype.Swap = function (b) { + var tempValue = this.value; + var tempProxyId = this.proxyId; + var tempStabbingCount = this.stabbingCount; + + this.value = b.value; + this.proxyId = b.proxyId; + this.stabbingCount = b.stabbingCount; + + b.value = tempValue; + b.proxyId = tempProxyId; + b.stabbingCount = tempStabbingCount; + } +exports.b2Bound = b2Bound; + + +var b2BoundValues = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2BoundValues.prototype.__constructor = function(){} +b2BoundValues.prototype.__varz = function(){ +this.lowerValues = [0,0]; +this.upperValues = [0,0]; +} +b2BoundValues.prototype.lowerValues = [0,0]; +b2BoundValues.prototype.upperValues = [0,0]; +exports.b2BoundValues = b2BoundValues; + + +var b2Collision = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Collision.prototype.__constructor = function(){} +b2Collision.prototype.__varz = function(){ +} +b2Collision.b2_nullFeature = 0x000000ff; +b2Collision.b2CollidePolyTempVec = new b2Vec2(); +b2Collision.ClipSegmentToLine = function (vOut, vIn, normal, offset) { + var cv; + + + var numOut = 0; + + cv = vIn[0]; + var vIn0 = cv.v; + cv = vIn[1]; + var vIn1 = cv.v; + + + var distance0 = b2Math.b2Dot(normal, vIn0) - offset; + var distance1 = b2Math.b2Dot(normal, vIn1) - offset; + + + if (distance0 <= 0.0) vOut[numOut++] = vIn[0]; + if (distance1 <= 0.0) vOut[numOut++] = vIn[1]; + + + if (distance0 * distance1 < 0.0) + { + + var interp = distance0 / (distance0 - distance1); + + + cv = vOut[numOut]; + var tVec = cv.v; + tVec.x = vIn0.x + interp * (vIn1.x - vIn0.x); + tVec.y = vIn0.y + interp * (vIn1.y - vIn0.y); + cv = vOut[numOut]; + var cv2; + if (distance0 > 0.0) + { + cv2 = vIn[0]; + cv.id = cv2.id; + } + else + { + cv2 = vIn[1]; + cv.id = cv2.id; + } + ++numOut; + } + + return numOut; + } +b2Collision.EdgeSeparation = function ( poly1, xf1, edge1, + poly2, xf2) { + var count1 = poly1.m_vertexCount; + var vertices1 = poly1.m_vertices; + var normals1 = poly1.m_normals; + + var count2 = poly2.m_vertexCount; + var vertices2 = poly2.m_vertices; + + + + var tMat; + var tVec; + + + + tMat = xf1.R; + tVec = normals1[edge1]; + var normal1WorldX = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var normal1WorldY = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + tMat = xf2.R; + var normal1X = (tMat.col1.x * normal1WorldX + tMat.col1.y * normal1WorldY); + var normal1Y = (tMat.col2.x * normal1WorldX + tMat.col2.y * normal1WorldY); + + + var index = 0; + var minDot = Number.MAX_VALUE; + for (var i = 0; i < count2; ++i) + { + + tVec = vertices2[i]; + var dot = tVec.x * normal1X + tVec.y * normal1Y; + if (dot < minDot) + { + minDot = dot; + index = i; + } + } + + + tVec = vertices1[edge1]; + tMat = xf1.R; + var v1X = xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var v1Y = xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + tVec = vertices2[index]; + tMat = xf2.R; + var v2X = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var v2Y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + + v2X -= v1X; + v2Y -= v1Y; + + var separation = v2X * normal1WorldX + v2Y * normal1WorldY; + return separation; + } +b2Collision.FindMaxSeparation = function (edgeIndex , + poly1, xf1, + poly2, xf2) { + var count1 = poly1.m_vertexCount; + var normals1 = poly1.m_normals; + + var tVec; + var tMat; + + + + tMat = xf2.R; + tVec = poly2.m_centroid; + var dX = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var dY = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = xf1.R; + tVec = poly1.m_centroid; + dX -= xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + dY -= xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + + var dLocal1X = (dX * xf1.R.col1.x + dY * xf1.R.col1.y); + var dLocal1Y = (dX * xf1.R.col2.x + dY * xf1.R.col2.y); + + + var edge = 0; + var maxDot = -Number.MAX_VALUE; + for (var i = 0; i < count1; ++i) + { + + tVec = normals1[i]; + var dot = (tVec.x * dLocal1X + tVec.y * dLocal1Y); + if (dot > maxDot) + { + maxDot = dot; + edge = i; + } + } + + + var s = b2Collision.EdgeSeparation(poly1, xf1, edge, poly2, xf2); + if (s > 0.0) + { + return s; + } + + + var prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1; + var sPrev = b2Collision.EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); + if (sPrev > 0.0) + { + return sPrev; + } + + + var nextEdge = edge + 1 < count1 ? edge + 1 : 0; + var sNext = b2Collision.EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); + if (sNext > 0.0) + { + return sNext; + } + + + var bestEdge = 0; + var bestSeparation; + var increment = 0; + if (sPrev > s && sPrev > sNext) + { + increment = -1; + bestEdge = prevEdge; + bestSeparation = sPrev; + } + else if (sNext > s) + { + increment = 1; + bestEdge = nextEdge; + bestSeparation = sNext; + } + else + { + + edgeIndex[0] = edge; + return s; + } + + + while (true) + { + + if (increment == -1) + edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; + else + edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0; + + s = b2Collision.EdgeSeparation(poly1, xf1, edge, poly2, xf2); + if (s > 0.0) + { + return s; + } + + if (s > bestSeparation) + { + bestEdge = edge; + bestSeparation = s; + } + else + { + break; + } + } + + + edgeIndex[0] = bestEdge; + return bestSeparation; + } +b2Collision.FindIncidentEdge = function (c, + poly1, xf1, edge1, + poly2, xf2) { + var count1 = poly1.m_vertexCount; + var normals1 = poly1.m_normals; + + var count2 = poly2.m_vertexCount; + var vertices2 = poly2.m_vertices; + var normals2 = poly2.m_normals; + + + + var tMat; + var tVec; + + + + tMat = xf1.R; + tVec = normals1[edge1]; + var normal1X = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var normal1Y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = xf2.R; + var tX = (tMat.col1.x * normal1X + tMat.col1.y * normal1Y); + normal1Y = (tMat.col2.x * normal1X + tMat.col2.y * normal1Y); + normal1X = tX; + + + var index = 0; + var minDot = Number.MAX_VALUE; + for (var i = 0; i < count2; ++i) + { + + tVec = normals2[i]; + var dot = (normal1X * tVec.x + normal1Y * tVec.y); + if (dot < minDot) + { + minDot = dot; + index = i; + } + } + + var tClip; + + var i1 = index; + var i2 = i1 + 1 < count2 ? i1 + 1 : 0; + + tClip = c[0]; + + tVec = vertices2[i1]; + tMat = xf2.R; + tClip.v.x = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + tClip.v.y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + tClip.id.features.referenceEdge = edge1; + tClip.id.features.incidentEdge = i1; + tClip.id.features.incidentVertex = 0; + + tClip = c[1]; + + tVec = vertices2[i2]; + tMat = xf2.R; + tClip.v.x = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + tClip.v.y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + tClip.id.features.referenceEdge = edge1; + tClip.id.features.incidentEdge = i2; + tClip.id.features.incidentVertex = 1; + } +b2Collision.b2CollidePolygons = function (manifold, + polyA, xfA, + polyB, xfB) { + var cv; + + manifold.pointCount = 0; + + var edgeA = 0; + var edgeAO = [edgeA]; + var separationA = b2Collision.FindMaxSeparation(edgeAO, polyA, xfA, polyB, xfB); + edgeA = edgeAO[0]; + if (separationA > 0.0) + return; + + var edgeB = 0; + var edgeBO = [edgeB]; + var separationB = b2Collision.FindMaxSeparation(edgeBO, polyB, xfB, polyA, xfA); + edgeB = edgeBO[0]; + if (separationB > 0.0) + return; + + var poly1; + var poly2; + var xf1 = new b2XForm(); + var xf2 = new b2XForm(); + var edge1 = 0; + var flip = 0; + var k_relativeTol = 0.98; + var k_absoluteTol = 0.001; + + + if (separationB > k_relativeTol * separationA + k_absoluteTol) + { + poly1 = polyB; + poly2 = polyA; + xf1.Set(xfB); + xf2.Set(xfA); + edge1 = edgeB; + flip = 1; + } + else + { + poly1 = polyA; + poly2 = polyB; + xf1.Set(xfA); + xf2.Set(xfB); + edge1 = edgeA; + flip = 0; + } + + var incidentEdge = [new ClipVertex(), new ClipVertex()]; + b2Collision.FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); + + var count1 = poly1.m_vertexCount; + var vertices1 = poly1.m_vertices; + + var tVec = vertices1[edge1]; + var v11 = tVec.Copy(); + if (edge1 + 1 < count1) { + tVec = vertices1[parseInt(edge1+1)]; + var v12 = tVec.Copy(); + } else { + tVec = vertices1[0]; + v12 = tVec.Copy(); + } + + var dv = b2Math.SubtractVV(v12 , v11); + var sideNormal = b2Math.b2MulMV(xf1.R, b2Math.SubtractVV(v12 , v11)); + sideNormal.Normalize(); + var frontNormal = b2Math.b2CrossVF(sideNormal, 1.0); + + v11 = b2Math.b2MulX(xf1, v11); + v12 = b2Math.b2MulX(xf1, v12); + + var frontOffset = b2Math.b2Dot(frontNormal, v11); + var sideOffset1 = -b2Math.b2Dot(sideNormal, v11); + var sideOffset2 = b2Math.b2Dot(sideNormal, v12); + + + var clipPoints1 = [new ClipVertex(), new ClipVertex()]; + var clipPoints2 = [new ClipVertex(), new ClipVertex()]; + var np = 0; + + + + np = b2Collision.ClipSegmentToLine(clipPoints1, incidentEdge, sideNormal.Negative(), sideOffset1); + + if (np < 2) + return; + + + np = b2Collision.ClipSegmentToLine(clipPoints2, clipPoints1, sideNormal, sideOffset2); + + if (np < 2) + return; + + + manifold.normal = flip ? frontNormal.Negative() : frontNormal.Copy(); + + var pointCount = 0; + for (var i = 0; i < b2Settings.b2_maxManifoldPoints; ++i) + { + cv = clipPoints2[i]; + var separation = b2Math.b2Dot(frontNormal, cv.v) - frontOffset; + + if (separation <= 0.0) + { + var cp = manifold.points[ pointCount ]; + cp.separation = separation; + cp.localPoint1 = b2Math.b2MulXT(xfA, cv.v); + cp.localPoint2 = b2Math.b2MulXT(xfB, cv.v); + cp.id.key = cv.id._key; + cp.id.features.flip = flip; + ++pointCount; + } + } + + manifold.pointCount = pointCount; + } +b2Collision.b2CollideCircles = function ( + manifold, + circle1, xf1, + circle2, xf2) { + manifold.pointCount = 0; + + var tMat; + var tVec; + + + tMat = xf1.R; tVec = circle1.m_localPosition; + var p1X = xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var p1Y = xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + tMat = xf2.R; tVec = circle2.m_localPosition; + var p2X = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var p2Y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + var dX = p2X - p1X; + var dY = p2Y - p1Y; + + var distSqr = dX * dX + dY * dY; + var r1 = circle1.m_radius; + var r2 = circle2.m_radius; + var radiusSum = r1 + r2; + if (distSqr > radiusSum * radiusSum) + { + return; + } + + var separation; + if (distSqr < Number.MIN_VALUE) + { + separation = -radiusSum; + manifold.normal.Set(0.0, 1.0); + } + else + { + var dist = Math.sqrt(distSqr); + separation = dist - radiusSum; + var a = 1.0 / dist; + manifold.normal.x = a * dX; + manifold.normal.y = a * dY; + } + + manifold.pointCount = 1; + var tPoint = manifold.points[0]; + tPoint.id.key = 0; + tPoint.separation = separation; + + p1X += r1 * manifold.normal.x; + p1Y += r1 * manifold.normal.y; + p2X -= r2 * manifold.normal.x; + p2Y -= r2 * manifold.normal.y; + + + var pX = 0.5 * (p1X + p2X); + var pY = 0.5 * (p1Y + p2Y); + + + var tX = pX - xf1.position.x; + var tY = pY - xf1.position.y; + tPoint.localPoint1.x = (tX * xf1.R.col1.x + tY * xf1.R.col1.y ); + tPoint.localPoint1.y = (tX * xf1.R.col2.x + tY * xf1.R.col2.y ); + + tX = pX - xf2.position.x; + tY = pY - xf2.position.y; + tPoint.localPoint2.x = (tX * xf2.R.col1.x + tY * xf2.R.col1.y ); + tPoint.localPoint2.y = (tX * xf2.R.col2.x + tY * xf2.R.col2.y ); + } +b2Collision.b2CollidePolygonAndCircle = function ( + manifold, + polygon, xf1, + circle, xf2) { + manifold.pointCount = 0; + var tPoint; + + var dX; + var dY; + var positionX; + var positionY; + + var tVec; + var tMat; + + + + tMat = xf2.R; + tVec = circle.m_localPosition; + var cX = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var cY = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + + dX = cX - xf1.position.x; + dY = cY - xf1.position.y; + tMat = xf1.R; + var cLocalX = (dX * tMat.col1.x + dY * tMat.col1.y); + var cLocalY = (dX * tMat.col2.x + dY * tMat.col2.y); + + var dist; + + + var normalIndex = 0; + var separation = -Number.MAX_VALUE; + var radius = circle.m_radius; + var vertexCount = polygon.m_vertexCount; + var vertices = polygon.m_vertices; + var normals = polygon.m_normals; + + for (var i = 0; i < vertexCount; ++i) + { + + tVec = vertices[i]; + dX = cLocalX-tVec.x; + dY = cLocalY-tVec.y; + tVec = normals[i]; + var s = tVec.x * dX + tVec.y * dY; + + if (s > radius) + { + + return; + } + + if (s > separation) + { + separation = s; + normalIndex = i; + } + } + + + if (separation < Number.MIN_VALUE) + { + manifold.pointCount = 1; + + tVec = normals[normalIndex]; + tMat = xf1.R; + manifold.normal.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + manifold.normal.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + tPoint = manifold.points[0]; + tPoint.id.features.incidentEdge = normalIndex; + tPoint.id.features.incidentVertex = b2Collision.b2_nullFeature; + tPoint.id.features.referenceEdge = 0; + tPoint.id.features.flip = 0; + + positionX = cX - radius * manifold.normal.x; + positionY = cY - radius * manifold.normal.y; + + dX = positionX - xf1.position.x; + dY = positionY - xf1.position.y; + tMat = xf1.R; + tPoint.localPoint1.x = (dX*tMat.col1.x + dY*tMat.col1.y); + tPoint.localPoint1.y = (dX*tMat.col2.x + dY*tMat.col2.y); + + dX = positionX - xf2.position.x; + dY = positionY - xf2.position.y; + tMat = xf2.R; + tPoint.localPoint2.x = (dX*tMat.col1.x + dY*tMat.col1.y); + tPoint.localPoint2.y = (dX*tMat.col2.x + dY*tMat.col2.y); + + tPoint.separation = separation - radius; + return; + } + + + var vertIndex1 = normalIndex; + var vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0; + tVec = vertices[vertIndex1]; + var tVec2 = vertices[vertIndex2]; + + var eX = tVec2.x - tVec.x; + var eY = tVec2.y - tVec.y; + + + var length = Math.sqrt(eX*eX + eY*eY); + eX /= length; + eY /= length; + + + + + dX = cLocalX - tVec.x; + dY = cLocalY - tVec.y; + var u = dX*eX + dY*eY; + + tPoint = manifold.points[0]; + + var pX, pY; + if (u <= 0.0) + { + pX = tVec.x; + pY = tVec.y; + tPoint.id.features.incidentEdge = b2Collision.b2_nullFeature; + tPoint.id.features.incidentVertex = vertIndex1; + } + else if (u >= length) + { + pX = tVec2.x; + pY = tVec2.y; + tPoint.id.features.incidentEdge = b2Collision.b2_nullFeature; + tPoint.id.features.incidentVertex = vertIndex2; + } + else + { + + pX = eX * u + tVec.x; + pY = eY * u + tVec.y; + tPoint.id.features.incidentEdge = normalIndex; + tPoint.id.features.incidentVertex = b2Collision.b2_nullFeature; + } + + + dX = cLocalX - pX; + dY = cLocalY - pY; + + dist = Math.sqrt(dX*dX + dY*dY); + dX /= dist; + dY /= dist; + if (dist > radius) + { + return; + } + + manifold.pointCount = 1; + + tMat = xf1.R; + manifold.normal.x = tMat.col1.x * dX + tMat.col2.x * dY; + manifold.normal.y = tMat.col1.y * dX + tMat.col2.y * dY; + + positionX = cX - radius * manifold.normal.x; + positionY = cY - radius * manifold.normal.y; + + dX = positionX - xf1.position.x; + dY = positionY - xf1.position.y; + tMat = xf1.R; + tPoint.localPoint1.x = (dX*tMat.col1.x + dY*tMat.col1.y); + tPoint.localPoint1.y = (dX*tMat.col2.x + dY*tMat.col2.y); + + dX = positionX - xf2.position.x; + dY = positionY - xf2.position.y; + tMat = xf2.R; + tPoint.localPoint2.x = (dX*tMat.col1.x + dY*tMat.col1.y); + tPoint.localPoint2.y = (dX*tMat.col2.x + dY*tMat.col2.y); + tPoint.separation = dist - radius; + tPoint.id.features.referenceEdge = 0; + tPoint.id.features.flip = 0; + } +b2Collision.b2TestOverlap = function (a, b) { + var t1 = b.lowerBound; + var t2 = a.upperBound; + + var d1X = t1.x - t2.x; + var d1Y = t1.y - t2.y; + + t1 = a.lowerBound; + t2 = b.upperBound; + var d2X = t1.x - t2.x; + var d2Y = t1.y - t2.y; + + if (d1X > 0.0 || d1Y > 0.0) + return false; + + if (d2X > 0.0 || d2Y > 0.0) + return false; + + return true; + } +exports.b2Collision = b2Collision; + + +var b2Proxy = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Proxy.prototype.__constructor = function(){} +b2Proxy.prototype.__varz = function(){ +this.lowerBounds = [parseInt(0), parseInt(0)]; +this.upperBounds = [parseInt(0), parseInt(0)]; +} +b2Proxy.prototype.lowerBounds = [parseInt(0), parseInt(0)]; +b2Proxy.prototype.upperBounds = [parseInt(0), parseInt(0)]; +b2Proxy.prototype.overlapCount = 0; +b2Proxy.prototype.timeStamp = 0; +b2Proxy.prototype.userData = null; +b2Proxy.prototype.GetNext = function () { return this.lowerBounds[0]; } +b2Proxy.prototype.SetNext = function (next) { this.lowerBounds[0] = next % 65535; } +b2Proxy.prototype.IsValid = function () { return this.overlapCount != b2BroadPhase.b2_invalid; } +exports.b2Proxy = b2Proxy; + + +var b2Segment = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Segment.prototype.__constructor = function(){} +b2Segment.prototype.__varz = function(){ +this.p1 = new b2Vec2(); +this.p2 = new b2Vec2(); +} +b2Segment.prototype.p1 = new b2Vec2(); +b2Segment.prototype.p2 = new b2Vec2(); +b2Segment.prototype.TestSegment = function (lambda, + normal, + segment, + maxLambda) { + + var s = segment.p1; + + var rX = segment.p2.x - s.x; + var rY = segment.p2.y - s.y; + + var dX = this.p2.x - this.p1.x; + var dY = this.p2.y - this.p1.y; + + var nX = dY; + var nY = -dX; + + var k_slop = 100.0 * Number.MIN_VALUE; + + var denom = -(rX*nX + rY*nY); + + + if (denom > k_slop) + { + + + var bX = s.x - this.p1.x; + var bY = s.y - this.p1.y; + + var a = (bX*nX + bY*nY); + + if (0.0 <= a && a <= maxLambda * denom) + { + var mu2 = -rX * bY + rY * bX; + + + if (-k_slop * denom <= mu2 && mu2 <= denom * (1.0 + k_slop)) + { + a /= denom; + + var nLen = Math.sqrt(nX*nX + nY*nY); + nX /= nLen; + nY /= nLen; + + lambda[0] = a; + + normal.Set(nX, nY); + return true; + } + } + } + + return false; + } +exports.b2Segment = b2Segment; + + +var b2Distance = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Distance.prototype.__constructor = function(){} +b2Distance.prototype.__varz = function(){ +} +b2Distance.g_GJK_Iterations = 0; +b2Distance.s_p1s = [new b2Vec2(), new b2Vec2(), new b2Vec2()]; +b2Distance.s_p2s = [new b2Vec2(), new b2Vec2(), new b2Vec2()]; +b2Distance.s_points = [new b2Vec2(), new b2Vec2(), new b2Vec2()]; +b2Distance.gPoint = new b2Point(); +b2Distance.ProcessTwo = function (x1, x2, p1s, p2s, points) { + var points_0 = points[0]; + var points_1 = points[1]; + var p1s_0 = p1s[0]; + var p1s_1 = p1s[1]; + var p2s_0 = p2s[0]; + var p2s_1 = p2s[1]; + + + + var rX = -points_1.x; + var rY = -points_1.y; + + var dX = points_0.x - points_1.x; + var dY = points_0.y - points_1.y; + + var length = Math.sqrt(dX*dX + dY*dY); + dX /= length; + dY /= length; + + + var lambda = rX * dX + rY * dY; + if (lambda <= 0.0 || length < Number.MIN_VALUE) + { + + + x1.SetV(p1s_1); + + x2.SetV(p2s_1); + + p1s_0.SetV(p1s_1); + + p2s_0.SetV(p2s_1); + points_0.SetV(points_1); + return 1; + } + + + lambda /= length; + + x1.x = p1s_1.x + lambda * (p1s_0.x - p1s_1.x); + x1.y = p1s_1.y + lambda * (p1s_0.y - p1s_1.y); + + x2.x = p2s_1.x + lambda * (p2s_0.x - p2s_1.x); + x2.y = p2s_1.y + lambda * (p2s_0.y - p2s_1.y); + return 2; +} +b2Distance.ProcessThree = function (x1, x2, p1s, p2s, points) { + var points_0 = points[0]; + var points_1 = points[1]; + var points_2 = points[2]; + var p1s_0 = p1s[0]; + var p1s_1 = p1s[1]; + var p1s_2 = p1s[2]; + var p2s_0 = p2s[0]; + var p2s_1 = p2s[1]; + var p2s_2 = p2s[2]; + + + var aX = points_0.x; + var aY = points_0.y; + + var bX = points_1.x; + var bY = points_1.y; + + var cX = points_2.x; + var cY = points_2.y; + + + var abX = bX - aX; + var abY = bY - aY; + + var acX = cX - aX; + var acY = cY - aY; + + var bcX = cX - bX; + var bcY = cY - bY; + + + var sn = -(aX * abX + aY * abY); + var sd = (bX * abX + bY * abY); + + var tn = -(aX * acX + aY * acY); + var td = (cX * acX + cY * acY); + + var un = -(bX * bcX + bY * bcY); + var ud = (cX * bcX + cY * bcY); + + + if (td <= 0.0 && ud <= 0.0) + { + + + x1.SetV(p1s_2); + + x2.SetV(p2s_2); + + p1s_0.SetV(p1s_2); + + p2s_0.SetV(p2s_2); + points_0.SetV(points_2); + return 1; + } + + + + + + + var n = abX * acY - abY * acX; + + + + var vc = n * (aX * bY - aY * bX); + + var lambda; + + + + var va = n * (bX * cY - bY * cX); + if (va <= 0.0 && un >= 0.0 && ud >= 0.0 && (un+ud) > 0.0) + { + + + + lambda = un / (un + ud); + + x1.x = p1s_1.x + lambda * (p1s_2.x - p1s_1.x); + x1.y = p1s_1.y + lambda * (p1s_2.y - p1s_1.y); + + x2.x = p2s_1.x + lambda * (p2s_2.x - p2s_1.x); + x2.y = p2s_1.y + lambda * (p2s_2.y - p2s_1.y); + + p1s_0.SetV(p1s_2); + + p2s_0.SetV(p2s_2); + + points_0.SetV(points_2); + return 2; + } + + + + var vb = n * (cX * aY - cY * aX); + if (vb <= 0.0 && tn >= 0.0 && td >= 0.0 && (tn+td) > 0.0) + { + + + + lambda = tn / (tn + td); + + x1.x = p1s_0.x + lambda * (p1s_2.x - p1s_0.x); + x1.y = p1s_0.y + lambda * (p1s_2.y - p1s_0.y); + + x2.x = p2s_0.x + lambda * (p2s_2.x - p2s_0.x); + x2.y = p2s_0.y + lambda * (p2s_2.y - p2s_0.y); + + p1s_1.SetV(p1s_2); + + p2s_1.SetV(p2s_2); + + points_1.SetV(points_2); + return 2; + } + + + + var denom = va + vb + vc; + + denom = 1.0 / denom; + + var u = va * denom; + + var v = vb * denom; + + var w = 1.0 - u - v; + + x1.x = u * p1s_0.x + v * p1s_1.x + w * p1s_2.x; + x1.y = u * p1s_0.y + v * p1s_1.y + w * p1s_2.y; + + x2.x = u * p2s_0.x + v * p2s_1.x + w * p2s_2.x; + x2.y = u * p2s_0.y + v * p2s_1.y + w * p2s_2.y; + return 3; +} +b2Distance.InPoints = function (w, points, pointCount) { + var k_tolerance = 100.0 * Number.MIN_VALUE; + for (var i = 0; i < pointCount; ++i) + { + var points_i = points[i]; + + var dX = Math.abs(w.x - points_i.x); + var dY = Math.abs(w.y - points_i.y); + + var mX = Math.max(Math.abs(w.x), Math.abs(points_i.x)); + var mY = Math.max(Math.abs(w.y), Math.abs(points_i.y)); + + if (dX < k_tolerance * (mX + 1.0) && + dY < k_tolerance * (mY + 1.0)){ + return true; + } + } + + return false; +} +b2Distance.DistanceGeneric = function (x1, x2, + shape1, xf1, + shape2, xf2) { + var tVec; + + + var p1s = b2Distance.s_p1s; + var p2s = b2Distance.s_p2s; + + var points = b2Distance.s_points; + + var pointCount = 0; + + + x1.SetV(shape1.GetFirstVertex(xf1)); + + x2.SetV(shape2.GetFirstVertex(xf2)); + + var vSqr = 0.0; + var maxIterations = 20; + for (var iter = 0; iter < maxIterations; ++iter) + { + + var vX = x2.x - x1.x; + var vY = x2.y - x1.y; + + var w1 = shape1.Support(xf1, vX, vY); + + var w2 = shape2.Support(xf2, -vX, -vY); + + vSqr = (vX*vX + vY*vY); + + var wX = w2.x - w1.x; + var wY = w2.y - w1.y; + + var vw = (vX*wX + vY*wY); + + if (vSqr - vw <= 0.01 * vSqr) + { + if (pointCount == 0) + { + + x1.SetV(w1); + + x2.SetV(w2); + } + b2Distance.g_GJK_Iterations = iter; + return Math.sqrt(vSqr); + } + + switch (pointCount) + { + case 0: + + tVec = p1s[0]; + tVec.SetV(w1); + + tVec = p2s[0]; + tVec.SetV(w2); + + tVec = points[0]; + tVec.x = wX; + tVec.y = wY; + + x1.SetV(p1s[0]); + + x2.SetV(p2s[0]); + ++pointCount; + break; + + case 1: + + tVec = p1s[1]; + tVec.SetV(w1); + + tVec = p2s[1]; + tVec.SetV(w2); + + tVec = points[1]; + tVec.x = wX; + tVec.y = wY; + pointCount = b2Distance.ProcessTwo(x1, x2, p1s, p2s, points); + break; + + case 2: + + tVec = p1s[2]; + tVec.SetV(w1); + + tVec = p2s[2]; + tVec.SetV(w2); + + tVec = points[2]; + tVec.x = wX; + tVec.y = wY; + pointCount = b2Distance.ProcessThree(x1, x2, p1s, p2s, points); + break; + } + + + if (pointCount == 3) + { + b2Distance.g_GJK_Iterations = iter; + return 0.0; + } + + + var maxSqr = -Number.MAX_VALUE; + for (var i = 0; i < pointCount; ++i) + { + + tVec = points[i]; + maxSqr = b2Math.b2Max(maxSqr, (tVec.x*tVec.x + tVec.y*tVec.y)); + } + + if (pointCount == 3 || vSqr <= 100.0 * Number.MIN_VALUE * maxSqr) + { + b2Distance.g_GJK_Iterations = iter; + + vX = x2.x - x1.x; + vY = x2.y - x1.y; + + vSqr = (vX*vX + vY*vY); + return Math.sqrt(vSqr); + } + } + + b2Distance.g_GJK_Iterations = maxIterations; + return Math.sqrt(vSqr); +} +b2Distance.DistanceCC = function ( + x1, x2, + circle1, xf1, + circle2, xf2) { + var tMat; + var tVec; + + tMat = xf1.R; + tVec = circle1.m_localPosition; + var p1X = xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var p1Y = xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + tMat = xf2.R; + tVec = circle2.m_localPosition; + var p2X = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var p2Y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + + var dX = p2X - p1X; + var dY = p2Y - p1Y; + var dSqr = (dX*dX + dY*dY); + var r1 = circle1.m_radius - b2Settings.b2_toiSlop; + var r2 = circle2.m_radius - b2Settings.b2_toiSlop; + var r = r1 + r2; + if (dSqr > r * r) + { + + var dLen = Math.sqrt(dSqr); + dX /= dLen; + dY /= dLen; + var distance = dLen - r; + + x1.x = p1X + r1 * dX; + x1.y = p1Y + r1 * dY; + + x2.x = p2X - r2 * dX; + x2.y = p2Y - r2 * dY; + return distance; + } + else if (dSqr > Number.MIN_VALUE * Number.MIN_VALUE) + { + + dLen = Math.sqrt(dSqr); + dX /= dLen; + dY /= dLen; + + x1.x = p1X + r1 * dX; + x1.y = p1Y + r1 * dY; + + x2.x = x1.x; + x2.y = x1.y; + return 0.0; + } + + + x1.x = p1X; + x1.y = p1Y; + + x2.x = x1.x; + x2.y = x1.y; + return 0.0; +} +b2Distance.DistancePC = function ( + x1, x2, + polygon, xf1, + circle, xf2) { + + var tMat; + var tVec; + + var point = b2Distance.gPoint; + + tVec = circle.m_localPosition; + tMat = xf2.R; + point.p.x = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + point.p.y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + + var distance = b2Distance.DistanceGeneric(x1, x2, polygon, xf1, point, b2Math.b2XForm_identity); + + var r = circle.m_radius - b2Settings.b2_toiSlop; + + if (distance > r) + { + distance -= r; + + var dX = x2.x - x1.x; + var dY = x2.y - x1.y; + + var dLen = Math.sqrt(dX*dX + dY*dY); + dX /= dLen; + dY /= dLen; + + x2.x -= r * dX; + x2.y -= r * dY; + } + else + { + distance = 0.0; + + x2.x = x1.x; + x2.y = x1.y; + } + + return distance; +} +b2Distance.Distance = function (x1, x2, + shape1, xf1, + shape2, xf2) { + + var type1 = shape1.m_type; + + var type2 = shape2.m_type; + + if (type1 == b2Shape.e_circleShape && type2 == b2Shape.e_circleShape) + { + + return b2Distance.DistanceCC(x1, x2, shape1, xf1, shape2, xf2); + } + + if (type1 == b2Shape.e_polygonShape && type2 == b2Shape.e_circleShape) + { + + return b2Distance.DistancePC(x1, x2, shape1, xf1, shape2, xf2); + } + + if (type1 == b2Shape.e_circleShape && type2 == b2Shape.e_polygonShape) + { + return b2Distance.DistancePC(x2, x1, shape2, xf2, shape1, xf1); + } + + if (type1 == b2Shape.e_polygonShape && type2 == b2Shape.e_polygonShape) + { + return b2Distance.DistanceGeneric(x1, x2, shape1, xf1, shape2, xf2); + } + + return 0.0; +} +exports.b2Distance = b2Distance; + + +var b2OBB = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2OBB.prototype.__constructor = function(){} +b2OBB.prototype.__varz = function(){ +this.R = new b2Mat22(); +this.center = new b2Vec2(); +this.extents = new b2Vec2(); +} +b2OBB.prototype.R = new b2Mat22(); +b2OBB.prototype.center = new b2Vec2(); +b2OBB.prototype.extents = new b2Vec2(); +exports.b2OBB = b2OBB; + + +var b2BroadPhase = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2BroadPhase.prototype.__constructor = function (worldAABB, callback) { + + var i = 0; + + this.m_pairManager.Initialize(this, callback); + + this.m_worldAABB = worldAABB; + + this.m_proxyCount = 0; + + + for (i = 0; i < b2Settings.b2_maxProxies; i++){ + this.m_queryResults[i] = 0; + } + + + this.m_bounds = new Array(2); + for (i = 0; i < 2; i++){ + this.m_bounds[i] = new Array(2*b2Settings.b2_maxProxies); + for (var j = 0; j < 2*b2Settings.b2_maxProxies; j++){ + this.m_bounds[i][j] = new b2Bound(); + } + } + + + var dX = worldAABB.upperBound.x - worldAABB.lowerBound.x;; + var dY = worldAABB.upperBound.y - worldAABB.lowerBound.y; + + this.m_quantizationFactor.x = b2Settings.USHRT_MAX / dX; + this.m_quantizationFactor.y = b2Settings.USHRT_MAX / dY; + + var tProxy; + for (i = 0; i < b2Settings.b2_maxProxies - 1; ++i) + { + tProxy = new b2Proxy(); + this.m_proxyPool[i] = tProxy; + tProxy.SetNext(i + 1); + tProxy.timeStamp = 0; + tProxy.overlapCount = b2BroadPhase.b2_invalid; + tProxy.userData = null; + } + tProxy = new b2Proxy(); + this.m_proxyPool[parseInt(b2Settings.b2_maxProxies-1)] = tProxy; + tProxy.SetNext(b2Pair.b2_nullProxy); + tProxy.timeStamp = 0; + tProxy.overlapCount = b2BroadPhase.b2_invalid; + tProxy.userData = null; + this.m_freeProxy = 0; + + this.m_timeStamp = 1; + this.m_queryResultCount = 0; + } +b2BroadPhase.prototype.__varz = function(){ +this.m_pairManager = new b2PairManager(); +this.m_proxyPool = new Array(b2Settings.b2_maxPairs); +this.m_bounds = new Array(2*b2Settings.b2_maxProxies); +this.m_queryResults = new Array(b2Settings.b2_maxProxies); +this.m_quantizationFactor = new b2Vec2(); +} +b2BroadPhase.s_validate = false; +b2BroadPhase.b2_invalid = b2Settings.USHRT_MAX; +b2BroadPhase.b2_nullEdge = b2Settings.USHRT_MAX; +b2BroadPhase.BinarySearch = function (bounds, count, value) { + var low = 0; + var high = count - 1; + while (low <= high) + { + var mid = Math.round((low + high) / 2); + var bound = bounds[mid]; + if (bound.value > value) + { + high = mid - 1; + } + else if (bound.value < value) + { + low = mid + 1; + } + else + { + return parseInt(mid); + } + } + + return parseInt(low); + } +b2BroadPhase.prototype.m_pairManager = new b2PairManager(); +b2BroadPhase.prototype.m_proxyPool = new Array(b2Settings.b2_maxPairs); +b2BroadPhase.prototype.m_freeProxy = 0; +b2BroadPhase.prototype.m_bounds = new Array(2*b2Settings.b2_maxProxies); +b2BroadPhase.prototype.m_queryResults = new Array(b2Settings.b2_maxProxies); +b2BroadPhase.prototype.m_queryResultCount = 0; +b2BroadPhase.prototype.m_worldAABB = null; +b2BroadPhase.prototype.m_quantizationFactor = new b2Vec2(); +b2BroadPhase.prototype.m_proxyCount = 0; +b2BroadPhase.prototype.m_timeStamp = 0; +b2BroadPhase.prototype.ComputeBounds = function (lowerValues, upperValues, aabb) { + + + + + var minVertexX = aabb.lowerBound.x; + var minVertexY = aabb.lowerBound.y; + minVertexX = b2Math.b2Min(minVertexX, this.m_worldAABB.upperBound.x); + minVertexY = b2Math.b2Min(minVertexY, this.m_worldAABB.upperBound.y); + minVertexX = b2Math.b2Max(minVertexX, this.m_worldAABB.lowerBound.x); + minVertexY = b2Math.b2Max(minVertexY, this.m_worldAABB.lowerBound.y); + + + var maxVertexX = aabb.upperBound.x; + var maxVertexY = aabb.upperBound.y; + maxVertexX = b2Math.b2Min(maxVertexX, this.m_worldAABB.upperBound.x); + maxVertexY = b2Math.b2Min(maxVertexY, this.m_worldAABB.upperBound.y); + maxVertexX = b2Math.b2Max(maxVertexX, this.m_worldAABB.lowerBound.x); + maxVertexY = b2Math.b2Max(maxVertexY, this.m_worldAABB.lowerBound.y); + + + + + lowerValues[0] = parseInt(this.m_quantizationFactor.x * (minVertexX - this.m_worldAABB.lowerBound.x)) & (b2Settings.USHRT_MAX - 1); + upperValues[0] = (parseInt(this.m_quantizationFactor.x * (maxVertexX - this.m_worldAABB.lowerBound.x))% 65535) | 1; + + lowerValues[1] = parseInt(this.m_quantizationFactor.y * (minVertexY - this.m_worldAABB.lowerBound.y)) & (b2Settings.USHRT_MAX - 1); + upperValues[1] = (parseInt(this.m_quantizationFactor.y * (maxVertexY - this.m_worldAABB.lowerBound.y))% 65535) | 1; + } +b2BroadPhase.prototype.TestOverlapValidate = function (p1, p2) { + + for (var axis = 0; axis < 2; ++axis) + { + var bounds = this.m_bounds[axis]; + + + + + + + var bound1 = bounds[p1.lowerBounds[axis]]; + var bound2 = bounds[p2.upperBounds[axis]]; + if (bound1.value > bound2.value) + return false; + + bound1 = bounds[p1.upperBounds[axis]]; + bound2 = bounds[p2.lowerBounds[axis]]; + if (bound1.value < bound2.value) + return false; + } + + return true; + } +b2BroadPhase.prototype.Query = function (lowerQueryOut, upperQueryOut, lowerValue, upperValue, bounds, boundCount, axis) { + + var lowerQuery = b2BroadPhase.BinarySearch(bounds, boundCount, lowerValue); + var upperQuery = b2BroadPhase.BinarySearch(bounds, boundCount, upperValue); + var bound; + + + + for (var j = lowerQuery; j < upperQuery; ++j) + { + bound = bounds[j]; + if (bound.IsLower()) + { + this.IncrementOverlapCount(bound.proxyId); + } + } + + + + if (lowerQuery > 0) + { + var i = lowerQuery - 1; + bound = bounds[i]; + var s = bound.stabbingCount; + + + while (s) + { + + bound = bounds[i]; + if (bound.IsLower()) + { + var proxy = this.m_proxyPool[ bound.proxyId ]; + if (lowerQuery <= proxy.upperBounds[axis]) + { + this.IncrementOverlapCount(bound.proxyId); + --s; + } + } + --i; + } + } + + lowerQueryOut[0] = lowerQuery; + upperQueryOut[0] = upperQuery; + } +b2BroadPhase.prototype.IncrementOverlapCount = function (proxyId) { + var proxy = this.m_proxyPool[ proxyId ]; + if (proxy.timeStamp < this.m_timeStamp) + { + proxy.timeStamp = this.m_timeStamp; + proxy.overlapCount = 1; + } + else + { + proxy.overlapCount = 2; + + this.m_queryResults[this.m_queryResultCount] = proxyId; + ++this.m_queryResultCount; + } + } +b2BroadPhase.prototype.IncrementTimeStamp = function () { + if (this.m_timeStamp == b2Settings.USHRT_MAX) + { + for (var i = 0; i < b2Settings.b2_maxProxies; ++i) + { + (this.m_proxyPool[i]).timeStamp = 0; + } + this.m_timeStamp = 1; + } + else + { + ++this.m_timeStamp; + } + } +b2BroadPhase.prototype.InRange = function (aabb) { + + var dX; + var dY; + var d2X; + var d2Y; + + dX = aabb.lowerBound.x; + dY = aabb.lowerBound.y; + dX -= this.m_worldAABB.upperBound.x; + dY -= this.m_worldAABB.upperBound.y; + + d2X = this.m_worldAABB.lowerBound.x; + d2Y = this.m_worldAABB.lowerBound.y; + d2X -= aabb.upperBound.x; + d2Y -= aabb.upperBound.y; + + dX = b2Math.b2Max(dX, d2X); + dY = b2Math.b2Max(dY, d2Y); + + return b2Math.b2Max(dX, dY) < 0.0; + } +b2BroadPhase.prototype.GetProxy = function (proxyId) { + var proxy = this.m_proxyPool[proxyId]; + if (proxyId == b2Pair.b2_nullProxy || proxy.IsValid() == false) + { + return null; + } + + return proxy; + } +b2BroadPhase.prototype.CreateProxy = function (aabb, userData) { + var index = 0; + var proxy; + + + + + var proxyId = this.m_freeProxy; + proxy = this.m_proxyPool[ proxyId ]; + this.m_freeProxy = proxy.GetNext(); + + proxy.overlapCount = 0; + proxy.userData = userData; + + var boundCount = 2 * this.m_proxyCount; + + var lowerValues = new Array(); + var upperValues = new Array(); + this.ComputeBounds(lowerValues, upperValues, aabb); + + for (var axis = 0; axis < 2; ++axis) + { + var bounds = this.m_bounds[axis]; + var lowerIndex = 0; + var upperIndex = 0; + var lowerIndexOut = [lowerIndex]; + var upperIndexOut = [upperIndex]; + this.Query(lowerIndexOut, upperIndexOut, lowerValues[axis], upperValues[axis], bounds, boundCount, axis); + lowerIndex = lowerIndexOut[0]; + upperIndex = upperIndexOut[0]; + + + + var tArr = new Array(); + var j = 0; + var tEnd = boundCount - upperIndex + var tBound1; + var tBound2; + var tBoundAS3; + + for (j = 0; j < tEnd; j++){ + tArr[j] = new b2Bound(); + tBound1 = tArr[j]; + tBound2 = bounds[parseInt(upperIndex+j)]; + tBound1.value = tBound2.value; + tBound1.proxyId = tBound2.proxyId; + tBound1.stabbingCount = tBound2.stabbingCount; + } + + tEnd = tArr.length; + var tIndex = upperIndex+2; + for (j = 0; j < tEnd; j++){ + + tBound2 = tArr[j]; + tBound1 = bounds[parseInt(tIndex+j)] + tBound1.value = tBound2.value; + tBound1.proxyId = tBound2.proxyId; + tBound1.stabbingCount = tBound2.stabbingCount; + } + + + tArr = new Array(); + tEnd = upperIndex - lowerIndex; + for (j = 0; j < tEnd; j++){ + tArr[j] = new b2Bound(); + tBound1 = tArr[j]; + tBound2 = bounds[parseInt(lowerIndex+j)]; + tBound1.value = tBound2.value; + tBound1.proxyId = tBound2.proxyId; + tBound1.stabbingCount = tBound2.stabbingCount; + } + + tEnd = tArr.length; + tIndex = lowerIndex+1; + for (j = 0; j < tEnd; j++){ + + tBound2 = tArr[j]; + tBound1 = bounds[parseInt(tIndex+j)] + tBound1.value = tBound2.value; + tBound1.proxyId = tBound2.proxyId; + tBound1.stabbingCount = tBound2.stabbingCount; + } + + + ++upperIndex; + + + tBound1 = bounds[lowerIndex]; + tBound2 = bounds[upperIndex]; + tBound1.value = lowerValues[axis]; + tBound1.proxyId = proxyId; + tBound2.value = upperValues[axis]; + tBound2.proxyId = proxyId; + + tBoundAS3 = bounds[parseInt(lowerIndex-1)]; + tBound1.stabbingCount = lowerIndex == 0 ? 0 : tBoundAS3.stabbingCount; + tBoundAS3 = bounds[parseInt(upperIndex-1)]; + tBound2.stabbingCount = tBoundAS3.stabbingCount; + + + for (index = lowerIndex; index < upperIndex; ++index) + { + tBoundAS3 = bounds[index]; + tBoundAS3.stabbingCount++; + } + + + for (index = lowerIndex; index < boundCount + 2; ++index) + { + tBound1 = bounds[index]; + var proxy2 = this.m_proxyPool[ tBound1.proxyId ]; + if (tBound1.IsLower()) + { + proxy2.lowerBounds[axis] = index; + } + else + { + proxy2.upperBounds[axis] = index; + } + } + } + + ++this.m_proxyCount; + + + + for (var i = 0; i < this.m_queryResultCount; ++i) + { + + + + this.m_pairManager.AddBufferedPair(proxyId, this.m_queryResults[i]); + } + + this.m_pairManager.Commit(); + + + this.m_queryResultCount = 0; + this.IncrementTimeStamp(); + + return proxyId; + } +b2BroadPhase.prototype.DestroyProxy = function (proxyId) { + var tBound1; + var tBound2; + + + + var proxy = this.m_proxyPool[ proxyId ]; + + + var boundCount = 2 * this.m_proxyCount; + + for (var axis = 0; axis < 2; ++axis) + { + var bounds = this.m_bounds[axis]; + + var lowerIndex = proxy.lowerBounds[axis]; + var upperIndex = proxy.upperBounds[axis]; + tBound1 = bounds[lowerIndex]; + var lowerValue = tBound1.value; + tBound2 = bounds[upperIndex]; + var upperValue = tBound2.value; + + + + var tArr = new Array(); + var j = 0; + var tEnd = upperIndex - lowerIndex - 1; + + for (j = 0; j < tEnd; j++){ + tArr[j] = new b2Bound(); + tBound1 = tArr[j]; + tBound2 = bounds[parseInt(lowerIndex+1+j)]; + tBound1.value = tBound2.value; + tBound1.proxyId = tBound2.proxyId; + tBound1.stabbingCount = tBound2.stabbingCount; + } + + tEnd = tArr.length; + var tIndex = lowerIndex; + for (j = 0; j < tEnd; j++){ + + tBound2 = tArr[j]; + tBound1 = bounds[parseInt(tIndex+j)] + tBound1.value = tBound2.value; + tBound1.proxyId = tBound2.proxyId; + tBound1.stabbingCount = tBound2.stabbingCount; + } + + + tArr = new Array(); + tEnd = boundCount - upperIndex - 1; + for (j = 0; j < tEnd; j++){ + tArr[j] = new b2Bound(); + tBound1 = tArr[j]; + tBound2 = bounds[parseInt(upperIndex+1+j)]; + tBound1.value = tBound2.value; + tBound1.proxyId = tBound2.proxyId; + tBound1.stabbingCount = tBound2.stabbingCount; + } + + tEnd = tArr.length; + tIndex = upperIndex-1; + for (j = 0; j < tEnd; j++){ + + tBound2 = tArr[j]; + tBound1 = bounds[parseInt(tIndex+j)] + tBound1.value = tBound2.value; + tBound1.proxyId = tBound2.proxyId; + tBound1.stabbingCount = tBound2.stabbingCount; + } + + + tEnd = boundCount - 2; + for (var index = lowerIndex; index < tEnd; ++index) + { + tBound1 = bounds[index]; + var proxy2 = this.m_proxyPool[ tBound1.proxyId ]; + if (tBound1.IsLower()) + { + proxy2.lowerBounds[axis] = index; + } + else + { + proxy2.upperBounds[axis] = index; + } + } + + + tEnd = upperIndex - 1; + for (var index2 = lowerIndex; index2 < tEnd; ++index2) + { + tBound1 = bounds[index2]; + tBound1.stabbingCount--; + } + + + + this.Query([0], [0], lowerValue, upperValue, bounds, boundCount - 2, axis); + } + + + + for (var i = 0; i < this.m_queryResultCount; ++i) + { + + + this.m_pairManager.RemoveBufferedPair(proxyId, this.m_queryResults[i]); + } + + this.m_pairManager.Commit(); + + + this.m_queryResultCount = 0; + this.IncrementTimeStamp(); + + + proxy.userData = null; + proxy.overlapCount = b2BroadPhase.b2_invalid; + proxy.lowerBounds[0] = b2BroadPhase.b2_invalid; + proxy.lowerBounds[1] = b2BroadPhase.b2_invalid; + proxy.upperBounds[0] = b2BroadPhase.b2_invalid; + proxy.upperBounds[1] = b2BroadPhase.b2_invalid; + + proxy.SetNext(this.m_freeProxy); + this.m_freeProxy = proxyId; + --this.m_proxyCount; + } +b2BroadPhase.prototype.MoveProxy = function (proxyId, aabb) { + var as3arr; + var as3int; + + var axis = 0; + var index = 0; + var bound; + var prevBound; + var nextBound; + var nextProxyId = 0; + var nextProxy; + + if (proxyId == b2Pair.b2_nullProxy || b2Settings.b2_maxProxies <= proxyId) + { + + return; + } + + if (aabb.IsValid() == false) + { + + return; + } + + var boundCount = 2 * this.m_proxyCount; + + var proxy = this.m_proxyPool[ proxyId ]; + + var newValues = new b2BoundValues(); + this.ComputeBounds(newValues.lowerValues, newValues.upperValues, aabb); + + + var oldValues = new b2BoundValues(); + for (axis = 0; axis < 2; ++axis) + { + bound = this.m_bounds[axis][proxy.lowerBounds[axis]]; + oldValues.lowerValues[axis] = bound.value; + bound = this.m_bounds[axis][proxy.upperBounds[axis]]; + oldValues.upperValues[axis] = bound.value; + } + + for (axis = 0; axis < 2; ++axis) + { + var bounds = this.m_bounds[axis]; + + var lowerIndex = proxy.lowerBounds[axis]; + var upperIndex = proxy.upperBounds[axis]; + + var lowerValue = newValues.lowerValues[axis]; + var upperValue = newValues.upperValues[axis]; + + bound = bounds[lowerIndex]; + var deltaLower = lowerValue - bound.value; + bound.value = lowerValue; + + bound = bounds[upperIndex]; + var deltaUpper = upperValue - bound.value; + bound.value = upperValue; + + + + + + + if (deltaLower < 0) + { + index = lowerIndex; + while (index > 0 && lowerValue < (bounds[parseInt(index-1)]).value) + { + bound = bounds[index]; + prevBound = bounds[parseInt(index - 1)]; + + var prevProxyId = prevBound.proxyId; + var prevProxy = this.m_proxyPool[ prevBound.proxyId ]; + + prevBound.stabbingCount++; + + if (prevBound.IsUpper() == true) + { + if (this.TestOverlap(newValues, prevProxy)) + { + this.m_pairManager.AddBufferedPair(proxyId, prevProxyId); + } + + + as3arr = prevProxy.upperBounds; + as3int = as3arr[axis]; + as3int++; + as3arr[axis] = as3int; + + bound.stabbingCount++; + } + else + { + + as3arr = prevProxy.lowerBounds; + as3int = as3arr[axis]; + as3int++; + as3arr[axis] = as3int; + + bound.stabbingCount--; + } + + + as3arr = proxy.lowerBounds; + as3int = as3arr[axis]; + as3int--; + as3arr[axis] = as3int; + + + + + + bound.Swap(prevBound); + + --index; + } + } + + + if (deltaUpper > 0) + { + index = upperIndex; + while (index < boundCount-1 && (bounds[parseInt(index+1)]).value <= upperValue) + { + bound = bounds[ index ]; + nextBound = bounds[ parseInt(index + 1) ]; + nextProxyId = nextBound.proxyId; + nextProxy = this.m_proxyPool[ nextProxyId ]; + + nextBound.stabbingCount++; + + if (nextBound.IsLower() == true) + { + if (this.TestOverlap(newValues, nextProxy)) + { + this.m_pairManager.AddBufferedPair(proxyId, nextProxyId); + } + + + as3arr = nextProxy.lowerBounds; + as3int = as3arr[axis]; + as3int--; + as3arr[axis] = as3int; + + bound.stabbingCount++; + } + else + { + + as3arr = nextProxy.upperBounds; + as3int = as3arr[axis]; + as3int--; + as3arr[axis] = as3int; + + bound.stabbingCount--; + } + + + as3arr = proxy.upperBounds; + as3int = as3arr[axis]; + as3int++; + as3arr[axis] = as3int; + + + + + + bound.Swap(nextBound); + + index++; + } + } + + + + + + + if (deltaLower > 0) + { + index = lowerIndex; + while (index < boundCount-1 && (bounds[parseInt(index+1)]).value <= lowerValue) + { + bound = bounds[ index ]; + nextBound = bounds[ parseInt(index + 1) ]; + + nextProxyId = nextBound.proxyId; + nextProxy = this.m_proxyPool[ nextProxyId ]; + + nextBound.stabbingCount--; + + if (nextBound.IsUpper()) + { + if (this.TestOverlap(oldValues, nextProxy)) + { + this.m_pairManager.RemoveBufferedPair(proxyId, nextProxyId); + } + + + as3arr = nextProxy.upperBounds; + as3int = as3arr[axis]; + as3int--; + as3arr[axis] = as3int; + + bound.stabbingCount--; + } + else + { + + as3arr = nextProxy.lowerBounds; + as3int = as3arr[axis]; + as3int--; + as3arr[axis] = as3int; + + bound.stabbingCount++; + } + + + as3arr = proxy.lowerBounds; + as3int = as3arr[axis]; + as3int++; + as3arr[axis] = as3int; + + + + + + bound.Swap(nextBound); + + index++; + } + } + + + if (deltaUpper < 0) + { + index = upperIndex; + while (index > 0 && upperValue < (bounds[parseInt(index-1)]).value) + { + bound = bounds[index]; + prevBound = bounds[parseInt(index - 1)]; + + prevProxyId = prevBound.proxyId; + prevProxy = this.m_proxyPool[ prevProxyId ]; + + prevBound.stabbingCount--; + + if (prevBound.IsLower() == true) + { + if (this.TestOverlap(oldValues, prevProxy)) + { + this.m_pairManager.RemoveBufferedPair(proxyId, prevProxyId); + } + + + as3arr = prevProxy.lowerBounds; + as3int = as3arr[axis]; + as3int++; + as3arr[axis] = as3int; + + bound.stabbingCount--; + } + else + { + + as3arr = prevProxy.upperBounds; + as3int = as3arr[axis]; + as3int++; + as3arr[axis] = as3int; + + bound.stabbingCount++; + } + + + as3arr = proxy.upperBounds; + as3int = as3arr[axis]; + as3int--; + as3arr[axis] = as3int; + + + + + + bound.Swap(prevBound); + + index--; + } + } + } + } +b2BroadPhase.prototype.Commit = function () { + this.m_pairManager.Commit(); + } +b2BroadPhase.prototype.QueryAABB = function (aabb, userData, maxCount) { + var lowerValues = new Array(); + var upperValues = new Array(); + this.ComputeBounds(lowerValues, upperValues, aabb); + + var lowerIndex = 0; + var upperIndex = 0; + var lowerIndexOut = [lowerIndex]; + var upperIndexOut = [upperIndex]; + this.Query(lowerIndexOut, upperIndexOut, lowerValues[0], upperValues[0], this.m_bounds[0], 2*this.m_proxyCount, 0); + this.Query(lowerIndexOut, upperIndexOut, lowerValues[1], upperValues[1], this.m_bounds[1], 2*this.m_proxyCount, 1); + + + + var count = 0; + for (var i = 0; i < this.m_queryResultCount && count < maxCount; ++i, ++count) + { + + var proxy = this.m_proxyPool[ this.m_queryResults[i] ]; + + userData[i] = proxy.userData; + } + + + this.m_queryResultCount = 0; + this.IncrementTimeStamp(); + + return count; + } +b2BroadPhase.prototype.Validate = function () { + var pair; + var proxy1; + var proxy2; + var overlap; + + for (var axis = 0; axis < 2; ++axis) + { + var bounds = this.m_bounds[axis]; + + var boundCount = 2 * this.m_proxyCount; + var stabbingCount = 0; + + for (var i = 0; i < boundCount; ++i) + { + var bound = bounds[i]; + + + + + if (bound.IsLower() == true) + { + + stabbingCount++; + } + else + { + + stabbingCount--; + } + + + } + } + + } +b2BroadPhase.prototype.TestOverlap = function (b, p) { + for (var axis = 0; axis < 2; ++axis) + { + var bounds = this.m_bounds[axis]; + + + + + var bound = bounds[p.upperBounds[axis]]; + if (b.lowerValues[axis] > bound.value) + return false; + + bound = bounds[p.lowerBounds[axis]]; + if (b.upperValues[axis] < bound.value) + return false; + } + + return true; + } +exports.b2BroadPhase = b2BroadPhase; + + +var b2TimeOfImpact = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2TimeOfImpact.prototype.__constructor = function(){} +b2TimeOfImpact.prototype.__varz = function(){ +} +b2TimeOfImpact.s_p1 = new b2Vec2(); +b2TimeOfImpact.s_p2 = new b2Vec2(); +b2TimeOfImpact.s_xf1 = new b2XForm(); +b2TimeOfImpact.s_xf2 = new b2XForm(); +b2TimeOfImpact.TimeOfImpact = function ( shape1, sweep1, + shape2, sweep2) { + var math1; + var math2; + + var r1 = shape1.m_sweepRadius; + var r2 = shape2.m_sweepRadius; + + + + + var t0 = sweep1.t0; + + var v1X = sweep1.c.x - sweep1.c0.x; + var v1Y = sweep1.c.y - sweep1.c0.y; + + var v2X = sweep2.c.x - sweep2.c0.x; + var v2Y = sweep2.c.y - sweep2.c0.y; + var omega1 = sweep1.a - sweep1.a0; + var omega2 = sweep2.a - sweep2.a0; + + var alpha = 0.0; + + var p1 = b2TimeOfImpact.s_p1; + var p2 = b2TimeOfImpact.s_p2; + var k_maxIterations = 20; + var iter = 0; + + var normalX = 0.0; + var normalY = 0.0; + var distance = 0.0; + var targetDistance = 0.0; + for(;;) + { + var t = (1.0 - alpha) * t0 + alpha; + + var xf1 = b2TimeOfImpact.s_xf1; + var xf2 = b2TimeOfImpact.s_xf2; + sweep1.GetXForm(xf1, t); + sweep2.GetXForm(xf2, t); + + + distance = b2Distance.Distance(p1, p2, shape1, xf1, shape2, xf2); + + if (iter == 0) + { + + + if (distance > 2.0 * b2Settings.b2_toiSlop) + { + targetDistance = 1.5 * b2Settings.b2_toiSlop; + } + else + { + + math1 = 0.05 * b2Settings.b2_toiSlop; + math2 = distance - 0.5 * b2Settings.b2_toiSlop; + targetDistance = math1 > math2 ? math1 : math2; + } + } + + if (distance - targetDistance < 0.05 * b2Settings.b2_toiSlop || iter == k_maxIterations) + { + break; + } + + + normalX = p2.x - p1.x; + normalY = p2.y - p1.y; + + var nLen = Math.sqrt(normalX*normalX + normalY*normalY); + normalX /= nLen; + normalY /= nLen; + + + + var approachVelocityBound = (normalX*(v1X - v2X) + normalY*(v1Y - v2Y)) + + (omega1 < 0 ? -omega1 : omega1) * r1 + + (omega2 < 0 ? -omega2 : omega2) * r2; + + if (approachVelocityBound == 0) + { + alpha = 1.0; + break; + } + + + var dAlpha = (distance - targetDistance) / approachVelocityBound; + + var newAlpha = alpha + dAlpha; + + + if (newAlpha < 0.0 || 1.0 < newAlpha) + { + alpha = 1.0; + break; + } + + + if (newAlpha < (1.0 + 100.0 * Number.MIN_VALUE) * alpha) + { + break; + } + + alpha = newAlpha; + + ++iter; + } + + return alpha; +} +exports.b2TimeOfImpact = b2TimeOfImpact; + + +var b2ContactPoint = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2ContactPoint.prototype.__constructor = function(){} +b2ContactPoint.prototype.__varz = function(){ +this.position = new b2Vec2(); +this.velocity = new b2Vec2(); +this.normal = new b2Vec2(); +this.id = new b2ContactID(); +} +b2ContactPoint.prototype.shape1 = null; +b2ContactPoint.prototype.shape2 = null; +b2ContactPoint.prototype.position = new b2Vec2(); +b2ContactPoint.prototype.velocity = new b2Vec2(); +b2ContactPoint.prototype.normal = new b2Vec2(); +b2ContactPoint.prototype.separation = null; +b2ContactPoint.prototype.friction = null; +b2ContactPoint.prototype.restitution = null; +b2ContactPoint.prototype.id = new b2ContactID(); +exports.b2ContactPoint= b2ContactPoint; + + +var ClipVertex = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +ClipVertex.prototype.__constructor = function(){} +ClipVertex.prototype.__varz = function(){ +this.v = new b2Vec2(); +this.id = new b2ContactID(); +} +ClipVertex.prototype.v = new b2Vec2(); +ClipVertex.prototype.id = new b2ContactID(); +exports.ClipVertex = ClipVertex; + + +var b2MassData = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2MassData.prototype.__constructor = function(){} +b2MassData.prototype.__varz = function(){ +this.center = new b2Vec2(0,0); +} +b2MassData.prototype.mass = 0.0; +b2MassData.prototype.center = new b2Vec2(0,0); +b2MassData.prototype.I = 0.0; +exports.b2MassData = b2MassData; + + +var b2FilterData = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2FilterData.prototype.__constructor = function(){} +b2FilterData.prototype.__varz = function(){ +this.categoryBits = 0x0001; +this.maskBits = 0xFFFF; +} +b2FilterData.prototype.categoryBits = 0x0001; +b2FilterData.prototype.maskBits = 0xFFFF; +b2FilterData.prototype.groupIndex = 0; +b2FilterData.prototype.Copy = function () { + var copy = new b2FilterData(); + copy.categoryBits = this.categoryBits; + copy.maskBits = this.maskBits; + copy.groupIndex = this.groupIndex; + return copy; + } +exports.b2FilterData = b2FilterData; + + +var b2Shape = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Shape.prototype.__constructor = function (def) { + + this.m_userData = def.userData; + this.m_friction = def.friction; + this.m_restitution = def.restitution; + this.m_density = def.density; + this.m_body = null; + this.m_sweepRadius = 0.0; + + this.m_next = null; + + this.m_proxyId = b2Pair.b2_nullProxy; + + this.m_filter = def.filter.Copy(); + + this.m_isSensor = def.isSensor; + + } +b2Shape.prototype.__varz = function(){ +} +b2Shape.e_unknownShape = -1; +b2Shape.e_circleShape = 0; +b2Shape.e_polygonShape = 1; +b2Shape.e_shapeTypeCount = 2; +b2Shape.s_proxyAABB = new b2AABB(); +b2Shape.s_syncAABB = new b2AABB(); +b2Shape.s_resetAABB = new b2AABB(); +b2Shape.Create = function (def, allocator) { + switch (def.type) + { + case b2Shape.e_circleShape: + { + + return new b2CircleShape(def); + } + + case b2Shape.e_polygonShape: + { + + return new b2PolygonShape(def); + } + + default: + + return null; + } + } +b2Shape.Destroy = function (shape, allocator) { + + } +b2Shape.prototype.m_type = 0; +b2Shape.prototype.m_next = null; +b2Shape.prototype.m_body = null; +b2Shape.prototype.m_sweepRadius = null; +b2Shape.prototype.m_density = null; +b2Shape.prototype.m_friction = null; +b2Shape.prototype.m_restitution = null; +b2Shape.prototype.m_proxyId = 0; +b2Shape.prototype.m_filter = null; +b2Shape.prototype.m_isSensor = null; +b2Shape.prototype.m_userData = null; +b2Shape.prototype.GetType = function () { + return this.m_type; + } +b2Shape.prototype.IsSensor = function () { + return this.m_isSensor; + } +b2Shape.prototype.SetFilterData = function (filter) { + this.m_filter = filter.Copy(); + } +b2Shape.prototype.GetFilterData = function () { + return this.m_filter.Copy(); + } +b2Shape.prototype.GetBody = function () { + return this.m_body; + } +b2Shape.prototype.GetNext = function () { + return this.m_next; + } +b2Shape.prototype.GetUserData = function () { + return this.m_userData; + } +b2Shape.prototype.SetUserData = function (data) { + this.m_userData = data; + } +b2Shape.prototype.TestPoint = function (xf, p) {return false} +b2Shape.prototype.TestSegment = function (xf, + lambda, + normal, + segment, + maxLambda) {return false} +b2Shape.prototype.ComputeAABB = function (aabb, xf) {} +b2Shape.prototype.ComputeSweptAABB = function ( aabb, + xf1, + xf2) {} +b2Shape.prototype.ComputeMass = function (massData) {} +b2Shape.prototype.GetSweepRadius = function () { + return this.m_sweepRadius; + } +b2Shape.prototype.GetFriction = function () { + return this.m_friction; + } +b2Shape.prototype.GetRestitution = function () { + return this.m_restitution; + } +b2Shape.prototype.CreateProxy = function (broadPhase, transform) { + + + + var aabb = b2Shape.s_proxyAABB; + this.ComputeAABB(aabb, transform); + + var inRange = broadPhase.InRange(aabb); + + + + + if (inRange) + { + this.m_proxyId = broadPhase.CreateProxy(aabb, this); + } + else + { + this.m_proxyId = b2Pair.b2_nullProxy; + } + + } +b2Shape.prototype.DestroyProxy = function (broadPhase) { + + if (this.m_proxyId != b2Pair.b2_nullProxy) + { + broadPhase.DestroyProxy(this.m_proxyId); + this.m_proxyId = b2Pair.b2_nullProxy; + } + + } +b2Shape.prototype.Synchronize = function (broadPhase, transform1, transform2) { + + if (this.m_proxyId == b2Pair.b2_nullProxy) + { + return false; + } + + + var aabb = b2Shape.s_syncAABB; + this.ComputeSweptAABB(aabb, transform1, transform2); + + if (broadPhase.InRange(aabb)) + { + broadPhase.MoveProxy(this.m_proxyId, aabb); + return true; + } + else + { + return false; + } + + } +b2Shape.prototype.RefilterProxy = function (broadPhase, transform) { + + if (this.m_proxyId == b2Pair.b2_nullProxy) + { + return; + } + + broadPhase.DestroyProxy(this.m_proxyId); + + var aabb = b2Shape.s_resetAABB; + this.ComputeAABB(aabb, transform); + + var inRange = broadPhase.InRange(aabb); + + if (inRange) + { + this.m_proxyId = broadPhase.CreateProxy(aabb, this); + } + else + { + this.m_proxyId = b2Pair.b2_nullProxy; + } + + } +b2Shape.prototype.UpdateSweepRadius = function (center) {} +exports.b2Shape = b2Shape; + + +var b2CircleShape = function() { +b2Shape.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2CircleShape.prototype, b2Shape.prototype) +b2CircleShape.prototype._super = function(){ b2Shape.prototype.__constructor.apply(this, arguments) } +b2CircleShape.prototype.__constructor = function (def) { + this._super(def); + + + var circleDef = def; + + this.m_type = b2Shape.e_circleShape; + this.m_localPosition.SetV(circleDef.localPosition); + this.m_radius = circleDef.radius; + + } +b2CircleShape.prototype.__varz = function(){ +this.m_localPosition = new b2Vec2(); +} +b2CircleShape.prototype.m_localPosition = new b2Vec2(); +b2CircleShape.prototype.m_radius = null; +b2CircleShape.prototype.TestPoint = function (transform, p) { + + var tMat = transform.R; + var dX = transform.position.x + (tMat.col1.x * this.m_localPosition.x + tMat.col2.x * this.m_localPosition.y); + var dY = transform.position.y + (tMat.col1.y * this.m_localPosition.x + tMat.col2.y * this.m_localPosition.y); + + dX = p.x - dX; + dY = p.y - dY; + + return (dX*dX + dY*dY) <= this.m_radius * this.m_radius; + } +b2CircleShape.prototype.TestSegment = function ( transform, + lambda, + normal, + segment, + maxLambda) { + + var tMat = transform.R; + var positionX = transform.position.x + (tMat.col1.x * this.m_localPosition.x + tMat.col2.x * this.m_localPosition.y); + var positionY = transform.position.y + (tMat.col1.y * this.m_localPosition.x + tMat.col2.y * this.m_localPosition.y); + + + var sX = segment.p1.x - positionX; + var sY = segment.p1.y - positionY; + + var b = (sX*sX + sY*sY) - this.m_radius * this.m_radius; + + + if (b < 0.0) + { + return false; + } + + + + var rX = segment.p2.x - segment.p1.x; + var rY = segment.p2.y - segment.p1.y; + + var c = (sX*rX + sY*rY); + + var rr = (rX*rX + rY*rY); + var sigma = c * c - rr * b; + + + if (sigma < 0.0 || rr < Number.MIN_VALUE) + { + return false; + } + + + var a = -(c + Math.sqrt(sigma)); + + + if (0.0 <= a && a <= maxLambda * rr) + { + a /= rr; + + lambda[0] = a; + + normal.x = sX + a * rX; + normal.y = sY + a * rY; + normal.Normalize(); + return true; + } + + return false; + } +b2CircleShape.prototype.ComputeAABB = function (aabb, transform) { + + var tMat = transform.R; + var pX = transform.position.x + (tMat.col1.x * this.m_localPosition.x + tMat.col2.x * this.m_localPosition.y); + var pY = transform.position.y + (tMat.col1.y * this.m_localPosition.x + tMat.col2.y * this.m_localPosition.y); + aabb.lowerBound.Set(pX - this.m_radius, pY - this.m_radius); + aabb.upperBound.Set(pX + this.m_radius, pY + this.m_radius); + } +b2CircleShape.prototype.ComputeSweptAABB = function ( aabb, + transform1, + transform2) { + var tMat; + + tMat = transform1.R; + var p1X = transform1.position.x + (tMat.col1.x * this.m_localPosition.x + tMat.col2.x * this.m_localPosition.y); + var p1Y = transform1.position.y + (tMat.col1.y * this.m_localPosition.x + tMat.col2.y * this.m_localPosition.y); + + tMat = transform2.R; + var p2X = transform2.position.x + (tMat.col1.x * this.m_localPosition.x + tMat.col2.x * this.m_localPosition.y); + var p2Y = transform2.position.y + (tMat.col1.y * this.m_localPosition.x + tMat.col2.y * this.m_localPosition.y); + + + + + + aabb.lowerBound.Set((p1X < p2X ? p1X : p2X) - this.m_radius, (p1Y < p2Y ? p1Y : p2Y) - this.m_radius); + + aabb.upperBound.Set((p1X > p2X ? p1X : p2X) + this.m_radius, (p1Y > p2Y ? p1Y : p2Y) + this.m_radius); + } +b2CircleShape.prototype.ComputeMass = function (massData) { + massData.mass = this.m_density * b2Settings.b2_pi * this.m_radius * this.m_radius; + massData.center.SetV(this.m_localPosition); + + + + massData.I = massData.mass * (0.5 * this.m_radius * this.m_radius + (this.m_localPosition.x*this.m_localPosition.x + this.m_localPosition.y*this.m_localPosition.y)); + } +b2CircleShape.prototype.GetLocalPosition = function () { + return this.m_localPosition; + } +b2CircleShape.prototype.GetRadius = function () { + return this.m_radius; + } +b2CircleShape.prototype.UpdateSweepRadius = function (center) { + + + + var dX = this.m_localPosition.x - center.x; + var dY = this.m_localPosition.y - center.y; + dX = Math.sqrt(dX*dX + dY*dY); + + this.m_sweepRadius = dX + this.m_radius - b2Settings.b2_toiSlop; + } +exports.b2CircleShape = b2CircleShape; + + +var b2ShapeDef = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2ShapeDef.prototype.__constructor = function(){} +b2ShapeDef.prototype.__varz = function(){ +this.type = b2Shape.e_unknownShape; +this.filter = new b2FilterData(); +} +b2ShapeDef.prototype.type = b2Shape.e_unknownShape; +b2ShapeDef.prototype.userData = null; +b2ShapeDef.prototype.friction = 0.2; +b2ShapeDef.prototype.restitution = 0.0; +b2ShapeDef.prototype.density = 0.0; +b2ShapeDef.prototype.isSensor = false; +b2ShapeDef.prototype.filter = new b2FilterData(); +exports.b2ShapeDef = b2ShapeDef; + + +var b2PolygonDef = function() { +b2ShapeDef.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2PolygonDef.prototype, b2ShapeDef.prototype) +b2PolygonDef.prototype._super = function(){ b2ShapeDef.prototype.__constructor.apply(this, arguments) } +b2PolygonDef.prototype.__constructor = function () { + this.type = b2Shape.e_polygonShape; + this.vertexCount = 0; + + for (var i = 0; i < b2Settings.b2_maxPolygonVertices; i++){ + this.vertices[i] = new b2Vec2(); + } + } +b2PolygonDef.prototype.__varz = function(){ +this.vertices = new Array(b2Settings.b2_maxPolygonVertices); +} +b2PolygonDef.s_mat = new b2Mat22(); +b2PolygonDef.prototype.vertices = new Array(b2Settings.b2_maxPolygonVertices); +b2PolygonDef.prototype.vertexCount = 0; +b2PolygonDef.prototype.SetAsBox = function (hx, hy) { + this.vertexCount = 4; + this.vertices[0].Set(-hx, -hy); + this.vertices[1].Set( hx, -hy); + this.vertices[2].Set( hx, hy); + this.vertices[3].Set(-hx, hy); + } +b2PolygonDef.prototype.SetAsOrientedBox = function (hx, hy, center, angle) { + + { + this.vertexCount = 4; + this.vertices[0].Set(-hx, -hy); + this.vertices[1].Set( hx, -hy); + this.vertices[2].Set( hx, hy); + this.vertices[3].Set(-hx, hy); + } + + if (center){ + + + var xfPosition = center; + + var xfR = b2PolygonDef.s_mat; + xfR.Set(angle); + + for (var i = 0; i < this.vertexCount; ++i) + { + + + center = this.vertices[i]; + hx = xfPosition.x + (xfR.col1.x * center.x + xfR.col2.x * center.y) + center.y = xfPosition.y + (xfR.col1.y * center.x + xfR.col2.y * center.y) + center.x = hx; + } + } + } +exports.b2PolygonDef = b2PolygonDef; + + +var b2PolygonShape = function() { +b2Shape.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2PolygonShape.prototype, b2Shape.prototype) +b2PolygonShape.prototype._super = function(){ b2Shape.prototype.__constructor.apply(this, arguments) } +b2PolygonShape.prototype.__constructor = function (def) { + this._super(def); + + + this.m_type = b2Shape.e_polygonShape; + var poly = def; + + + this.m_vertexCount = poly.vertexCount; + + + var i = 0; + var i1 = i; + var i2 = i; + + + for (i = 0; i < this.m_vertexCount; ++i) + { + this.m_vertices[i] = poly.vertices[i].Copy(); + } + + + for (i = 0; i < this.m_vertexCount; ++i) + { + i1 = i; + i2 = i + 1 < this.m_vertexCount ? i + 1 : 0; + + var edgeX = this.m_vertices[i2].x - this.m_vertices[i1].x; + var edgeY = this.m_vertices[i2].y - this.m_vertices[i1].y; + + + var len = Math.sqrt(edgeX*edgeX + edgeY*edgeY); + + this.m_normals[i] = new b2Vec2(edgeY/len, -edgeX/len); + } + + + + + this.m_centroid = b2PolygonShape.ComputeCentroid(poly.vertices, poly.vertexCount); + + + b2PolygonShape.ComputeOBB(this.m_obb, this.m_vertices, this.m_vertexCount); + + + + for (i = 0; i < this.m_vertexCount; ++i) + { + i1 = i - 1 >= 0 ? i - 1 : this.m_vertexCount - 1; + i2 = i; + + + var n1X = this.m_normals[i1].x; + var n1Y = this.m_normals[i1].y; + + var n2X = this.m_normals[i2].x; + var n2Y = this.m_normals[i2].y; + + var vX = this.m_vertices[i].x - this.m_centroid.x; + var vY = this.m_vertices[i].y - this.m_centroid.y; + + + var dX = (n1X*vX + n1Y*vY) - b2Settings.b2_toiSlop; + var dY = (n2X*vX + n2Y*vY) - b2Settings.b2_toiSlop; + + + + + + + + + + + + + var det = 1.0/(n1X * n2Y - n1Y * n2X); + + this.m_coreVertices[i] = new b2Vec2( det * (n2Y * dX - n1Y * dY) + this.m_centroid.x, + det * (n1X * dY - n2X * dX) + this.m_centroid.y); + } + } +b2PolygonShape.prototype.__varz = function(){ +this.s_supportVec = new b2Vec2(); +this.m_obb = new b2OBB(); +this.m_vertices = new Array(b2Settings.b2_maxPolygonVertices); +this.m_normals = new Array(b2Settings.b2_maxPolygonVertices); +this.m_coreVertices = new Array(b2Settings.b2_maxPolygonVertices); +} +b2PolygonShape.s_computeMat = new b2Mat22(); +b2PolygonShape.s_sweptAABB1 = new b2AABB(); +b2PolygonShape.s_sweptAABB2 = new b2AABB(); +b2PolygonShape.ComputeCentroid = function (vs, count) { + + + var c = new b2Vec2(); + var area = 0.0; + + + + + var p1X = 0.0; + var p1Y = 0.0; + + + var inv3 = 1.0 / 3.0; + + for (var i = 0; i < count; ++i) + { + + + + + var p2 = vs[i]; + + var p3 = i + 1 < count ? vs[parseInt(i+1)] : vs[0]; + + + var e1X = p2.x - p1X; + var e1Y = p2.y - p1Y; + + var e2X = p3.x - p1X; + var e2Y = p3.y - p1Y; + + + var D = (e1X * e2Y - e1Y * e2X); + + + var triangleArea = 0.5 * D; + area += triangleArea; + + + + c.x += triangleArea * inv3 * (p1X + p2.x + p3.x); + c.y += triangleArea * inv3 * (p1Y + p2.y + p3.y); + } + + + + + c.x *= 1.0 / area; + c.y *= 1.0 / area; + return c; + } +b2PolygonShape.ComputeOBB = function (obb, vs, count) { + var i = 0; + + var p = new Array(b2Settings.b2_maxPolygonVertices + 1); + for (i = 0; i < count; ++i) + { + p[i] = vs[i]; + } + p[count] = p[0]; + + var minArea = Number.MAX_VALUE; + + for (i = 1; i <= count; ++i) + { + var root = p[parseInt(i-1)]; + + var uxX = p[i].x - root.x; + var uxY = p[i].y - root.y; + + var length = Math.sqrt(uxX*uxX + uxY*uxY); + uxX /= length; + uxY /= length; + + + var uyX = -uxY; + var uyY = uxX; + + var lowerX = Number.MAX_VALUE; + var lowerY = Number.MAX_VALUE; + + var upperX = -Number.MAX_VALUE; + var upperY = -Number.MAX_VALUE; + + for (var j = 0; j < count; ++j) + { + + var dX = p[j].x - root.x; + var dY = p[j].y - root.y; + + + var rX = (uxX*dX + uxY*dY); + + var rY = (uyX*dX + uyY*dY); + + if (rX < lowerX) lowerX = rX; + if (rY < lowerY) lowerY = rY; + + if (rX > upperX) upperX = rX; + if (rY > upperY) upperY = rY; + } + + var area = (upperX - lowerX) * (upperY - lowerY); + if (area < 0.95 * minArea) + { + minArea = area; + + obb.R.col1.x = uxX; + obb.R.col1.y = uxY; + + obb.R.col2.x = uyX; + obb.R.col2.y = uyY; + + var centerX = 0.5 * (lowerX + upperX); + var centerY = 0.5 * (lowerY + upperY); + + var tMat = obb.R; + obb.center.x = root.x + (tMat.col1.x * centerX + tMat.col2.x * centerY); + obb.center.y = root.y + (tMat.col1.y * centerX + tMat.col2.y * centerY); + + obb.extents.x = 0.5 * (upperX - lowerX); + obb.extents.y = 0.5 * (upperY - lowerY); + } + } + + + } +b2PolygonShape.prototype.s_supportVec = new b2Vec2(); +b2PolygonShape.prototype.m_centroid = null; +b2PolygonShape.prototype.m_obb = new b2OBB(); +b2PolygonShape.prototype.m_vertices = new Array(b2Settings.b2_maxPolygonVertices); +b2PolygonShape.prototype.m_normals = new Array(b2Settings.b2_maxPolygonVertices); +b2PolygonShape.prototype.m_coreVertices = new Array(b2Settings.b2_maxPolygonVertices); +b2PolygonShape.prototype.m_vertexCount = 0; +b2PolygonShape.prototype.TestPoint = function (xf, p) { + var tVec; + + + var tMat = xf.R; + var tX = p.x - xf.position.x; + var tY = p.y - xf.position.y; + var pLocalX = (tX*tMat.col1.x + tY*tMat.col1.y); + var pLocalY = (tX*tMat.col2.x + tY*tMat.col2.y); + + for (var i = 0; i < this.m_vertexCount; ++i) + { + + tVec = this.m_vertices[i]; + tX = pLocalX - tVec.x; + tY = pLocalY - tVec.y; + tVec = this.m_normals[i]; + var dot = (tVec.x * tX + tVec.y * tY); + if (dot > 0.0) + { + return false; + } + } + + return true; + } +b2PolygonShape.prototype.TestSegment = function ( xf, + lambda, + normal, + segment, + maxLambda) { + var lower = 0.0; + var upper = maxLambda; + + var tX; + var tY; + var tMat; + var tVec; + + + tX = segment.p1.x - xf.position.x; + tY = segment.p1.y - xf.position.y; + tMat = xf.R; + var p1X = (tX * tMat.col1.x + tY * tMat.col1.y); + var p1Y = (tX * tMat.col2.x + tY * tMat.col2.y); + + tX = segment.p2.x - xf.position.x; + tY = segment.p2.y - xf.position.y; + tMat = xf.R; + var p2X = (tX * tMat.col1.x + tY * tMat.col1.y); + var p2Y = (tX * tMat.col2.x + tY * tMat.col2.y); + + var dX = p2X - p1X; + var dY = p2Y - p1Y; + var index = -1; + + for (var i = 0; i < this.m_vertexCount; ++i) + { + + + + + + tVec = this.m_vertices[i]; + tX = tVec.x - p1X; + tY = tVec.y - p1Y; + tVec = this.m_normals[i]; + var numerator = (tVec.x*tX + tVec.y*tY); + + var denominator = (tVec.x*dX + tVec.y*dY); + + + + + + + if (denominator < 0.0 && numerator < lower * denominator) + { + + + lower = numerator / denominator; + index = i; + } + else if (denominator > 0.0 && numerator < upper * denominator) + { + + + upper = numerator / denominator; + } + + if (upper < lower) + { + return false; + } + } + + + + if (index >= 0) + { + + lambda[0] = lower; + + tMat = xf.R; + tVec = this.m_normals[index]; + normal.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + normal.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + return true; + } + + return false; + } +b2PolygonShape.prototype.ComputeAABB = function (aabb, xf) { + var tMat; + var tVec; + + var R = b2PolygonShape.s_computeMat; + + tMat = xf.R; + tVec = this.m_obb.R.col1; + + R.col1.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + R.col1.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + tVec = this.m_obb.R.col2; + + R.col2.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + R.col2.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + + R.Abs(); + var absR = R; + + tVec = this.m_obb.extents; + var hX = (absR.col1.x * tVec.x + absR.col2.x * tVec.y); + var hY = (absR.col1.y * tVec.x + absR.col2.y * tVec.y); + + tMat = xf.R; + tVec = this.m_obb.center; + var positionX = xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var positionY = xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + aabb.lowerBound.Set(positionX - hX, positionY - hY); + + aabb.upperBound.Set(positionX + hX, positionY + hY); + } +b2PolygonShape.prototype.ComputeSweptAABB = function ( aabb, + transform1, + transform2) { + + var aabb1 = b2PolygonShape.s_sweptAABB1; + var aabb2 = b2PolygonShape.s_sweptAABB2; + this.ComputeAABB(aabb1, transform1); + this.ComputeAABB(aabb2, transform2); + + aabb.lowerBound.Set((aabb1.lowerBound.x < aabb2.lowerBound.x ? aabb1.lowerBound.x : aabb2.lowerBound.x), + (aabb1.lowerBound.y < aabb2.lowerBound.y ? aabb1.lowerBound.y : aabb2.lowerBound.y)); + + aabb.upperBound.Set((aabb1.upperBound.x > aabb2.upperBound.x ? aabb1.upperBound.x : aabb2.upperBound.x), + (aabb1.upperBound.y > aabb2.upperBound.y ? aabb1.upperBound.y : aabb2.upperBound.y)); + } +b2PolygonShape.prototype.ComputeMass = function (massData) { + + + + + + + + + + + + + + + + + + + + + + + + + + + + var centerX = 0.0; + var centerY = 0.0; + var area = 0.0; + var I = 0.0; + + + + + var p1X = 0.0; + var p1Y = 0.0; + + + var k_inv3 = 1.0 / 3.0; + + for (var i = 0; i < this.m_vertexCount; ++i) + { + + + + + var p2 = this.m_vertices[i]; + + var p3 = i + 1 < this.m_vertexCount ? this.m_vertices[parseInt(i+1)] : this.m_vertices[0]; + + + var e1X = p2.x - p1X; + var e1Y = p2.y - p1Y; + + var e2X = p3.x - p1X; + var e2Y = p3.y - p1Y; + + + var D = e1X * e2Y - e1Y * e2X; + + + var triangleArea = 0.5 * D; + area += triangleArea; + + + + centerX += triangleArea * k_inv3 * (p1X + p2.x + p3.x); + centerY += triangleArea * k_inv3 * (p1Y + p2.y + p3.y); + + + var px = p1X; + var py = p1Y; + + var ex1 = e1X; + var ey1 = e1Y; + + var ex2 = e2X; + var ey2 = e2Y; + + + var intx2 = k_inv3 * (0.25 * (ex1*ex1 + ex2*ex1 + ex2*ex2) + (px*ex1 + px*ex2)) + 0.5*px*px; + + var inty2 = k_inv3 * (0.25 * (ey1*ey1 + ey2*ey1 + ey2*ey2) + (py*ey1 + py*ey2)) + 0.5*py*py; + + I += D * (intx2 + inty2); + } + + + massData.mass = this.m_density * area; + + + + + centerX *= 1.0 / area; + centerY *= 1.0 / area; + + massData.center.Set(centerX, centerY); + + + massData.I = this.m_density * I; + } +b2PolygonShape.prototype.GetOBB = function () { + return this.m_obb; + } +b2PolygonShape.prototype.GetCentroid = function () { + return this.m_centroid; + } +b2PolygonShape.prototype.GetVertexCount = function () { + return this.m_vertexCount; + } +b2PolygonShape.prototype.GetVertices = function () { + return this.m_vertices; + } +b2PolygonShape.prototype.GetCoreVertices = function () { + return this.m_coreVertices; + } +b2PolygonShape.prototype.GetNormals = function () { + return this.m_normals; + } +b2PolygonShape.prototype.GetFirstVertex = function (xf) { + return b2Math.b2MulX(xf, this.m_coreVertices[0]); + } +b2PolygonShape.prototype.Centroid = function (xf) { + return b2Math.b2MulX(xf, this.m_centroid); + } +b2PolygonShape.prototype.Support = function (xf, dX, dY) { + var tVec; + + var tMat; + + tMat = xf.R; + var dLocalX = (dX * tMat.col1.x + dY * tMat.col1.y); + var dLocalY = (dX * tMat.col2.x + dY * tMat.col2.y); + + var bestIndex = 0; + + tVec = this.m_coreVertices[0]; + var bestValue = (tVec.x*dLocalX + tVec.y*dLocalY); + for (var i = 1; i < this.m_vertexCount; ++i) + { + + tVec = this.m_coreVertices[i]; + var value = (tVec.x*dLocalX + tVec.y*dLocalY); + if (value > bestValue) + { + bestIndex = i; + bestValue = value; + } + } + + + tMat = xf.R; + tVec = this.m_coreVertices[bestIndex]; + this.s_supportVec.x = xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + this.s_supportVec.y = xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + return this.s_supportVec; + + } +b2PolygonShape.prototype.UpdateSweepRadius = function (center) { + var tVec; + + + + this.m_sweepRadius = 0.0; + for (var i = 0; i < this.m_vertexCount; ++i) + { + + tVec = this.m_coreVertices[i]; + var dX = tVec.x - center.x; + var dY = tVec.y - center.y; + dX = Math.sqrt(dX*dX + dY*dY); + + if (dX > this.m_sweepRadius) this.m_sweepRadius = dX; + } + } +exports.b2PolygonShape = b2PolygonShape; + + +var b2CircleDef = function() { +b2ShapeDef.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2CircleDef.prototype, b2ShapeDef.prototype) +b2CircleDef.prototype._super = function(){ b2ShapeDef.prototype.__constructor.apply(this, arguments) } +b2CircleDef.prototype.__constructor = function () { + this.type = b2Shape.e_circleShape; + this.radius = 1.0; + } +b2CircleDef.prototype.__varz = function(){ +this.localPosition = new b2Vec2(0.0, 0.0); +} +b2CircleDef.prototype.localPosition = new b2Vec2(0.0, 0.0); +b2CircleDef.prototype.radius = null; +exports.b2CircleDef = b2CircleDef; + + +var b2TimeStep = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2TimeStep.prototype.__constructor = function(){} +b2TimeStep.prototype.__varz = function(){ +} +b2TimeStep.prototype.dt = null; +b2TimeStep.prototype.inv_dt = null; +b2TimeStep.prototype.dtRatio = null; +b2TimeStep.prototype.maxIterations = 0; +b2TimeStep.prototype.warmStarting = null; +b2TimeStep.prototype.positionCorrection = null; +exports.b2TimeStep = b2TimeStep; + + +var b2BoundaryListener = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2BoundaryListener.prototype.__constructor = function(){} +b2BoundaryListener.prototype.__varz = function(){ +} +b2BoundaryListener.prototype.Violation = function (body) {} +exports.b2BoundaryListener = b2BoundaryListener; + + +var b2ContactListener = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2ContactListener.prototype.__constructor = function(){} +b2ContactListener.prototype.__varz = function(){ +} +b2ContactListener.prototype.Add = function (point) {} +b2ContactListener.prototype.Persist = function (point) {} +b2ContactListener.prototype.Remove = function (point) {} +b2ContactListener.prototype.Result = function (point) {} +exports.b2ContactListener = b2ContactListener; + + +var b2DestructionListener = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2DestructionListener.prototype.__constructor = function(){} +b2DestructionListener.prototype.__varz = function(){ +} +b2DestructionListener.prototype.SayGoodbyeJoint = function (joint) {} +b2DestructionListener.prototype.SayGoodbyeShape = function (shape) {} +exports.b2DestructionListener = b2DestructionListener; + + +var b2DebugDraw = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2DebugDraw.prototype.__constructor = function () { + this.m_drawFlags = 0; + } +b2DebugDraw.prototype.__varz = function(){ +} +b2DebugDraw.e_shapeBit = 0x0001; +b2DebugDraw.e_jointBit = 0x0002; +b2DebugDraw.e_coreShapeBit = 0x0004; +b2DebugDraw.e_aabbBit = 0x0008; +b2DebugDraw.e_obbBit = 0x0010; +b2DebugDraw.e_pairBit = 0x0020; +b2DebugDraw.e_centerOfMassBit = 0x0040; +b2DebugDraw.prototype.m_drawFlags = 0; +b2DebugDraw.prototype.m_sprite = null; +b2DebugDraw.prototype.m_drawScale = 1.0; +b2DebugDraw.prototype.m_lineThickness = 1.0; +b2DebugDraw.prototype.m_alpha = 1.0; +b2DebugDraw.prototype.m_fillAlpha = 1.0; +b2DebugDraw.prototype.m_xformScale = 1.0; +b2DebugDraw.prototype.SetFlags = function (flags) { + this.m_drawFlags = flags; + } +b2DebugDraw.prototype.GetFlags = function () { + return this.m_drawFlags; + } +b2DebugDraw.prototype.AppendFlags = function (flags) { + this.m_drawFlags |= flags; + } +b2DebugDraw.prototype.ClearFlags = function (flags) { + this.m_drawFlags &= ~flags; + } +b2DebugDraw.prototype.DrawPolygon = function (vertices, vertexCount, color) { + + this.m_sprite.graphics.lineStyle(this.m_lineThickness, color.color, this.m_alpha); + this.m_sprite.graphics.moveTo(vertices[0].x * this.m_drawScale, vertices[0].y * this.m_drawScale); + for (var i = 1; i < vertexCount; i++){ + this.m_sprite.graphics.lineTo(vertices[i].x * this.m_drawScale, vertices[i].y * this.m_drawScale); + } + this.m_sprite.graphics.lineTo(vertices[0].x * this.m_drawScale, vertices[0].y * this.m_drawScale); + + } +b2DebugDraw.prototype.DrawSolidPolygon = function (vertices, vertexCount, color) { + + this.m_sprite.graphics.lineStyle(this.m_lineThickness, color.color, this.m_alpha); + this.m_sprite.graphics.moveTo(vertices[0].x * this.m_drawScale, vertices[0].y * this.m_drawScale); + this.m_sprite.graphics.beginFill(color.color, this.m_fillAlpha); + for (var i = 1; i < vertexCount; i++){ + this.m_sprite.graphics.lineTo(vertices[i].x * this.m_drawScale, vertices[i].y * this.m_drawScale); + } + this.m_sprite.graphics.lineTo(vertices[0].x * this.m_drawScale, vertices[0].y * this.m_drawScale); + this.m_sprite.graphics.endFill(); + + } +b2DebugDraw.prototype.DrawCircle = function (center, radius, color) { + + this.m_sprite.graphics.lineStyle(this.m_lineThickness, color.color, this.m_alpha); + this.m_sprite.graphics.drawCircle(center.x * this.m_drawScale, center.y * this.m_drawScale, radius * this.m_drawScale); + + } +b2DebugDraw.prototype.DrawSolidCircle = function (center, radius, axis, color) { + + this.m_sprite.graphics.lineStyle(this.m_lineThickness, color.color, this.m_alpha); + this.m_sprite.graphics.moveTo(0,0); + this.m_sprite.graphics.beginFill(color.color, this.m_fillAlpha); + this.m_sprite.graphics.drawCircle(center.x * this.m_drawScale, center.y * this.m_drawScale, radius * this.m_drawScale); + this.m_sprite.graphics.endFill(); + this.m_sprite.graphics.moveTo(center.x * this.m_drawScale, center.y * this.m_drawScale); + this.m_sprite.graphics.lineTo((center.x + axis.x*radius) * this.m_drawScale, (center.y + axis.y*radius) * this.m_drawScale); + + } +b2DebugDraw.prototype.DrawSegment = function (p1, p2, color) { + + this.m_sprite.graphics.lineStyle(this.m_lineThickness, color.color, this.m_alpha); + this.m_sprite.graphics.moveTo(p1.x * this.m_drawScale, p1.y * this.m_drawScale); + this.m_sprite.graphics.lineTo(p2.x * this.m_drawScale, p2.y * this.m_drawScale); + + } +b2DebugDraw.prototype.DrawXForm = function (xf) { + + this.m_sprite.graphics.lineStyle(this.m_lineThickness, 0xff0000, this.m_alpha); + this.m_sprite.graphics.moveTo(xf.position.x * this.m_drawScale, xf.position.y * this.m_drawScale); + this.m_sprite.graphics.lineTo((xf.position.x + this.m_xformScale*xf.R.col1.x) * this.m_drawScale, (xf.position.y + this.m_xformScale*xf.R.col1.y) * this.m_drawScale); + + this.m_sprite.graphics.lineStyle(this.m_lineThickness, 0x00ff00, this.m_alpha); + this.m_sprite.graphics.moveTo(xf.position.x * this.m_drawScale, xf.position.y * this.m_drawScale); + this.m_sprite.graphics.lineTo((xf.position.x + this.m_xformScale*xf.R.col2.x) * this.m_drawScale, (xf.position.y + this.m_xformScale*xf.R.col2.y) * this.m_drawScale); + + } +exports.b2DebugDraw = b2DebugDraw; + + +var b2BodyDef = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2BodyDef.prototype.__constructor = function () { + this.massData.center.SetZero(); + this.massData.mass = 0.0; + this.massData.I = 0.0; + this.userData = null; + this.position.Set(0.0, 0.0); + this.angle = 0.0; + this.linearDamping = 0.0; + this.angularDamping = 0.0; + this.allowSleep = true; + this.isSleeping = false; + this.fixedRotation = false; + this.isBullet = false; + } +b2BodyDef.prototype.__varz = function(){ +this.massData = new b2MassData(); +this.position = new b2Vec2(); +} +b2BodyDef.prototype.massData = new b2MassData(); +b2BodyDef.prototype.userData = null; +b2BodyDef.prototype.position = new b2Vec2(); +b2BodyDef.prototype.angle = null; +b2BodyDef.prototype.linearDamping = null; +b2BodyDef.prototype.angularDamping = null; +b2BodyDef.prototype.allowSleep = null; +b2BodyDef.prototype.isSleeping = null; +b2BodyDef.prototype.fixedRotation = null; +b2BodyDef.prototype.isBullet = null; +exports.b2BodyDef = b2BodyDef; + + +var b2Body = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Body.prototype.__constructor = function (bd, world) { + + + this.m_flags = 0; + + if (bd.isBullet) + { + this.m_flags |= b2Body.e_bulletFlag; + } + if (bd.fixedRotation) + { + this.m_flags |= b2Body.e_fixedRotationFlag; + } + if (bd.allowSleep) + { + this.m_flags |= b2Body.e_allowSleepFlag; + } + if (bd.isSleeping) + { + this.m_flags |= b2Body.e_sleepFlag; + } + + this.m_world = world; + + this.m_xf.position.SetV(bd.position); + this.m_xf.R.Set(bd.angle); + + this.m_sweep.localCenter.SetV(bd.massData.center); + this.m_sweep.t0 = 1.0; + this.m_sweep.a0 = this.m_sweep.a = bd.angle; + + + + var tMat = this.m_xf.R; + var tVec = this.m_sweep.localCenter; + + this.m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + + this.m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + this.m_sweep.c.x += this.m_xf.position.x; + this.m_sweep.c.y += this.m_xf.position.y; + + this.m_sweep.c0.SetV(this.m_sweep.c); + + this.m_jointList = null; + this.m_contactList = null; + this.m_prev = null; + this.m_next = null; + + this.m_linearDamping = bd.linearDamping; + this.m_angularDamping = bd.angularDamping; + + this.m_force.Set(0.0, 0.0); + this.m_torque = 0.0; + + this.m_linearVelocity.SetZero(); + this.m_angularVelocity = 0.0; + + this.m_sleepTime = 0.0; + + this.m_invMass = 0.0; + this.m_I = 0.0; + this.m_invI = 0.0; + + this.m_mass = bd.massData.mass; + + if (this.m_mass > 0.0) + { + this.m_invMass = 1.0 / this.m_mass; + } + + if ((this.m_flags & b2Body.e_fixedRotationFlag) == 0) + { + this.m_I = bd.massData.I; + } + + if (this.m_I > 0.0) + { + this.m_invI = 1.0 / this.m_I; + } + + if (this.m_invMass == 0.0 && this.m_invI == 0.0) + { + this.m_type = b2Body.e_staticType; + } + else + { + this.m_type = b2Body.e_dynamicType; + } + + this.m_userData = bd.userData; + + this.m_shapeList = null; + this.m_shapeCount = 0; + } +b2Body.prototype.__varz = function(){ +this.m_xf = new b2XForm(); +this.m_sweep = new b2Sweep(); +this.m_linearVelocity = new b2Vec2(); +this.m_force = new b2Vec2(); +} +b2Body.e_frozenFlag = 0x0002; +b2Body.e_islandFlag = 0x0004; +b2Body.e_sleepFlag = 0x0008; +b2Body.e_allowSleepFlag = 0x0010; +b2Body.e_bulletFlag = 0x0020; +b2Body.e_fixedRotationFlag = 0x0040; +b2Body.e_staticType = 1; +b2Body.e_dynamicType = 2; +b2Body.e_maxTypes = 3; +b2Body.s_massData = new b2MassData(); +b2Body.s_xf1 = new b2XForm(); +b2Body.prototype.m_flags = 0; +b2Body.prototype.m_type = 0; +b2Body.prototype.m_xf = new b2XForm(); +b2Body.prototype.m_sweep = new b2Sweep(); +b2Body.prototype.m_linearVelocity = new b2Vec2(); +b2Body.prototype.m_angularVelocity = null; +b2Body.prototype.m_force = new b2Vec2(); +b2Body.prototype.m_torque = null; +b2Body.prototype.m_world = null; +b2Body.prototype.m_prev = null; +b2Body.prototype.m_next = null; +b2Body.prototype.m_shapeList = null; +b2Body.prototype.m_shapeCount = 0; +b2Body.prototype.m_jointList = null; +b2Body.prototype.m_contactList = null; +b2Body.prototype.m_mass = null; +b2Body.prototype.m_invMass = null; +b2Body.prototype.m_I = null; +b2Body.prototype.m_invI = null; +b2Body.prototype.m_linearDamping = null; +b2Body.prototype.m_angularDamping = null; +b2Body.prototype.m_sleepTime = null; +b2Body.prototype.m_userData = null; +b2Body.prototype.CreateShape = function (def) { + + if (this.m_world.m_lock == true) + { + return null; + } + + var s = b2Shape.Create(def, this.m_world.m_blockAllocator); + + s.m_next = this.m_shapeList; + this.m_shapeList = s; + ++this.m_shapeCount; + + s.m_body = this; + + + s.CreateProxy(this.m_world.m_broadPhase, this.m_xf); + + + s.UpdateSweepRadius(this.m_sweep.localCenter); + + return s; + } +b2Body.prototype.DestroyShape = function (s) { + + if (this.m_world.m_lock == true) + { + return; + } + + + s.DestroyProxy(this.m_world.m_broadPhase); + + + + var node = this.m_shapeList; + var ppS = null; + var found = false; + while (node != null) + { + if (node == s) + { + if (ppS) + ppS.m_next = s.m_next; + else + this.m_shapeList = s.m_next; + + found = true; + break; + } + + ppS = node; + node = node.m_next; + } + + + + + s.m_body = null; + s.m_next = null; + + --this.m_shapeCount; + + b2Shape.Destroy(s, this.m_world.m_blockAllocator); + } +b2Body.prototype.SetMass = function (massData) { + var s; + + + if (this.m_world.m_lock == true) + { + return; + } + + this.m_invMass = 0.0; + this.m_I = 0.0; + this.m_invI = 0.0; + + this.m_mass = massData.mass; + + if (this.m_mass > 0.0) + { + this.m_invMass = 1.0 / this.m_mass; + } + + if ((this.m_flags & b2Body.e_fixedRotationFlag) == 0) + { + this.m_I = massData.I; + } + + if (this.m_I > 0.0) + { + this.m_invI = 1.0 / this.m_I; + } + + + this.m_sweep.localCenter.SetV(massData.center); + + + var tMat = this.m_xf.R; + var tVec = this.m_sweep.localCenter; + + this.m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + + this.m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + this.m_sweep.c.x += this.m_xf.position.x; + this.m_sweep.c.y += this.m_xf.position.y; + + this.m_sweep.c0.SetV(this.m_sweep.c); + + + for (s = this.m_shapeList; s; s = s.m_next) + { + s.UpdateSweepRadius(this.m_sweep.localCenter); + } + + var oldType = this.m_type; + if (this.m_invMass == 0.0 && this.m_invI == 0.0) + { + this.m_type = b2Body.e_staticType; + } + else + { + this.m_type = b2Body.e_dynamicType; + } + + + if (oldType != this.m_type) + { + for (s = this.m_shapeList; s; s = s.m_next) + { + s.RefilterProxy(this.m_world.m_broadPhase, this.m_xf); + } + } + } +b2Body.prototype.SetMassFromShapes = function () { + + var s; + + + if (this.m_world.m_lock == true) + { + return; + } + + + this.m_mass = 0.0; + this.m_invMass = 0.0; + this.m_I = 0.0; + this.m_invI = 0.0; + + + var centerX = 0.0; + var centerY = 0.0; + var massData = b2Body.s_massData; + for (s = this.m_shapeList; s; s = s.m_next) + { + s.ComputeMass(massData); + this.m_mass += massData.mass; + + centerX += massData.mass * massData.center.x; + centerY += massData.mass * massData.center.y; + this.m_I += massData.I; + } + + + if (this.m_mass > 0.0) + { + this.m_invMass = 1.0 / this.m_mass; + centerX *= this.m_invMass; + centerY *= this.m_invMass; + } + + if (this.m_I > 0.0 && (this.m_flags & b2Body.e_fixedRotationFlag) == 0) + { + + + this.m_I -= this.m_mass * (centerX * centerX + centerY * centerY); + + this.m_invI = 1.0 / this.m_I; + } + else + { + this.m_I = 0.0; + this.m_invI = 0.0; + } + + + this.m_sweep.localCenter.Set(centerX, centerY); + + + var tMat = this.m_xf.R; + var tVec = this.m_sweep.localCenter; + + this.m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + + this.m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + this.m_sweep.c.x += this.m_xf.position.x; + this.m_sweep.c.y += this.m_xf.position.y; + + this.m_sweep.c0.SetV(this.m_sweep.c); + + + for (s = this.m_shapeList; s; s = s.m_next) + { + s.UpdateSweepRadius(this.m_sweep.localCenter); + } + + var oldType = this.m_type; + if (this.m_invMass == 0.0 && this.m_invI == 0.0) + { + this.m_type = b2Body.e_staticType; + } + else + { + this.m_type = b2Body.e_dynamicType; + } + + + if (oldType != this.m_type) + { + for (s = this.m_shapeList; s; s = s.m_next) + { + s.RefilterProxy(this.m_world.m_broadPhase, this.m_xf); + } + } + } +b2Body.prototype.SetXForm = function (position, angle) { + + var s; + + + if (this.m_world.m_lock == true) + { + return true; + } + + if (this.IsFrozen()) + { + return false; + } + + this.m_xf.R.Set(angle); + this.m_xf.position.SetV(position); + + + + var tMat = this.m_xf.R; + var tVec = this.m_sweep.localCenter; + + this.m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + + this.m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + this.m_sweep.c.x += this.m_xf.position.x; + this.m_sweep.c.y += this.m_xf.position.y; + + this.m_sweep.c0.SetV(this.m_sweep.c); + + this.m_sweep.a0 = this.m_sweep.a = angle; + + var freeze = false; + for (s = this.m_shapeList; s; s = s.m_next) + { + var inRange = s.Synchronize(this.m_world.m_broadPhase, this.m_xf, this.m_xf); + + if (inRange == false) + { + freeze = true; + break; + } + } + + if (freeze == true) + { + this.m_flags |= b2Body.e_frozenFlag; + this.m_linearVelocity.SetZero(); + this.m_angularVelocity = 0.0; + for (s = this.m_shapeList; s; s = s.m_next) + { + s.DestroyProxy(this.m_world.m_broadPhase); + } + + + return false; + } + + + this.m_world.m_broadPhase.Commit(); + return true; + + } +b2Body.prototype.GetXForm = function () { + return this.m_xf; + } +b2Body.prototype.GetPosition = function () { + return this.m_xf.position; + } +b2Body.prototype.GetAngle = function () { + return this.m_sweep.a; + } +b2Body.prototype.GetWorldCenter = function () { + return this.m_sweep.c; + } +b2Body.prototype.GetLocalCenter = function () { + return this.m_sweep.localCenter; + } +b2Body.prototype.SetLinearVelocity = function (v) { + this.m_linearVelocity.SetV(v); + } +b2Body.prototype.GetLinearVelocity = function () { + return this.m_linearVelocity; + } +b2Body.prototype.SetAngularVelocity = function (omega) { + this.m_angularVelocity = omega; + } +b2Body.prototype.GetAngularVelocity = function () { + return this.m_angularVelocity; + } +b2Body.prototype.ApplyForce = function (force, point) { + if (this.IsSleeping()) + { + this.WakeUp(); + } + + this.m_force.x += force.x; + this.m_force.y += force.y; + + this.m_torque += ((point.x - this.m_sweep.c.x) * force.y - (point.y - this.m_sweep.c.y) * force.x); + } +b2Body.prototype.ApplyTorque = function (torque) { + if (this.IsSleeping()) + { + this.WakeUp(); + } + this.m_torque += torque; + } +b2Body.prototype.ApplyImpulse = function (impulse, point) { + if (this.IsSleeping()) + { + this.WakeUp(); + } + + this.m_linearVelocity.x += this.m_invMass * impulse.x; + this.m_linearVelocity.y += this.m_invMass * impulse.y; + + this.m_angularVelocity += this.m_invI * ((point.x - this.m_sweep.c.x) * impulse.y - (point.y - this.m_sweep.c.y) * impulse.x); + } +b2Body.prototype.GetMass = function () { + return this.m_mass; + } +b2Body.prototype.GetInertia = function () { + return this.m_I; + } +b2Body.prototype.GetWorldPoint = function (localPoint) { + + var A = this.m_xf.R; + var u = new b2Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, + A.col1.y * localPoint.x + A.col2.y * localPoint.y); + u.x += this.m_xf.position.x; + u.y += this.m_xf.position.y; + return u; + } +b2Body.prototype.GetWorldVector = function (localVector) { + return b2Math.b2MulMV(this.m_xf.R, localVector); + } +b2Body.prototype.GetLocalPoint = function (worldPoint) { + return b2Math.b2MulXT(this.m_xf, worldPoint); + } +b2Body.prototype.GetLocalVector = function (worldVector) { + return b2Math.b2MulTMV(this.m_xf.R, worldVector); + } +b2Body.prototype.GetLinearVelocityFromWorldPoint = function (worldPoint) { + + return new b2Vec2( this.m_linearVelocity.x - this.m_angularVelocity * (worldPoint.y - this.m_sweep.c.y), + this.m_linearVelocity.y + this.m_angularVelocity * (worldPoint.x - this.m_sweep.c.x)); + } +b2Body.prototype.GetLinearVelocityFromLocalPoint = function (localPoint) { + + var A = this.m_xf.R; + var worldPoint = new b2Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, + A.col1.y * localPoint.x + A.col2.y * localPoint.y); + worldPoint.x += this.m_xf.position.x; + worldPoint.y += this.m_xf.position.y; + return new b2Vec2(this.m_linearVelocity.x + this.m_angularVelocity * (worldPoint.y - this.m_sweep.c.y), + this.m_linearVelocity.x - this.m_angularVelocity * (worldPoint.x - this.m_sweep.c.x)); + } +b2Body.prototype.IsBullet = function () { + return (this.m_flags & b2Body.e_bulletFlag) == b2Body.e_bulletFlag; + } +b2Body.prototype.SetBullet = function (flag) { + if (flag) + { + this.m_flags |= b2Body.e_bulletFlag; + } + else + { + this.m_flags &= ~b2Body.e_bulletFlag; + } + } +b2Body.prototype.IsStatic = function () { + return this.m_type == b2Body.e_staticType; + } +b2Body.prototype.IsDynamic = function () { + return this.m_type == b2Body.e_dynamicType; + } +b2Body.prototype.IsFrozen = function () { + return (this.m_flags & b2Body.e_frozenFlag) == b2Body.e_frozenFlag; + } +b2Body.prototype.IsSleeping = function () { + return (this.m_flags & b2Body.e_sleepFlag) == b2Body.e_sleepFlag; + } +b2Body.prototype.AllowSleeping = function (flag) { + if (flag) + { + this.m_flags |= b2Body.e_allowSleepFlag; + } + else + { + this.m_flags &= ~b2Body.e_allowSleepFlag; + this.WakeUp(); + } + } +b2Body.prototype.WakeUp = function () { + this.m_flags &= ~b2Body.e_sleepFlag; + this.m_sleepTime = 0.0; + } +b2Body.prototype.PutToSleep = function () { + this.m_flags |= b2Body.e_sleepFlag; + this.m_sleepTime = 0.0; + this.m_linearVelocity.SetZero(); + this.m_angularVelocity = 0.0; + this.m_force.SetZero(); + this.m_torque = 0.0; + } +b2Body.prototype.GetShapeList = function () { + return this.m_shapeList; + } +b2Body.prototype.GetJointList = function () { + return this.m_jointList; + } +b2Body.prototype.GetNext = function () { + return this.m_next; + } +b2Body.prototype.GetUserData = function () { + return this.m_userData; + } +b2Body.prototype.SetUserData = function (data) { + this.m_userData = data; + } +b2Body.prototype.GetWorld = function () { + return this.m_world; + } +b2Body.prototype.SynchronizeShapes = function () { + + var xf1 = b2Body.s_xf1; + xf1.R.Set(this.m_sweep.a0); + + var tMat = xf1.R; + var tVec = this.m_sweep.localCenter; + xf1.position.x = this.m_sweep.c0.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + xf1.position.y = this.m_sweep.c0.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + + var s; + + var inRange = true; + for (s = this.m_shapeList; s; s = s.m_next) + { + inRange = s.Synchronize(this.m_world.m_broadPhase, xf1, this.m_xf); + if (inRange == false) + { + break; + } + } + + if (inRange == false) + { + this.m_flags |= b2Body.e_frozenFlag; + this.m_linearVelocity.SetZero(); + this.m_angularVelocity = 0.0; + for (s = this.m_shapeList; s; s = s.m_next) + { + s.DestroyProxy(this.m_world.m_broadPhase); + } + + + return false; + } + + + return true; + + } +b2Body.prototype.SynchronizeTransform = function () { + this.m_xf.R.Set(this.m_sweep.a); + + var tMat = this.m_xf.R; + var tVec = this.m_sweep.localCenter; + this.m_xf.position.x = this.m_sweep.c.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + this.m_xf.position.y = this.m_sweep.c.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + } +b2Body.prototype.IsConnected = function (other) { + for (var jn = this.m_jointList; jn; jn = jn.next) + { + if (jn.other == other) + return jn.joint.m_collideConnected == false; + } + + return false; + } +b2Body.prototype.Advance = function (t) { + + this.m_sweep.Advance(t); + this.m_sweep.c.SetV(this.m_sweep.c0); + this.m_sweep.a = this.m_sweep.a0; + this.SynchronizeTransform(); + } +exports.b2Body = b2Body; + + +var b2ContactFilter = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2ContactFilter.prototype.__constructor = function(){} +b2ContactFilter.prototype.__varz = function(){ +} +b2ContactFilter.b2_defaultFilter = new b2ContactFilter(); +b2ContactFilter.prototype.ShouldCollide = function (shape1, shape2) { + var filter1 = shape1.GetFilterData(); + var filter2 = shape2.GetFilterData(); + + if (filter1.groupIndex == filter2.groupIndex && filter1.groupIndex != 0) + { + return filter1.groupIndex > 0; + } + + var collide = (filter1.maskBits & filter2.categoryBits) != 0 && (filter1.categoryBits & filter2.maskBits) != 0; + return collide; + } +exports.b2ContactFilter = b2ContactFilter; + + +var b2ContactResult = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2ContactResult.prototype.__constructor = function(){} +b2ContactResult.prototype.__varz = function(){ +this.position = new b2Vec2(); +this.normal = new b2Vec2(); +this.id = new b2ContactID(); +} +b2ContactResult.prototype.shape1 = null; +b2ContactResult.prototype.shape2 = null; +b2ContactResult.prototype.position = new b2Vec2(); +b2ContactResult.prototype.normal = new b2Vec2(); +b2ContactResult.prototype.normalImpulse = null; +b2ContactResult.prototype.tangentImpulse = null; +b2ContactResult.prototype.id = new b2ContactID(); +exports.b2ContactResult = b2ContactResult; + + +var b2Island = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Island.prototype.__constructor = function ( + bodyCapacity, + contactCapacity, + jointCapacity, + allocator, + listener) { + var i = 0; + + this.m_bodyCapacity = bodyCapacity; + this.m_contactCapacity = contactCapacity; + this.m_jointCapacity = jointCapacity; + this.m_bodyCount = 0; + this.m_contactCount = 0; + this.m_jointCount = 0; + + this.m_allocator = allocator; + this.m_listener = listener; + + + this.m_bodies = new Array(bodyCapacity); + for (i = 0; i < bodyCapacity; i++) + this.m_bodies[i] = null; + + + this.m_contacts = new Array(contactCapacity); + for (i = 0; i < contactCapacity; i++) + this.m_contacts[i] = null; + + + this.m_joints = new Array(jointCapacity); + for (i = 0; i < jointCapacity; i++) + this.m_joints[i] = null; + + this.m_positionIterationCount = 0; + + } +b2Island.prototype.__varz = function(){ +} +b2Island.s_reportCR = new b2ContactResult(); +b2Island.prototype.m_allocator = null; +b2Island.prototype.m_listener = null; +b2Island.prototype.m_bodies = null; +b2Island.prototype.m_contacts = null; +b2Island.prototype.m_joints = null; +b2Island.prototype.m_bodyCount = 0; +b2Island.prototype.m_jointCount = 0; +b2Island.prototype.m_contactCount = 0; +b2Island.prototype.m_bodyCapacity = 0; +b2Island.prototype.m_contactCapacity = 0; +b2Island.prototype.m_jointCapacity = 0; +b2Island.prototype.m_positionIterationCount = 0; +b2Island.prototype.Clear = function () { + this.m_bodyCount = 0; + this.m_contactCount = 0; + this.m_jointCount = 0; + } +b2Island.prototype.Solve = function (step, gravity, correctPositions, allowSleep) { + var i = 0; + var b; + var joint; + + + for (i = 0; i < this.m_bodyCount; ++i) + { + b = this.m_bodies[i]; + + if (b.IsStatic()) + continue; + + + + b.m_linearVelocity.x += step.dt * (gravity.x + b.m_invMass * b.m_force.x); + b.m_linearVelocity.y += step.dt * (gravity.y + b.m_invMass * b.m_force.y); + b.m_angularVelocity += step.dt * b.m_invI * b.m_torque; + + + b.m_force.SetZero(); + b.m_torque = 0.0; + + + + + + + + + b.m_linearVelocity.Multiply( b2Math.b2Clamp(1.0 - step.dt * b.m_linearDamping, 0.0, 1.0) ); + b.m_angularVelocity *= b2Math.b2Clamp(1.0 - step.dt * b.m_angularDamping, 0.0, 1.0); + + + + if ((b.m_linearVelocity.LengthSquared()) > b2Settings.b2_maxLinearVelocitySquared) + { + b.m_linearVelocity.Normalize(); + b.m_linearVelocity.x *= b2Settings.b2_maxLinearVelocity; + b.m_linearVelocity.y *= b2Settings.b2_maxLinearVelocity; + } + + if (b.m_angularVelocity * b.m_angularVelocity > b2Settings.b2_maxAngularVelocitySquared) + { + if (b.m_angularVelocity < 0.0) + { + b.m_angularVelocity = -b2Settings.b2_maxAngularVelocity; + } + else + { + b.m_angularVelocity = b2Settings.b2_maxAngularVelocity; + } + } + } + + var contactSolver = new b2ContactSolver(step, this.m_contacts, this.m_contactCount, this.m_allocator); + + + contactSolver.InitVelocityConstraints(step); + + for (i = 0; i < this.m_jointCount; ++i) + { + joint = this.m_joints[i]; + joint.InitVelocityConstraints(step); + } + + + for (i = 0; i < step.maxIterations; ++i) + { + contactSolver.SolveVelocityConstraints(); + + for (var j = 0; j < this.m_jointCount; ++j) + { + joint = this.m_joints[j]; + joint.SolveVelocityConstraints(step); + } + } + + + contactSolver.FinalizeVelocityConstraints(); + + + for (i = 0; i < this.m_bodyCount; ++i) + { + b = this.m_bodies[i]; + + if (b.IsStatic()) + continue; + + + b.m_sweep.c0.SetV(b.m_sweep.c); + b.m_sweep.a0 = b.m_sweep.a; + + + + b.m_sweep.c.x += step.dt * b.m_linearVelocity.x; + b.m_sweep.c.y += step.dt * b.m_linearVelocity.y; + b.m_sweep.a += step.dt * b.m_angularVelocity; + + + b.SynchronizeTransform(); + + + } + + if (correctPositions) + { + + + for (i = 0; i < this.m_jointCount; ++i) + { + joint = this.m_joints[i]; + joint.InitPositionConstraints(); + } + + + for (this.m_positionIterationCount = 0; this.m_positionIterationCount < step.maxIterations; ++this.m_positionIterationCount) + { + var contactsOkay = contactSolver.SolvePositionConstraints(b2Settings.b2_contactBaumgarte); + + var jointsOkay = true; + for (i = 0; i < this.m_jointCount; ++i) + { + joint = this.m_joints[i]; + var jointOkay = joint.SolvePositionConstraints(); + jointsOkay = jointsOkay && jointOkay; + } + + if (contactsOkay && jointsOkay) + { + break; + } + } + } + + this.Report(contactSolver.m_constraints); + + if (allowSleep){ + + var minSleepTime = Number.MAX_VALUE; + + var linTolSqr = b2Settings.b2_linearSleepTolerance * b2Settings.b2_linearSleepTolerance; + var angTolSqr = b2Settings.b2_angularSleepTolerance * b2Settings.b2_angularSleepTolerance; + + for (i = 0; i < this.m_bodyCount; ++i) + { + b = this.m_bodies[i]; + if (b.m_invMass == 0.0) + { + continue; + } + + if ((b.m_flags & b2Body.e_allowSleepFlag) == 0) + { + b.m_sleepTime = 0.0; + minSleepTime = 0.0; + } + + if ((b.m_flags & b2Body.e_allowSleepFlag) == 0 || + b.m_angularVelocity * b.m_angularVelocity > angTolSqr || + b2Math.b2Dot(b.m_linearVelocity, b.m_linearVelocity) > linTolSqr) + { + b.m_sleepTime = 0.0; + minSleepTime = 0.0; + } + else + { + b.m_sleepTime += step.dt; + minSleepTime = b2Math.b2Min(minSleepTime, b.m_sleepTime); + } + } + + if (minSleepTime >= b2Settings.b2_timeToSleep) + { + for (i = 0; i < this.m_bodyCount; ++i) + { + b = this.m_bodies[i]; + b.m_flags |= b2Body.e_sleepFlag; + b.m_linearVelocity.SetZero(); + b.m_angularVelocity = 0.0; + } + } + } + } +b2Island.prototype.SolveTOI = function (subStep) { + var i = 0; + var contactSolver = new b2ContactSolver(subStep, this.m_contacts, this.m_contactCount, this.m_allocator); + + + + + for (i = 0; i < subStep.maxIterations; ++i) + { + contactSolver.SolveVelocityConstraints(); + } + + + + + + for (i = 0; i < this.m_bodyCount; ++i) + { + var b = this.m_bodies[i]; + + if (b.IsStatic()) + continue; + + + b.m_sweep.c0.SetV(b.m_sweep.c); + b.m_sweep.a0 = b.m_sweep.a; + + + b.m_sweep.c.x += subStep.dt * b.m_linearVelocity.x; + b.m_sweep.c.y += subStep.dt * b.m_linearVelocity.y; + b.m_sweep.a += subStep.dt * b.m_angularVelocity; + + + b.SynchronizeTransform(); + + + } + + + var k_toiBaumgarte = 0.75; + for (i = 0; i < subStep.maxIterations; ++i) + { + var contactsOkay = contactSolver.SolvePositionConstraints(k_toiBaumgarte); + if (contactsOkay) + { + break; + } + } + + this.Report(contactSolver.m_constraints); + } +b2Island.prototype.Report = function (constraints) { + var tMat; + var tVec; + if (this.m_listener == null) + { + return; + } + + for (var i = 0; i < this.m_contactCount; ++i) + { + var c = this.m_contacts[i]; + var cc = constraints[ i ]; + var cr = b2Island.s_reportCR; + cr.shape1 = c.m_shape1; + cr.shape2 = c.m_shape2; + var b1 = cr.shape1.m_body; + var manifoldCount = c.m_manifoldCount; + var manifolds = c.GetManifolds(); + for (var j = 0; j < manifoldCount; ++j) + { + var manifold = manifolds[ j ]; + cr.normal.SetV( manifold.normal ); + for (var k = 0; k < manifold.pointCount; ++k) + { + var point = manifold.points[ k ]; + var ccp = cc.points[ k ]; + cr.position = b1.GetWorldPoint(point.localPoint1); + + + + cr.normalImpulse = ccp.normalImpulse; + cr.tangentImpulse = ccp.tangentImpulse; + cr.id.key = point.id.key; + + this.m_listener.Result(cr); + } + } + } + } +b2Island.prototype.AddBody = function (body) { + + this.m_bodies[this.m_bodyCount++] = body; + } +b2Island.prototype.AddContact = function (contact) { + + this.m_contacts[this.m_contactCount++] = contact; + } +b2Island.prototype.AddJoint = function (joint) { + + this.m_joints[this.m_jointCount++] = joint; + } +exports.b2Island = b2Island; + + +var b2ContactEdge = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2ContactEdge.prototype.__constructor = function(){} +b2ContactEdge.prototype.__varz = function(){ +} +b2ContactEdge.prototype.other = null; +b2ContactEdge.prototype.contact = null; +b2ContactEdge.prototype.prev = null; +b2ContactEdge.prototype.next = null; +exports.b2ContactEdge = b2ContactEdge; + + +var b2Contact = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Contact.prototype.__constructor = function (s1, s2) { + this.m_flags = 0; + + if (!s1 || !s2){ + this.m_shape1 = null; + this.m_shape2 = null; + return; + } + + if (s1.IsSensor() || s2.IsSensor()) + { + this.m_flags |= b2Contact.e_nonSolidFlag; + } + + this.m_shape1 = s1; + this.m_shape2 = s2; + + this.m_manifoldCount = 0; + + this.m_friction = Math.sqrt(this.m_shape1.m_friction * this.m_shape2.m_friction); + this.m_restitution = b2Math.b2Max(this.m_shape1.m_restitution, this.m_shape2.m_restitution); + + this.m_prev = null; + this.m_next = null; + + this.m_node1.contact = null; + this.m_node1.prev = null; + this.m_node1.next = null; + this.m_node1.other = null; + + this.m_node2.contact = null; + this.m_node2.prev = null; + this.m_node2.next = null; + this.m_node2.other = null; + } +b2Contact.prototype.__varz = function(){ +this.m_node1 = new b2ContactEdge(); +this.m_node2 = new b2ContactEdge(); +} +b2Contact.e_nonSolidFlag = 0x0001; +b2Contact.e_slowFlag = 0x0002; +b2Contact.e_islandFlag = 0x0004; +b2Contact.e_toiFlag = 0x0008; +b2Contact.s_registers = null; +b2Contact.s_initialized = false; +b2Contact.AddType = function (createFcn, destroyFcn, type1, type2) { + + + + b2Contact.s_registers[type1][type2].createFcn = createFcn; + b2Contact.s_registers[type1][type2].destroyFcn = destroyFcn; + b2Contact.s_registers[type1][type2].primary = true; + + if (type1 != type2) + { + b2Contact.s_registers[type2][type1].createFcn = createFcn; + b2Contact.s_registers[type2][type1].destroyFcn = destroyFcn; + b2Contact.s_registers[type2][type1].primary = false; + } + } +b2Contact.InitializeRegisters = function () { + b2Contact.s_registers = new Array(b2Shape.e_shapeTypeCount); + for (var i = 0; i < b2Shape.e_shapeTypeCount; i++){ + b2Contact.s_registers[i] = new Array(b2Shape.e_shapeTypeCount); + for (var j = 0; j < b2Shape.e_shapeTypeCount; j++){ + b2Contact.s_registers[i][j] = new b2ContactRegister(); + } + } + + b2Contact.AddType(b2CircleContact.Create, b2CircleContact.Destroy, b2Shape.e_circleShape, b2Shape.e_circleShape); + b2Contact.AddType(b2PolyAndCircleContact.Create, b2PolyAndCircleContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_circleShape); + b2Contact.AddType(b2PolygonContact.Create, b2PolygonContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_polygonShape); + + } +b2Contact.Create = function (shape1, shape2, allocator) { + if (b2Contact.s_initialized == false) + { + b2Contact.InitializeRegisters(); + b2Contact.s_initialized = true; + } + + var type1 = shape1.m_type; + var type2 = shape2.m_type; + + + + + var reg = b2Contact.s_registers[type1][type2]; + var createFcn = reg.createFcn; + if (createFcn != null) + { + if (reg.primary) + { + return createFcn(shape1, shape2, allocator); + } + else + { + var c = createFcn(shape2, shape1, allocator); + for (var i = 0; i < c.m_manifoldCount; ++i) + { + var m = c.GetManifolds()[ i ]; + m.normal = m.normal.Negative(); + } + return c; + } + } + else + { + return null; + } + } +b2Contact.Destroy = function (contact, allocator) { + + + if (contact.m_manifoldCount > 0) + { + contact.m_shape1.m_body.WakeUp(); + contact.m_shape2.m_body.WakeUp(); + } + + var type1 = contact.m_shape1.m_type; + var type2 = contact.m_shape2.m_type; + + + + + var reg = b2Contact.s_registers[type1][type2]; + var destroyFcn = reg.destroyFcn; + destroyFcn(contact, allocator); + } +b2Contact.prototype.m_flags = 0; +b2Contact.prototype.m_prev = null; +b2Contact.prototype.m_next = null; +b2Contact.prototype.m_node1 = new b2ContactEdge(); +b2Contact.prototype.m_node2 = new b2ContactEdge(); +b2Contact.prototype.m_shape1 = null; +b2Contact.prototype.m_shape2 = null; +b2Contact.prototype.m_manifoldCount = 0; +b2Contact.prototype.m_friction = null; +b2Contact.prototype.m_restitution = null; +b2Contact.prototype.m_toi = null; +b2Contact.prototype.GetManifolds = function () {return null} +b2Contact.prototype.GetManifoldCount = function () { + return this.m_manifoldCount; + } +b2Contact.prototype.IsSolid = function () { + return (this.m_flags & b2Contact.e_nonSolidFlag) == 0; + } +b2Contact.prototype.GetNext = function () { + return this.m_next; + } +b2Contact.prototype.GetShape1 = function () { + return this.m_shape1; + } +b2Contact.prototype.GetShape2 = function () { + return this.m_shape2; + } +b2Contact.prototype.Update = function (listener) { + var oldCount = this.m_manifoldCount; + + this.Evaluate(listener); + + var newCount = this.m_manifoldCount; + + var body1 = this.m_shape1.m_body; + var body2 = this.m_shape2.m_body; + + if (newCount == 0 && oldCount > 0) + { + body1.WakeUp(); + body2.WakeUp(); + } + + + if (body1.IsStatic() || body1.IsBullet() || body2.IsStatic() || body2.IsBullet()) + { + this.m_flags &= ~b2Contact.e_slowFlag; + } + else + { + this.m_flags |= b2Contact.e_slowFlag; + } + } +b2Contact.prototype.Evaluate = function (listener) {} +exports.b2Contact = b2Contact; + + +var b2NullContact = function() { +b2Contact.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2NullContact.prototype, b2Contact.prototype) +b2NullContact.prototype._super = function(){ b2Contact.prototype.__constructor.apply(this, arguments) } +b2NullContact.prototype.__constructor = function () {} +b2NullContact.prototype.__varz = function(){ +} +b2NullContact.prototype.Evaluate = function (l) {} +b2NullContact.prototype.GetManifolds = function () { return null; } +exports.b2NullContact = b2NullContact; + + +var b2ContactManager = function() { +b2PairCallback.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2ContactManager.prototype, b2PairCallback.prototype) +b2ContactManager.prototype._super = function(){ b2PairCallback.prototype.__constructor.apply(this, arguments) } +b2ContactManager.prototype.__constructor = function () { + this.m_world = null; + this.m_destroyImmediate = false; + } +b2ContactManager.prototype.__varz = function(){ +this.m_nullContact = new b2NullContact(); +} +b2ContactManager.s_evalCP = new b2ContactPoint(); +b2ContactManager.prototype.m_world = null; +b2ContactManager.prototype.m_nullContact = new b2NullContact(); +b2ContactManager.prototype.m_destroyImmediate = null; +b2ContactManager.prototype.PairAdded = function (proxyUserData1, proxyUserData2) { + var shape1 = proxyUserData1; + var shape2 = proxyUserData2; + + var body1 = shape1.m_body; + var body2 = shape2.m_body; + + if (body1.IsStatic() && body2.IsStatic()) + { + return this.m_nullContact; + } + + if (shape1.m_body == shape2.m_body) + { + return this.m_nullContact; + } + + if (body2.IsConnected(body1)) + { + return this.m_nullContact; + } + + if (this.m_world.m_contactFilter != null && this.m_world.m_contactFilter.ShouldCollide(shape1, shape2) == false) + { + return this.m_nullContact; + } + + + var c = b2Contact.Create(shape1, shape2, this.m_world.m_blockAllocator); + + if (c == null) + { + return this.m_nullContact; + } + + + shape1 = c.m_shape1; + shape2 = c.m_shape2; + body1 = shape1.m_body; + body2 = shape2.m_body; + + + c.m_prev = null; + c.m_next = this.m_world.m_contactList; + if (this.m_world.m_contactList != null) + { + this.m_world.m_contactList.m_prev = c; + } + this.m_world.m_contactList = c; + + + + + + c.m_node1.contact = c; + c.m_node1.other = body2; + + c.m_node1.prev = null; + c.m_node1.next = body1.m_contactList; + if (body1.m_contactList != null) + { + body1.m_contactList.prev = c.m_node1; + } + body1.m_contactList = c.m_node1; + + + c.m_node2.contact = c; + c.m_node2.other = body1; + + c.m_node2.prev = null; + c.m_node2.next = body2.m_contactList; + if (body2.m_contactList != null) + { + body2.m_contactList.prev = c.m_node2; + } + body2.m_contactList = c.m_node2; + + ++this.m_world.m_contactCount; + return c; + + } +b2ContactManager.prototype.PairRemoved = function (proxyUserData1, proxyUserData2, pairUserData) { + + if (pairUserData == null) + { + return; + } + + var c = pairUserData; + if (c == this.m_nullContact) + { + return; + } + + + + this.Destroy(c); + } +b2ContactManager.prototype.Destroy = function (c) { + + var shape1 = c.m_shape1; + var shape2 = c.m_shape2; + + + var manifoldCount = c.m_manifoldCount; + if (manifoldCount > 0 && this.m_world.m_contactListener) + { + var b1 = shape1.m_body; + var b2 = shape2.m_body; + + var manifolds = c.GetManifolds(); + var cp = b2ContactManager.s_evalCP; + cp.shape1 = c.m_shape1; + cp.shape2 = c.m_shape2; + cp.friction = c.m_friction; + cp.restitution = c.m_restitution; + + for (var i = 0; i < manifoldCount; ++i) + { + var manifold = manifolds[ i ]; + cp.normal.SetV(manifold.normal); + + for (var j = 0; j < manifold.pointCount; ++j) + { + var mp = manifold.points[j]; + cp.position = b1.GetWorldPoint(mp.localPoint1); + var v1 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1); + var v2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2); + cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); + cp.separation = mp.separation; + cp.id.key = mp.id._key; + this.m_world.m_contactListener.Remove(cp); + } + } + } + + + if (c.m_prev) + { + c.m_prev.m_next = c.m_next; + } + + if (c.m_next) + { + c.m_next.m_prev = c.m_prev; + } + + if (c == this.m_world.m_contactList) + { + this.m_world.m_contactList = c.m_next; + } + + var body1 = shape1.m_body; + var body2 = shape2.m_body; + + + if (c.m_node1.prev) + { + c.m_node1.prev.next = c.m_node1.next; + } + + if (c.m_node1.next) + { + c.m_node1.next.prev = c.m_node1.prev; + } + + if (c.m_node1 == body1.m_contactList) + { + body1.m_contactList = c.m_node1.next; + } + + + if (c.m_node2.prev) + { + c.m_node2.prev.next = c.m_node2.next; + } + + if (c.m_node2.next) + { + c.m_node2.next.prev = c.m_node2.prev; + } + + if (c.m_node2 == body2.m_contactList) + { + body2.m_contactList = c.m_node2.next; + } + + + b2Contact.Destroy(c, this.m_world.m_blockAllocator); + --this.m_world.m_contactCount; + } +b2ContactManager.prototype.Collide = function () { + + for (var c = this.m_world.m_contactList; c; c = c.m_next) + { + var body1 = c.m_shape1.m_body; + var body2 = c.m_shape2.m_body; + if (body1.IsSleeping() && body2.IsSleeping()) + { + continue; + } + + c.Update(this.m_world.m_contactListener); + } + } +exports.b2ContactManager = b2ContactManager; + + +var b2ContactSolver = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2ContactSolver.prototype.__constructor = function (step, contacts, contactCount, allocator) { + var contact; + + + this.m_step.dt = step.dt; + this.m_step.inv_dt = step.inv_dt; + this.m_step.maxIterations = step.maxIterations; + + this.m_allocator = allocator; + + var i = 0; + var tVec; + var tMat; + + this.m_constraintCount = 0; + for (i = 0; i < contactCount; ++i) + { + + contact = contacts[i]; + this.m_constraintCount += contact.m_manifoldCount; + } + + + for (i = 0; i < this.m_constraintCount; i++){ + this.m_constraints[i] = new b2ContactConstraint(); + } + + var count = 0; + for (i = 0; i < contactCount; ++i) + { + contact = contacts[i]; + var b1 = contact.m_shape1.m_body; + var b2 = contact.m_shape2.m_body; + var manifoldCount = contact.m_manifoldCount; + var manifolds = contact.GetManifolds(); + var friction = contact.m_friction; + var restitution = contact.m_restitution; + + + var v1X = b1.m_linearVelocity.x; + var v1Y = b1.m_linearVelocity.y; + + var v2X = b2.m_linearVelocity.x; + var v2Y = b2.m_linearVelocity.y; + var w1 = b1.m_angularVelocity; + var w2 = b2.m_angularVelocity; + + for (var j = 0; j < manifoldCount; ++j) + { + var manifold = manifolds[ j ]; + + + + + var normalX = manifold.normal.x; + var normalY = manifold.normal.y; + + + var c = this.m_constraints[ count ]; + c.body1 = b1; + c.body2 = b2; + c.manifold = manifold; + + c.normal.x = normalX; + c.normal.y = normalY; + c.pointCount = manifold.pointCount; + c.friction = friction; + c.restitution = restitution; + + for (var k = 0; k < c.pointCount; ++k) + { + var cp = manifold.points[ k ]; + var ccp = c.points[ k ]; + + ccp.normalImpulse = cp.normalImpulse; + ccp.tangentImpulse = cp.tangentImpulse; + ccp.separation = cp.separation; + ccp.positionImpulse = 0.0; + + ccp.localAnchor1.SetV(cp.localPoint1); + ccp.localAnchor2.SetV(cp.localPoint2); + + var tX; + var tY; + + + tMat = b1.m_xf.R; + var r1X = cp.localPoint1.x - b1.m_sweep.localCenter.x; + var r1Y = cp.localPoint1.y - b1.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + ccp.r1.Set(r1X,r1Y); + + tMat = b2.m_xf.R; + var r2X = cp.localPoint2.x - b2.m_sweep.localCenter.x; + var r2Y = cp.localPoint2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + ccp.r2.Set(r2X,r2Y); + + var r1Sqr = r1X * r1X + r1Y * r1Y; + var r2Sqr = r2X * r2X + r2Y * r2Y; + + + var rn1 = r1X*normalX + r1Y*normalY; + + var rn2 = r2X*normalX + r2Y*normalY; + var kNormal = b1.m_invMass + b2.m_invMass; + kNormal += b1.m_invI * (r1Sqr - rn1 * rn1) + b2.m_invI * (r2Sqr - rn2 * rn2); + + ccp.normalMass = 1.0 / kNormal; + + var kEqualized = b1.m_mass * b1.m_invMass + b2.m_mass * b2.m_invMass; + kEqualized += b1.m_mass * b1.m_invI * (r1Sqr - rn1 * rn1) + b2.m_mass * b2.m_invI * (r2Sqr - rn2 * rn2); + + ccp.equalizedMass = 1.0 / kEqualized; + + + var tangentX = normalY + var tangentY = -normalX; + + + var rt1 = r1X*tangentX + r1Y*tangentY; + + var rt2 = r2X*tangentX + r2Y*tangentY; + var kTangent = b1.m_invMass + b2.m_invMass; + kTangent += b1.m_invI * (r1Sqr - rt1 * rt1) + b2.m_invI * (r2Sqr - rt2 * rt2); + + ccp.tangentMass = 1.0 / kTangent; + + + ccp.velocityBias = 0.0; + if (ccp.separation > 0.0) + { + ccp.velocityBias = -60.0 * ccp.separation; + } + + tX = v2X + (-w2*r2Y) - v1X - (-w1*r1Y); + tY = v2Y + (w2*r2X) - v1Y - (w1*r1X); + + var vRel = c.normal.x*tX + c.normal.y*tY; + if (vRel < -b2Settings.b2_velocityThreshold) + { + ccp.velocityBias += -c.restitution * vRel; + } + } + + ++count; + } + } + + + } +b2ContactSolver.prototype.__varz = function(){ +this.m_step = new b2TimeStep(); +this.m_constraints = new Array(); +} +b2ContactSolver.prototype.m_step = new b2TimeStep(); +b2ContactSolver.prototype.m_allocator = null; +b2ContactSolver.prototype.m_constraints = new Array(); +b2ContactSolver.prototype.m_constraintCount = 0; +b2ContactSolver.prototype.InitVelocityConstraints = function (step) { + var tVec; + var tVec2; + var tMat; + + + for (var i = 0; i < this.m_constraintCount; ++i) + { + var c = this.m_constraints[ i ]; + + var b1 = c.body1; + var b2 = c.body2; + var invMass1 = b1.m_invMass; + var invI1 = b1.m_invI; + var invMass2 = b2.m_invMass; + var invI2 = b2.m_invI; + + var normalX = c.normal.x; + var normalY = c.normal.y; + + var tangentX = normalY; + var tangentY = -normalX; + + var tX; + + var j = 0; + var tCount = 0; + if (step.warmStarting) + { + tCount = c.pointCount; + for (j = 0; j < tCount; ++j) + { + var ccp = c.points[ j ]; + ccp.normalImpulse *= step.dtRatio; + ccp.tangentImpulse *= step.dtRatio; + + var PX = ccp.normalImpulse * normalX + ccp.tangentImpulse * tangentX; + var PY = ccp.normalImpulse * normalY + ccp.tangentImpulse * tangentY; + + + b1.m_angularVelocity -= invI1 * (ccp.r1.x * PY - ccp.r1.y * PX); + + b1.m_linearVelocity.x -= invMass1 * PX; + b1.m_linearVelocity.y -= invMass1 * PY; + + b2.m_angularVelocity += invI2 * (ccp.r2.x * PY - ccp.r2.y * PX); + + b2.m_linearVelocity.x += invMass2 * PX; + b2.m_linearVelocity.y += invMass2 * PY; + } + } + else{ + tCount = c.pointCount; + for (j = 0; j < tCount; ++j) + { + var ccp2 = c.points[ j ]; + ccp2.normalImpulse = 0.0; + ccp2.tangentImpulse = 0.0; + } + } + } + } +b2ContactSolver.prototype.SolveVelocityConstraints = function () { + var j = 0; + var ccp; + var r1X; + var r1Y; + var r2X; + var r2Y; + var dvX; + var dvY; + var vn; + var vt; + var lambda_n; + var lambda_t; + var newImpulse_n; + var newImpulse_t; + var PX; + var PY; + + var tMat; + var tVec; + + for (var i = 0; i < this.m_constraintCount; ++i) + { + var c = this.m_constraints[ i ]; + var b1 = c.body1; + var b2 = c.body2; + var w1 = b1.m_angularVelocity; + var w2 = b2.m_angularVelocity; + var v1 = b1.m_linearVelocity; + var v2 = b2.m_linearVelocity; + + var invMass1 = b1.m_invMass; + var invI1 = b1.m_invI; + var invMass2 = b2.m_invMass; + var invI2 = b2.m_invI; + + var normalX = c.normal.x; + var normalY = c.normal.y; + + var tangentX = normalY; + var tangentY = -normalX; + var friction = c.friction; + + var tX; + + var tCount = c.pointCount; + for (j = 0; j < tCount; ++j) + { + ccp = c.points[ j ]; + + + + dvX = v2.x + (-w2 * ccp.r2.y) - v1.x - (-w1 * ccp.r1.y); + dvY = v2.y + (w2 * ccp.r2.x) - v1.y - (w1 * ccp.r1.x); + + + + vn = dvX * normalX + dvY * normalY; + lambda_n = -ccp.normalMass * (vn - ccp.velocityBias); + + + vt = dvX*tangentX + dvY*tangentY; + lambda_t = ccp.tangentMass * (-vt); + + + newImpulse_n = b2Math.b2Max(ccp.normalImpulse + lambda_n, 0.0); + lambda_n = newImpulse_n - ccp.normalImpulse; + + + var maxFriction = friction * ccp.normalImpulse; + newImpulse_t = b2Math.b2Clamp(ccp.tangentImpulse + lambda_t, -maxFriction, maxFriction); + lambda_t = newImpulse_t - ccp.tangentImpulse; + + + + PX = lambda_n * normalX + lambda_t * tangentX; + PY = lambda_n * normalY + lambda_t * tangentY; + + + v1.x -= invMass1 * PX; + v1.y -= invMass1 * PY; + w1 -= invI1 * (ccp.r1.x * PY - ccp.r1.y * PX); + + + v2.x += invMass2 * PX; + v2.y += invMass2 * PY; + w2 += invI2 * (ccp.r2.x * PY - ccp.r2.y * PX); + + ccp.normalImpulse = newImpulse_n; + ccp.tangentImpulse = newImpulse_t; + } + + + + + + + b1.m_angularVelocity = w1; + b2.m_angularVelocity = w2; + } + } +b2ContactSolver.prototype.FinalizeVelocityConstraints = function () { + for (var i = 0; i < this.m_constraintCount; ++i) + { + var c = this.m_constraints[ i ]; + var m = c.manifold; + + for (var j = 0; j < c.pointCount; ++j) + { + var point1 = m.points[j]; + var point2 = c.points[j]; + point1.normalImpulse = point2.normalImpulse; + point1.tangentImpulse = point2.tangentImpulse; + } + } + } +b2ContactSolver.prototype.SolvePositionConstraints = function (baumgarte) { + var minSeparation = 0.0; + + var tMat; + var tVec; + + for (var i = 0; i < this.m_constraintCount; ++i) + { + var c = this.m_constraints[ i ]; + var b1 = c.body1; + var b2 = c.body2; + var b1_sweep_c = b1.m_sweep.c; + var b1_sweep_a = b1.m_sweep.a; + var b2_sweep_c = b2.m_sweep.c; + var b2_sweep_a = b2.m_sweep.a; + + var invMass1 = b1.m_mass * b1.m_invMass; + var invI1 = b1.m_mass * b1.m_invI; + var invMass2 = b2.m_mass * b2.m_invMass; + var invI2 = b2.m_mass * b2.m_invI; + + var normalX = c.normal.x; + var normalY = c.normal.y; + + + var tCount = c.pointCount; + for (var j = 0; j < tCount; ++j) + { + var ccp = c.points[ j ]; + + + tMat = b1.m_xf.R; + tVec = b1.m_sweep.localCenter; + var r1X = ccp.localAnchor1.x - tVec.x; + var r1Y = ccp.localAnchor1.y - tVec.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + + tMat = b2.m_xf.R; + tVec = b2.m_sweep.localCenter; + var r2X = ccp.localAnchor2.x - tVec.x; + var r2Y = ccp.localAnchor2.y - tVec.y; + var tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + + var p1X = b1_sweep_c.x + r1X; + var p1Y = b1_sweep_c.y + r1Y; + + + var p2X = b2_sweep_c.x + r2X; + var p2Y = b2_sweep_c.y + r2Y; + + + var dpX = p2X - p1X; + var dpY = p2Y - p1Y; + + + + var separation = (dpX*normalX + dpY*normalY) + ccp.separation; + + + minSeparation = b2Math.b2Min(minSeparation, separation); + + + var C = baumgarte * b2Math.b2Clamp(separation + b2Settings.b2_linearSlop, -b2Settings.b2_maxLinearCorrection, 0.0); + + + var dImpulse = -ccp.equalizedMass * C; + + + var impulse0 = ccp.positionImpulse; + ccp.positionImpulse = b2Math.b2Max(impulse0 + dImpulse, 0.0); + dImpulse = ccp.positionImpulse - impulse0; + + + var impulseX = dImpulse * normalX; + var impulseY = dImpulse * normalY; + + + b1_sweep_c.x -= invMass1 * impulseX; + b1_sweep_c.y -= invMass1 * impulseY; + b1_sweep_a -= invI1 * (r1X * impulseY - r1Y * impulseX); + b1.m_sweep.a = b1_sweep_a; + b1.SynchronizeTransform(); + + + b2_sweep_c.x += invMass2 * impulseX; + b2_sweep_c.y += invMass2 * impulseY; + b2_sweep_a += invI2 * (r2X * impulseY - r2Y * impulseX); + b2.m_sweep.a = b2_sweep_a; + b2.SynchronizeTransform(); + } + + + + } + + + + return minSeparation >= -1.5 * b2Settings.b2_linearSlop; + } +exports.b2ContactSolver = b2ContactSolver; + + +var b2ContactConstraintPoint = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2ContactConstraintPoint.prototype.__constructor = function(){} +b2ContactConstraintPoint.prototype.__varz = function(){ +this.localAnchor1 = new b2Vec2(); +this.localAnchor2 = new b2Vec2(); +this.r1 = new b2Vec2(); +this.r2 = new b2Vec2(); +} +b2ContactConstraintPoint.prototype.localAnchor1 = new b2Vec2(); +b2ContactConstraintPoint.prototype.localAnchor2 = new b2Vec2(); +b2ContactConstraintPoint.prototype.r1 = new b2Vec2(); +b2ContactConstraintPoint.prototype.r2 = new b2Vec2(); +b2ContactConstraintPoint.prototype.normalImpulse = null; +b2ContactConstraintPoint.prototype.tangentImpulse = null; +b2ContactConstraintPoint.prototype.positionImpulse = null; +b2ContactConstraintPoint.prototype.normalMass = null; +b2ContactConstraintPoint.prototype.tangentMass = null; +b2ContactConstraintPoint.prototype.equalizedMass = null; +b2ContactConstraintPoint.prototype.separation = null; +b2ContactConstraintPoint.prototype.velocityBias = null; +exports.b2ContactConstraintPoint = b2ContactConstraintPoint; + + +var b2ContactRegister = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2ContactRegister.prototype.__constructor = function(){} +b2ContactRegister.prototype.__varz = function(){ +} +b2ContactRegister.prototype.createFcn = null; +b2ContactRegister.prototype.destroyFcn = null; +b2ContactRegister.prototype.primary = null; +exports.b2ContactRegister = b2ContactRegister; + + +var b2ContactConstraint = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2ContactConstraint.prototype.__constructor = function () { + this.points = new Array(b2Settings.b2_maxManifoldPoints); + for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++){ + this.points[i] = new b2ContactConstraintPoint(); + } + + + } +b2ContactConstraint.prototype.__varz = function(){ +this.normal = new b2Vec2(); +} +b2ContactConstraint.prototype.points = null; +b2ContactConstraint.prototype.normal = new b2Vec2(); +b2ContactConstraint.prototype.manifold = null; +b2ContactConstraint.prototype.body1 = null; +b2ContactConstraint.prototype.body2 = null; +b2ContactConstraint.prototype.friction = null; +b2ContactConstraint.prototype.restitution = null; +b2ContactConstraint.prototype.pointCount = 0; +exports.b2ContactConstraint = b2ContactConstraint; + + +var b2PolygonContact = function() { +b2Contact.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2PolygonContact.prototype, b2Contact.prototype) +b2PolygonContact.prototype._super = function(){ b2Contact.prototype.__constructor.apply(this, arguments) } +b2PolygonContact.prototype.__constructor = function (shape1, shape2) { + this._super(shape1, shape2); + this.m_manifold = this.m_manifolds[0]; + + + this.m_manifold.pointCount = 0; + } +b2PolygonContact.prototype.__varz = function(){ +this.m0 = new b2Manifold(); +this.m_manifolds = [new b2Manifold()]; +} +b2PolygonContact.s_evalCP = new b2ContactPoint(); +b2PolygonContact.Create = function (shape1, shape2, allocator) { + + return new b2PolygonContact(shape1, shape2); + } +b2PolygonContact.Destroy = function (contact, allocator) { + + + } +b2PolygonContact.prototype.m0 = new b2Manifold(); +b2PolygonContact.prototype.m_manifolds = [new b2Manifold()]; +b2PolygonContact.prototype.m_manifold = null; +b2PolygonContact.prototype.Evaluate = function (listener) { + var v1; + var v2; + var mp0; + + var b1 = this.m_shape1.m_body; + var b2 = this.m_shape2.m_body; + + var cp; + var i = 0; + + + + + this.m0.Set(this.m_manifold); + + b2Collision.b2CollidePolygons(this.m_manifold, this.m_shape1, b1.m_xf, this.m_shape2, b2.m_xf); + var persisted = [false, false]; + + cp = b2PolygonContact.s_evalCP; + cp.shape1 = this.m_shape1; + cp.shape2 = this.m_shape2; + cp.friction = this.m_friction; + cp.restitution = this.m_restitution; + + + if (this.m_manifold.pointCount > 0) + { + + + + for (i = 0; i < this.m_manifold.pointCount; ++i) + { + var mp = this.m_manifold.points[ i ]; + mp.normalImpulse = 0.0; + mp.tangentImpulse = 0.0; + var found = false; + var idKey = mp.id._key; + + for (var j = 0; j < this.m0.pointCount; ++j) + { + if (persisted[j] == true) + { + continue; + } + + mp0 = this.m0.points[ j ]; + + if (mp0.id._key == idKey) + { + persisted[j] = true; + mp.normalImpulse = mp0.normalImpulse; + mp.tangentImpulse = mp0.tangentImpulse; + + + found = true; + + + if (listener != null) + { + cp.position = b1.GetWorldPoint(mp.localPoint1); + v1 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1); + v2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2); + cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); + cp.normal.SetV(this.m_manifold.normal); + cp.separation = mp.separation; + cp.id.key = idKey; + listener.Persist(cp); + } + break; + } + } + + + if (found == false && listener != null) + { + cp.position = b1.GetWorldPoint(mp.localPoint1); + v1 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1); + v2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2); + cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); + cp.normal.SetV(this.m_manifold.normal); + cp.separation = mp.separation; + cp.id.key = idKey; + listener.Add(cp); + } + } + + this.m_manifoldCount = 1; + } + else + { + this.m_manifoldCount = 0; + } + + if (listener == null) + { + return; + } + + + for (i = 0; i < this.m0.pointCount; ++i) + { + if (persisted[i]) + { + continue; + } + + mp0 = this.m0.points[ i ]; + cp.position = b1.GetWorldPoint(mp0.localPoint1); + v1 = b1.GetLinearVelocityFromLocalPoint(mp0.localPoint1); + v2 = b2.GetLinearVelocityFromLocalPoint(mp0.localPoint2); + cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); + cp.normal.SetV(this.m0.normal); + cp.separation = mp0.separation; + cp.id.key = mp0.id._key; + listener.Remove(cp); + } + } +b2PolygonContact.prototype.GetManifolds = function () { + return this.m_manifolds; + } +exports.b2PolygonContact = b2PolygonContact; + + +var b2CircleContact = function() { +b2Contact.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2CircleContact.prototype, b2Contact.prototype) +b2CircleContact.prototype._super = function(){ b2Contact.prototype.__constructor.apply(this, arguments) } +b2CircleContact.prototype.__constructor = function (shape1, shape2) { + this._super(shape1, shape2); + + this.m_manifold = this.m_manifolds[0]; + + + + this.m_manifold.pointCount = 0; + var point = this.m_manifold.points[0]; + point.normalImpulse = 0.0; + point.tangentImpulse = 0.0; + } +b2CircleContact.prototype.__varz = function(){ +this.m_manifolds = [new b2Manifold()]; +this.m0 = new b2Manifold(); +} +b2CircleContact.s_evalCP = new b2ContactPoint(); +b2CircleContact.Create = function (shape1, shape2, allocator) { + return new b2CircleContact(shape1, shape2); + } +b2CircleContact.Destroy = function (contact, allocator) { + + } +b2CircleContact.prototype.m_manifolds = [new b2Manifold()]; +b2CircleContact.prototype.m0 = new b2Manifold(); +b2CircleContact.prototype.m_manifold = null; +b2CircleContact.prototype.Evaluate = function (listener) { + var v1; + var v2; + var mp0; + + var b1 = this.m_shape1.m_body; + var b2 = this.m_shape2.m_body; + + + + + this.m0.Set(this.m_manifold); + + b2Collision.b2CollideCircles(this.m_manifold, this.m_shape1, b1.m_xf, this.m_shape2, b2.m_xf); + + var cp = b2CircleContact.s_evalCP; + cp.shape1 = this.m_shape1; + cp.shape2 = this.m_shape2; + cp.friction = this.m_friction; + cp.restitution = this.m_restitution; + + if (this.m_manifold.pointCount > 0) + { + this.m_manifoldCount = 1; + var mp = this.m_manifold.points[ 0 ]; + + if (this.m0.pointCount == 0) + { + mp.normalImpulse = 0.0; + mp.tangentImpulse = 0.0; + + if (listener) + { + cp.position = b1.GetWorldPoint(mp.localPoint1); + v1 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1); + v2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2); + cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); + cp.normal.SetV(this.m_manifold.normal); + cp.separation = mp.separation; + cp.id.key = mp.id._key; + listener.Add(cp); + } + } else + { + mp0 = this.m0.points[ 0 ]; + mp.normalImpulse = mp0.normalImpulse; + mp.tangentImpulse = mp0.tangentImpulse; + + if (listener) + { + cp.position = b1.GetWorldPoint(mp.localPoint1); + v1 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1); + v2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2); + cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); + cp.normal.SetV(this.m_manifold.normal); + cp.separation = mp.separation; + cp.id.key = mp.id._key; + listener.Persist(cp); + } + } + } + else + { + this.m_manifoldCount = 0; + if (this.m0.pointCount > 0 && listener) + { + mp0 = this.m0.points[ 0 ]; + cp.position = b1.GetWorldPoint(mp0.localPoint1); + v1 = b1.GetLinearVelocityFromLocalPoint(mp0.localPoint1); + v2 = b2.GetLinearVelocityFromLocalPoint(mp0.localPoint2); + cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); + cp.normal.SetV(this.m0.normal); + cp.separation = mp0.separation; + cp.id.key = mp0.id._key; + listener.Remove(cp); + } + } + } +b2CircleContact.prototype.GetManifolds = function () { + return this.m_manifolds; + } +exports.b2CircleContact = b2CircleContact; + + +var b2PolyAndCircleContact = function() { +b2Contact.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2PolyAndCircleContact.prototype, b2Contact.prototype) +b2PolyAndCircleContact.prototype._super = function(){ b2Contact.prototype.__constructor.apply(this, arguments) } +b2PolyAndCircleContact.prototype.__constructor = function (shape1, shape2) { + this._super(shape1, shape2); + + this.m_manifold = this.m_manifolds[0]; + + b2Settings.b2Assert(this.m_shape1.m_type == b2Shape.e_polygonShape); + b2Settings.b2Assert(this.m_shape2.m_type == b2Shape.e_circleShape); + this.m_manifold.pointCount = 0; + var point = this.m_manifold.points[0]; + point.normalImpulse = 0.0; + point.tangentImpulse = 0.0; + } +b2PolyAndCircleContact.prototype.__varz = function(){ +this.m_manifolds = [new b2Manifold()]; +this.m0 = new b2Manifold(); +} +b2PolyAndCircleContact.s_evalCP = new b2ContactPoint(); +b2PolyAndCircleContact.Create = function (shape1, shape2, allocator) { + return new b2PolyAndCircleContact(shape1, shape2); + } +b2PolyAndCircleContact.Destroy = function (contact, allocator) { + } +b2PolyAndCircleContact.prototype.m_manifolds = [new b2Manifold()]; +b2PolyAndCircleContact.prototype.m0 = new b2Manifold(); +b2PolyAndCircleContact.prototype.m_manifold = null; +b2PolyAndCircleContact.prototype.Evaluate = function (listener) { + var i = 0; + var v1; + var v2; + var mp0; + + var b1 = this.m_shape1.m_body; + var b2 = this.m_shape2.m_body; + + + + + this.m0.Set(this.m_manifold); + + b2Collision.b2CollidePolygonAndCircle(this.m_manifold, this.m_shape1, b1.m_xf, this.m_shape2, b2.m_xf); + + var persisted = [false, false]; + + var cp = b2PolyAndCircleContact.s_evalCP; + cp.shape1 = this.m_shape1; + cp.shape2 = this.m_shape2; + cp.friction = this.m_friction; + cp.restitution = this.m_restitution; + + + if (this.m_manifold.pointCount > 0) + { + + + for (i = 0; i < this.m_manifold.pointCount; ++i) + { + var mp = this.m_manifold.points[ i ]; + mp.normalImpulse = 0.0; + mp.tangentImpulse = 0.0; + var found = false; + var idKey = mp.id._key; + + for (var j = 0; j < this.m0.pointCount; ++j) + { + if (persisted[j] == true) + { + continue; + } + + mp0 = this.m0.points[ j ]; + + if (mp0.id._key == idKey) + { + persisted[j] = true; + mp.normalImpulse = mp0.normalImpulse; + mp.tangentImpulse = mp0.tangentImpulse; + + + found = true; + + + if (listener != null) + { + cp.position = b1.GetWorldPoint(mp.localPoint1); + v1 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1); + v2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2); + cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); + cp.normal.SetV(this.m_manifold.normal); + cp.separation = mp.separation; + cp.id.key = idKey; + listener.Persist(cp); + } + break; + } + } + + + if (found == false && listener != null) + { + cp.position = b1.GetWorldPoint(mp.localPoint1); + v1 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1); + v2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2); + cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); + cp.normal.SetV(this.m_manifold.normal); + cp.separation = mp.separation; + cp.id.key = idKey; + listener.Add(cp); + } + } + + this.m_manifoldCount = 1; + } + else + { + this.m_manifoldCount = 0; + } + + if (listener == null) + { + return; + } + + + for (i = 0; i < this.m0.pointCount; ++i) + { + if (persisted[i]) + { + continue; + } + + mp0 = this.m0.points[ i ]; + cp.position = b1.GetWorldPoint(mp0.localPoint1); + v1 = b1.GetLinearVelocityFromLocalPoint(mp0.localPoint1); + v2 = b2.GetLinearVelocityFromLocalPoint(mp0.localPoint2); + cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); + cp.normal.SetV(this.m0.normal); + cp.separation = mp0.separation; + cp.id.key = mp0.id._key; + listener.Remove(cp); + } + } +b2PolyAndCircleContact.prototype.GetManifolds = function () { + return this.m_manifolds; + } +exports.b2PolyAndCircleContact = b2PolyAndCircleContact; + + +var b2JointEdge = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2JointEdge.prototype.__constructor = function(){} +b2JointEdge.prototype.__varz = function(){ +} +b2JointEdge.prototype.other = null; +b2JointEdge.prototype.joint = null; +b2JointEdge.prototype.prev = null; +b2JointEdge.prototype.next = null; +exports.b2JointEdge = b2JointEdge; + + +var b2JointDef = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2JointDef.prototype.__constructor = function () { + this.type = b2Joint.e_unknownJoint; + this.userData = null; + this.body1 = null; + this.body2 = null; + this.collideConnected = false; + } +b2JointDef.prototype.__varz = function(){ +} +b2JointDef.prototype.type = 0; +b2JointDef.prototype.userData = null; +b2JointDef.prototype.body1 = null; +b2JointDef.prototype.body2 = null; +b2JointDef.prototype.collideConnected = null; +exports.b2JointDef = b2JointDef; + + +var b2MouseJointDef = function() { +b2JointDef.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2MouseJointDef.prototype, b2JointDef.prototype) +b2MouseJointDef.prototype._super = function(){ b2JointDef.prototype.__constructor.apply(this, arguments) } +b2MouseJointDef.prototype.__constructor = function () { + this.type = b2Joint.e_mouseJoint; + this.maxForce = 0.0; + this.frequencyHz = 5.0; + this.dampingRatio = 0.7; + this.timeStep = 1.0 / 60.0; + } +b2MouseJointDef.prototype.__varz = function(){ +this.target = new b2Vec2(); +} +b2MouseJointDef.prototype.target = new b2Vec2(); +b2MouseJointDef.prototype.maxForce = null; +b2MouseJointDef.prototype.frequencyHz = null; +b2MouseJointDef.prototype.dampingRatio = null; +b2MouseJointDef.prototype.timeStep = null; +exports.b2MouseJointDef = b2MouseJointDef; + + +var b2PulleyJointDef = function() { +b2JointDef.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2PulleyJointDef.prototype, b2JointDef.prototype) +b2PulleyJointDef.prototype._super = function(){ b2JointDef.prototype.__constructor.apply(this, arguments) } +b2PulleyJointDef.prototype.__constructor = function () { + this.type = b2Joint.e_pulleyJoint; + this.groundAnchor1.Set(-1.0, 1.0); + this.groundAnchor2.Set(1.0, 1.0); + this.localAnchor1.Set(-1.0, 0.0); + this.localAnchor2.Set(1.0, 0.0); + this.length1 = 0.0; + this.maxLength1 = 0.0; + this.length2 = 0.0; + this.maxLength2 = 0.0; + this.ratio = 1.0; + this.collideConnected = true; + } +b2PulleyJointDef.prototype.__varz = function(){ +this.groundAnchor1 = new b2Vec2(); +this.groundAnchor2 = new b2Vec2(); +this.localAnchor1 = new b2Vec2(); +this.localAnchor2 = new b2Vec2(); +} +b2PulleyJointDef.prototype.groundAnchor1 = new b2Vec2(); +b2PulleyJointDef.prototype.groundAnchor2 = new b2Vec2(); +b2PulleyJointDef.prototype.localAnchor1 = new b2Vec2(); +b2PulleyJointDef.prototype.localAnchor2 = new b2Vec2(); +b2PulleyJointDef.prototype.length1 = null; +b2PulleyJointDef.prototype.maxLength1 = null; +b2PulleyJointDef.prototype.length2 = null; +b2PulleyJointDef.prototype.maxLength2 = null; +b2PulleyJointDef.prototype.ratio = null; +b2PulleyJointDef.prototype.Initialize = function (b1, b2, + ga1, ga2, + anchor1, anchor2, + r) { + this.body1 = b1; + this.body2 = b2; + this.groundAnchor1.SetV( ga1 ); + this.groundAnchor2.SetV( ga2 ); + this.localAnchor1 = this.body1.GetLocalPoint(anchor1); + this.localAnchor2 = this.body2.GetLocalPoint(anchor2); + + var d1X = anchor1.x - ga1.x; + var d1Y = anchor1.y - ga1.y; + + this.length1 = Math.sqrt(d1X*d1X + d1Y*d1Y); + + + var d2X = anchor2.x - ga2.x; + var d2Y = anchor2.y - ga2.y; + + this.length2 = Math.sqrt(d2X*d2X + d2Y*d2Y); + + this.ratio = r; + + var C = this.length1 + this.ratio * this.length2; + this.maxLength1 = C - this.ratio * b2PulleyJoint.b2_minPulleyLength; + this.maxLength2 = (C - b2PulleyJoint.b2_minPulleyLength) / this.ratio; + } +exports.b2PulleyJointDef = b2PulleyJointDef; + + +var b2Jacobian = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Jacobian.prototype.__constructor = function(){} +b2Jacobian.prototype.__varz = function(){ +this.linear1 = new b2Vec2(); +this.linear2 = new b2Vec2(); +} +b2Jacobian.prototype.linear1 = new b2Vec2(); +b2Jacobian.prototype.angular1 = null; +b2Jacobian.prototype.linear2 = new b2Vec2(); +b2Jacobian.prototype.angular2 = null; +b2Jacobian.prototype.SetZero = function () { + this.linear1.SetZero(); this.angular1 = 0.0; + this.linear2.SetZero(); this.angular2 = 0.0; + } +b2Jacobian.prototype.Set = function (x1, a1, x2, a2) { + this.linear1.SetV(x1); this.angular1 = a1; + this.linear2.SetV(x2); this.angular2 = a2; + } +b2Jacobian.prototype.Compute = function (x1, a1, x2, a2) { + + + return (this.linear1.x*x1.x + this.linear1.y*x1.y) + this.angular1 * a1 + (this.linear2.x*x2.x + this.linear2.y*x2.y) + this.angular2 * a2; + } +exports.b2Jacobian = b2Jacobian; + + +var b2DistanceJointDef = function() { +b2JointDef.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2DistanceJointDef.prototype, b2JointDef.prototype) +b2DistanceJointDef.prototype._super = function(){ b2JointDef.prototype.__constructor.apply(this, arguments) } +b2DistanceJointDef.prototype.__constructor = function () { + this.type = b2Joint.e_distanceJoint; + + + this.length = 1.0; + this.frequencyHz = 0.0; + this.dampingRatio = 0.0; + } +b2DistanceJointDef.prototype.__varz = function(){ +this.localAnchor1 = new b2Vec2(); +this.localAnchor2 = new b2Vec2(); +} +b2DistanceJointDef.prototype.localAnchor1 = new b2Vec2(); +b2DistanceJointDef.prototype.localAnchor2 = new b2Vec2(); +b2DistanceJointDef.prototype.length = null; +b2DistanceJointDef.prototype.frequencyHz = null; +b2DistanceJointDef.prototype.dampingRatio = null; +b2DistanceJointDef.prototype.Initialize = function (b1, b2, + anchor1, anchor2) { + this.body1 = b1; + this.body2 = b2; + this.localAnchor1.SetV( this.body1.GetLocalPoint(anchor1)); + this.localAnchor2.SetV( this.body2.GetLocalPoint(anchor2)); + var dX = anchor2.x - anchor1.x; + var dY = anchor2.y - anchor1.y; + this.length = Math.sqrt(dX*dX + dY*dY); + this.frequencyHz = 0.0; + this.dampingRatio = 0.0; + } +exports.b2DistanceJointDef = b2DistanceJointDef; + + +var b2PrismaticJointDef = function() { +b2JointDef.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2PrismaticJointDef.prototype, b2JointDef.prototype) +b2PrismaticJointDef.prototype._super = function(){ b2JointDef.prototype.__constructor.apply(this, arguments) } +b2PrismaticJointDef.prototype.__constructor = function () { + this.type = b2Joint.e_prismaticJoint; + + + this.localAxis1.Set(1.0, 0.0); + this.referenceAngle = 0.0; + this.enableLimit = false; + this.lowerTranslation = 0.0; + this.upperTranslation = 0.0; + this.enableMotor = false; + this.maxMotorForce = 0.0; + this.motorSpeed = 0.0; + } +b2PrismaticJointDef.prototype.__varz = function(){ +this.localAnchor1 = new b2Vec2(); +this.localAnchor2 = new b2Vec2(); +this.localAxis1 = new b2Vec2(); +} +b2PrismaticJointDef.prototype.localAnchor1 = new b2Vec2(); +b2PrismaticJointDef.prototype.localAnchor2 = new b2Vec2(); +b2PrismaticJointDef.prototype.localAxis1 = new b2Vec2(); +b2PrismaticJointDef.prototype.referenceAngle = null; +b2PrismaticJointDef.prototype.enableLimit = null; +b2PrismaticJointDef.prototype.lowerTranslation = null; +b2PrismaticJointDef.prototype.upperTranslation = null; +b2PrismaticJointDef.prototype.enableMotor = null; +b2PrismaticJointDef.prototype.maxMotorForce = null; +b2PrismaticJointDef.prototype.motorSpeed = null; +b2PrismaticJointDef.prototype.Initialize = function (b1, b2, anchor, axis) { + this.body1 = b1; + this.body2 = b2; + this.localAnchor1 = this.body1.GetLocalPoint(anchor); + this.localAnchor2 = this.body2.GetLocalPoint(anchor); + this.localAxis1 = this.body1.GetLocalVector(axis); + this.referenceAngle = this.body2.GetAngle() - this.body1.GetAngle(); + } +exports.b2PrismaticJointDef = b2PrismaticJointDef; + + +var b2RevoluteJointDef = function() { +b2JointDef.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2RevoluteJointDef.prototype, b2JointDef.prototype) +b2RevoluteJointDef.prototype._super = function(){ b2JointDef.prototype.__constructor.apply(this, arguments) } +b2RevoluteJointDef.prototype.__constructor = function () { + this.type = b2Joint.e_revoluteJoint; + this.localAnchor1.Set(0.0, 0.0); + this.localAnchor2.Set(0.0, 0.0); + this.referenceAngle = 0.0; + this.lowerAngle = 0.0; + this.upperAngle = 0.0; + this.maxMotorTorque = 0.0; + this.motorSpeed = 0.0; + this.enableLimit = false; + this.enableMotor = false; + } +b2RevoluteJointDef.prototype.__varz = function(){ +this.localAnchor1 = new b2Vec2(); +this.localAnchor2 = new b2Vec2(); +} +b2RevoluteJointDef.prototype.localAnchor1 = new b2Vec2(); +b2RevoluteJointDef.prototype.localAnchor2 = new b2Vec2(); +b2RevoluteJointDef.prototype.referenceAngle = null; +b2RevoluteJointDef.prototype.enableLimit = null; +b2RevoluteJointDef.prototype.lowerAngle = null; +b2RevoluteJointDef.prototype.upperAngle = null; +b2RevoluteJointDef.prototype.enableMotor = null; +b2RevoluteJointDef.prototype.motorSpeed = null; +b2RevoluteJointDef.prototype.maxMotorTorque = null; +b2RevoluteJointDef.prototype.Initialize = function (b1, b2, anchor) { + this.body1 = b1; + this.body2 = b2; + this.localAnchor1 = this.body1.GetLocalPoint(anchor); + this.localAnchor2 = this.body2.GetLocalPoint(anchor); + this.referenceAngle = this.body2.GetAngle() - this.body1.GetAngle(); + } +exports.b2RevoluteJointDef = b2RevoluteJointDef; + + +var b2Joint = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2Joint.prototype.__constructor = function (def) { + this.m_type = def.type; + this.m_prev = null; + this.m_next = null; + this.m_body1 = def.body1; + this.m_body2 = def.body2; + this.m_collideConnected = def.collideConnected; + this.m_islandFlag = false; + this.m_userData = def.userData; + } +b2Joint.prototype.__varz = function(){ +this.m_node1 = new b2JointEdge(); +this.m_node2 = new b2JointEdge(); +} +b2Joint.e_unknownJoint = 0; +b2Joint.e_revoluteJoint = 1; +b2Joint.e_prismaticJoint = 2; +b2Joint.e_distanceJoint = 3; +b2Joint.e_pulleyJoint = 4; +b2Joint.e_mouseJoint = 5; +b2Joint.e_gearJoint = 6; +b2Joint.e_inactiveLimit = 0; +b2Joint.e_atLowerLimit = 1; +b2Joint.e_atUpperLimit = 2; +b2Joint.e_equalLimits = 3; +b2Joint.Create = function (def, allocator) { + var joint = null; + + switch (def.type) + { + case b2Joint.e_distanceJoint: + { + + joint = new b2DistanceJoint(def); + } + break; + + case b2Joint.e_mouseJoint: + { + + joint = new b2MouseJoint(def); + } + break; + + case b2Joint.e_prismaticJoint: + { + + joint = new b2PrismaticJoint(def); + } + break; + + case b2Joint.e_revoluteJoint: + { + + joint = new b2RevoluteJoint(def); + } + break; + + case b2Joint.e_pulleyJoint: + { + + joint = new b2PulleyJoint(def); + } + break; + + case b2Joint.e_gearJoint: + { + + joint = new b2GearJoint(def); + } + break; + + default: + + break; + } + + return joint; + } +b2Joint.Destroy = function (joint, allocator) { + + } +b2Joint.prototype.m_type = 0; +b2Joint.prototype.m_prev = null; +b2Joint.prototype.m_next = null; +b2Joint.prototype.m_node1 = new b2JointEdge(); +b2Joint.prototype.m_node2 = new b2JointEdge(); +b2Joint.prototype.m_body1 = null; +b2Joint.prototype.m_body2 = null; +b2Joint.prototype.m_inv_dt = null; +b2Joint.prototype.m_islandFlag = null; +b2Joint.prototype.m_collideConnected = null; +b2Joint.prototype.m_userData = null; +b2Joint.prototype.GetType = function () { + return this.m_type; + } +b2Joint.prototype.GetAnchor1 = function () {return null} +b2Joint.prototype.GetAnchor2 = function () {return null} +b2Joint.prototype.GetReactionForce = function () {return null} +b2Joint.prototype.GetReactionTorque = function () {return 0.0} +b2Joint.prototype.GetBody1 = function () { + return this.m_body1; + } +b2Joint.prototype.GetBody2 = function () { + return this.m_body2; + } +b2Joint.prototype.GetNext = function () { + return this.m_next; + } +b2Joint.prototype.GetUserData = function () { + return this.m_userData; + } +b2Joint.prototype.SetUserData = function (data) { + this.m_userData = data; + } +b2Joint.prototype.InitVelocityConstraints = function (step) {} +b2Joint.prototype.SolveVelocityConstraints = function (step) {} +b2Joint.prototype.InitPositionConstraints = function () {} +b2Joint.prototype.SolvePositionConstraints = function () {return false} +exports.b2Joint = b2Joint; + + +var b2GearJoint = function() { +b2Joint.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2GearJoint.prototype, b2Joint.prototype) +b2GearJoint.prototype._super = function(){ b2Joint.prototype.__constructor.apply(this, arguments) } +b2GearJoint.prototype.__constructor = function (def) { + + this._super(def); + + var type1 = def.joint1.m_type; + var type2 = def.joint2.m_type; + + + + + + + this.m_revolute1 = null; + this.m_prismatic1 = null; + this.m_revolute2 = null; + this.m_prismatic2 = null; + + var coordinate1; + var coordinate2; + + this.m_ground1 = def.joint1.m_body1; + this.m_body1 = def.joint1.m_body2; + if (type1 == b2Joint.e_revoluteJoint) + { + this.m_revolute1 = def.joint1; + this.m_groundAnchor1.SetV( this.m_revolute1.m_localAnchor1 ); + this.m_localAnchor1.SetV( this.m_revolute1.m_localAnchor2 ); + coordinate1 = this.m_revolute1.GetJointAngle(); + } + else + { + this.m_prismatic1 = def.joint1; + this.m_groundAnchor1.SetV( this.m_prismatic1.m_localAnchor1 ); + this.m_localAnchor1.SetV( this.m_prismatic1.m_localAnchor2 ); + coordinate1 = this.m_prismatic1.GetJointTranslation(); + } + + this.m_ground2 = def.joint2.m_body1; + this.m_body2 = def.joint2.m_body2; + if (type2 == b2Joint.e_revoluteJoint) + { + this.m_revolute2 = def.joint2; + this.m_groundAnchor2.SetV( this.m_revolute2.m_localAnchor1 ); + this.m_localAnchor2.SetV( this.m_revolute2.m_localAnchor2 ); + coordinate2 = this.m_revolute2.GetJointAngle(); + } + else + { + this.m_prismatic2 = def.joint2; + this.m_groundAnchor2.SetV( this.m_prismatic2.m_localAnchor1 ); + this.m_localAnchor2.SetV( this.m_prismatic2.m_localAnchor2 ); + coordinate2 = this.m_prismatic2.GetJointTranslation(); + } + + this.m_ratio = def.ratio; + + this.m_constant = coordinate1 + this.m_ratio * coordinate2; + + this.m_force = 0.0; + + } +b2GearJoint.prototype.__varz = function(){ +this.m_groundAnchor1 = new b2Vec2(); +this.m_groundAnchor2 = new b2Vec2(); +this.m_localAnchor1 = new b2Vec2(); +this.m_localAnchor2 = new b2Vec2(); +this.m_J = new b2Jacobian(); +} +b2GearJoint.prototype.m_ground1 = null; +b2GearJoint.prototype.m_ground2 = null; +b2GearJoint.prototype.m_revolute1 = null; +b2GearJoint.prototype.m_prismatic1 = null; +b2GearJoint.prototype.m_revolute2 = null; +b2GearJoint.prototype.m_prismatic2 = null; +b2GearJoint.prototype.m_groundAnchor1 = new b2Vec2(); +b2GearJoint.prototype.m_groundAnchor2 = new b2Vec2(); +b2GearJoint.prototype.m_localAnchor1 = new b2Vec2(); +b2GearJoint.prototype.m_localAnchor2 = new b2Vec2(); +b2GearJoint.prototype.m_J = new b2Jacobian(); +b2GearJoint.prototype.m_constant = null; +b2GearJoint.prototype.m_ratio = null; +b2GearJoint.prototype.m_mass = null; +b2GearJoint.prototype.m_force = null; +b2GearJoint.prototype.GetAnchor1 = function () { + + return this.m_body1.GetWorldPoint(this.m_localAnchor1); + } +b2GearJoint.prototype.GetAnchor2 = function () { + + return this.m_body2.GetWorldPoint(this.m_localAnchor2); + } +b2GearJoint.prototype.GetReactionForce = function () { + + var F = new b2Vec2(this.m_force * this.m_J.linear2.x, this.m_force * this.m_J.linear2.y); + return F; + } +b2GearJoint.prototype.GetReactionTorque = function () { + + + var tMat = this.m_body2.m_xf.R; + var rX = this.m_localAnchor1.x - this.m_body2.m_sweep.localCenter.x; + var rY = this.m_localAnchor1.y - this.m_body2.m_sweep.localCenter.y; + var tX = tMat.col1.x * rX + tMat.col2.x * rY; + rY = tMat.col1.y * rX + tMat.col2.y * rY; + rX = tX; + + + tX = this.m_force * this.m_J.angular2 - (rX * (this.m_force * this.m_J.linear2.y) - rY * (this.m_force * this.m_J.linear2.x)); + return tX; + } +b2GearJoint.prototype.GetRatio = function () { + return this.m_ratio; + } +b2GearJoint.prototype.InitVelocityConstraints = function (step) { + var g1 = this.m_ground1; + var g2 = this.m_ground2; + var b1 = this.m_body1; + var b2 = this.m_body2; + + + var ugX; + var ugY; + var rX; + var rY; + var tMat; + var tVec; + var crug; + var tX; + + var K = 0.0; + this.m_J.SetZero(); + + if (this.m_revolute1) + { + this.m_J.angular1 = -1.0; + K += b1.m_invI; + } + else + { + + tMat = g1.m_xf.R; + tVec = this.m_prismatic1.m_localXAxis1; + ugX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + ugY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + + tMat = b1.m_xf.R; + rX = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + rY = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + tX = tMat.col1.x * rX + tMat.col2.x * rY; + rY = tMat.col1.y * rX + tMat.col2.y * rY; + rX = tX; + + + crug = rX * ugY - rY * ugX; + + this.m_J.linear1.Set(-ugX, -ugY); + this.m_J.angular1 = -crug; + K += b1.m_invMass + b1.m_invI * crug * crug; + } + + if (this.m_revolute2) + { + this.m_J.angular2 = -this.m_ratio; + K += this.m_ratio * this.m_ratio * b2.m_invI; + } + else + { + + tMat = g2.m_xf.R; + tVec = this.m_prismatic2.m_localXAxis1; + ugX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + ugY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + + tMat = b2.m_xf.R; + rX = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + rY = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = tMat.col1.x * rX + tMat.col2.x * rY; + rY = tMat.col1.y * rX + tMat.col2.y * rY; + rX = tX; + + + crug = rX * ugY - rY * ugX; + + this.m_J.linear2.Set(-this.m_ratio*ugX, -this.m_ratio*ugY); + this.m_J.angular2 = -this.m_ratio * crug; + K += this.m_ratio * this.m_ratio * (b2.m_invMass + b2.m_invI * crug * crug); + } + + + + this.m_mass = 1.0 / K; + + if (step.warmStarting) + { + + var P = step.dt * this.m_force; + + b1.m_linearVelocity.x += b1.m_invMass * P * this.m_J.linear1.x; + b1.m_linearVelocity.y += b1.m_invMass * P * this.m_J.linear1.y; + b1.m_angularVelocity += b1.m_invI * P * this.m_J.angular1; + + b2.m_linearVelocity.x += b2.m_invMass * P * this.m_J.linear2.x; + b2.m_linearVelocity.y += b2.m_invMass * P * this.m_J.linear2.y; + b2.m_angularVelocity += b2.m_invI * P * this.m_J.angular2; + } + else + { + this.m_force = 0.0; + } + } +b2GearJoint.prototype.SolveVelocityConstraints = function (step) { + var b1 = this.m_body1; + var b2 = this.m_body2; + + var Cdot = this.m_J.Compute( b1.m_linearVelocity, b1.m_angularVelocity, + b2.m_linearVelocity, b2.m_angularVelocity); + + var force = -step.inv_dt * this.m_mass * Cdot; + this.m_force += force; + + var P = step.dt * force; + b1.m_linearVelocity.x += b1.m_invMass * P * this.m_J.linear1.x; + b1.m_linearVelocity.y += b1.m_invMass * P * this.m_J.linear1.y; + b1.m_angularVelocity += b1.m_invI * P * this.m_J.angular1; + b2.m_linearVelocity.x += b2.m_invMass * P * this.m_J.linear2.x; + b2.m_linearVelocity.y += b2.m_invMass * P * this.m_J.linear2.y; + b2.m_angularVelocity += b2.m_invI * P * this.m_J.angular2; + } +b2GearJoint.prototype.SolvePositionConstraints = function () { + var linearError = 0.0; + + var b1 = this.m_body1; + var b2 = this.m_body2; + + var coordinate1; + var coordinate2; + if (this.m_revolute1) + { + coordinate1 = this.m_revolute1.GetJointAngle(); + } + else + { + coordinate1 = this.m_prismatic1.GetJointTranslation(); + } + + if (this.m_revolute2) + { + coordinate2 = this.m_revolute2.GetJointAngle(); + } + else + { + coordinate2 = this.m_prismatic2.GetJointTranslation(); + } + + var C = this.m_constant - (coordinate1 + this.m_ratio * coordinate2); + + var impulse = -this.m_mass * C; + + b1.m_sweep.c.x += b1.m_invMass * impulse * this.m_J.linear1.x; + b1.m_sweep.c.y += b1.m_invMass * impulse * this.m_J.linear1.y; + b1.m_sweep.a += b1.m_invI * impulse * this.m_J.angular1; + b2.m_sweep.c.x += b2.m_invMass * impulse * this.m_J.linear2.x; + b2.m_sweep.c.y += b2.m_invMass * impulse * this.m_J.linear2.y; + b2.m_sweep.a += b2.m_invI * impulse * this.m_J.angular2; + + b1.SynchronizeTransform(); + b2.SynchronizeTransform(); + + return linearError < b2Settings.b2_linearSlop; + } +exports.b2GearJoint = b2GearJoint; + + +var b2GearJointDef = function() { +b2JointDef.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2GearJointDef.prototype, b2JointDef.prototype) +b2GearJointDef.prototype._super = function(){ b2JointDef.prototype.__constructor.apply(this, arguments) } +b2GearJointDef.prototype.__constructor = function () { + this.type = b2Joint.e_gearJoint; + this.joint1 = null; + this.joint2 = null; + this.ratio = 1.0; + } +b2GearJointDef.prototype.__varz = function(){ +} +b2GearJointDef.prototype.joint1 = null; +b2GearJointDef.prototype.joint2 = null; +b2GearJointDef.prototype.ratio = null; +exports.b2GearJointDef = b2GearJointDef; + + +var b2DistanceJoint = function() { +b2Joint.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2DistanceJoint.prototype, b2Joint.prototype) +b2DistanceJoint.prototype._super = function(){ b2Joint.prototype.__constructor.apply(this, arguments) } +b2DistanceJoint.prototype.__constructor = function (def) { + this._super(def); + + var tMat; + var tX; + var tY; + + this.m_localAnchor1.SetV(def.localAnchor1); + + this.m_localAnchor2.SetV(def.localAnchor2); + + this.m_length = def.length; + this.m_frequencyHz = def.frequencyHz; + this.m_dampingRatio = def.dampingRatio; + this.m_impulse = 0.0; + this.m_gamma = 0.0; + this.m_bias = 0.0; + this.m_inv_dt = 0.0; + } +b2DistanceJoint.prototype.__varz = function(){ +this.m_localAnchor1 = new b2Vec2(); +this.m_localAnchor2 = new b2Vec2(); +this.m_u = new b2Vec2(); +} +b2DistanceJoint.prototype.m_localAnchor1 = new b2Vec2(); +b2DistanceJoint.prototype.m_localAnchor2 = new b2Vec2(); +b2DistanceJoint.prototype.m_u = new b2Vec2(); +b2DistanceJoint.prototype.m_frequencyHz = null; +b2DistanceJoint.prototype.m_dampingRatio = null; +b2DistanceJoint.prototype.m_gamma = null; +b2DistanceJoint.prototype.m_bias = null; +b2DistanceJoint.prototype.m_impulse = null; +b2DistanceJoint.prototype.m_mass = null; +b2DistanceJoint.prototype.m_length = null; +b2DistanceJoint.prototype.InitVelocityConstraints = function (step) { + + var tMat; + var tX; + + this.m_inv_dt = step.inv_dt; + + var b1 = this.m_body1; + var b2 = this.m_body2; + + + + tMat = b1.m_xf.R; + var r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + tMat = b2.m_xf.R; + var r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + + this.m_u.x = b2.m_sweep.c.x + r2X - b1.m_sweep.c.x - r1X; + this.m_u.y = b2.m_sweep.c.y + r2Y - b1.m_sweep.c.y - r1Y; + + + + var length = Math.sqrt(this.m_u.x*this.m_u.x + this.m_u.y*this.m_u.y); + if (length > b2Settings.b2_linearSlop) + { + + this.m_u.Multiply( 1.0 / length ); + } + else + { + this.m_u.SetZero(); + } + + + var cr1u = (r1X * this.m_u.y - r1Y * this.m_u.x); + + var cr2u = (r2X * this.m_u.y - r2Y * this.m_u.x); + + var invMass = b1.m_invMass + b1.m_invI * cr1u * cr1u + b2.m_invMass + b2.m_invI * cr2u * cr2u; + + this.m_mass = 1.0 / invMass; + + if (this.m_frequencyHz > 0.0) + { + var C = length - this.m_length; + + + var omega = 2.0 * Math.PI * this.m_frequencyHz; + + + var d = 2.0 * this.m_mass * this.m_dampingRatio * omega; + + + var k = this.m_mass * omega * omega; + + + this.m_gamma = 1.0 / (step.dt * (d + step.dt * k)); + this.m_bias = C * step.dt * k * this.m_gamma; + + this.m_mass = 1.0 / (invMass + this.m_gamma); + } + + if (step.warmStarting) + { + this.m_impulse *= step.dtRatio; + + var PX = this.m_impulse * this.m_u.x; + var PY = this.m_impulse * this.m_u.y; + + b1.m_linearVelocity.x -= b1.m_invMass * PX; + b1.m_linearVelocity.y -= b1.m_invMass * PY; + + b1.m_angularVelocity -= b1.m_invI * (r1X * PY - r1Y * PX); + + b2.m_linearVelocity.x += b2.m_invMass * PX; + b2.m_linearVelocity.y += b2.m_invMass * PY; + + b2.m_angularVelocity += b2.m_invI * (r2X * PY - r2Y * PX); + } + else + { + this.m_impulse = 0.0; + } + } +b2DistanceJoint.prototype.SolveVelocityConstraints = function (step) { + + var tMat; + + var b1 = this.m_body1; + var b2 = this.m_body2; + + + tMat = b1.m_xf.R; + var r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + tMat = b2.m_xf.R; + var r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + + + var v1X = b1.m_linearVelocity.x + (-b1.m_angularVelocity * r1Y); + var v1Y = b1.m_linearVelocity.y + (b1.m_angularVelocity * r1X); + + var v2X = b2.m_linearVelocity.x + (-b2.m_angularVelocity * r2Y); + var v2Y = b2.m_linearVelocity.y + (b2.m_angularVelocity * r2X); + + var Cdot = (this.m_u.x * (v2X - v1X) + this.m_u.y * (v2Y - v1Y)); + + var impulse = -this.m_mass * (Cdot + this.m_bias + this.m_gamma * this.m_impulse); + this.m_impulse += impulse; + + + var PX = impulse * this.m_u.x; + var PY = impulse * this.m_u.y; + + b1.m_linearVelocity.x -= b1.m_invMass * PX; + b1.m_linearVelocity.y -= b1.m_invMass * PY; + + b1.m_angularVelocity -= b1.m_invI * (r1X * PY - r1Y * PX); + + b2.m_linearVelocity.x += b2.m_invMass * PX; + b2.m_linearVelocity.y += b2.m_invMass * PY; + + b2.m_angularVelocity += b2.m_invI * (r2X * PY - r2Y * PX); + } +b2DistanceJoint.prototype.SolvePositionConstraints = function () { + + var tMat; + + if (this.m_frequencyHz > 0.0) + { + return true; + } + + var b1 = this.m_body1; + var b2 = this.m_body2; + + + tMat = b1.m_xf.R; + var r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + tMat = b2.m_xf.R; + var r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + + var dX = b2.m_sweep.c.x + r2X - b1.m_sweep.c.x - r1X; + var dY = b2.m_sweep.c.y + r2Y - b1.m_sweep.c.y - r1Y; + + + var length = Math.sqrt(dX*dX + dY*dY); + dX /= length; + dY /= length; + + var C = length - this.m_length; + C = b2Math.b2Clamp(C, -b2Settings.b2_maxLinearCorrection, b2Settings.b2_maxLinearCorrection); + + var impulse = -this.m_mass * C; + + this.m_u.Set(dX, dY); + + var PX = impulse * this.m_u.x; + var PY = impulse * this.m_u.y; + + + b1.m_sweep.c.x -= b1.m_invMass * PX; + b1.m_sweep.c.y -= b1.m_invMass * PY; + + b1.m_sweep.a -= b1.m_invI * (r1X * PY - r1Y * PX); + + b2.m_sweep.c.x += b2.m_invMass * PX; + b2.m_sweep.c.y += b2.m_invMass * PY; + + b2.m_sweep.a += b2.m_invI * (r2X * PY - r2Y * PX); + + b1.SynchronizeTransform(); + b2.SynchronizeTransform(); + + return b2Math.b2Abs(C) < b2Settings.b2_linearSlop; + + } +b2DistanceJoint.prototype.GetAnchor1 = function () { + return this.m_body1.GetWorldPoint(this.m_localAnchor1); + } +b2DistanceJoint.prototype.GetAnchor2 = function () { + return this.m_body2.GetWorldPoint(this.m_localAnchor2); + } +b2DistanceJoint.prototype.GetReactionForce = function () { + + var F = new b2Vec2(); + F.SetV(this.m_u); + F.Multiply(this.m_inv_dt * this.m_impulse); + return F; + } +b2DistanceJoint.prototype.GetReactionTorque = function () { + + return 0.0; + } +exports.b2DistanceJoint = b2DistanceJoint; + + +var b2MouseJoint = function() { +b2Joint.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2MouseJoint.prototype, b2Joint.prototype) +b2MouseJoint.prototype._super = function(){ b2Joint.prototype.__constructor.apply(this, arguments) } +b2MouseJoint.prototype.__constructor = function (def) { + this._super(def); + + this.m_target.SetV(def.target); + + var tX = this.m_target.x - this.m_body2.m_xf.position.x; + var tY = this.m_target.y - this.m_body2.m_xf.position.y; + var tMat = this.m_body2.m_xf.R; + this.m_localAnchor.x = (tX * tMat.col1.x + tY * tMat.col1.y); + this.m_localAnchor.y = (tX * tMat.col2.x + tY * tMat.col2.y); + + this.m_maxForce = def.maxForce; + this.m_impulse.SetZero(); + + var mass = this.m_body2.m_mass; + + + var omega = 2.0 * b2Settings.b2_pi * def.frequencyHz; + + + var d = 2.0 * mass * def.dampingRatio * omega; + + + var k = (def.timeStep * mass) * (omega * omega); + + + + this.m_gamma = 1.0 / (d + k); + this.m_beta = k / (d + k); + } +b2MouseJoint.prototype.__varz = function(){ +this.K = new b2Mat22(); +this.K1 = new b2Mat22(); +this.K2 = new b2Mat22(); +this.m_localAnchor = new b2Vec2(); +this.m_target = new b2Vec2(); +this.m_impulse = new b2Vec2(); +this.m_mass = new b2Mat22(); +this.m_C = new b2Vec2(); +} +b2MouseJoint.prototype.K = new b2Mat22(); +b2MouseJoint.prototype.K1 = new b2Mat22(); +b2MouseJoint.prototype.K2 = new b2Mat22(); +b2MouseJoint.prototype.m_localAnchor = new b2Vec2(); +b2MouseJoint.prototype.m_target = new b2Vec2(); +b2MouseJoint.prototype.m_impulse = new b2Vec2(); +b2MouseJoint.prototype.m_mass = new b2Mat22(); +b2MouseJoint.prototype.m_C = new b2Vec2(); +b2MouseJoint.prototype.m_maxForce = null; +b2MouseJoint.prototype.m_beta = null; +b2MouseJoint.prototype.m_gamma = null; +b2MouseJoint.prototype.GetAnchor1 = function () { + return this.m_target; + } +b2MouseJoint.prototype.GetAnchor2 = function () { + return this.m_body2.GetWorldPoint(this.m_localAnchor); + } +b2MouseJoint.prototype.GetReactionForce = function () { + return this.m_impulse; + } +b2MouseJoint.prototype.GetReactionTorque = function () { + return 0.0; + } +b2MouseJoint.prototype.SetTarget = function (target) { + if (this.m_body2.IsSleeping()){ + this.m_body2.WakeUp(); + } + this.m_target = target; + } +b2MouseJoint.prototype.InitVelocityConstraints = function (step) { + var b = this.m_body2; + + var tMat; + + + + tMat = b.m_xf.R; + var rX = this.m_localAnchor.x - b.m_sweep.localCenter.x; + var rY = this.m_localAnchor.y - b.m_sweep.localCenter.y; + var tX = (tMat.col1.x * rX + tMat.col2.x * rY); + rY = (tMat.col1.y * rX + tMat.col2.y * rY); + rX = tX; + + + + + var invMass = b.m_invMass; + var invI = b.m_invI; + + + this.K1.col1.x = invMass; this.K1.col2.x = 0.0; + this.K1.col1.y = 0.0; this.K1.col2.y = invMass; + + + this.K2.col1.x = invI * rY * rY; this.K2.col2.x = -invI * rX * rY; + this.K2.col1.y = -invI * rX * rY; this.K2.col2.y = invI * rX * rX; + + + this.K.SetM(this.K1); + this.K.AddM(this.K2); + this.K.col1.x += this.m_gamma; + this.K.col2.y += this.m_gamma; + + + this.K.Invert(this.m_mass); + + + this.m_C.x = b.m_sweep.c.x + rX - this.m_target.x; + this.m_C.y = b.m_sweep.c.y + rY - this.m_target.y; + + + b.m_angularVelocity *= 0.98; + + + + var PX = step.dt * this.m_impulse.x; + var PY = step.dt * this.m_impulse.y; + + b.m_linearVelocity.x += invMass * PX; + b.m_linearVelocity.y += invMass * PY; + + b.m_angularVelocity += invI * (rX * PY - rY * PX); + } +b2MouseJoint.prototype.SolveVelocityConstraints = function (step) { + var b = this.m_body2; + + var tMat; + var tX; + var tY; + + + + tMat = b.m_xf.R; + var rX = this.m_localAnchor.x - b.m_sweep.localCenter.x; + var rY = this.m_localAnchor.y - b.m_sweep.localCenter.y; + tX = (tMat.col1.x * rX + tMat.col2.x * rY); + rY = (tMat.col1.y * rX + tMat.col2.y * rY); + rX = tX; + + + + var CdotX = b.m_linearVelocity.x + (-b.m_angularVelocity * rY); + var CdotY = b.m_linearVelocity.y + (b.m_angularVelocity * rX); + + tMat = this.m_mass; + tX = CdotX + (this.m_beta * step.inv_dt) * this.m_C.x + this.m_gamma * step.dt * this.m_impulse.x; + tY = CdotY + (this.m_beta * step.inv_dt) * this.m_C.y + this.m_gamma * step.dt * this.m_impulse.y; + var forceX = -step.inv_dt * (tMat.col1.x * tX + tMat.col2.x * tY); + var forceY = -step.inv_dt * (tMat.col1.y * tX + tMat.col2.y * tY); + + var oldForceX = this.m_impulse.x; + var oldForceY = this.m_impulse.y; + + this.m_impulse.x += forceX; + this.m_impulse.y += forceY; + var forceMagnitude = this.m_impulse.Length(); + if (forceMagnitude > this.m_maxForce) + { + + this.m_impulse.Multiply(this.m_maxForce / forceMagnitude); + } + + forceX = this.m_impulse.x - oldForceX; + forceY = this.m_impulse.y - oldForceY; + + + var PX = step.dt * forceX; + var PY = step.dt * forceY; + + b.m_linearVelocity.x += b.m_invMass * PX; + b.m_linearVelocity.y += b.m_invMass * PY; + + b.m_angularVelocity += b.m_invI * (rX * PY - rY * PX); + } +b2MouseJoint.prototype.SolvePositionConstraints = function () { + return true; + } +exports.b2MouseJoint = b2MouseJoint; + + +var b2PulleyJoint = function() { +b2Joint.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2PulleyJoint.prototype, b2Joint.prototype) +b2PulleyJoint.prototype._super = function(){ b2Joint.prototype.__constructor.apply(this, arguments) } +b2PulleyJoint.prototype.__constructor = function (def) { + + + this._super(def); + + var tMat; + var tX; + var tY; + + this.m_ground = this.m_body1.m_world.m_groundBody; + + this.m_groundAnchor1.x = def.groundAnchor1.x - this.m_ground.m_xf.position.x; + this.m_groundAnchor1.y = def.groundAnchor1.y - this.m_ground.m_xf.position.y; + + this.m_groundAnchor2.x = def.groundAnchor2.x - this.m_ground.m_xf.position.x; + this.m_groundAnchor2.y = def.groundAnchor2.y - this.m_ground.m_xf.position.y; + + this.m_localAnchor1.SetV(def.localAnchor1); + + this.m_localAnchor2.SetV(def.localAnchor2); + + + this.m_ratio = def.ratio; + + this.m_constant = def.length1 + this.m_ratio * def.length2; + + this.m_maxLength1 = b2Math.b2Min(def.maxLength1, this.m_constant - this.m_ratio * b2PulleyJoint.b2_minPulleyLength); + this.m_maxLength2 = b2Math.b2Min(def.maxLength2, (this.m_constant - b2PulleyJoint.b2_minPulleyLength) / this.m_ratio); + + this.m_force = 0.0; + this.m_limitForce1 = 0.0; + this.m_limitForce2 = 0.0; + + } +b2PulleyJoint.prototype.__varz = function(){ +this.m_groundAnchor1 = new b2Vec2(); +this.m_groundAnchor2 = new b2Vec2(); +this.m_localAnchor1 = new b2Vec2(); +this.m_localAnchor2 = new b2Vec2(); +this.m_u1 = new b2Vec2(); +this.m_u2 = new b2Vec2(); +} +b2PulleyJoint.b2_minPulleyLength = 2.0; +b2PulleyJoint.prototype.m_ground = null; +b2PulleyJoint.prototype.m_groundAnchor1 = new b2Vec2(); +b2PulleyJoint.prototype.m_groundAnchor2 = new b2Vec2(); +b2PulleyJoint.prototype.m_localAnchor1 = new b2Vec2(); +b2PulleyJoint.prototype.m_localAnchor2 = new b2Vec2(); +b2PulleyJoint.prototype.m_u1 = new b2Vec2(); +b2PulleyJoint.prototype.m_u2 = new b2Vec2(); +b2PulleyJoint.prototype.m_constant = null; +b2PulleyJoint.prototype.m_ratio = null; +b2PulleyJoint.prototype.m_maxLength1 = null; +b2PulleyJoint.prototype.m_maxLength2 = null; +b2PulleyJoint.prototype.m_pulleyMass = null; +b2PulleyJoint.prototype.m_limitMass1 = null; +b2PulleyJoint.prototype.m_limitMass2 = null; +b2PulleyJoint.prototype.m_force = null; +b2PulleyJoint.prototype.m_limitForce1 = null; +b2PulleyJoint.prototype.m_limitForce2 = null; +b2PulleyJoint.prototype.m_positionImpulse = null; +b2PulleyJoint.prototype.m_limitPositionImpulse1 = null; +b2PulleyJoint.prototype.m_limitPositionImpulse2 = null; +b2PulleyJoint.prototype.m_state = 0; +b2PulleyJoint.prototype.m_limitState1 = 0; +b2PulleyJoint.prototype.m_limitState2 = 0; +b2PulleyJoint.prototype.GetAnchor1 = function () { + return this.m_body1.GetWorldPoint(this.m_localAnchor1); + } +b2PulleyJoint.prototype.GetAnchor2 = function () { + return this.m_body2.GetWorldPoint(this.m_localAnchor2); + } +b2PulleyJoint.prototype.GetReactionForce = function () { + + var F = this.m_u2.Copy(); + F.Multiply(this.m_force); + return F; + } +b2PulleyJoint.prototype.GetReactionTorque = function () { + return 0.0; + } +b2PulleyJoint.prototype.GetGroundAnchor1 = function () { + + var a = this.m_ground.m_xf.position.Copy(); + a.Add(this.m_groundAnchor1); + return a; + } +b2PulleyJoint.prototype.GetGroundAnchor2 = function () { + + var a = this.m_ground.m_xf.position.Copy(); + a.Add(this.m_groundAnchor2); + return a; + } +b2PulleyJoint.prototype.GetLength1 = function () { + var p = this.m_body1.GetWorldPoint(this.m_localAnchor1); + + var sX = this.m_ground.m_xf.position.x + this.m_groundAnchor1.x; + var sY = this.m_ground.m_xf.position.y + this.m_groundAnchor1.y; + + var dX = p.x - sX; + var dY = p.y - sY; + + return Math.sqrt(dX*dX + dY*dY); + } +b2PulleyJoint.prototype.GetLength2 = function () { + var p = this.m_body2.GetWorldPoint(this.m_localAnchor2); + + var sX = this.m_ground.m_xf.position.x + this.m_groundAnchor2.x; + var sY = this.m_ground.m_xf.position.y + this.m_groundAnchor2.y; + + var dX = p.x - sX; + var dY = p.y - sY; + + return Math.sqrt(dX*dX + dY*dY); + } +b2PulleyJoint.prototype.GetRatio = function () { + return this.m_ratio; + } +b2PulleyJoint.prototype.InitVelocityConstraints = function (step) { + var b1 = this.m_body1; + var b2 = this.m_body2; + + var tMat; + + + tMat = b1.m_xf.R; + var r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + tMat = b2.m_xf.R; + var r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + + var p1X = b1.m_sweep.c.x + r1X; + var p1Y = b1.m_sweep.c.y + r1Y; + + var p2X = b2.m_sweep.c.x + r2X; + var p2Y = b2.m_sweep.c.y + r2Y; + + + var s1X = this.m_ground.m_xf.position.x + this.m_groundAnchor1.x; + var s1Y = this.m_ground.m_xf.position.y + this.m_groundAnchor1.y; + + var s2X = this.m_ground.m_xf.position.x + this.m_groundAnchor2.x; + var s2Y = this.m_ground.m_xf.position.y + this.m_groundAnchor2.y; + + + + this.m_u1.Set(p1X - s1X, p1Y - s1Y); + + this.m_u2.Set(p2X - s2X, p2Y - s2Y); + + var length1 = this.m_u1.Length(); + var length2 = this.m_u2.Length(); + + if (length1 > b2Settings.b2_linearSlop) + { + + this.m_u1.Multiply(1.0 / length1); + } + else + { + this.m_u1.SetZero(); + } + + if (length2 > b2Settings.b2_linearSlop) + { + + this.m_u2.Multiply(1.0 / length2); + } + else + { + this.m_u2.SetZero(); + } + + var C = this.m_constant - length1 - this.m_ratio * length2; + if (C > 0.0) + { + this.m_state = b2Joint.e_inactiveLimit; + this.m_force = 0.0; + } + else + { + this.m_state = b2Joint.e_atUpperLimit; + this.m_positionImpulse = 0.0; + } + + if (length1 < this.m_maxLength1) + { + this.m_limitState1 = b2Joint.e_inactiveLimit; + this.m_limitForce1 = 0.0; + } + else + { + this.m_limitState1 = b2Joint.e_atUpperLimit; + this.m_limitPositionImpulse1 = 0.0; + } + + if (length2 < this.m_maxLength2) + { + this.m_limitState2 = b2Joint.e_inactiveLimit; + this.m_limitForce2 = 0.0; + } + else + { + this.m_limitState2 = b2Joint.e_atUpperLimit; + this.m_limitPositionImpulse2 = 0.0; + } + + + + var cr1u1 = r1X * this.m_u1.y - r1Y * this.m_u1.x; + + var cr2u2 = r2X * this.m_u2.y - r2Y * this.m_u2.x; + + this.m_limitMass1 = b1.m_invMass + b1.m_invI * cr1u1 * cr1u1; + this.m_limitMass2 = b2.m_invMass + b2.m_invI * cr2u2 * cr2u2; + this.m_pulleyMass = this.m_limitMass1 + this.m_ratio * this.m_ratio * this.m_limitMass2; + + + + this.m_limitMass1 = 1.0 / this.m_limitMass1; + this.m_limitMass2 = 1.0 / this.m_limitMass2; + this.m_pulleyMass = 1.0 / this.m_pulleyMass; + + if (step.warmStarting) + { + + + + var P1X = step.dt * (-this.m_force - this.m_limitForce1) * this.m_u1.x; + var P1Y = step.dt * (-this.m_force - this.m_limitForce1) * this.m_u1.y; + + + var P2X = step.dt * (-this.m_ratio * this.m_force - this.m_limitForce2) * this.m_u2.x; + var P2Y = step.dt * (-this.m_ratio * this.m_force - this.m_limitForce2) * this.m_u2.y; + + b1.m_linearVelocity.x += b1.m_invMass * P1X; + b1.m_linearVelocity.y += b1.m_invMass * P1Y; + + b1.m_angularVelocity += b1.m_invI * (r1X * P1Y - r1Y * P1X); + + b2.m_linearVelocity.x += b2.m_invMass * P2X; + b2.m_linearVelocity.y += b2.m_invMass * P2Y; + + b2.m_angularVelocity += b2.m_invI * (r2X * P2Y - r2Y * P2X); + } + else + { + this.m_force = 0.0; + this.m_limitForce1 = 0.0; + this.m_limitForce2 = 0.0; + } + } +b2PulleyJoint.prototype.SolveVelocityConstraints = function (step) { + var b1 = this.m_body1; + var b2 = this.m_body2; + + var tMat; + + + tMat = b1.m_xf.R; + var r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + tMat = b2.m_xf.R; + var r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + + var v1X; + var v1Y; + var v2X; + var v2Y; + var P1X; + var P1Y; + var P2X; + var P2Y; + var Cdot; + var force; + var oldForce; + + if (this.m_state == b2Joint.e_atUpperLimit) + { + + v1X = b1.m_linearVelocity.x + (-b1.m_angularVelocity * r1Y); + v1Y = b1.m_linearVelocity.y + (b1.m_angularVelocity * r1X); + + v2X = b2.m_linearVelocity.x + (-b2.m_angularVelocity * r2Y); + v2Y = b2.m_linearVelocity.y + (b2.m_angularVelocity * r2X); + + + Cdot = -(this.m_u1.x * v1X + this.m_u1.y * v1Y) - this.m_ratio * (this.m_u2.x * v2X + this.m_u2.y * v2Y); + force = -step.inv_dt * this.m_pulleyMass * Cdot; + oldForce = this.m_force; + this.m_force = b2Math.b2Max(0.0, this.m_force + force); + force = this.m_force - oldForce; + + + P1X = -step.dt * force * this.m_u1.x; + P1Y = -step.dt * force * this.m_u1.y; + + P2X = -step.dt * this.m_ratio * force * this.m_u2.x; + P2Y = -step.dt * this.m_ratio * force * this.m_u2.y; + + b1.m_linearVelocity.x += b1.m_invMass * P1X; + b1.m_linearVelocity.y += b1.m_invMass * P1Y; + + b1.m_angularVelocity += b1.m_invI * (r1X * P1Y - r1Y * P1X); + + b2.m_linearVelocity.x += b2.m_invMass * P2X; + b2.m_linearVelocity.y += b2.m_invMass * P2Y; + + b2.m_angularVelocity += b2.m_invI * (r2X * P2Y - r2Y * P2X); + } + + if (this.m_limitState1 == b2Joint.e_atUpperLimit) + { + + v1X = b1.m_linearVelocity.x + (-b1.m_angularVelocity * r1Y); + v1Y = b1.m_linearVelocity.y + (b1.m_angularVelocity * r1X); + + + Cdot = -(this.m_u1.x * v1X + this.m_u1.y * v1Y); + force = -step.inv_dt * this.m_limitMass1 * Cdot; + oldForce = this.m_limitForce1; + this.m_limitForce1 = b2Math.b2Max(0.0, this.m_limitForce1 + force); + force = this.m_limitForce1 - oldForce; + + + P1X = -step.dt * force * this.m_u1.x; + P1Y = -step.dt * force * this.m_u1.y; + + b1.m_linearVelocity.x += b1.m_invMass * P1X; + b1.m_linearVelocity.y += b1.m_invMass * P1Y; + + b1.m_angularVelocity += b1.m_invI * (r1X * P1Y - r1Y * P1X); + } + + if (this.m_limitState2 == b2Joint.e_atUpperLimit) + { + + v2X = b2.m_linearVelocity.x + (-b2.m_angularVelocity * r2Y); + v2Y = b2.m_linearVelocity.y + (b2.m_angularVelocity * r2X); + + + Cdot = -(this.m_u2.x * v2X + this.m_u2.y * v2Y); + force = -step.inv_dt * this.m_limitMass2 * Cdot; + oldForce = this.m_limitForce2; + this.m_limitForce2 = b2Math.b2Max(0.0, this.m_limitForce2 + force); + force = this.m_limitForce2 - oldForce; + + + P2X = -step.dt * force * this.m_u2.x; + P2Y = -step.dt * force * this.m_u2.y; + + b2.m_linearVelocity.x += b2.m_invMass * P2X; + b2.m_linearVelocity.y += b2.m_invMass * P2Y; + + b2.m_angularVelocity += b2.m_invI * (r2X * P2Y - r2Y * P2X); + } + } +b2PulleyJoint.prototype.SolvePositionConstraints = function () { + var b1 = this.m_body1; + var b2 = this.m_body2; + + var tMat; + + + var s1X = this.m_ground.m_xf.position.x + this.m_groundAnchor1.x; + var s1Y = this.m_ground.m_xf.position.y + this.m_groundAnchor1.y; + + var s2X = this.m_ground.m_xf.position.x + this.m_groundAnchor2.x; + var s2Y = this.m_ground.m_xf.position.y + this.m_groundAnchor2.y; + + + var r1X; + var r1Y; + var r2X; + var r2Y; + var p1X; + var p1Y; + var p2X; + var p2Y; + var length1; + var length2; + var C; + var impulse; + var oldImpulse; + var oldLimitPositionImpulse; + + var tX; + + var linearError = 0.0; + + if (this.m_state == b2Joint.e_atUpperLimit) + { + + tMat = b1.m_xf.R; + r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + tMat = b2.m_xf.R; + r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + + p1X = b1.m_sweep.c.x + r1X; + p1Y = b1.m_sweep.c.y + r1Y; + + p2X = b2.m_sweep.c.x + r2X; + p2Y = b2.m_sweep.c.y + r2Y; + + + + this.m_u1.Set(p1X - s1X, p1Y - s1Y); + + this.m_u2.Set(p2X - s2X, p2Y - s2Y); + + length1 = this.m_u1.Length(); + length2 = this.m_u2.Length(); + + if (length1 > b2Settings.b2_linearSlop) + { + + this.m_u1.Multiply( 1.0 / length1 ); + } + else + { + this.m_u1.SetZero(); + } + + if (length2 > b2Settings.b2_linearSlop) + { + + this.m_u2.Multiply( 1.0 / length2 ); + } + else + { + this.m_u2.SetZero(); + } + + C = this.m_constant - length1 - this.m_ratio * length2; + linearError = b2Math.b2Max(linearError, -C); + C = b2Math.b2Clamp(C + b2Settings.b2_linearSlop, -b2Settings.b2_maxLinearCorrection, 0.0); + impulse = -this.m_pulleyMass * C; + + oldImpulse = this.m_positionImpulse; + this.m_positionImpulse = b2Math.b2Max(0.0, this.m_positionImpulse + impulse); + impulse = this.m_positionImpulse - oldImpulse; + + p1X = -impulse * this.m_u1.x; + p1Y = -impulse * this.m_u1.y; + p2X = -this.m_ratio * impulse * this.m_u2.x; + p2Y = -this.m_ratio * impulse * this.m_u2.y; + + b1.m_sweep.c.x += b1.m_invMass * p1X; + b1.m_sweep.c.y += b1.m_invMass * p1Y; + b1.m_sweep.a += b1.m_invI * (r1X * p1Y - r1Y * p1X); + b2.m_sweep.c.x += b2.m_invMass * p2X; + b2.m_sweep.c.y += b2.m_invMass * p2Y; + b2.m_sweep.a += b2.m_invI * (r2X * p2Y - r2Y * p2X); + + b1.SynchronizeTransform(); + b2.SynchronizeTransform(); + } + + if (this.m_limitState1 == b2Joint.e_atUpperLimit) + { + + tMat = b1.m_xf.R; + r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + p1X = b1.m_sweep.c.x + r1X; + p1Y = b1.m_sweep.c.y + r1Y; + + + this.m_u1.Set(p1X - s1X, p1Y - s1Y); + + length1 = this.m_u1.Length(); + + if (length1 > b2Settings.b2_linearSlop) + { + + this.m_u1.x *= 1.0 / length1; + this.m_u1.y *= 1.0 / length1; + } + else + { + this.m_u1.SetZero(); + } + + C = this.m_maxLength1 - length1; + linearError = b2Math.b2Max(linearError, -C); + C = b2Math.b2Clamp(C + b2Settings.b2_linearSlop, -b2Settings.b2_maxLinearCorrection, 0.0); + impulse = -this.m_limitMass1 * C; + oldLimitPositionImpulse = this.m_limitPositionImpulse1; + this.m_limitPositionImpulse1 = b2Math.b2Max(0.0, this.m_limitPositionImpulse1 + impulse); + impulse = this.m_limitPositionImpulse1 - oldLimitPositionImpulse; + + + p1X = -impulse * this.m_u1.x; + p1Y = -impulse * this.m_u1.y; + + b1.m_sweep.c.x += b1.m_invMass * p1X; + b1.m_sweep.c.y += b1.m_invMass * p1Y; + + b1.m_sweep.a += b1.m_invI * (r1X * p1Y - r1Y * p1X); + + b1.SynchronizeTransform(); + } + + if (this.m_limitState2 == b2Joint.e_atUpperLimit) + { + + tMat = b2.m_xf.R; + r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + p2X = b2.m_sweep.c.x + r2X; + p2Y = b2.m_sweep.c.y + r2Y; + + + this.m_u2.Set(p2X - s2X, p2Y - s2Y); + + length2 = this.m_u2.Length(); + + if (length2 > b2Settings.b2_linearSlop) + { + + this.m_u2.x *= 1.0 / length2; + this.m_u2.y *= 1.0 / length2; + } + else + { + this.m_u2.SetZero(); + } + + C = this.m_maxLength2 - length2; + linearError = b2Math.b2Max(linearError, -C); + C = b2Math.b2Clamp(C + b2Settings.b2_linearSlop, -b2Settings.b2_maxLinearCorrection, 0.0); + impulse = -this.m_limitMass2 * C; + oldLimitPositionImpulse = this.m_limitPositionImpulse2; + this.m_limitPositionImpulse2 = b2Math.b2Max(0.0, this.m_limitPositionImpulse2 + impulse); + impulse = this.m_limitPositionImpulse2 - oldLimitPositionImpulse; + + + p2X = -impulse * this.m_u2.x; + p2Y = -impulse * this.m_u2.y; + + + b2.m_sweep.c.x += b2.m_invMass * p2X; + b2.m_sweep.c.y += b2.m_invMass * p2Y; + + b2.m_sweep.a += b2.m_invI * (r2X * p2Y - r2Y * p2X); + + b2.SynchronizeTransform(); + } + + return linearError < b2Settings.b2_linearSlop; + } +exports.b2PulleyJoint = b2PulleyJoint; + + +var b2RevoluteJoint = function() { +b2Joint.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2RevoluteJoint.prototype, b2Joint.prototype) +b2RevoluteJoint.prototype._super = function(){ b2Joint.prototype.__constructor.apply(this, arguments) } +b2RevoluteJoint.prototype.__constructor = function (def) { + this._super(def); + + + this.m_localAnchor1.SetV(def.localAnchor1); + + this.m_localAnchor2.SetV(def.localAnchor2); + + this.m_referenceAngle = def.referenceAngle; + + this.m_pivotForce.Set(0.0, 0.0); + this.m_motorForce = 0.0; + this.m_limitForce = 0.0; + this.m_limitPositionImpulse = 0.0; + + this.m_lowerAngle = def.lowerAngle; + this.m_upperAngle = def.upperAngle; + this.m_maxMotorTorque = def.maxMotorTorque; + this.m_motorSpeed = def.motorSpeed; + this.m_enableLimit = def.enableLimit; + this.m_enableMotor = def.enableMotor; + } +b2RevoluteJoint.prototype.__varz = function(){ +this.K = new b2Mat22(); +this.K1 = new b2Mat22(); +this.K2 = new b2Mat22(); +this.K3 = new b2Mat22(); +this.m_localAnchor1 = new b2Vec2(); +this.m_localAnchor2 = new b2Vec2(); +this.m_pivotForce = new b2Vec2(); +this.m_pivotMass = new b2Mat22(); +} +b2RevoluteJoint.tImpulse = new b2Vec2(); +b2RevoluteJoint.prototype.K = new b2Mat22(); +b2RevoluteJoint.prototype.K1 = new b2Mat22(); +b2RevoluteJoint.prototype.K2 = new b2Mat22(); +b2RevoluteJoint.prototype.K3 = new b2Mat22(); +b2RevoluteJoint.prototype.m_localAnchor1 = new b2Vec2(); +b2RevoluteJoint.prototype.m_localAnchor2 = new b2Vec2(); +b2RevoluteJoint.prototype.m_pivotForce = new b2Vec2(); +b2RevoluteJoint.prototype.m_motorForce = null; +b2RevoluteJoint.prototype.m_limitForce = null; +b2RevoluteJoint.prototype.m_limitPositionImpulse = null; +b2RevoluteJoint.prototype.m_pivotMass = new b2Mat22(); +b2RevoluteJoint.prototype.m_motorMass = null; +b2RevoluteJoint.prototype.m_enableMotor = null; +b2RevoluteJoint.prototype.m_maxMotorTorque = null; +b2RevoluteJoint.prototype.m_motorSpeed = null; +b2RevoluteJoint.prototype.m_enableLimit = null; +b2RevoluteJoint.prototype.m_referenceAngle = null; +b2RevoluteJoint.prototype.m_lowerAngle = null; +b2RevoluteJoint.prototype.m_upperAngle = null; +b2RevoluteJoint.prototype.m_limitState = 0; +b2RevoluteJoint.prototype.GetAnchor1 = function () { + return this.m_body1.GetWorldPoint(this.m_localAnchor1); + } +b2RevoluteJoint.prototype.GetAnchor2 = function () { + return this.m_body2.GetWorldPoint(this.m_localAnchor2); + } +b2RevoluteJoint.prototype.GetReactionForce = function () { + return this.m_pivotForce; + } +b2RevoluteJoint.prototype.GetReactionTorque = function () { + return this.m_limitForce; + } +b2RevoluteJoint.prototype.GetJointAngle = function () { + + + return this.m_body2.m_sweep.a - this.m_body1.m_sweep.a - this.m_referenceAngle; + } +b2RevoluteJoint.prototype.GetJointSpeed = function () { + + + return this.m_body2.m_angularVelocity - this.m_body1.m_angularVelocity; + } +b2RevoluteJoint.prototype.IsLimitEnabled = function () { + return this.m_enableLimit; + } +b2RevoluteJoint.prototype.EnableLimit = function (flag) { + this.m_enableLimit = flag; + } +b2RevoluteJoint.prototype.GetLowerLimit = function () { + return this.m_lowerAngle; + } +b2RevoluteJoint.prototype.GetUpperLimit = function () { + return this.m_upperAngle; + } +b2RevoluteJoint.prototype.SetLimits = function (lower, upper) { + + this.m_lowerAngle = lower; + this.m_upperAngle = upper; + } +b2RevoluteJoint.prototype.IsMotorEnabled = function () { + return this.m_enableMotor; + } +b2RevoluteJoint.prototype.EnableMotor = function (flag) { + this.m_enableMotor = flag; + } +b2RevoluteJoint.prototype.SetMotorSpeed = function (speed) { + this.m_motorSpeed = speed; + } +b2RevoluteJoint.prototype.GetMotorSpeed = function () { + return this.m_motorSpeed; + } +b2RevoluteJoint.prototype.SetMaxMotorTorque = function (torque) { + this.m_maxMotorTorque = torque; + } +b2RevoluteJoint.prototype.GetMotorTorque = function () { + return this.m_motorForce; + } +b2RevoluteJoint.prototype.InitVelocityConstraints = function (step) { + var b1 = this.m_body1; + var b2 = this.m_body2; + + var tMat; + var tX; + + + + tMat = b1.m_xf.R; + var r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + tMat = b2.m_xf.R; + var r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + + + + var invMass1 = b1.m_invMass; + var invMass2 = b2.m_invMass; + var invI1 = b1.m_invI; + var invI2 = b2.m_invI; + + + this.K1.col1.x = invMass1 + invMass2; this.K1.col2.x = 0.0; + this.K1.col1.y = 0.0; this.K1.col2.y = invMass1 + invMass2; + + + this.K2.col1.x = invI1 * r1Y * r1Y; this.K2.col2.x = -invI1 * r1X * r1Y; + this.K2.col1.y = -invI1 * r1X * r1Y; this.K2.col2.y = invI1 * r1X * r1X; + + + this.K3.col1.x = invI2 * r2Y * r2Y; this.K3.col2.x = -invI2 * r2X * r2Y; + this.K3.col1.y = -invI2 * r2X * r2Y; this.K3.col2.y = invI2 * r2X * r2X; + + + this.K.SetM(this.K1); + this.K.AddM(this.K2); + this.K.AddM(this.K3); + + + this.K.Invert(this.m_pivotMass); + + this.m_motorMass = 1.0 / (invI1 + invI2); + + if (this.m_enableMotor == false) + { + this.m_motorForce = 0.0; + } + + if (this.m_enableLimit) + { + + var jointAngle = b2.m_sweep.a - b1.m_sweep.a - this.m_referenceAngle; + if (b2Math.b2Abs(this.m_upperAngle - this.m_lowerAngle) < 2.0 * b2Settings.b2_angularSlop) + { + this.m_limitState = b2Joint.e_equalLimits; + } + else if (jointAngle <= this.m_lowerAngle) + { + if (this.m_limitState != b2Joint.e_atLowerLimit) + { + this.m_limitForce = 0.0; + } + this.m_limitState = b2Joint.e_atLowerLimit; + } + else if (jointAngle >= this.m_upperAngle) + { + if (this.m_limitState != b2Joint.e_atUpperLimit) + { + this.m_limitForce = 0.0; + } + this.m_limitState = b2Joint.e_atUpperLimit; + } + else + { + this.m_limitState = b2Joint.e_inactiveLimit; + this.m_limitForce = 0.0; + } + } + else + { + this.m_limitForce = 0.0; + } + + + if (step.warmStarting) + { + + b1.m_linearVelocity.x -= step.dt * invMass1 * this.m_pivotForce.x; + b1.m_linearVelocity.y -= step.dt * invMass1 * this.m_pivotForce.y; + + b1.m_angularVelocity -= step.dt * invI1 * ((r1X * this.m_pivotForce.y - r1Y * this.m_pivotForce.x) + this.m_motorForce + this.m_limitForce); + + + b2.m_linearVelocity.x += step.dt * invMass2 * this.m_pivotForce.x; + b2.m_linearVelocity.y += step.dt * invMass2 * this.m_pivotForce.y; + + b2.m_angularVelocity += step.dt * invI2 * ((r2X * this.m_pivotForce.y - r2Y * this.m_pivotForce.x) + this.m_motorForce + this.m_limitForce); + } + else{ + this.m_pivotForce.SetZero(); + this.m_motorForce = 0.0; + this.m_limitForce = 0.0; + } + + this.m_limitPositionImpulse = 0.0; + } +b2RevoluteJoint.prototype.SolveVelocityConstraints = function (step) { + var b1 = this.m_body1; + var b2 = this.m_body2; + + var tMat; + var tX; + + + tMat = b1.m_xf.R; + var r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + tMat = b2.m_xf.R; + var r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + var oldLimitForce; + + + + var pivotCdotX = b2.m_linearVelocity.x + (-b2.m_angularVelocity * r2Y) - b1.m_linearVelocity.x - (-b1.m_angularVelocity * r1Y); + var pivotCdotY = b2.m_linearVelocity.y + (b2.m_angularVelocity * r2X) - b1.m_linearVelocity.y - (b1.m_angularVelocity * r1X); + + + var pivotForceX = -step.inv_dt * (this.m_pivotMass.col1.x * pivotCdotX + this.m_pivotMass.col2.x * pivotCdotY); + var pivotForceY = -step.inv_dt * (this.m_pivotMass.col1.y * pivotCdotX + this.m_pivotMass.col2.y * pivotCdotY); + this.m_pivotForce.x += pivotForceX; + this.m_pivotForce.y += pivotForceY; + + + var PX = step.dt * pivotForceX; + var PY = step.dt * pivotForceY; + + + b1.m_linearVelocity.x -= b1.m_invMass * PX; + b1.m_linearVelocity.y -= b1.m_invMass * PY; + + b1.m_angularVelocity -= b1.m_invI * (r1X * PY - r1Y * PX); + + + b2.m_linearVelocity.x += b2.m_invMass * PX; + b2.m_linearVelocity.y += b2.m_invMass * PY; + + b2.m_angularVelocity += b2.m_invI * (r2X * PY - r2Y * PX); + + if (this.m_enableMotor && this.m_limitState != b2Joint.e_equalLimits) + { + var motorCdot = b2.m_angularVelocity - b1.m_angularVelocity - this.m_motorSpeed; + var motorForce = -step.inv_dt * this.m_motorMass * motorCdot; + var oldMotorForce = this.m_motorForce; + this.m_motorForce = b2Math.b2Clamp(this.m_motorForce + motorForce, -this.m_maxMotorTorque, this.m_maxMotorTorque); + motorForce = this.m_motorForce - oldMotorForce; + + b1.m_angularVelocity -= b1.m_invI * step.dt * motorForce; + b2.m_angularVelocity += b2.m_invI * step.dt * motorForce; + } + + if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) + { + var limitCdot = b2.m_angularVelocity - b1.m_angularVelocity; + var limitForce = -step.inv_dt * this.m_motorMass * limitCdot; + + if (this.m_limitState == b2Joint.e_equalLimits) + { + this.m_limitForce += limitForce; + } + else if (this.m_limitState == b2Joint.e_atLowerLimit) + { + oldLimitForce = this.m_limitForce; + this.m_limitForce = b2Math.b2Max(this.m_limitForce + limitForce, 0.0); + limitForce = this.m_limitForce - oldLimitForce; + } + else if (this.m_limitState == b2Joint.e_atUpperLimit) + { + oldLimitForce = this.m_limitForce; + this.m_limitForce = b2Math.b2Min(this.m_limitForce + limitForce, 0.0); + limitForce = this.m_limitForce - oldLimitForce; + } + + b1.m_angularVelocity -= b1.m_invI * step.dt * limitForce; + b2.m_angularVelocity += b2.m_invI * step.dt * limitForce; + } + } +b2RevoluteJoint.prototype.SolvePositionConstraints = function () { + + var oldLimitImpulse; + var limitC; + + var b1 = this.m_body1; + var b2 = this.m_body2; + + var positionError = 0.0; + + var tMat; + + + + tMat = b1.m_xf.R; + var r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + tMat = b2.m_xf.R; + var r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + + var p1X = b1.m_sweep.c.x + r1X; + var p1Y = b1.m_sweep.c.y + r1Y; + + var p2X = b2.m_sweep.c.x + r2X; + var p2Y = b2.m_sweep.c.y + r2Y; + + + var ptpCX = p2X - p1X; + var ptpCY = p2Y - p1Y; + + + positionError = Math.sqrt(ptpCX*ptpCX + ptpCY*ptpCY); + + + + + + + var invMass1 = b1.m_invMass; + var invMass2 = b2.m_invMass; + + var invI1 = b1.m_invI; + var invI2 = b2.m_invI; + + + this.K1.col1.x = invMass1 + invMass2; this.K1.col2.x = 0.0; + this.K1.col1.y = 0.0; this.K1.col2.y = invMass1 + invMass2; + + + this.K2.col1.x = invI1 * r1Y * r1Y; this.K2.col2.x = -invI1 * r1X * r1Y; + this.K2.col1.y = -invI1 * r1X * r1Y; this.K2.col2.y = invI1 * r1X * r1X; + + + this.K3.col1.x = invI2 * r2Y * r2Y; this.K3.col2.x = -invI2 * r2X * r2Y; + this.K3.col1.y = -invI2 * r2X * r2Y; this.K3.col2.y = invI2 * r2X * r2X; + + + this.K.SetM(this.K1); + this.K.AddM(this.K2); + this.K.AddM(this.K3); + + this.K.Solve(b2RevoluteJoint.tImpulse, -ptpCX, -ptpCY); + var impulseX = b2RevoluteJoint.tImpulse.x; + var impulseY = b2RevoluteJoint.tImpulse.y; + + + b1.m_sweep.c.x -= b1.m_invMass * impulseX; + b1.m_sweep.c.y -= b1.m_invMass * impulseY; + + b1.m_sweep.a -= b1.m_invI * (r1X * impulseY - r1Y * impulseX); + + + b2.m_sweep.c.x += b2.m_invMass * impulseX; + b2.m_sweep.c.y += b2.m_invMass * impulseY; + + b2.m_sweep.a += b2.m_invI * (r2X * impulseY - r2Y * impulseX); + + b1.SynchronizeTransform(); + b2.SynchronizeTransform(); + + + + var angularError = 0.0; + + if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) + { + var angle = b2.m_sweep.a - b1.m_sweep.a - this.m_referenceAngle; + var limitImpulse = 0.0; + + if (this.m_limitState == b2Joint.e_equalLimits) + { + + limitC = b2Math.b2Clamp(angle, -b2Settings.b2_maxAngularCorrection, b2Settings.b2_maxAngularCorrection); + limitImpulse = -this.m_motorMass * limitC; + angularError = b2Math.b2Abs(limitC); + } + else if (this.m_limitState == b2Joint.e_atLowerLimit) + { + limitC = angle - this.m_lowerAngle; + angularError = b2Math.b2Max(0.0, -limitC); + + + limitC = b2Math.b2Clamp(limitC + b2Settings.b2_angularSlop, -b2Settings.b2_maxAngularCorrection, 0.0); + limitImpulse = -this.m_motorMass * limitC; + oldLimitImpulse = this.m_limitPositionImpulse; + this.m_limitPositionImpulse = b2Math.b2Max(this.m_limitPositionImpulse + limitImpulse, 0.0); + limitImpulse = this.m_limitPositionImpulse - oldLimitImpulse; + } + else if (this.m_limitState == b2Joint.e_atUpperLimit) + { + limitC = angle - this.m_upperAngle; + angularError = b2Math.b2Max(0.0, limitC); + + + limitC = b2Math.b2Clamp(limitC - b2Settings.b2_angularSlop, 0.0, b2Settings.b2_maxAngularCorrection); + limitImpulse = -this.m_motorMass * limitC; + oldLimitImpulse = this.m_limitPositionImpulse; + this.m_limitPositionImpulse = b2Math.b2Min(this.m_limitPositionImpulse + limitImpulse, 0.0); + limitImpulse = this.m_limitPositionImpulse - oldLimitImpulse; + } + + b1.m_sweep.a -= b1.m_invI * limitImpulse; + b2.m_sweep.a += b2.m_invI * limitImpulse; + + b1.SynchronizeTransform(); + b2.SynchronizeTransform(); + } + + return positionError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop; + } +exports.b2RevoluteJoint = b2RevoluteJoint; + + +var b2PrismaticJoint = function() { +b2Joint.prototype.__varz.call(this) +this.__varz(); +this.__constructor.apply(this, arguments); +} +extend(b2PrismaticJoint.prototype, b2Joint.prototype) +b2PrismaticJoint.prototype._super = function(){ b2Joint.prototype.__constructor.apply(this, arguments) } +b2PrismaticJoint.prototype.__constructor = function (def) { + this._super(def); + + var tMat; + var tX; + var tY; + + this.m_localAnchor1.SetV(def.localAnchor1); + this.m_localAnchor2.SetV(def.localAnchor2); + this.m_localXAxis1.SetV(def.localAxis1); + + + this.m_localYAxis1.x = -this.m_localXAxis1.y; + this.m_localYAxis1.y = this.m_localXAxis1.x; + + this.m_refAngle = def.referenceAngle; + + this.m_linearJacobian.SetZero(); + this.m_linearMass = 0.0; + this.m_force = 0.0; + + this.m_angularMass = 0.0; + this.m_torque = 0.0; + + this.m_motorJacobian.SetZero(); + this.m_motorMass = 0.0; + this.m_motorForce = 0.0; + this.m_limitForce = 0.0; + this.m_limitPositionImpulse = 0.0; + + this.m_lowerTranslation = def.lowerTranslation; + this.m_upperTranslation = def.upperTranslation; + this.m_maxMotorForce = def.maxMotorForce; + this.m_motorSpeed = def.motorSpeed; + this.m_enableLimit = def.enableLimit; + this.m_enableMotor = def.enableMotor; + } +b2PrismaticJoint.prototype.__varz = function(){ +this.m_localAnchor1 = new b2Vec2(); +this.m_localAnchor2 = new b2Vec2(); +this.m_localXAxis1 = new b2Vec2(); +this.m_localYAxis1 = new b2Vec2(); +this.m_linearJacobian = new b2Jacobian(); +this.m_motorJacobian = new b2Jacobian(); +} +b2PrismaticJoint.prototype.m_localAnchor1 = new b2Vec2(); +b2PrismaticJoint.prototype.m_localAnchor2 = new b2Vec2(); +b2PrismaticJoint.prototype.m_localXAxis1 = new b2Vec2(); +b2PrismaticJoint.prototype.m_localYAxis1 = new b2Vec2(); +b2PrismaticJoint.prototype.m_refAngle = null; +b2PrismaticJoint.prototype.m_linearJacobian = new b2Jacobian(); +b2PrismaticJoint.prototype.m_linearMass = null; +b2PrismaticJoint.prototype.m_force = null; +b2PrismaticJoint.prototype.m_angularMass = null; +b2PrismaticJoint.prototype.m_torque = null; +b2PrismaticJoint.prototype.m_motorJacobian = new b2Jacobian(); +b2PrismaticJoint.prototype.m_motorMass = null; +b2PrismaticJoint.prototype.m_motorForce = null; +b2PrismaticJoint.prototype.m_limitForce = null; +b2PrismaticJoint.prototype.m_limitPositionImpulse = null; +b2PrismaticJoint.prototype.m_lowerTranslation = null; +b2PrismaticJoint.prototype.m_upperTranslation = null; +b2PrismaticJoint.prototype.m_maxMotorForce = null; +b2PrismaticJoint.prototype.m_motorSpeed = null; +b2PrismaticJoint.prototype.m_enableLimit = null; +b2PrismaticJoint.prototype.m_enableMotor = null; +b2PrismaticJoint.prototype.m_limitState = 0; +b2PrismaticJoint.prototype.GetAnchor1 = function () { + return this.m_body1.GetWorldPoint(this.m_localAnchor1); + } +b2PrismaticJoint.prototype.GetAnchor2 = function () { + return this.m_body2.GetWorldPoint(this.m_localAnchor2); + } +b2PrismaticJoint.prototype.GetReactionForce = function () { + var tMat = this.m_body1.m_xf.R; + + var ax1X = this.m_limitForce* (tMat.col1.x * this.m_localXAxis1.x + tMat.col2.x * this.m_localXAxis1.y); + var ax1Y = this.m_limitForce* (tMat.col1.y * this.m_localXAxis1.x + tMat.col2.y * this.m_localXAxis1.y); + + var ay1X = this.m_force* (tMat.col1.x * this.m_localYAxis1.x + tMat.col2.x * this.m_localYAxis1.y); + var ay1Y = this.m_force* (tMat.col1.y * this.m_localYAxis1.x + tMat.col2.y * this.m_localYAxis1.y); + + + return new b2Vec2( this.m_limitForce*ax1X + this.m_force*ay1X, this.m_limitForce*ax1Y + this.m_force*ay1Y); + } +b2PrismaticJoint.prototype.GetReactionTorque = function () { + return this.m_torque; + } +b2PrismaticJoint.prototype.GetJointTranslation = function () { + var b1 = this.m_body1; + var b2 = this.m_body2; + + var tMat; + + var p1 = b1.GetWorldPoint(this.m_localAnchor1); + var p2 = b2.GetWorldPoint(this.m_localAnchor2); + + var dX = p2.x - p1.x; + var dY = p2.y - p1.y; + + var axis = b1.GetWorldVector(this.m_localXAxis1); + + + var translation = axis.x*dX + axis.y*dY; + return translation; + } +b2PrismaticJoint.prototype.GetJointSpeed = function () { + var b1 = this.m_body1; + var b2 = this.m_body2; + + var tMat; + + + tMat = b1.m_xf.R; + var r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + tMat = b2.m_xf.R; + var r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + + var p1X = b1.m_sweep.c.x + r1X; + var p1Y = b1.m_sweep.c.y + r1Y; + + var p2X = b2.m_sweep.c.x + r2X; + var p2Y = b2.m_sweep.c.y + r2Y; + + var dX = p2X - p1X; + var dY = p2Y - p1Y; + + var axis = b1.GetWorldVector(this.m_localXAxis1); + + var v1 = b1.m_linearVelocity; + var v2 = b2.m_linearVelocity; + var w1 = b1.m_angularVelocity; + var w2 = b2.m_angularVelocity; + + + + + var speed = (dX*(-w1 * axis.y) + dY*(w1 * axis.x)) + (axis.x * ((( v2.x + (-w2 * r2Y)) - v1.x) - (-w1 * r1Y)) + axis.y * ((( v2.y + (w2 * r2X)) - v1.y) - (w1 * r1X))); + + return speed; + } +b2PrismaticJoint.prototype.IsLimitEnabled = function () { + return this.m_enableLimit; + } +b2PrismaticJoint.prototype.EnableLimit = function (flag) { + this.m_enableLimit = flag; + } +b2PrismaticJoint.prototype.GetLowerLimit = function () { + return this.m_lowerTranslation; + } +b2PrismaticJoint.prototype.GetUpperLimit = function () { + return this.m_upperTranslation; + } +b2PrismaticJoint.prototype.SetLimits = function (lower, upper) { + + this.m_lowerTranslation = lower; + this.m_upperTranslation = upper; + } +b2PrismaticJoint.prototype.IsMotorEnabled = function () { + return this.m_enableMotor; + } +b2PrismaticJoint.prototype.EnableMotor = function (flag) { + this.m_enableMotor = flag; + } +b2PrismaticJoint.prototype.SetMotorSpeed = function (speed) { + this.m_motorSpeed = speed; + } +b2PrismaticJoint.prototype.GetMotorSpeed = function () { + return this.m_motorSpeed; + } +b2PrismaticJoint.prototype.SetMaxMotorForce = function (force) { + this.m_maxMotorForce = force; + } +b2PrismaticJoint.prototype.GetMotorForce = function () { + return this.m_motorForce; + } +b2PrismaticJoint.prototype.InitVelocityConstraints = function (step) { + var b1 = this.m_body1; + var b2 = this.m_body2; + + var tMat; + var tX; + + + + tMat = b1.m_xf.R; + var r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + tMat = b2.m_xf.R; + var r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + + var invMass1 = b1.m_invMass; + var invMass2 = b2.m_invMass; + + var invI1 = b1.m_invI; + var invI2 = b2.m_invI; + + + + + tMat = b1.m_xf.R; + var ay1X = tMat.col1.x * this.m_localYAxis1.x + tMat.col2.x * this.m_localYAxis1.y; + var ay1Y = tMat.col1.y * this.m_localYAxis1.x + tMat.col2.y * this.m_localYAxis1.y; + + var eX = b2.m_sweep.c.x + r2X - b1.m_sweep.c.x; + var eY = b2.m_sweep.c.y + r2Y - b1.m_sweep.c.y; + + + this.m_linearJacobian.linear1.x = -ay1X; + this.m_linearJacobian.linear1.y = -ay1Y; + this.m_linearJacobian.linear2.x = ay1X; + this.m_linearJacobian.linear2.y = ay1Y; + this.m_linearJacobian.angular1 = -(eX * ay1Y - eY * ay1X); + this.m_linearJacobian.angular2 = r2X * ay1Y - r2Y * ay1X; + + this.m_linearMass = invMass1 + invI1 * this.m_linearJacobian.angular1 * this.m_linearJacobian.angular1 + + invMass2 + invI2 * this.m_linearJacobian.angular2 * this.m_linearJacobian.angular2; + + this.m_linearMass = 1.0 / this.m_linearMass; + + + this.m_angularMass = invI1 + invI2; + if (this.m_angularMass > Number.MIN_VALUE) + { + this.m_angularMass = 1.0 / this.m_angularMass; + } + + + if (this.m_enableLimit || this.m_enableMotor) + { + + + tMat = b1.m_xf.R; + var ax1X = tMat.col1.x * this.m_localXAxis1.x + tMat.col2.x * this.m_localXAxis1.y; + var ax1Y = tMat.col1.y * this.m_localXAxis1.x + tMat.col2.y * this.m_localXAxis1.y; + + this.m_motorJacobian.linear1.x = -ax1X; this.m_motorJacobian.linear1.y = -ax1Y; + this.m_motorJacobian.linear2.x = ax1X; this.m_motorJacobian.linear2.y = ax1Y; + this.m_motorJacobian.angular1 = -(eX * ax1Y - eY * ax1X); + this.m_motorJacobian.angular2 = r2X * ax1Y - r2Y * ax1X; + + this.m_motorMass = invMass1 + invI1 * this.m_motorJacobian.angular1 * this.m_motorJacobian.angular1 + + invMass2 + invI2 * this.m_motorJacobian.angular2 * this.m_motorJacobian.angular2; + + this.m_motorMass = 1.0 / this.m_motorMass; + + if (this.m_enableLimit) + { + + var dX = eX - r1X; + var dY = eY - r1Y; + + var jointTranslation = ax1X * dX + ax1Y * dY; + if (b2Math.b2Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2.0 * b2Settings.b2_linearSlop) + { + this.m_limitState = b2Joint.e_equalLimits; + } + else if (jointTranslation <= this.m_lowerTranslation) + { + if (this.m_limitState != b2Joint.e_atLowerLimit) + { + this.m_limitForce = 0.0; + } + this.m_limitState = b2Joint.e_atLowerLimit; + } + else if (jointTranslation >= this.m_upperTranslation) + { + if (this.m_limitState != b2Joint.e_atUpperLimit) + { + this.m_limitForce = 0.0; + } + this.m_limitState = b2Joint.e_atUpperLimit; + } + else + { + this.m_limitState = b2Joint.e_inactiveLimit; + this.m_limitForce = 0.0; + } + } + } + + if (this.m_enableMotor == false) + { + this.m_motorForce = 0.0; + } + + if (this.m_enableLimit == false) + { + this.m_limitForce = 0.0; + } + + if (step.warmStarting) + { + + var P1X = step.dt * (this.m_force * this.m_linearJacobian.linear1.x + (this.m_motorForce + this.m_limitForce) * this.m_motorJacobian.linear1.x); + var P1Y = step.dt * (this.m_force * this.m_linearJacobian.linear1.y + (this.m_motorForce + this.m_limitForce) * this.m_motorJacobian.linear1.y); + + var P2X = step.dt * (this.m_force * this.m_linearJacobian.linear2.x + (this.m_motorForce + this.m_limitForce) * this.m_motorJacobian.linear2.x); + var P2Y = step.dt * (this.m_force * this.m_linearJacobian.linear2.y + (this.m_motorForce + this.m_limitForce) * this.m_motorJacobian.linear2.y); + + var L1 = step.dt * (this.m_force * this.m_linearJacobian.angular1 - this.m_torque + (this.m_motorForce + this.m_limitForce) * this.m_motorJacobian.angular1); + + var L2 = step.dt * (this.m_force * this.m_linearJacobian.angular2 + this.m_torque + (this.m_motorForce + this.m_limitForce) * this.m_motorJacobian.angular2); + + + b1.m_linearVelocity.x += invMass1 * P1X; + b1.m_linearVelocity.y += invMass1 * P1Y; + + b1.m_angularVelocity += invI1 * L1; + + + b2.m_linearVelocity.x += invMass2 * P2X; + b2.m_linearVelocity.y += invMass2 * P2Y; + + b2.m_angularVelocity += invI2 * L2; + } + else + { + this.m_force = 0.0; + this.m_torque = 0.0; + this.m_limitForce = 0.0; + this.m_motorForce = 0.0; + } + + this.m_limitPositionImpulse = 0.0; + + } +b2PrismaticJoint.prototype.SolveVelocityConstraints = function (step) { + var b1 = this.m_body1; + var b2 = this.m_body2; + + var invMass1 = b1.m_invMass; + var invMass2 = b2.m_invMass; + var invI1 = b1.m_invI; + var invI2 = b2.m_invI; + + var oldLimitForce; + + + var linearCdot = this.m_linearJacobian.Compute(b1.m_linearVelocity, b1.m_angularVelocity, b2.m_linearVelocity, b2.m_angularVelocity); + var force = -step.inv_dt * this.m_linearMass * linearCdot; + this.m_force += force; + + var P = step.dt * force; + + b1.m_linearVelocity.x += (invMass1 * P) * this.m_linearJacobian.linear1.x; + b1.m_linearVelocity.y += (invMass1 * P) * this.m_linearJacobian.linear1.y; + + b1.m_angularVelocity += invI1 * P * this.m_linearJacobian.angular1; + + + b2.m_linearVelocity.x += (invMass2 * P) * this.m_linearJacobian.linear2.x; + b2.m_linearVelocity.y += (invMass2 * P) * this.m_linearJacobian.linear2.y; + + b2.m_angularVelocity += invI2 * P * this.m_linearJacobian.angular2; + + + var angularCdot = b2.m_angularVelocity - b1.m_angularVelocity; + var torque = -step.inv_dt * this.m_angularMass * angularCdot; + this.m_torque += torque; + + var L = step.dt * torque; + b1.m_angularVelocity -= invI1 * L; + b2.m_angularVelocity += invI2 * L; + + + if (this.m_enableMotor && this.m_limitState != b2Joint.e_equalLimits) + { + var motorCdot = this.m_motorJacobian.Compute(b1.m_linearVelocity, b1.m_angularVelocity, b2.m_linearVelocity, b2.m_angularVelocity) - this.m_motorSpeed; + var motorForce = -step.inv_dt * this.m_motorMass * motorCdot; + var oldMotorForce = this.m_motorForce; + this.m_motorForce = b2Math.b2Clamp(this.m_motorForce + motorForce, -this.m_maxMotorForce, this.m_maxMotorForce); + motorForce = this.m_motorForce - oldMotorForce; + + P = step.dt * motorForce; + + b1.m_linearVelocity.x += (invMass1 * P) * this.m_motorJacobian.linear1.x; + b1.m_linearVelocity.y += (invMass1 * P) * this.m_motorJacobian.linear1.y; + + b1.m_angularVelocity += invI1 * P * this.m_motorJacobian.angular1; + + + b2.m_linearVelocity.x += (invMass2 * P) * this.m_motorJacobian.linear2.x; + b2.m_linearVelocity.y += (invMass2 * P) * this.m_motorJacobian.linear2.y; + + b2.m_angularVelocity += invI2 * P * this.m_motorJacobian.angular2; + } + + + if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) + { + var limitCdot = this.m_motorJacobian.Compute(b1.m_linearVelocity, b1.m_angularVelocity, b2.m_linearVelocity, b2.m_angularVelocity); + var limitForce = -step.inv_dt * this.m_motorMass * limitCdot; + + if (this.m_limitState == b2Joint.e_equalLimits) + { + this.m_limitForce += limitForce; + } + else if (this.m_limitState == b2Joint.e_atLowerLimit) + { + oldLimitForce = this.m_limitForce; + this.m_limitForce = b2Math.b2Max(this.m_limitForce + limitForce, 0.0); + limitForce = this.m_limitForce - oldLimitForce; + } + else if (this.m_limitState == b2Joint.e_atUpperLimit) + { + oldLimitForce = this.m_limitForce; + this.m_limitForce = b2Math.b2Min(this.m_limitForce + limitForce, 0.0); + limitForce = this.m_limitForce - oldLimitForce; + } + + P = step.dt * limitForce; + + b1.m_linearVelocity.x += (invMass1 * P) * this.m_motorJacobian.linear1.x; + b1.m_linearVelocity.y += (invMass1 * P) * this.m_motorJacobian.linear1.y; + + b1.m_angularVelocity += invI1 * P * this.m_motorJacobian.angular1; + + + b2.m_linearVelocity.x += (invMass2 * P) * this.m_motorJacobian.linear2.x; + b2.m_linearVelocity.y += (invMass2 * P) * this.m_motorJacobian.linear2.y; + + b2.m_angularVelocity += invI2 * P * this.m_motorJacobian.angular2; + } + } +b2PrismaticJoint.prototype.SolvePositionConstraints = function () { + + var limitC; + var oldLimitImpulse; + + var b1 = this.m_body1; + var b2 = this.m_body2; + + var invMass1 = b1.m_invMass; + var invMass2 = b2.m_invMass; + var invI1 = b1.m_invI; + var invI2 = b2.m_invI; + + var tMat; + var tX; + + + tMat = b1.m_xf.R; + var r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + tMat = b2.m_xf.R; + var r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + + var p1X = b1.m_sweep.c.x + r1X; + var p1Y = b1.m_sweep.c.y + r1Y; + + var p2X = b2.m_sweep.c.x + r2X; + var p2Y = b2.m_sweep.c.y + r2Y; + + var dX = p2X - p1X; + var dY = p2Y - p1Y; + + tMat = b1.m_xf.R; + var ay1X = tMat.col1.x * this.m_localYAxis1.x + tMat.col2.x * this.m_localYAxis1.y; + var ay1Y = tMat.col1.y * this.m_localYAxis1.x + tMat.col2.y * this.m_localYAxis1.y; + + + + var linearC = ay1X*dX + ay1Y*dY; + + linearC = b2Math.b2Clamp(linearC, -b2Settings.b2_maxLinearCorrection, b2Settings.b2_maxLinearCorrection); + var linearImpulse = -this.m_linearMass * linearC; + + + b1.m_sweep.c.x += (invMass1 * linearImpulse) * this.m_linearJacobian.linear1.x; + b1.m_sweep.c.y += (invMass1 * linearImpulse) * this.m_linearJacobian.linear1.y; + + b1.m_sweep.a += invI1 * linearImpulse * this.m_linearJacobian.angular1; + + + + b2.m_sweep.c.x += (invMass2 * linearImpulse) * this.m_linearJacobian.linear2.x; + b2.m_sweep.c.y += (invMass2 * linearImpulse) * this.m_linearJacobian.linear2.y; + + b2.m_sweep.a += invI2 * linearImpulse * this.m_linearJacobian.angular2; + + + var positionError = b2Math.b2Abs(linearC); + + + var angularC = b2.m_sweep.a - b1.m_sweep.a - this.m_refAngle; + + angularC = b2Math.b2Clamp(angularC, -b2Settings.b2_maxAngularCorrection, b2Settings.b2_maxAngularCorrection); + var angularImpulse = -this.m_angularMass * angularC; + + b1.m_sweep.a -= b1.m_invI * angularImpulse; + b2.m_sweep.a += b2.m_invI * angularImpulse; + b1.SynchronizeTransform(); + b2.SynchronizeTransform(); + + var angularError = b2Math.b2Abs(angularC); + + + if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) + { + + + tMat = b1.m_xf.R; + r1X = this.m_localAnchor1.x - b1.m_sweep.localCenter.x; + r1Y = this.m_localAnchor1.y - b1.m_sweep.localCenter.y; + tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); + r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); + r1X = tX; + + tMat = b2.m_xf.R; + r2X = this.m_localAnchor2.x - b2.m_sweep.localCenter.x; + r2Y = this.m_localAnchor2.y - b2.m_sweep.localCenter.y; + tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); + r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); + r2X = tX; + + + p1X = b1.m_sweep.c.x + r1X; + p1Y = b1.m_sweep.c.y + r1Y; + + p2X = b2.m_sweep.c.x + r2X; + p2Y = b2.m_sweep.c.y + r2Y; + + dX = p2X - p1X; + dY = p2Y - p1Y; + + tMat = b1.m_xf.R; + var ax1X = tMat.col1.x * this.m_localXAxis1.x + tMat.col2.x * this.m_localXAxis1.y; + var ax1Y = tMat.col1.y * this.m_localXAxis1.x + tMat.col2.y * this.m_localXAxis1.y; + + + var translation = (ax1X*dX + ax1Y*dY); + var limitImpulse = 0.0; + + if (this.m_limitState == b2Joint.e_equalLimits) + { + + limitC = b2Math.b2Clamp(translation, -b2Settings.b2_maxLinearCorrection, b2Settings.b2_maxLinearCorrection); + limitImpulse = -this.m_motorMass * limitC; + positionError = b2Math.b2Max(positionError, b2Math.b2Abs(angularC)); + } + else if (this.m_limitState == b2Joint.e_atLowerLimit) + { + limitC = translation - this.m_lowerTranslation; + positionError = b2Math.b2Max(positionError, -limitC); + + + limitC = b2Math.b2Clamp(limitC + b2Settings.b2_linearSlop, -b2Settings.b2_maxLinearCorrection, 0.0); + limitImpulse = -this.m_motorMass * limitC; + oldLimitImpulse = this.m_limitPositionImpulse; + this.m_limitPositionImpulse = b2Math.b2Max(this.m_limitPositionImpulse + limitImpulse, 0.0); + limitImpulse = this.m_limitPositionImpulse - oldLimitImpulse; + } + else if (this.m_limitState == b2Joint.e_atUpperLimit) + { + limitC = translation - this.m_upperTranslation; + positionError = b2Math.b2Max(positionError, limitC); + + + limitC = b2Math.b2Clamp(limitC - b2Settings.b2_linearSlop, 0.0, b2Settings.b2_maxLinearCorrection); + limitImpulse = -this.m_motorMass * limitC; + oldLimitImpulse = this.m_limitPositionImpulse; + this.m_limitPositionImpulse = b2Math.b2Min(this.m_limitPositionImpulse + limitImpulse, 0.0); + limitImpulse = this.m_limitPositionImpulse - oldLimitImpulse; + } + + + b1.m_sweep.c.x += (invMass1 * limitImpulse) * this.m_motorJacobian.linear1.x; + b1.m_sweep.c.y += (invMass1 * limitImpulse) * this.m_motorJacobian.linear1.y; + + b1.m_sweep.a += invI1 * limitImpulse * this.m_motorJacobian.angular1; + + + b2.m_sweep.c.x += (invMass2 * limitImpulse) * this.m_motorJacobian.linear2.x; + b2.m_sweep.c.y += (invMass2 * limitImpulse) * this.m_motorJacobian.linear2.y; + + b2.m_sweep.a += invI2 * limitImpulse * this.m_motorJacobian.angular2; + + b1.SynchronizeTransform(); + b2.SynchronizeTransform(); + + } + + return positionError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop; + + } +exports.b2PrismaticJoint = b2PrismaticJoint; + + +var b2World = function() { +this.__varz(); +this.__constructor.apply(this, arguments); +} +b2World.prototype.__constructor = function (worldAABB, gravity, doSleep) { + + this.m_destructionListener = null; + this.m_boundaryListener = null; + this.m_contactFilter = b2ContactFilter.b2_defaultFilter; + this.m_contactListener = null; + this.m_debugDraw = null; + + this.m_bodyList = null; + this.m_contactList = null; + this.m_jointList = null; + + this.m_bodyCount = 0; + this.m_contactCount = 0; + this.m_jointCount = 0; + + b2World.m_positionCorrection = true; + b2World.m_warmStarting = true; + b2World.m_continuousPhysics = true; + + this.m_allowSleep = doSleep; + this.m_gravity = gravity; + + this.m_lock = false; + + this.m_inv_dt0 = 0.0; + + this.m_contactManager.m_world = this; + + this.m_broadPhase = new b2BroadPhase(worldAABB, this.m_contactManager); + + var bd = new b2BodyDef(); + this.m_groundBody = this.CreateBody(bd); + } +b2World.prototype.__varz = function(){ +this.m_contactManager = new b2ContactManager(); +} +// static attributes +b2World.m_positionCorrection = null; +b2World.m_warmStarting = null; +b2World.m_continuousPhysics = null; +b2World.s_jointColor = new b2Color(0.5, 0.8, 0.8); +b2World.s_coreColor = new b2Color(0.9, 0.6, 0.6); +b2World.s_xf = new b2XForm(); +// static methods +// attributes +b2World.prototype.m_blockAllocator = null; +b2World.prototype.m_stackAllocator = null; +b2World.prototype.m_lock = null; +b2World.prototype.m_broadPhase = null; +b2World.prototype.m_contactManager = new b2ContactManager(); +b2World.prototype.m_bodyList = null; +b2World.prototype.m_jointList = null; +b2World.prototype.m_contactList = null; +b2World.prototype.m_bodyCount = 0; +b2World.prototype.m_contactCount = 0; +b2World.prototype.m_jointCount = 0; +b2World.prototype.m_gravity = null; +b2World.prototype.m_allowSleep = null; +b2World.prototype.m_groundBody = null; +b2World.prototype.m_destructionListener = null; +b2World.prototype.m_boundaryListener = null; +b2World.prototype.m_contactFilter = null; +b2World.prototype.m_contactListener = null; +b2World.prototype.m_debugDraw = null; +b2World.prototype.m_inv_dt0 = null; +b2World.prototype.m_positionIterationCount = 0; +// methods +b2World.prototype.SetDestructionListener = function (listener) { + this.m_destructionListener = listener; + } +b2World.prototype.SetBoundaryListener = function (listener) { + this.m_boundaryListener = listener; + } +b2World.prototype.SetContactFilter = function (filter) { + this.m_contactFilter = filter; + } +b2World.prototype.SetContactListener = function (listener) { + this.m_contactListener = listener; + } +b2World.prototype.SetDebugDraw = function (debugDraw) { + this.m_debugDraw = debugDraw; + } +b2World.prototype.Validate = function () { + this.m_broadPhase.Validate(); + } +b2World.prototype.GetProxyCount = function () { + return this.m_broadPhase.m_proxyCount; + } +b2World.prototype.GetPairCount = function () { + return this.m_broadPhase.m_pairManager.m_pairCount; + } +b2World.prototype.CreateBody = function (def) { + + + if (this.m_lock == true) + { + return null; + } + + + var b = new b2Body(def, this); + + + b.m_prev = null; + b.m_next = this.m_bodyList; + if (this.m_bodyList) + { + this.m_bodyList.m_prev = b; + } + this.m_bodyList = b; + ++this.m_bodyCount; + + return b; + + } +b2World.prototype.DestroyBody = function (b) { + + + + if (this.m_lock == true) + { + return; + } + + + var jn = b.m_jointList; + while (jn) + { + var jn0 = jn; + jn = jn.next; + + if (this.m_destructionListener) + { + this.m_destructionListener.SayGoodbyeJoint(jn0.joint); + } + + this.DestroyJoint(jn0.joint); + } + + + + var s = b.m_shapeList; + while (s) + { + var s0 = s; + s = s.m_next; + + if (this.m_destructionListener) + { + this.m_destructionListener.SayGoodbyeShape(s0); + } + + s0.DestroyProxy(this.m_broadPhase); + b2Shape.Destroy(s0, this.m_blockAllocator); + } + + + if (b.m_prev) + { + b.m_prev.m_next = b.m_next; + } + + if (b.m_next) + { + b.m_next.m_prev = b.m_prev; + } + + if (b == this.m_bodyList) + { + this.m_bodyList = b.m_next; + } + + --this.m_bodyCount; + + + + } +b2World.prototype.CreateJoint = function (def) { + + + + var j = b2Joint.Create(def, this.m_blockAllocator); + + + j.m_prev = null; + j.m_next = this.m_jointList; + if (this.m_jointList) + { + this.m_jointList.m_prev = j; + } + this.m_jointList = j; + ++this.m_jointCount; + + + j.m_node1.joint = j; + j.m_node1.other = j.m_body2; + j.m_node1.prev = null; + j.m_node1.next = j.m_body1.m_jointList; + if (j.m_body1.m_jointList) j.m_body1.m_jointList.prev = j.m_node1; + j.m_body1.m_jointList = j.m_node1; + + j.m_node2.joint = j; + j.m_node2.other = j.m_body1; + j.m_node2.prev = null; + j.m_node2.next = j.m_body2.m_jointList; + if (j.m_body2.m_jointList) j.m_body2.m_jointList.prev = j.m_node2; + j.m_body2.m_jointList = j.m_node2; + + + if (def.collideConnected == false) + { + + var b = def.body1.m_shapeCount < def.body2.m_shapeCount ? def.body1 : def.body2; + for (var s = b.m_shapeList; s; s = s.m_next) + { + s.RefilterProxy(this.m_broadPhase, b.m_xf); + } + } + + return j; + + } +b2World.prototype.DestroyJoint = function (j) { + + + + var collideConnected = j.m_collideConnected; + + + if (j.m_prev) + { + j.m_prev.m_next = j.m_next; + } + + if (j.m_next) + { + j.m_next.m_prev = j.m_prev; + } + + if (j == this.m_jointList) + { + this.m_jointList = j.m_next; + } + + + var body1 = j.m_body1; + var body2 = j.m_body2; + + + body1.WakeUp(); + body2.WakeUp(); + + + if (j.m_node1.prev) + { + j.m_node1.prev.next = j.m_node1.next; + } + + if (j.m_node1.next) + { + j.m_node1.next.prev = j.m_node1.prev; + } + + if (j.m_node1 == body1.m_jointList) + { + body1.m_jointList = j.m_node1.next; + } + + j.m_node1.prev = null; + j.m_node1.next = null; + + + if (j.m_node2.prev) + { + j.m_node2.prev.next = j.m_node2.next; + } + + if (j.m_node2.next) + { + j.m_node2.next.prev = j.m_node2.prev; + } + + if (j.m_node2 == body2.m_jointList) + { + body2.m_jointList = j.m_node2.next; + } + + j.m_node2.prev = null; + j.m_node2.next = null; + + b2Joint.Destroy(j, this.m_blockAllocator); + + + --this.m_jointCount; + + + if (collideConnected == false) + { + + var b = body1.m_shapeCount < body2.m_shapeCount ? body1 : body2; + for (var s = b.m_shapeList; s; s = s.m_next) + { + s.RefilterProxy(this.m_broadPhase, b.m_xf); + } + } + + } +b2World.prototype.Refilter = function (shape) { + shape.RefilterProxy(this.m_broadPhase, shape.m_body.m_xf); + } +b2World.prototype.SetWarmStarting = function (flag) { b2World.m_warmStarting = flag; } +b2World.prototype.SetPositionCorrection = function (flag) { b2World.m_positionCorrection = flag; } +b2World.prototype.SetContinuousPhysics = function (flag) { b2World.m_continuousPhysics = flag; } +b2World.prototype.GetBodyCount = function () { + return this.m_bodyCount; + } +b2World.prototype.GetJointCount = function () { + return this.m_jointCount; + } +b2World.prototype.GetContactCount = function () { + return this.m_contactCount; + } +b2World.prototype.SetGravity = function (gravity) { + this.m_gravity = gravity; + } +b2World.prototype.GetGroundBody = function () { + return this.m_groundBody; + } +b2World.prototype.Step = function (dt, iterations) { + + this.m_lock = true; + + var step = new b2TimeStep(); + step.dt = dt; + step.maxIterations = iterations; + if (dt > 0.0) + { + step.inv_dt = 1.0 / dt; + } + else + { + step.inv_dt = 0.0; + } + + step.dtRatio = this.m_inv_dt0 * dt; + + step.positionCorrection = b2World.m_positionCorrection; + step.warmStarting = b2World.m_warmStarting; + + + this.m_contactManager.Collide(); + + + if (step.dt > 0.0) + { + this.Solve(step); + } + + + if (b2World.m_continuousPhysics && step.dt > 0.0) + { + this.SolveTOI(step); + } + + + this.DrawDebugData(); + + this.m_inv_dt0 = step.inv_dt; + this.m_lock = false; + } +b2World.prototype.Query = function (aabb, shapes, maxCount) { + + + var results = new Array(maxCount); + + var count = this.m_broadPhase.QueryAABB(aabb, results, maxCount); + + for (var i = 0; i < count; ++i) + { + shapes[i] = results[i]; + } + + + return count; + + } +b2World.prototype.GetBodyList = function () { + return this.m_bodyList; + } +b2World.prototype.GetJointList = function () { + return this.m_jointList; + } +b2World.prototype.Solve = function (step) { + + var b; + + this.m_positionIterationCount = 0; + + + var island = new b2Island(this.m_bodyCount, this.m_contactCount, this.m_jointCount, this.m_stackAllocator, this.m_contactListener); + + + for (b = this.m_bodyList; b; b = b.m_next) + { + b.m_flags &= ~b2Body.e_islandFlag; + } + for (var c = this.m_contactList; c; c = c.m_next) + { + c.m_flags &= ~b2Contact.e_islandFlag; + } + for (var j = this.m_jointList; j; j = j.m_next) + { + j.m_islandFlag = false; + } + + + var stackSize = this.m_bodyCount; + + var stack = new Array(stackSize); + for (var seed = this.m_bodyList; seed; seed = seed.m_next) + { + if (seed.m_flags & (b2Body.e_islandFlag | b2Body.e_sleepFlag | b2Body.e_frozenFlag)) + { + continue; + } + + if (seed.IsStatic()) + { + continue; + } + + + island.Clear(); + var stackCount = 0; + stack[stackCount++] = seed; + seed.m_flags |= b2Body.e_islandFlag; + + + while (stackCount > 0) + { + + b = stack[--stackCount]; + island.AddBody(b); + + + b.m_flags &= ~b2Body.e_sleepFlag; + + + + if (b.IsStatic()) + { + continue; + } + + var other; + + for (var cn = b.m_contactList; cn; cn = cn.next) + { + + if (cn.contact.m_flags & (b2Contact.e_islandFlag | b2Contact.e_nonSolidFlag)) + { + continue; + } + + + if (cn.contact.m_manifoldCount == 0) + { + continue; + } + + island.AddContact(cn.contact); + cn.contact.m_flags |= b2Contact.e_islandFlag; + + + other = cn.other; + + + if (other.m_flags & b2Body.e_islandFlag) + { + continue; + } + + + stack[stackCount++] = other; + other.m_flags |= b2Body.e_islandFlag; + } + + + for (var jn = b.m_jointList; jn; jn = jn.next) + { + if (jn.joint.m_islandFlag == true) + { + continue; + } + + island.AddJoint(jn.joint); + jn.joint.m_islandFlag = true; + + + other = jn.other; + if (other.m_flags & b2Body.e_islandFlag) + { + continue; + } + + + stack[stackCount++] = other; + other.m_flags |= b2Body.e_islandFlag; + } + } + + island.Solve(step, this.m_gravity, b2World.m_positionCorrection, this.m_allowSleep); + + if (island.m_positionIterationCount > this.m_positionIterationCount) { + this.m_positionIterationCount = island.m_positionIterationCount; + } + + + for (var i = 0; i < island.m_bodyCount; ++i) + { + + b = island.m_bodies[i]; + if (b.IsStatic()) + { + b.m_flags &= ~b2Body.e_islandFlag; + } + } + } + + + + + for (b = this.m_bodyList; b; b = b.m_next) + { + if (b.m_flags & (b2Body.e_sleepFlag | b2Body.e_frozenFlag)) + { + continue; + } + + if (b.IsStatic()) + { + continue; + } + + + + + var inRange = b.SynchronizeShapes(); + + + if (inRange == false && this.m_boundaryListener != null) + { + this.m_boundaryListener.Violation(b); + } + } + + + + this.m_broadPhase.Commit(); + + } +b2World.prototype.SolveTOI = function (step) { + + var b; + var s1; + var s2; + var b1; + var b2; + var cn; + + + var island = new b2Island(this.m_bodyCount, b2Settings.b2_maxTOIContactsPerIsland, 0, this.m_stackAllocator, this.m_contactListener); + var stackSize = this.m_bodyCount; + + + var stack = new Array(stackSize); + + for (b = this.m_bodyList; b; b = b.m_next) + { + b.m_flags &= ~b2Body.e_islandFlag; + b.m_sweep.t0 = 0.0; + } + + var c; + for (c = this.m_contactList; c; c = c.m_next) + { + + c.m_flags &= ~(b2Contact.e_toiFlag | b2Contact.e_islandFlag); + } + + + for (;;) + { + + var minContact = null; + var minTOI = 1.0; + + for (c = this.m_contactList; c; c = c.m_next) + { + if (c.m_flags & (b2Contact.e_slowFlag | b2Contact.e_nonSolidFlag)) + { + continue; + } + + + + var toi = 1.0; + if (c.m_flags & b2Contact.e_toiFlag) + { + + toi = c.m_toi; + } + else + { + + s1 = c.m_shape1; + s2 = c.m_shape2; + b1 = s1.m_body; + b2 = s2.m_body; + + if ((b1.IsStatic() || b1.IsSleeping()) && (b2.IsStatic() || b2.IsSleeping())) + { + continue; + } + + + var t0 = b1.m_sweep.t0; + + if (b1.m_sweep.t0 < b2.m_sweep.t0) + { + t0 = b2.m_sweep.t0; + b1.m_sweep.Advance(t0); + } + else if (b2.m_sweep.t0 < b1.m_sweep.t0) + { + t0 = b1.m_sweep.t0; + b2.m_sweep.Advance(t0); + } + + + + + toi = b2TimeOfImpact.TimeOfImpact(c.m_shape1, b1.m_sweep, c.m_shape2, b2.m_sweep); + + + if (toi > 0.0 && toi < 1.0) + { + + toi = (1.0 - toi) * t0 + toi; + if (toi > 1) toi = 1; + } + + + c.m_toi = toi; + c.m_flags |= b2Contact.e_toiFlag; + } + + if (Number.MIN_VALUE < toi && toi < minTOI) + { + + minContact = c; + minTOI = toi; + } + } + + if (minContact == null || 1.0 - 100.0 * Number.MIN_VALUE < minTOI) + { + + break; + } + + + s1 = minContact.m_shape1; + s2 = minContact.m_shape2; + b1 = s1.m_body; + b2 = s2.m_body; + b1.Advance(minTOI); + b2.Advance(minTOI); + + + minContact.Update(this.m_contactListener); + minContact.m_flags &= ~b2Contact.e_toiFlag; + + if (minContact.m_manifoldCount == 0) + { + + + continue; + } + + + var seed = b1; + if (seed.IsStatic()) + { + seed = b2; + } + + + island.Clear(); + var stackCount = 0; + stack[stackCount++] = seed; + seed.m_flags |= b2Body.e_islandFlag; + + + while (stackCount > 0) + { + + b = stack[--stackCount]; + island.AddBody(b); + + + b.m_flags &= ~b2Body.e_sleepFlag; + + + + if (b.IsStatic()) + { + continue; + } + + + for (cn = b.m_contactList; cn; cn = cn.next) + { + + if (island.m_contactCount == island.m_contactCapacity) + { + continue; + } + + + if (cn.contact.m_flags & (b2Contact.e_islandFlag | b2Contact.e_slowFlag | b2Contact.e_nonSolidFlag)) + { + continue; + } + + + if (cn.contact.m_manifoldCount == 0) + { + continue; + } + + island.AddContact(cn.contact); + cn.contact.m_flags |= b2Contact.e_islandFlag; + + + var other = cn.other; + + + if (other.m_flags & b2Body.e_islandFlag) + { + continue; + } + + + if (other.IsStatic() == false) + { + other.Advance(minTOI); + other.WakeUp(); + } + + + stack[stackCount++] = other; + other.m_flags |= b2Body.e_islandFlag; + } + } + + var subStep = new b2TimeStep(); + subStep.dt = (1.0 - minTOI) * step.dt; + + subStep.inv_dt = 1.0 / subStep.dt; + subStep.maxIterations = step.maxIterations; + + island.SolveTOI(subStep); + + var i = 0; + + for (i = 0; i < island.m_bodyCount; ++i) + { + + b = island.m_bodies[i]; + b.m_flags &= ~b2Body.e_islandFlag; + + if (b.m_flags & (b2Body.e_sleepFlag | b2Body.e_frozenFlag)) + { + continue; + } + + if (b.IsStatic()) + { + continue; + } + + + + + var inRange = b.SynchronizeShapes(); + + + if (inRange == false && this.m_boundaryListener != null) + { + this.m_boundaryListener.Violation(b); + } + + + + for (cn = b.m_contactList; cn; cn = cn.next) + { + cn.contact.m_flags &= ~b2Contact.e_toiFlag; + } + } + + for (i = 0; i < island.m_contactCount; ++i) + { + + c = island.m_contacts[i]; + c.m_flags &= ~(b2Contact.e_toiFlag | b2Contact.e_islandFlag); + } + + + + this.m_broadPhase.Commit(); + } + + + + } +b2World.prototype.DrawJoint = function (joint) { + + var b1 = joint.m_body1; + var b2 = joint.m_body2; + var xf1 = b1.m_xf; + var xf2 = b2.m_xf; + var x1 = xf1.position; + var x2 = xf2.position; + var p1 = joint.GetAnchor1(); + var p2 = joint.GetAnchor2(); + + + var color = b2World.s_jointColor; + + switch (joint.m_type) + { + case b2Joint.e_distanceJoint: + this.m_debugDraw.DrawSegment(p1, p2, color); + break; + + case b2Joint.e_pulleyJoint: + { + var pulley = (joint); + var s1 = pulley.GetGroundAnchor1(); + var s2 = pulley.GetGroundAnchor2(); + this.m_debugDraw.DrawSegment(s1, p1, color); + this.m_debugDraw.DrawSegment(s2, p2, color); + this.m_debugDraw.DrawSegment(s1, s2, color); + } + break; + + case b2Joint.e_mouseJoint: + this.m_debugDraw.DrawSegment(p1, p2, color); + break; + + default: + if (b1 != this.m_groundBody) + this.m_debugDraw.DrawSegment(x1, p1, color); + this.m_debugDraw.DrawSegment(p1, p2, color); + if (b2 != this.m_groundBody) + this.m_debugDraw.DrawSegment(x2, p2, color); + } + } +b2World.prototype.DrawShape = function (shape, xf, color, core) { + + var coreColor = b2World.s_coreColor; + + switch (shape.m_type) + { + case b2Shape.e_circleShape: + { + var circle = (shape); + + var center = b2Math.b2MulX(xf, circle.m_localPosition); + var radius = circle.m_radius; + var axis = xf.R.col1; + + this.m_debugDraw.DrawSolidCircle(center, radius, axis, color); + + if (core) + { + this.m_debugDraw.DrawCircle(center, radius - b2Settings.b2_toiSlop, coreColor); + } + } + break; + + case b2Shape.e_polygonShape: + { + var i = 0; + var poly = (shape); + var vertexCount = poly.GetVertexCount(); + var localVertices = poly.GetVertices(); + + + var vertices = new Array(b2Settings.b2_maxPolygonVertices); + + for (i = 0; i < vertexCount; ++i) + { + vertices[i] = b2Math.b2MulX(xf, localVertices[i]); + } + + this.m_debugDraw.DrawSolidPolygon(vertices, vertexCount, color); + + if (core) + { + var localCoreVertices = poly.GetCoreVertices(); + for (i = 0; i < vertexCount; ++i) + { + vertices[i] = b2Math.b2MulX(xf, localCoreVertices[i]); + } + this.m_debugDraw.DrawPolygon(vertices, vertexCount, coreColor); + } + } + break; + } + } +b2World.prototype.DrawDebugData = function () { + + if (this.m_debugDraw == null) + { + return; + } + + this.m_debugDraw.m_sprite.graphics.clear(); + + var flags = this.m_debugDraw.GetFlags(); + + var i = 0; + var b; + var s; + var j; + var bp; + var invQ = new b2Vec2; + var x1 = new b2Vec2; + var x2 = new b2Vec2; + var color = new b2Color(0,0,0); + var xf; + var b1 = new b2AABB(); + var b2 = new b2AABB(); + var vs = [new b2Vec2(), new b2Vec2(), new b2Vec2(), new b2Vec2()]; + + if (flags & b2DebugDraw.e_shapeBit) + { + var core = (flags & b2DebugDraw.e_coreShapeBit) == b2DebugDraw.e_coreShapeBit; + + for (b = this.m_bodyList; b; b = b.m_next) + { + xf = b.m_xf; + for (s = b.GetShapeList(); s; s = s.m_next) + { + if (b.IsStatic()) + { + this.DrawShape(s, xf, new b2Color(0.5, 0.9, 0.5), core); + } + else if (b.IsSleeping()) + { + this.DrawShape(s, xf, new b2Color(0.5, 0.5, 0.9), core); + } + else + { + this.DrawShape(s, xf, new b2Color(0.9, 0.9, 0.9), core); + } + } + } + } + + if (flags & b2DebugDraw.e_jointBit) + { + for (j = this.m_jointList; j; j = j.m_next) + { + + + this.DrawJoint(j); + + } + } + + if (flags & b2DebugDraw.e_pairBit) + { + bp = this.m_broadPhase; + + invQ.Set(1.0 / bp.m_quantizationFactor.x, 1.0 / bp.m_quantizationFactor.y); + + color.Set(0.9, 0.9, 0.3); + + for (i = 0; i < b2Pair.b2_tableCapacity; ++i) + { + var index = bp.m_pairManager.m_hashTable[i]; + while (index != b2Pair.b2_nullPair) + { + var pair = bp.m_pairManager.m_pairs[ index ]; + var p1 = bp.m_proxyPool[ pair.proxyId1 ]; + var p2 = bp.m_proxyPool[ pair.proxyId2 ]; + + + b1.lowerBound.x = bp.m_worldAABB.lowerBound.x + invQ.x * bp.m_bounds[0][p1.lowerBounds[0]].value; + b1.lowerBound.y = bp.m_worldAABB.lowerBound.y + invQ.y * bp.m_bounds[1][p1.lowerBounds[1]].value; + b1.upperBound.x = bp.m_worldAABB.lowerBound.x + invQ.x * bp.m_bounds[0][p1.upperBounds[0]].value; + b1.upperBound.y = bp.m_worldAABB.lowerBound.y + invQ.y * bp.m_bounds[1][p1.upperBounds[1]].value; + b2.lowerBound.x = bp.m_worldAABB.lowerBound.x + invQ.x * bp.m_bounds[0][p2.lowerBounds[0]].value; + b2.lowerBound.y = bp.m_worldAABB.lowerBound.y + invQ.y * bp.m_bounds[1][p2.lowerBounds[1]].value; + b2.upperBound.x = bp.m_worldAABB.lowerBound.x + invQ.x * bp.m_bounds[0][p2.upperBounds[0]].value; + b2.upperBound.y = bp.m_worldAABB.lowerBound.y + invQ.y * bp.m_bounds[1][p2.upperBounds[1]].value; + + + x1.x = 0.5 * (b1.lowerBound.x + b1.upperBound.x); + x1.y = 0.5 * (b1.lowerBound.y + b1.upperBound.y); + + x2.x = 0.5 * (b2.lowerBound.x + b2.upperBound.x); + x2.y = 0.5 * (b2.lowerBound.y + b2.upperBound.y); + + this.m_debugDraw.DrawSegment(x1, x2, color); + + index = pair.next; + } + } + } + + if (flags & b2DebugDraw.e_aabbBit) + { + bp = this.m_broadPhase; + var worldLower = bp.m_worldAABB.lowerBound; + var worldUpper = bp.m_worldAABB.upperBound; + + + invQ.Set(1.0 / bp.m_quantizationFactor.x, 1.0 / bp.m_quantizationFactor.y); + + color.Set(0.9, 0.3, 0.9); + for (i = 0; i < b2Settings.b2_maxProxies; ++i) + { + var p = bp.m_proxyPool[ i]; + if (p.IsValid() == false) + { + continue; + } + + + b1.lowerBound.x = worldLower.x + invQ.x * bp.m_bounds[0][p.lowerBounds[0]].value; + b1.lowerBound.y = worldLower.y + invQ.y * bp.m_bounds[1][p.lowerBounds[1]].value; + b1.upperBound.x = worldLower.x + invQ.x * bp.m_bounds[0][p.upperBounds[0]].value; + b1.upperBound.y = worldLower.y + invQ.y * bp.m_bounds[1][p.upperBounds[1]].value; + + + vs[0].Set(b1.lowerBound.x, b1.lowerBound.y); + vs[1].Set(b1.upperBound.x, b1.lowerBound.y); + vs[2].Set(b1.upperBound.x, b1.upperBound.y); + vs[3].Set(b1.lowerBound.x, b1.upperBound.y); + + this.m_debugDraw.DrawPolygon(vs, 4, color); + } + + + vs[0].Set(worldLower.x, worldLower.y); + vs[1].Set(worldUpper.x, worldLower.y); + vs[2].Set(worldUpper.x, worldUpper.y); + vs[3].Set(worldLower.x, worldUpper.y); + this.m_debugDraw.DrawPolygon(vs, 4, new b2Color(0.3, 0.9, 0.9)); + } + + if (flags & b2DebugDraw.e_obbBit) + { + + color.Set(0.5, 0.3, 0.5); + + for (b = this.m_bodyList; b; b = b.m_next) + { + xf = b.m_xf; + for (s = b.GetShapeList(); s; s = s.m_next) + { + if (s.m_type != b2Shape.e_polygonShape) + { + continue; + } + + var poly = (s); + var obb = poly.GetOBB(); + var h = obb.extents; + + vs[0].Set(-h.x, -h.y); + vs[1].Set( h.x, -h.y); + vs[2].Set( h.x, h.y); + vs[3].Set(-h.x, h.y); + + for (i = 0; i < 4; ++i) + { + + var tMat = obb.R; + var tVec = vs[i]; + var tX; + tX = obb.center.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + vs[i].y = obb.center.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + vs[i].x = tX; + + tMat = xf.R; + tX = xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + vs[i].y = xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + vs[i].x = tX; + } + + this.m_debugDraw.DrawPolygon(vs, 4, color); + } + } + } + + if (flags & b2DebugDraw.e_centerOfMassBit) + { + for (b = this.m_bodyList; b; b = b.m_next) + { + xf = b2World.s_xf; + xf.R = b.m_xf.R; + xf.position = b.GetWorldCenter(); + this.m_debugDraw.DrawXForm(xf); + } + } + } +exports.b2World = b2World; diff --git a/networking/node_modules/box2d/package.json b/networking/node_modules/box2d/package.json new file mode 100644 index 0000000..e6f6adb --- /dev/null +++ b/networking/node_modules/box2d/package.json @@ -0,0 +1,24 @@ +{ + "name": "box2d", + "version": "1.0.0", + "description": "2D physics engine", + "homepage": "http://github.com/jadell/box2dnode", + "author": { + "name": "Josh Adell", + "email": "josh.adell@gmail.com", + "url": "http://everymansoftware.blogspot.com/" + }, + "main": "./box2dnode", + "engines": [ + "node" + ], + "_id": "box2d@1.0.0", + "dependencies": {}, + "devDependencies": {}, + "optionalDependencies": {}, + "_engineSupported": true, + "_npmVersion": "1.1.4", + "_nodeVersion": "v0.6.12", + "_defaultsLoaded": true, + "_from": "box2d" +} diff --git a/networking/node_modules/socket.io/.npmignore b/networking/node_modules/socket.io/.npmignore new file mode 100644 index 0000000..39e9864 --- /dev/null +++ b/networking/node_modules/socket.io/.npmignore @@ -0,0 +1,3 @@ +support +test +examples diff --git a/networking/node_modules/socket.io/.travis.yml b/networking/node_modules/socket.io/.travis.yml new file mode 100644 index 0000000..56eca03 --- /dev/null +++ b/networking/node_modules/socket.io/.travis.yml @@ -0,0 +1,6 @@ +language: node_js +node_js: + - 0.6 + +notifications: + irc: "irc.freenode.org#socket.io" diff --git a/networking/node_modules/socket.io/History.md b/networking/node_modules/socket.io/History.md new file mode 100644 index 0000000..23549d7 --- /dev/null +++ b/networking/node_modules/socket.io/History.md @@ -0,0 +1,260 @@ + +0.9.6 / 2012-04-17 +================== + + * Fixed XSS in jsonp-polling. + +0.9.5 / 2012-04-05 +================== + + * Added test for polling and socket close. + * Ensure close upon request close. + * Fix disconnection reason being lost for polling transports. + * Ensure that polling transports work with Connection: close. + * Log disconnection reason. + +0.9.4 / 2012-04-01 +================== + + * Disconnecting from namespace improvement (#795) [DanielBaulig] + * Bumped client with polling reconnection loop (#438) + +0.9.3 / 2012-03-28 +================== + + * Fix "Syntax error" on FF Web Console with XHR Polling [mikito] + +0.9.2 / 2012-03-13 +================== + + * More sensible close `timeout default` (fixes disconnect issue) + +0.9.1-1 / 2012-03-02 +==================== + + * Bumped client with NPM dependency fix. + +0.9.1 / 2012-03-02 +================== + + * Changed heartbeat timeout and interval defaults (60 and 25 seconds) + * Make tests work both on 0.4 and 0.6 + * Updated client (improvements + bug fixes). + +0.9.0 / 2012-02-26 +================== + + * Make it possible to use a regexp to match the socket.io resource URL. + We need this because we have to prefix the socket.io URL with a variable ID. + * Supplemental fix to gavinuhma/authfix, it looks like the same Access-Control-Origin logic is needed in the http and xhr-polling transports + * Updated express dep for windows compatibility. + * Combine two substr calls into one in decodePayload to improve performance + * Minor documentation fix + * Minor. Conform to style of other files. + * Switching setting to 'match origin protocol' + * Revert "Fixes leaking Redis subscriptions for #663. The local flag was not getting passed through onClientDisconnect()." + * Revert "Handle leaked dispatch:[id] subscription." + * Merge pull request #667 from dshaw/patch/redis-disconnect + * Handle leaked dispatch:[id] subscription. + * Fixes leaking Redis subscriptions for #663. The local flag was not getting passed through onClientDisconnect(). + * Prevent memory leaking on uncompleted requests & add max post size limitation + * Fix for testcase + * Set Access-Control-Allow-Credentials true, regardless of cookie + * Remove assertvarnish from package as it breaks on 0.6 + * Correct irc channel + * Added proper return after reserved field error + * Fixes manager.js failure to close connection after transport error has happened + * Added implicit port 80 for origin checks. fixes #638 + * Fixed bug #432 in 0.8.7 + * Set Access-Control-Allow-Origin header to origin to enable withCredentials + * Adding configuration variable matchOriginProtocol + * Fixes location mismatch error in Safari. + * Use tty to detect if we should add colors or not by default. + * Updated the package location. + +0.8.7 / 2011-11-05 +================== + + * Fixed memory leaks in closed clients. + * Fixed memory leaks in namespaces. + * Fixed websocket handling for malformed requests from proxies. [einaros] + * Node 0.6 compatibility. [einaros] [3rd-Eden] + * Adapted tests and examples. + +0.8.6 / 2011-10-27 +================== + + * Added JSON decoding on jsonp-polling transport. + * Fixed README example. + * Major speed optimizations [3rd-Eden] [einaros] [visionmedia] + * Added decode/encode benchmarks [visionmedia] + * Added support for black-listing client sent events. + * Fixed logging options, closes #540 [3rd-Eden] + * Added vary header for gzip [3rd-Eden] + * Properly cleaned up async websocket / flashsocket tests, after patching node-websocket-client + * Patched to properly shut down when a finishClose call is made during connection establishment + * Added support for socket.io version on url and far-future Expires [3rd-Eden] [getify] + * Began IE10 compatibility [einaros] [tbranyen] + * Misc WebSocket fixes [einaros] + * Added UTF8 to respone headers for htmlfile [3rd-Eden] + +0.8.5 / 2011-10-07 +================== + + * Added websocket draft HyBi-16 support. [einaros] + * Fixed websocket continuation bugs. [einaros] + * Fixed flashsocket transport name. + * Fixed websocket tests. + * Ensured `parser#decodePayload` doesn't choke. + * Added http referrer verification to manager verifyOrigin. + * Added access control for cross domain xhr handshakes [3rd-Eden] + * Added support for automatic generation of socket.io files [3rd-Eden] + * Added websocket binary support [einaros] + * Added gzip support for socket.io.js [3rd-Eden] + * Expose socket.transport [3rd-Eden] + * Updated client. + +0.8.4 / 2011-09-06 +================== + + * Client build + +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 +================== + + * Fixed double dispatch handling with emit to closed clients. + * Added test for emitting to closed clients to prevent regression. + * Fixed race condition in redis test. + * Changed Transport#end instrumentation. + * Leveraged $emit instead of emit internally. + * Made tests faster. + * Fixed double disconnect events. + * Fixed disconnect logic + * Simplified remote events handling in Socket. + * Increased testcase timeout. + * Fixed unknown room emitting (GH-291). [3rd-Eden] + * Fixed `address` in handshakeData. [3rd-Eden] + * Removed transports definition in chat example. + * Fixed room cleanup + * Fixed; make sure the client is cleaned up after booting. + * Make sure to mark the client as non-open if the connection is closed. + * Removed unneeded `buffer` declarations. + * Fixed; make sure to clear socket handlers and subscriptions upon transport close. + +0.7.6 / 2011-06-30 +================== + + * Fixed general dispatching when a client has closed. + +0.7.5 / 2011-06-30 +================== + + * Fixed dispatching to clients that are disconnected. + +0.7.4 / 2011-06-30 +================== + + * Fixed; only clear handlers if they were set. [level09] + +0.7.3 / 2011-06-30 +================== + + * Exposed handshake data to clients. + * Refactored dispatcher interface. + * Changed; Moved id generation method into the manager. + * Added sub-namespace authorization. [3rd-Eden] + * Changed; normalized SocketNamespace local eventing [dvv] + * Changed; Use packet.reason or default to 'packet' [3rd-Eden] + * Changed console.error to console.log. + * Fixed; bind both servers at the same time do that the test never times out. + * Added 304 support. + * Removed `Transport#name` for abstract interface. + * Changed; lazily require http and https module only when needed. [3rd-Eden] + +0.7.2 / 2011-06-22 +================== + + * Make sure to write a packet (of type `noop`) when closing a poll. + This solves a problem with cross-domain requests being flagged as aborted and + reconnection being triggered. + * Added `noop` message type. + +0.7.1 / 2011-06-21 +================== + + * Fixed cross-domain XHR. + * Added CORS test to xhr-polling suite. + +0.7.0 / 2010-06-21 +================== + + * http://socket.io/announcement.html diff --git a/networking/node_modules/socket.io/Makefile b/networking/node_modules/socket.io/Makefile new file mode 100644 index 0000000..832cba8 --- /dev/null +++ b/networking/node_modules/socket.io/Makefile @@ -0,0 +1,31 @@ + +ALL_TESTS = $(shell find test/ -name '*.test.js') +ALL_BENCH = $(shell find benchmarks -name '*.bench.js') + +run-tests: + @./node_modules/.bin/expresso \ + -t 3000 \ + -I support \ + --serial \ + $(TESTFLAGS) \ + $(TESTS) + +test: + @$(MAKE) NODE_PATH=lib TESTS="$(ALL_TESTS)" run-tests + +test-cov: + @TESTFLAGS=--cov $(MAKE) test + +test-leaks: + @ls test/leaks/* | xargs node --expose_debug_as=debug --expose_gc + +run-bench: + @node $(PROFILEFLAGS) benchmarks/runner.js + +bench: + @$(MAKE) BENCHMARKS="$(ALL_BENCH)" run-bench + +profile: + @PROFILEFLAGS='--prof --trace-opt --trace-bailout --trace-deopt' $(MAKE) bench + +.PHONY: test bench profile diff --git a/networking/node_modules/socket.io/Readme.md b/networking/node_modules/socket.io/Readme.md new file mode 100644 index 0000000..2a03a12 --- /dev/null +++ b/networking/node_modules/socket.io/Readme.md @@ -0,0 +1,345 @@ +# Socket.IO + +Socket.IO is a Node.JS project that makes WebSockets and realtime possible in +all browsers. It also enhances WebSockets by providing built-in multiplexing, +horizontal scalability, automatic JSON encoding/decoding, and more. + +## How to Install + +```bash +npm install socket.io +``` + +## How to use + +First, require `socket.io`: + +```js +var io = require('socket.io'); +``` + +Next, attach it to a HTTP/HTTPS server. If you're using the fantastic `express` +web framework: + +```js +var app = express.createServer() + , io = io.listen(app); + +app.listen(80); + +io.sockets.on('connection', function (socket) { + socket.emit('news', { hello: 'world' }); + socket.on('my other event', function (data) { + console.log(data); + }); +}); +``` + +Finally, load it from the client side code: + +```html + + +``` + +For more thorough examples, look at the `examples/` directory. + +## Short recipes + +### Sending and receiving events. + +Socket.IO allows you to emit and receive custom events. +Besides `connect`, `message` and `disconnect`, you can emit custom events: + +```js +// note, io.listen() will create a http server for you +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + 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); + }); + + socket.on('disconnect', function () { + io.sockets.emit('user disconnected'); + }); +}); +``` + +### Storing data associated to a client + +Sometimes it's necessary to store data associated with a client that's +necessary for the duration of the session. + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.on('set nickname', function (name) { + socket.set('nickname', name, function () { socket.emit('ready'); }); + }); + + socket.on('msg', function () { + socket.get('nickname', function (err, name) { + console.log('Chat message by ', name); + }); + }); +}); +``` + +#### Client side + +```html + +``` + +### Restricting yourself to a namespace + +If you have control over all the messages and events emitted for a particular +application, using the default `/` namespace works. + +If you want to leverage 3rd-party code, or produce code to share with others, +socket.io provides a way of namespacing a `socket`. + +This has the benefit of `multiplexing` a single connection. Instead of +socket.io using two `WebSocket` connections, it'll use one. + +The following example defines a socket that listens on '/chat' and one for +'/news': + +#### Server side + +```js +var io = require('socket.io').listen(80); + +var chat = io + .of('/chat') + .on('connection', function (socket) { + socket.emit('a message', { that: 'only', '/chat': 'will get' }); + chat.emit('a message', { everyone: 'in', '/chat': 'will get' }); + }); + +var news = io + .of('/news'); + .on('connection', function (socket) { + socket.emit('item', { news: 'item' }); + }); +``` + +#### Client side: + +```html + +``` + +### Sending volatile messages. + +Sometimes certain messages can be dropped. Let's say you have an app that +shows realtime tweets for the keyword `bieber`. + +If a certain client is not ready to receive messages (because of network slowness +or other issues, or because he's connected through long polling and is in the +middle of a request-response cycle), if he doesn't receive ALL the tweets related +to bieber your application won't suffer. + +In that case, you might want to send those messages as volatile messages. + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + var tweets = setInterval(function () { + getBieberTweet(function (tweet) { + socket.volatile.emit('bieber tweet', tweet); + }); + }, 100); + + socket.on('disconnect', function () { + clearInterval(tweets); + }); +}); +``` + +#### Client side + +In the client side, messages are received the same way whether they're volatile +or not. + +### Getting acknowledgements + +Sometimes, you might want to get a callback when the client confirmed the message +reception. + +To do this, simply pass a function as the last parameter of `.send` or `.emit`. +What's more, when you use `.emit`, the acknowledgement is done by you, which +means you can also pass data along: + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.on('ferret', function (name, fn) { + fn('woot'); + }); +}); +``` + +#### Client side + +```html + +``` + +### Broadcasting messages + +To broadcast, simply add a `broadcast` flag to `emit` and `send` method calls. +Broadcasting means sending a message to everyone else except for the socket +that starts it. + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.broadcast.emit('user connected'); + socket.broadcast.json.send({ a: 'message' }); +}); +``` + +### Rooms + +Sometimes you want to put certain sockets in the same room, so that it's easy +to broadcast to all of them together. + +Think of this as built-in channels for sockets. Sockets `join` and `leave` +rooms in each socket. + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.join('justin bieber fans'); + socket.broadcast.to('justin bieber fans').emit('new fan'); + io.sockets.in('rammstein fans').emit('new non-fan'); +}); +``` + +### Using it just as a cross-browser WebSocket + +If you just want the WebSocket semantics, you can do that too. +Simply leverage `send` and listen on the `message` event: + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.on('message', function () { }); + socket.on('disconnect', function () { }); +}); +``` + +#### Client side + +```html + +``` + +### Changing configuration + +Configuration in socket.io is TJ-style: + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.configure(function () { + io.set('transports', ['websocket', 'flashsocket', 'xhr-polling']); +}); + +io.configure('development', function () { + io.set('transports', ['websocket', 'xhr-polling']); + io.enable('log'); +}); +``` + +## License + +(The MIT License) + +Copyright (c) 2011 Guillermo Rauch <guillermo@learnboost.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS 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/networking/node_modules/socket.io/benchmarks/decode.bench.js b/networking/node_modules/socket.io/benchmarks/decode.bench.js new file mode 100644 index 0000000..4855d80 --- /dev/null +++ b/networking/node_modules/socket.io/benchmarks/decode.bench.js @@ -0,0 +1,64 @@ + +/** + * Module dependencies. + */ + +var benchmark = require('benchmark') + , colors = require('colors') + , io = require('../') + , parser = io.parser + , suite = new benchmark.Suite('Decode packet'); + +suite.add('string', function () { + parser.decodePacket('4:::"2"'); +}); + +suite.add('event', function () { + parser.decodePacket('5:::{"name":"woot"}'); +}); + +suite.add('event+ack', function () { + parser.decodePacket('5:1+::{"name":"tobi"}'); +}); + +suite.add('event+data', function () { + parser.decodePacket('5:::{"name":"edwald","args":[{"a": "b"},2,"3"]}'); +}); + +suite.add('heartbeat', function () { + parser.decodePacket('2:::'); +}); + +suite.add('error', function () { + parser.decodePacket('7:::2+0'); +}); + +var payload = parser.encodePayload([ + parser.encodePacket({ type: 'message', data: '5', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: '53d', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: 'foobar', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: 'foobarbaz', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: 'foobarbazfoobarbaz', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: 'foobarbaz', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: 'foobar', endpoint: '' }) +]); + +suite.add('payload', function () { + parser.decodePayload(payload); +}); + +suite.on('cycle', function (bench, details) { + console.log('\n' + suite.name.grey, details.name.white.bold); + console.log([ + details.hz.toFixed(2).cyan + ' ops/sec'.grey + , details.count.toString().white + ' times executed'.grey + , 'benchmark took '.grey + details.times.elapsed.toString().white + ' sec.'.grey + , + ].join(', '.grey)); +}); + +if (!module.parent) { + suite.run(); +} else { + module.exports = suite; +} diff --git a/networking/node_modules/socket.io/benchmarks/encode.bench.js b/networking/node_modules/socket.io/benchmarks/encode.bench.js new file mode 100644 index 0000000..5037702 --- /dev/null +++ b/networking/node_modules/socket.io/benchmarks/encode.bench.js @@ -0,0 +1,90 @@ + +/** + * Module dependencies. + */ + +var benchmark = require('benchmark') + , colors = require('colors') + , io = require('../') + , parser = io.parser + , suite = new benchmark.Suite('Encode packet'); + +suite.add('string', function () { + parser.encodePacket({ + type: 'json' + , endpoint: '' + , data: '2' + }); +}); + +suite.add('event', function () { + parser.encodePacket({ + type: 'event' + , name: 'woot' + , endpoint: '' + , args: [] + }); +}); + +suite.add('event+ack', function () { + parser.encodePacket({ + type: 'json' + , id: 1 + , ack: 'data' + , endpoint: '' + , data: { a: 'b' } + }); +}); + +suite.add('event+data', function () { + parser.encodePacket({ + type: 'event' + , name: 'edwald' + , endpoint: '' + , args: [{a: 'b'}, 2, '3'] + }); +}); + +suite.add('heartbeat', function () { + parser.encodePacket({ + type: 'heartbeat' + , endpoint: '' + }) +}); + +suite.add('error', function () { + parser.encodePacket({ + type: 'error' + , reason: 'unauthorized' + , advice: 'reconnect' + , endpoint: '' + }) +}) + +suite.add('payload', function () { + parser.encodePayload([ + parser.encodePacket({ type: 'message', data: '5', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: '53d', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: 'foobar', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: 'foobarbaz', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: 'foobarbazfoobarbaz', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: 'foobarbaz', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: 'foobar', endpoint: '' }) + ]); +}); + +suite.on('cycle', function (bench, details) { + console.log('\n' + suite.name.grey, details.name.white.bold); + console.log([ + details.hz.toFixed(2).cyan + ' ops/sec'.grey + , details.count.toString().white + ' times executed'.grey + , 'benchmark took '.grey + details.times.elapsed.toString().white + ' sec.'.grey + , + ].join(', '.grey)); +}); + +if (!module.parent) { + suite.run(); +} else { + module.exports = suite; +} diff --git a/networking/node_modules/socket.io/benchmarks/runner.js b/networking/node_modules/socket.io/benchmarks/runner.js new file mode 100644 index 0000000..81e55ca --- /dev/null +++ b/networking/node_modules/socket.io/benchmarks/runner.js @@ -0,0 +1,55 @@ +/** + * Benchmark runner dependencies + */ + +var colors = require('colors') + , path = require('path'); + +/** + * Find all the benchmarks + */ + +var benchmarks_files = process.env.BENCHMARKS.split(' ') + , all = [].concat(benchmarks_files) + , first = all.shift() + , benchmarks = {}; + +// find the benchmarks and load them all in our obj +benchmarks_files.forEach(function (file) { + benchmarks[file] = require(path.join(__dirname, '..', file)); +}); + +// setup the complete listeners +benchmarks_files.forEach(function (file) { + var benchmark = benchmarks[file] + , next_file = all.shift() + , next = benchmarks[next_file]; + + /** + * Generate a oncomplete function for the tests, either we are done or we + * have more benchmarks to process. + */ + + function complete () { + if (!next) { + console.log( + '\n\nBenchmark completed in'.grey + , (Date.now() - start).toString().green + ' ms'.grey + ); + } else { + console.log('\nStarting benchmark '.grey + next_file.yellow); + next.run(); + } + } + + // attach the listener + benchmark.on('complete', complete); +}); + +/** + * Start the benchmark + */ + +var start = Date.now(); +console.log('Starting benchmark '.grey + first.yellow); +benchmarks[first].run(); diff --git a/networking/node_modules/socket.io/examples/chat/app.js b/networking/node_modules/socket.io/examples/chat/app.js new file mode 100644 index 0000000..bdfad2a --- /dev/null +++ b/networking/node_modules/socket.io/examples/chat/app.js @@ -0,0 +1,80 @@ +/** + * Module dependencies. + */ + +var express = require('express') + , stylus = require('stylus') + , nib = require('nib') + , sio = require('../../lib/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/networking/node_modules/socket.io/examples/chat/index.jade b/networking/node_modules/socket.io/examples/chat/index.jade new file mode 100644 index 0000000..0633d8b --- /dev/null +++ b/networking/node_modules/socket.io/examples/chat/index.jade @@ -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($('

').append($('').text(msg))); + }); + + socket.on('nicknames', function (nicknames) { + $('#nicknames').empty().append($('Online: ')); + for (var i in nicknames) { + $('#nicknames').append($('').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($('

').append($('').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/networking/node_modules/socket.io/examples/chat/package.json b/networking/node_modules/socket.io/examples/chat/package.json new file mode 100644 index 0000000..6b375b0 --- /dev/null +++ b/networking/node_modules/socket.io/examples/chat/package.json @@ -0,0 +1,11 @@ +{ + "name": "chat.io" + , "description": "example chat application with socket.io" + , "version": "0.0.1" + , "dependencies": { + "express": "2.5.5" + , "jade": "0.16.4" + , "stylus": "0.19.0" + , "nib": "0.2.0" + } +} diff --git a/networking/node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl b/networking/node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl new file mode 100644 index 0000000..fb5644c --- /dev/null +++ b/networking/node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl @@ -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/networking/node_modules/socket.io/examples/chat/public/stylesheets/style.css b/networking/node_modules/socket.io/examples/chat/public/stylesheets/style.css new file mode 100644 index 0000000..42cf98f --- /dev/null +++ b/networking/node_modules/socket.io/examples/chat/public/stylesheets/style.css @@ -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/networking/node_modules/socket.io/examples/chat/public/stylesheets/style.styl b/networking/node_modules/socket.io/examples/chat/public/stylesheets/style.styl new file mode 100644 index 0000000..6289c94 --- /dev/null +++ b/networking/node_modules/socket.io/examples/chat/public/stylesheets/style.styl @@ -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/networking/node_modules/socket.io/examples/irc-output/app.js b/networking/node_modules/socket.io/examples/irc-output/app.js new file mode 100644 index 0000000..784886a --- /dev/null +++ b/networking/node_modules/socket.io/examples/irc-output/app.js @@ -0,0 +1,74 @@ +/** + * Module dependencies. + */ + +var express = require('express') + , stylus = require('stylus') + , nib = require('nib') + , sio = require('../../lib/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/networking/node_modules/socket.io/examples/irc-output/index.jade b/networking/node_modules/socket.io/examples/irc-output/index.jade new file mode 100644 index 0000000..5468632 --- /dev/null +++ b/networking/node_modules/socket.io/examples/irc-output/index.jade @@ -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($('

').append($('').text(msg))); + $('#messages').get(0).scrollTop = 10000000; + }); + + socket.on('irc message', function (user, msg) { + $('#messages').append($('

').append($('').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/networking/node_modules/socket.io/examples/irc-output/irc.js b/networking/node_modules/socket.io/examples/irc-output/irc.js new file mode 100644 index 0000000..cc679d5 --- /dev/null +++ b/networking/node_modules/socket.io/examples/irc-output/irc.js @@ -0,0 +1,164 @@ +/** + * From https://github.com/felixge/nodelog/ + */ + +var sys = require('util'); +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] +}; diff --git a/networking/node_modules/socket.io/examples/irc-output/package.json b/networking/node_modules/socket.io/examples/irc-output/package.json new file mode 100644 index 0000000..665ee33 --- /dev/null +++ b/networking/node_modules/socket.io/examples/irc-output/package.json @@ -0,0 +1,10 @@ +{ + "name": "socket.io-irc" + , "version": "0.0.1" + , "dependencies": { + "express": "2.5.5" + , "jade": "0.16.4" + , "stylus": "0.19.0" + , "nib": "0.2.0" + } +} diff --git a/networking/node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl b/networking/node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl new file mode 100644 index 0000000..2713512 --- /dev/null +++ b/networking/node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl @@ -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 diff --git a/networking/node_modules/socket.io/index.js b/networking/node_modules/socket.io/index.js new file mode 100644 index 0000000..cc00c10 --- /dev/null +++ b/networking/node_modules/socket.io/index.js @@ -0,0 +1,8 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +module.exports = require('./lib/socket.io'); diff --git a/networking/node_modules/socket.io/lib/client.js b/networking/node_modules/socket.io/lib/client.js new file mode 100644 index 0000000..d80067b --- /dev/null +++ b/networking/node_modules/socket.io/lib/client.js @@ -0,0 +1,167 @@ + +/** + * Module dependencies. + */ + +var parser = require('socket.io-client').parser + , EventEmitter = require('events').EventEmitter + +/** + * Client constructor. + * + * @api public + */ + +function Client (id, server) { + this.id = id; + this.acks = {}; + this.store = server.store; + + var self = this; + + store.subscribe(id, function (packet) { + + }); + + store.subscribe(id + '.disconect', function () { + self.onDisconnect(); + }); +} + +/** + * Inherits from EventEmitter. + */ + +Client.prototype.__proto__ = EventEmitter.prototype; + +/** + * Save reference to original `emit`. + * + * @api private + */ + +Client.prototype._emit = Client.prototype.emit; + +/** + * Broadcast flag. + * + * @api public + */ + +Client.prototype.__defineGetter__('broadcast', function () { + this.flags.broadcast = true; +}); + +/** + * JSON flag (deprecated) + * + * @api public + */ + +Client.prototype.__defineGetter__('json', function () { + this.flags.broadcast = true; +}); + +/** + * Joins a group. + * + * @param {String} group + * @return {Client} for chaining + * @api public + */ + +Client.prototype.join = function (group, fn) { + if (!~this.subscriptions.indexOf(group)) { + var self = this; + this.subscriptions.push(group); + this.store.addToGroup(group, this.sid, function (ev, args) { + self.onGroupEvent(ev, args); + }, fn); + } else { + fn && fn(); + } + + return this; +}; + +/** + * Leaves a group. + * + * @return {Client} for chaining + * @api public + */ + +Client.prototype.leave = function (group) { + var index = this.subscriptions.indexOf(group); + if (~index) { + this.subscriptions.splice(index, 1); + } + return this; +}; + +Client.prototype.disconnect = function () { + if (this.socket) { + this.socket.disconnect(); + } else { + this.publish('disconnect'); + } +} + +/** + * Called upon disconnect. + * + * @api private + */ + +Client.prototype.onDisconnect = function () { + for (var i = 0, l = this.subscriptions; i < l; i++) { + this.store.removeFromGroup(id, group, fn); + } +}; + +/** + * Registers ACK. + */ + +Client.prototype.ack = function (fn, callback) { + this.subscribe('ack'); +}; + +/** + * Emits an event. + */ + +Client.prototype.emit = function () { + var args = toArray(arguments), fn; + + if ('function' == typeof args[args.length - 1]) { + fn = args.pop(); + } + + var data = args.shift(); + if (args.length) { + data += '\n' + JSON.stringify(args); + } + + if (fn) { + this.ack(fn, function (id) { + self.sendPacket('event', data, id); + }); + } else { + this.sendPacket('event', data); + } + + return this; +}; + +/** + * Sends a packet. + */ + +Client.prototype.sendPacket = function (type, data, id) { + var data = parser.encode({ type: type, data: data, id: id }); + + if (this.server.sockets[id]) { + this.server.sockets[id].write(data); + } +}; diff --git a/networking/node_modules/socket.io/lib/logger.js b/networking/node_modules/socket.io/lib/logger.js new file mode 100644 index 0000000..49d02c9 --- /dev/null +++ b/networking/node_modules/socket.io/lib/logger.js @@ -0,0 +1,97 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var util = require('./util') + , toArray = util.toArray; + +/** + * Log levels. + */ + +var levels = [ + 'error' + , 'warn' + , 'info' + , 'debug' +]; + +/** + * Colors for log levels. + */ + +var colors = [ + 31 + , 33 + , 36 + , 90 +]; + +/** + * Pads the nice output to the longest log level. + */ + +function pad (str) { + var max = 0; + + for (var i = 0, l = levels.length; i < l; i++) + max = Math.max(max, levels[i].length); + + if (str.length < max) + return str + new Array(max - str.length + 1).join(' '); + + return str; +}; + +/** + * Logger (console). + * + * @api public + */ + +var Logger = module.exports = function (opts) { + opts = opts || {} + this.colors = false !== opts.colors; + this.level = 3; + this.enabled = true; +}; + +/** + * Log method. + * + * @api public + */ + +Logger.prototype.log = function (type) { + var index = levels.indexOf(type); + + if (index > this.level || !this.enabled) + return this; + + console.log.apply( + console + , [this.colors + ? ' \033[' + colors[index] + 'm' + pad(type) + ' -\033[39m' + : type + ':' + ].concat(toArray(arguments).slice(1)) + ); + + return this; +}; + +/** + * Generate methods. + */ + +levels.forEach(function (name) { + Logger.prototype[name] = function () { + this.log.apply(this, [name].concat(toArray(arguments))); + }; +}); diff --git a/networking/node_modules/socket.io/lib/manager.js b/networking/node_modules/socket.io/lib/manager.js new file mode 100644 index 0000000..6121662 --- /dev/null +++ b/networking/node_modules/socket.io/lib/manager.js @@ -0,0 +1,984 @@ +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , url = require('url') + , tty = require('tty') + , util = require('./util') + , store = require('./store') + , client = require('socket.io-client') + , transports = require('./transports') + , Logger = require('./logger') + , Socket = require('./socket') + , MemoryStore = require('./stores/memory') + , SocketNamespace = require('./namespace') + , Static = require('./static') + , EventEmitter = process.EventEmitter; + +/** + * Export the constructor. + */ + +exports = module.exports = Manager; + +/** + * Default transports. + */ + +var defaultTransports = exports.defaultTransports = [ + 'websocket' + , 'htmlfile' + , 'xhr-polling' + , 'jsonp-polling' +]; + +/** + * Inherited defaults. + */ + +var parent = module.parent.exports + , protocol = parent.protocol + , jsonpolling_re = /^\d+$/; + +/** + * Manager constructor. + * + * @param {HTTPServer} server + * @param {Object} options, optional + * @api public + */ + +function Manager (server, options) { + this.server = server; + this.namespaces = {}; + this.sockets = this.of(''); + this.settings = { + origins: '*:*' + , log: true + , store: new MemoryStore + , logger: new Logger + , static: new Static(this) + , heartbeats: true + , resource: '/socket.io' + , transports: defaultTransports + , authorization: false + , blacklist: ['disconnect'] + , 'log level': 3 + , 'log colors': tty.isatty(process.stdout.fd) + , 'close timeout': 60 + , 'heartbeat interval': 25 + , 'heartbeat timeout': 60 + , 'polling duration': 20 + , 'flash policy server': true + , 'flash policy port': 10843 + , 'destroy upgrade': true + , 'destroy buffer size': 10E7 + , 'browser client': true + , 'browser client cache': true + , 'browser client minification': false + , 'browser client etag': false + , 'browser client expires': 315360000 + , 'browser client gzip': false + , 'browser client handler': false + , 'client store expiration': 15 + , 'match origin protocol': false + }; + + for (var i in options) { + this.settings[i] = options[i]; + } + + var self = this; + + // default error handler + server.on('error', function(err) { + self.log.warn('error raised: ' + err); + }); + + this.initStore(); + + this.on('set:store', function() { + self.initStore(); + }); + + // reset listeners + this.oldListeners = server.listeners('request'); + server.removeAllListeners('request'); + + server.on('request', function (req, res) { + self.handleRequest(req, res); + }); + + server.on('upgrade', function (req, socket, head) { + 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); + } + } + + // forward-compatibility with 1.0 + var self = this; + this.sockets.on('connection', function (conn) { + self.emit('connection', conn); + }); + + this.log.info('socket.io started'); +}; + +Manager.prototype.__proto__ = EventEmitter.prototype + +/** + * Store accessor shortcut. + * + * @api public + */ + +Manager.prototype.__defineGetter__('store', function () { + var store = this.get('store'); + store.manager = this; + return store; +}); + +/** + * Logger accessor. + * + * @api public + */ + +Manager.prototype.__defineGetter__('log', function () { + var logger = this.get('logger'); + + logger.level = this.get('log level') || -1; + logger.colors = this.get('log colors'); + logger.enabled = this.enabled('log'); + + return logger; +}); + +/** + * Static accessor. + * + * @api public + */ + +Manager.prototype.__defineGetter__('static', function () { + return this.get('static'); +}); + +/** + * Get settings. + * + * @api public + */ + +Manager.prototype.get = function (key) { + return this.settings[key]; +}; + +/** + * Set settings + * + * @api public + */ + +Manager.prototype.set = function (key, value) { + if (arguments.length == 1) return this.get(key); + this.settings[key] = value; + this.emit('set:' + key, this.settings[key], key); + return this; +}; + +/** + * Enable a setting + * + * @api public + */ + +Manager.prototype.enable = function (key) { + this.settings[key] = true; + this.emit('set:' + key, this.settings[key], key); + return this; +}; + +/** + * Disable a setting + * + * @api public + */ + +Manager.prototype.disable = function (key) { + this.settings[key] = false; + this.emit('set:' + key, this.settings[key], key); + return this; +}; + +/** + * Checks if a setting is enabled + * + * @api public + */ + +Manager.prototype.enabled = function (key) { + return !!this.settings[key]; +}; + +/** + * Checks if a setting is disabled + * + * @api public + */ + +Manager.prototype.disabled = function (key) { + return !this.settings[key]; +}; + +/** + * Configure callbacks. + * + * @api public + */ + +Manager.prototype.configure = function (env, fn) { + if ('function' == typeof env) { + env.call(this); + } else if (env == (process.env.NODE_ENV || 'development')) { + fn.call(this); + } + + return this; +}; + +/** + * Initializes everything related to the message dispatcher. + * + * @api private + */ + +Manager.prototype.initStore = function () { + this.handshaken = {}; + this.connected = {}; + this.open = {}; + this.closed = {}; + this.rooms = {}; + this.roomClients = {}; + + var self = this; + + this.store.subscribe('handshake', function (id, data) { + self.onHandshake(id, data); + }); + + this.store.subscribe('connect', function (id) { + self.onConnect(id); + }); + + this.store.subscribe('open', function (id) { + self.onOpen(id); + }); + + this.store.subscribe('join', function (id, room) { + self.onJoin(id, room); + }); + + this.store.subscribe('leave', function (id, room) { + self.onLeave(id, room); + }); + + this.store.subscribe('close', function (id) { + self.onClose(id); + }); + + this.store.subscribe('dispatch', function (room, packet, volatile, exceptions) { + self.onDispatch(room, packet, volatile, exceptions); + }); + + this.store.subscribe('disconnect', function (id) { + self.onDisconnect(id); + }); +}; + +/** + * Called when a client handshakes. + * + * @param text + */ + +Manager.prototype.onHandshake = function (id, data) { + this.handshaken[id] = data; +}; + +/** + * Called when a client connects (ie: transport first opens) + * + * @api private + */ + +Manager.prototype.onConnect = function (id) { + this.connected[id] = true; +}; + +/** + * Called when a client opens a request in a different node. + * + * @api private + */ + +Manager.prototype.onOpen = function (id) { + this.open[id] = true; + + // if we were buffering messages for the client, clear them + if (this.closed[id]) { + var self = this; + + this.store.unsubscribe('dispatch:' + id, function () { + delete self.closed[id]; + }); + } + + // clear the current transport + if (this.transports[id]) { + this.transports[id].discard(); + this.transports[id] = null; + } +}; + +/** + * Called when a message is sent to a namespace and/or room. + * + * @api private + */ + +Manager.prototype.onDispatch = function (room, packet, volatile, exceptions) { + if (this.rooms[room]) { + for (var i = 0, l = this.rooms[room].length; i < l; i++) { + var id = this.rooms[room][i]; + + if (!~exceptions.indexOf(id)) { + if (this.transports[id] && this.transports[id].open) { + this.transports[id].onDispatch(packet, volatile); + } else if (!volatile) { + this.onClientDispatch(id, packet); + } + } + } + } +}; + +/** + * Called when a client joins a nsp / room. + * + * @api private + */ + +Manager.prototype.onJoin = function (id, name) { + if (!this.roomClients[id]) { + this.roomClients[id] = {}; + } + + if (!this.rooms[name]) { + this.rooms[name] = []; + } + + if (!~this.rooms[name].indexOf(id)) { + this.rooms[name].push(id); + this.roomClients[id][name] = true; + } +}; + +/** + * Called when a client leaves a nsp / room. + * + * @param private + */ + +Manager.prototype.onLeave = function (id, room) { + if (this.rooms[room]) { + 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]; + } +}; + +/** + * Called when a client closes a request in different node. + * + * @api private + */ + +Manager.prototype.onClose = function (id) { + if (this.open[id]) { + delete this.open[id]; + } + + this.closed[id] = []; + + var self = this; + + this.store.subscribe('dispatch:' + id, function (packet, volatile) { + if (!volatile) { + self.onClientDispatch(id, packet); + } + }); +}; + +/** + * Dispatches a message for a closed client. + * + * @api private + */ + +Manager.prototype.onClientDispatch = function (id, packet) { + if (this.closed[id]) { + this.closed[id].push(packet); + } +}; + +/** + * Receives a message for a client. + * + * @api private + */ + +Manager.prototype.onClientMessage = function (id, packet) { + if (this.namespaces[packet.endpoint]) { + this.namespaces[packet.endpoint].handlePacket(id, packet); + } +}; + +/** + * Fired when a client disconnects (not triggered). + * + * @api private + */ + +Manager.prototype.onClientDisconnect = function (id, reason) { + for (var name in this.namespaces) { + this.namespaces[name].handleDisconnect(id, reason, typeof this.roomClients[id] !== 'undefined' && + typeof this.roomClients[id][name] !== 'undefined'); + } + + this.onDisconnect(id); +}; + +/** + * Called when a client disconnects. + * + * @param text + */ + +Manager.prototype.onDisconnect = function (id, local) { + delete this.handshaken[id]; + + if (this.open[id]) { + delete this.open[id]; + } + + if (this.connected[id]) { + delete this.connected[id]; + } + + if (this.transports[id]) { + this.transports[id].discard(); + delete this.transports[id]; + } + + if (this.closed[id]) { + delete this.closed[id]; + } + + if (this.roomClients[id]) { + for (var room in this.roomClients[id]) { + this.onLeave(id, room); + } + delete this.roomClients[id] + } + + this.store.destroyClient(id, this.get('client store expiration')); + + this.store.unsubscribe('dispatch:' + id); + + if (local) { + this.store.unsubscribe('message:' + id); + this.store.unsubscribe('disconnect:' + id); + } +}; + +/** + * Handles an HTTP request. + * + * @api private + */ + +Manager.prototype.handleRequest = function (req, res) { + var data = this.checkRequest(req); + + if (!data) { + for (var i = 0, l = this.oldListeners.length; i < l; i++) { + this.oldListeners[i].call(this.server, req, res); + } + + return; + } + + if (data.static || !data.transport && !data.protocol) { + if (data.static && this.enabled('browser client')) { + this.static.write(data.path, req, res); + } else { + res.writeHead(200); + res.end('Welcome to socket.io.'); + + this.log.info('unhandled socket.io url'); + } + + return; + } + + if (data.protocol != protocol) { + res.writeHead(500); + res.end('Protocol version not supported.'); + + this.log.info('client protocol version unsupported'); + } else { + if (data.id) { + this.handleHTTPRequest(data, req, res); + } else { + this.handleHandshake(data, req, res); + } + } +}; + +/** + * Handles an HTTP Upgrade. + * + * @api private + */ + +Manager.prototype.handleUpgrade = function (req, socket, head) { + var data = this.checkRequest(req) + , self = this; + + if (!data) { + if (this.enabled('destroy upgrade')) { + socket.end(); + this.log.debug('destroying non-socket.io upgrade'); + } + + return; + } + + req.head = head; + this.handleClient(data, req); +}; + +/** + * Handles a normal handshaken HTTP request (eg: long-polling) + * + * @api private + */ + +Manager.prototype.handleHTTPRequest = function (data, req, res) { + req.res = res; + this.handleClient(data, req); +}; + +/** + * Intantiantes a new client. + * + * @api private + */ + +Manager.prototype.handleClient = function (data, req) { + var socket = req.socket + , store = this.store + , self = this; + + if (undefined != data.query.disconnect) { + if (this.transports[data.id] && this.transports[data.id].open) { + this.transports[data.id].onForcedDisconnect(); + } else { + this.store.publish('disconnect-force:' + data.id); + } + return; + } + + if (!~this.get('transports').indexOf(data.transport)) { + this.log.warn('unknown transport: "' + data.transport + '"'); + req.connection.end(); + return; + } + + var transport = new transports[data.transport](this, data, req) + , handshaken = this.handshaken[data.id]; + + if (transport.disconnected) { + // failed during transport setup + req.connection.end(); + return; + } + if (handshaken) { + if (transport.open) { + if (this.closed[data.id] && this.closed[data.id].length) { + transport.payload(this.closed[data.id]); + this.closed[data.id] = []; + } + + this.onOpen(data.id); + this.store.publish('open', data.id); + this.transports[data.id] = transport; + } + + if (!this.connected[data.id]) { + 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); + + // echo back connect packet and fire connection event + if (i === '') { + this.namespaces[i].handlePacket(data.id, { type: 'connect' }); + } + } + + this.store.subscribe('message:' + data.id, function (packet) { + self.onClientMessage(data.id, packet); + }); + + this.store.subscribe('disconnect:' + data.id, function (reason) { + self.onClientDisconnect(data.id, reason); + }); + } + } else { + if (transport.open) { + transport.error('client not handshaken', 'reconnect'); + } + + transport.discard(); + } +}; + +/** + * Generates a session id. + * + * @api private + */ + +Manager.prototype.generateId = function () { + return Math.abs(Math.random() * Math.random() * Date.now() | 0).toString() + + Math.abs(Math.random() * Math.random() * Date.now() | 0).toString(); +}; + +/** + * Handles a handshake request. + * + * @api private + */ + +Manager.prototype.handleHandshake = function (data, req, res) { + var self = this + , origin = req.headers.origin + , headers = { + 'Content-Type': 'text/plain' + }; + + function writeErr (status, message) { + if (data.query.jsonp && jsonpolling_re.test(data.query.jsonp)) { + res.writeHead(200, { 'Content-Type': 'application/javascript' }); + res.end('io.j[' + data.query.jsonp + '](new Error("' + message + '"));'); + } else { + res.writeHead(status, headers); + res.end(message); + } + }; + + function error (err) { + writeErr(500, 'handshake error'); + self.log.warn('handshake error ' + err); + }; + + if (!this.verifyOrigin(req)) { + writeErr(403, 'handshake bad origin'); + return; + } + + var handshakeData = this.handshakeData(data); + + if (origin) { + // https://developer.mozilla.org/En/HTTP_Access_Control + headers['Access-Control-Allow-Origin'] = origin; + headers['Access-Control-Allow-Credentials'] = 'true'; + } + + this.authorize(handshakeData, function (err, authorized, newData) { + if (err) return error(err); + + if (authorized) { + var id = self.generateId() + , hs = [ + id + , self.enabled('heartbeats') ? self.get('heartbeat timeout') || '' : '' + , self.get('close timeout') || '' + , self.transports(data).join(',') + ].join(':'); + + if (data.query.jsonp && jsonpolling_re.test(data.query.jsonp)) { + hs = 'io.j[' + data.query.jsonp + '](' + JSON.stringify(hs) + ');'; + res.writeHead(200, { 'Content-Type': 'application/javascript' }); + } else { + res.writeHead(200, headers); + } + + res.end(hs); + + self.onHandshake(id, newData || handshakeData); + self.store.publish('handshake', id, newData || handshakeData); + + self.log.info('handshake authorized', id); + } else { + writeErr(403, 'handshake unauthorized'); + self.log.info('handshake unauthorized'); + } + }) +}; + +/** + * Gets normalized handshake data + * + * @api private + */ + +Manager.prototype.handshakeData = function (data) { + var connection = data.request.connection + , connectionAddress + , date = new Date; + + if (connection.remoteAddress) { + connectionAddress = { + address: connection.remoteAddress + , port: connection.remotePort + }; + } else if (connection.socket && connection.socket.remoteAddress) { + connectionAddress = { + address: connection.socket.remoteAddress + , port: connection.socket.remotePort + }; + } + + return { + headers: data.headers + , address: connectionAddress + , time: date.toString() + , query: data.query + , url: data.request.url + , xdomain: !!data.request.headers.origin + , secure: data.request.connection.secure + , issued: +date + }; +}; + +/** + * Verifies the origin of a request. + * + * @api private + */ + +Manager.prototype.verifyOrigin = function (request) { + var origin = request.headers.origin || request.headers.referer + , origins = this.get('origins'); + + if (origin === 'null') origin = '*'; + + if (origins.indexOf('*:*') !== -1) { + return true; + } + + if (origin) { + try { + var parts = url.parse(origin); + parts.port = parts.port || 80; + var ok = + ~origins.indexOf(parts.hostname + ':' + parts.port) || + ~origins.indexOf(parts.hostname + ':*') || + ~origins.indexOf('*:' + parts.port); + 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; +}; + +/** + * Handles an incoming packet. + * + * @api private + */ + +Manager.prototype.handlePacket = function (sessid, packet) { + this.of(packet.endpoint || '').handlePacket(sessid, packet); +}; + +/** + * Performs authentication. + * + * @param Object client request data + * @api private + */ + +Manager.prototype.authorize = function (data, fn) { + if (this.get('authorization')) { + var self = this; + + this.get('authorization').call(this, data, function (err, authorized) { + self.log.debug('client ' + authorized ? 'authorized' : 'unauthorized'); + fn(err, authorized); + }); + } else { + this.log.debug('client authorized'); + fn(null, true); + } + + return this; +}; + +/** + * Retrieves the transports adviced to the user. + * + * @api private + */ + +Manager.prototype.transports = function (data) { + var transp = this.get('transports') + , ret = []; + + for (var i = 0, l = transp.length; i < l; i++) { + var transport = transp[i]; + + if (transport) { + if (!transport.checkClient || transport.checkClient(data)) { + ret.push(transport); + } + } + } + + return ret; +}; + +/** + * Checks whether a request is a socket.io one. + * + * @return {Object} a client request data object or `false` + * @api private + */ + +var regexp = /^\/([^\/]+)\/?([^\/]+)?\/?([^\/]+)?\/?$/ + +Manager.prototype.checkRequest = function (req) { + var resource = this.get('resource'); + + var match; + if (typeof resource === 'string') { + match = req.url.substr(0, resource.length); + if (match !== resource) match = null; + } else { + match = resource.exec(req.url); + if (match) match = match[0]; + } + + if (match) { + var uri = url.parse(req.url.substr(match.length), true) + , path = uri.pathname || '' + , pieces = path.match(regexp); + + // client request data + var data = { + query: uri.query || {} + , headers: req.headers + , request: req + , path: path + }; + + if (pieces) { + data.protocol = Number(pieces[1]); + data.transport = pieces[2]; + data.id = pieces[3]; + data.static = !!this.static.has(path); + }; + + return data; + } + + return false; +}; + +/** + * Declares a socket namespace + * + * @api public + */ + +Manager.prototype.of = function (nsp) { + if (this.namespaces[nsp]) { + return this.namespaces[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]); + } + } +}; diff --git a/networking/node_modules/socket.io/lib/namespace.js b/networking/node_modules/socket.io/lib/namespace.js new file mode 100644 index 0000000..6e1e1c9 --- /dev/null +++ b/networking/node_modules/socket.io/lib/namespace.js @@ -0,0 +1,355 @@ +/** + * Module dependencies. + */ + +var Socket = require('./socket') + , EventEmitter = process.EventEmitter + , parser = require('./parser') + , util = require('./util'); + +/** + * Exports the constructor. + */ + +exports = module.exports = SocketNamespace; + +/** + * Constructor. + * + * @api public. + */ + +function SocketNamespace (mgr, name) { + this.manager = mgr; + this.name = name || ''; + this.sockets = {}; + this.auth = false; + this.setFlags(); +}; + +/** + * Inherits from EventEmitter. + */ + +SocketNamespace.prototype.__proto__ = EventEmitter.prototype; + +/** + * Copies emit since we override it. + * + * @api private + */ + +SocketNamespace.prototype.$emit = EventEmitter.prototype.emit; + +/** + * Retrieves all clients as Socket instances as an array. + * + * @api public + */ + +SocketNamespace.prototype.clients = function (room) { + var room = this.name + (room !== undefined ? + '/' + room : ''); + + if (!this.manager.rooms[room]) { + return []; + } + + return this.manager.rooms[room].map(function (id) { + return this.socket(id); + }, this); +}; + +/** + * Access logger interface. + * + * @api public + */ + +SocketNamespace.prototype.__defineGetter__('log', function () { + return this.manager.log; +}); + +/** + * Access store. + * + * @api public + */ + +SocketNamespace.prototype.__defineGetter__('store', function () { + return this.manager.store; +}); + +/** + * JSON message flag. + * + * @api public + */ + +SocketNamespace.prototype.__defineGetter__('json', function () { + this.flags.json = true; + return this; +}); + +/** + * Volatile message flag. + * + * @api public + */ + +SocketNamespace.prototype.__defineGetter__('volatile', function () { + this.flags.volatile = true; + return this; +}); + +/** + * Overrides the room to relay messages to (flag). + * + * @api public + */ + +SocketNamespace.prototype.in = SocketNamespace.prototype.to = function (room) { + this.flags.endpoint = this.name + (room ? '/' + room : ''); + return this; +}; + +/** + * Adds a session id we should prevent relaying messages to (flag). + * + * @api public + */ + +SocketNamespace.prototype.except = function (id) { + this.flags.exceptions.push(id); + return this; +}; + +/** + * Sets the default flags. + * + * @api private + */ + +SocketNamespace.prototype.setFlags = function () { + this.flags = { + endpoint: this.name + , exceptions: [] + }; + return this; +}; + +/** + * Sends out a packet. + * + * @api private + */ + +SocketNamespace.prototype.packet = function (packet) { + packet.endpoint = this.name; + + var store = this.store + , log = this.log + , volatile = this.flags.volatile + , exceptions = this.flags.exceptions + , packet = parser.encodePacket(packet); + + this.manager.onDispatch(this.flags.endpoint, packet, volatile, exceptions); + this.store.publish('dispatch', this.flags.endpoint, packet, volatile, exceptions); + + this.setFlags(); + + return this; +}; + +/** + * Sends to everyone. + * + * @api public + */ + +SocketNamespace.prototype.send = function (data) { + return this.packet({ + type: this.flags.json ? 'json' : 'message' + , data: data + }); +}; + +/** + * Emits to everyone (override). + * + * @api public + */ + +SocketNamespace.prototype.emit = function (name) { + if (name == 'newListener') { + return this.$emit.apply(this, arguments); + } + + return this.packet({ + type: 'event' + , name: name + , args: util.toArray(arguments).slice(1) + }); +}; + +/** + * Retrieves or creates a write-only socket for a client, unless specified. + * + * @param {Boolean} whether the socket will be readable when initialized + * @api public + */ + +SocketNamespace.prototype.socket = function (sid, readable) { + if (!this.sockets[sid]) { + this.sockets[sid] = new Socket(this.manager, sid, this, readable); + } + + return this.sockets[sid]; +}; + +/** + * Sets authorization for this namespace. + * + * @api public + */ + +SocketNamespace.prototype.authorization = function (fn) { + this.auth = fn; + return this; +}; + +/** + * Called when a socket disconnects entirely. + * + * @api private + */ + +SocketNamespace.prototype.handleDisconnect = function (sid, reason, raiseOnDisconnect) { + if (this.sockets[sid] && this.sockets[sid].readable) { + if (raiseOnDisconnect) this.sockets[sid].onDisconnect(reason); + delete this.sockets[sid]; + } +}; + +/** + * Performs authentication. + * + * @param Object client request data + * @api private + */ + +SocketNamespace.prototype.authorize = function (data, fn) { + if (this.auth) { + var self = this; + + this.auth.call(this, data, function (err, authorized) { + self.log.debug('client ' + + (authorized ? '' : 'un') + 'authorized for ' + self.name); + fn(err, authorized); + }); + } else { + this.log.debug('client authorized for ' + this.name); + fn(null, true); + } + + return this; +}; + +/** + * Handles a packet. + * + * @api private + */ + +SocketNamespace.prototype.handlePacket = function (sessid, packet) { + var socket = this.socket(sessid) + , dataAck = packet.ack == 'data' + , manager = this.manager + , self = this; + + function ack () { + self.log.debug('sending data ack packet'); + socket.packet({ + type: 'ack' + , args: util.toArray(arguments) + , ackId: packet.id + }); + }; + + function error (err) { + self.log.warn('handshake error ' + err + ' for ' + self.name); + socket.packet({ type: 'error', reason: err }); + }; + + function connect () { + self.manager.onJoin(sessid, self.name); + self.store.publish('join', sessid, self.name); + + // packet echo + socket.packet({ type: 'connect' }); + + // emit connection event + self.$emit('connection', socket); + }; + + switch (packet.type) { + case 'connect': + if (packet.endpoint == '') { + connect(); + } else { + var handshakeData = manager.handshaken[sessid]; + + this.authorize(handshakeData, function (err, authorized, newData) { + if (err) return error(err); + + if (authorized) { + manager.onHandshake(sessid, newData || handshakeData); + self.store.publish('handshake', sessid, newData || handshakeData); + connect(); + } else { + error('unauthorized'); + } + }); + } + break; + + case 'ack': + if (socket.acks[packet.ackId]) { + socket.acks[packet.ackId].apply(socket, packet.args); + } else { + this.log.info('unknown ack packet'); + } + break; + + case 'event': + // check if the emitted event is not blacklisted + if (-~manager.get('blacklist').indexOf(packet.name)) { + this.log.debug('ignoring blacklisted event `' + packet.name + '`'); + } else { + var params = [packet.name].concat(packet.args); + + if (dataAck) { + params.push(ack); + } + + socket.$emit.apply(socket, params); + } + break; + + case 'disconnect': + this.manager.onLeave(sessid, this.name); + this.store.publish('leave', sessid, this.name); + + socket.$emit('disconnect', packet.reason || 'packet'); + break; + + case 'json': + case 'message': + var params = ['message', packet.data]; + + if (dataAck) + params.push(ack); + + socket.$emit.apply(socket, params); + }; +}; diff --git a/networking/node_modules/socket.io/lib/parser.js b/networking/node_modules/socket.io/lib/parser.js new file mode 100644 index 0000000..d56b550 --- /dev/null +++ b/networking/node_modules/socket.io/lib/parser.js @@ -0,0 +1,249 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +/** + * Packet types. + */ + +var packets = exports.packets = { + 'disconnect': 0 + , 'connect': 1 + , 'heartbeat': 2 + , 'message': 3 + , 'json': 4 + , 'event': 5 + , 'ack': 6 + , 'error': 7 + , 'noop': 8 + } + , packetslist = Object.keys(packets); + +/** + * Errors reasons. + */ + +var reasons = exports.reasons = { + 'transport not supported': 0 + , 'client not handshaken': 1 + , 'unauthorized': 2 + } + , reasonslist = Object.keys(reasons); + +/** + * Errors advice. + */ + +var advice = exports.advice = { + 'reconnect': 0 + } + , advicelist = Object.keys(advice); + +/** + * Encodes a packet. + * + * @api private + */ + +exports.encodePacket = function (packet) { + var type = packets[packet.type] + , id = packet.id || '' + , endpoint = packet.endpoint || '' + , ack = packet.ack + , data = null; + + switch (packet.type) { + case 'message': + if (packet.data !== '') + data = packet.data; + break; + + case 'event': + var ev = { name: packet.name }; + + if (packet.args && packet.args.length) { + ev.args = packet.args; + } + + data = JSON.stringify(ev); + break; + + case 'json': + data = JSON.stringify(packet.data); + break; + + case 'ack': + data = packet.ackId + + (packet.args && packet.args.length + ? '+' + JSON.stringify(packet.args) : ''); + break; + + case 'connect': + if (packet.qs) + data = packet.qs; + break; + + case 'error': + var reason = packet.reason ? reasons[packet.reason] : '' + , adv = packet.advice ? advice[packet.advice] : '' + + if (reason !== '' || adv !== '') + data = reason + (adv !== '' ? ('+' + adv) : '') + + break; + } + + // construct packet with required fragments + var encoded = type + ':' + id + (ack == 'data' ? '+' : '') + ':' + endpoint; + + // data fragment is optional + if (data !== null && data !== undefined) + encoded += ':' + data; + + return encoded; +}; + +/** + * Encodes multiple messages (payload). + * + * @param {Array} messages + * @api private + */ + +exports.encodePayload = function (packets) { + var decoded = ''; + + if (packets.length == 1) + return packets[0]; + + for (var i = 0, l = packets.length; i < l; i++) { + var packet = packets[i]; + decoded += '\ufffd' + packet.length + '\ufffd' + packets[i] + } + + return decoded; +}; + +/** + * Decodes a packet + * + * @api private + */ + +var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/; + +/** + * Wrap the JSON.parse in a seperate function the crankshaft optimizer will + * only punish this function for the usage for try catch + * + * @api private + */ + +function parse (data) { + try { return JSON.parse(data) } + catch (e) { return false } +} + +exports.decodePacket = function (data) { + var pieces = data.match(regexp); + + if (!pieces) return {}; + + var id = pieces[2] || '' + , data = pieces[5] || '' + , packet = { + type: packetslist[pieces[1]] + , endpoint: pieces[4] || '' + }; + + // whether we need to acknowledge the packet + if (id) { + packet.id = id; + if (pieces[3]) + packet.ack = 'data'; + else + packet.ack = true; + } + + // handle different packet types + switch (packet.type) { + case 'message': + packet.data = data || ''; + break; + + case 'event': + pieces = parse(data); + if (pieces) { + packet.name = pieces.name; + packet.args = pieces.args; + } + + packet.args = packet.args || []; + break; + + case 'json': + packet.data = parse(data); + break; + + case 'connect': + packet.qs = data || ''; + break; + + case 'ack': + pieces = data.match(/^([0-9]+)(\+)?(.*)/); + if (pieces) { + packet.ackId = pieces[1]; + packet.args = []; + + if (pieces[3]) { + packet.args = parse(pieces[3]) || []; + } + } + break; + + case 'error': + pieces = data.split('+'); + packet.reason = reasonslist[pieces[0]] || ''; + packet.advice = advicelist[pieces[1]] || ''; + } + + return packet; +}; + +/** + * Decodes data payload. Detects multiple messages + * + * @return {Array} messages + * @api public + */ + +exports.decodePayload = function (data) { + if (undefined == data || null == data) { + return []; + } + + if (data[0] == '\ufffd') { + var ret = []; + + for (var i = 1, length = ''; i < data.length; i++) { + if (data[i] == '\ufffd') { + ret.push(exports.decodePacket(data.substr(i + 1, length))); + i += Number(length) + 1; + length = ''; + } else { + length += data[i]; + } + } + + return ret; + } else { + return [exports.decodePacket(data)]; + } +}; diff --git a/networking/node_modules/socket.io/lib/socket.io.js b/networking/node_modules/socket.io/lib/socket.io.js new file mode 100644 index 0000000..a459738 --- /dev/null +++ b/networking/node_modules/socket.io/lib/socket.io.js @@ -0,0 +1,136 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var client = require('socket.io-client'); + +/** + * Version. + */ + +exports.version = '0.9.5'; + +/** + * Supported protocol version. + */ + +exports.protocol = 1; + +/** + * Client that we serve. + */ + +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 + */ + +exports.listen = function (server, options, fn) { + if ('function' == typeof options) { + fn = options; + options = {}; + } + + if ('undefined' == typeof server) { + // create a server that listens on port 80 + server = 80; + } + + if ('number' == typeof server) { + // if a port number is passed + var port = server; + + if (options && options.key) + server = require('https').createServer(options); + else + server = require('http').createServer(); + + // default response + server.on('request', function (req, res) { + res.writeHead(200); + res.end('Welcome to socket.io.'); + }); + + server.listen(port, fn); + } + + // otherwise assume a http/s server + return new exports.Manager(server, options); +}; + +/** + * Manager constructor. + * + * @api public + */ + +exports.Manager = require('./manager'); + +/** + * Transport constructor. + * + * @api public + */ + +exports.Transport = require('./transport'); + +/** + * Socket constructor. + * + * @api public + */ + +exports.Socket = require('./socket'); + +/** + * Static constructor. + * + * @api public + */ + +exports.Static = require('./static'); + +/** + * Store constructor. + * + * @api public + */ + +exports.Store = require('./store'); + +/** + * Memory Store constructor. + * + * @api public + */ + +exports.MemoryStore = require('./stores/memory'); + +/** + * Redis Store constructor. + * + * @api public + */ + +exports.RedisStore = require('./stores/redis'); + +/** + * Parser. + * + * @api public + */ + +exports.parser = require('./parser'); diff --git a/networking/node_modules/socket.io/lib/socket.js b/networking/node_modules/socket.io/lib/socket.js new file mode 100644 index 0000000..d9807f6 --- /dev/null +++ b/networking/node_modules/socket.io/lib/socket.js @@ -0,0 +1,369 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var parser = require('./parser') + , util = require('./util') + , EventEmitter = process.EventEmitter + +/** + * Export the constructor. + */ + +exports = module.exports = Socket; + +/** + * Default error event listener to prevent uncaught exceptions. + */ + +var defaultError = function () {}; + +/** + * Socket constructor. + * + * @param {Manager} manager instance + * @param {String} session id + * @param {Namespace} namespace the socket belongs to + * @param {Boolean} whether the + * @api public + */ + +function Socket (manager, id, nsp, readable) { + this.id = id; + this.namespace = nsp; + this.manager = manager; + this.disconnected = false; + this.ackPackets = 0; + this.acks = {}; + this.setFlags(); + this.readable = readable; + this.store = this.manager.store.client(this.id); + this.on('error', defaultError); +}; + +/** + * Inherits from EventEmitter. + */ + +Socket.prototype.__proto__ = EventEmitter.prototype; + +/** + * Accessor shortcut for the handshake data + * + * @api private + */ + +Socket.prototype.__defineGetter__('handshake', function () { + return this.manager.handshaken[this.id]; +}); + +/** + * Accessor shortcut for the transport type + * + * @api private + */ + +Socket.prototype.__defineGetter__('transport', function () { + return this.manager.transports[this.id].name; +}); + +/** + * Accessor shortcut for the logger. + * + * @api private + */ + +Socket.prototype.__defineGetter__('log', function () { + return this.manager.log; +}); + +/** + * JSON message flag. + * + * @api public + */ + +Socket.prototype.__defineGetter__('json', function () { + this.flags.json = true; + return this; +}); + +/** + * Volatile message flag. + * + * @api public + */ + +Socket.prototype.__defineGetter__('volatile', function () { + this.flags.volatile = true; + return this; +}); + +/** + * Broadcast message flag. + * + * @api public + */ + +Socket.prototype.__defineGetter__('broadcast', function () { + this.flags.broadcast = true; + return this; +}); + +/** + * Overrides the room to broadcast messages to (flag) + * + * @api public + */ + +Socket.prototype.to = Socket.prototype.in = function (room) { + this.flags.room = room; + return this; +}; + +/** + * Resets flags + * + * @api private + */ + +Socket.prototype.setFlags = function () { + this.flags = { + endpoint: this.namespace.name + , room: '' + }; + return this; +}; + +/** + * Triggered on disconnect + * + * @api private + */ + +Socket.prototype.onDisconnect = function (reason) { + if (!this.disconnected) { + this.$emit('disconnect', reason); + this.disconnected = true; + } +}; + +/** + * Joins a user to a room. + * + * @api public + */ + +Socket.prototype.join = function (name, fn) { + var nsp = this.namespace.name + , name = (nsp + '/') + name; + + this.manager.onJoin(this.id, name); + this.manager.store.publish('join', this.id, name); + + if (fn) { + this.log.warn('Client#join callback is deprecated'); + fn(); + } + + return this; +}; + +/** + * Un-joins a user from a room. + * + * @api public + */ + +Socket.prototype.leave = function (name, fn) { + var nsp = this.namespace.name + , name = (nsp + '/') + name; + + this.manager.onLeave(this.id, name); + this.manager.store.publish('leave', this.id, name); + + if (fn) { + this.log.warn('Client#leave callback is deprecated'); + fn(); + } + + return this; +}; + +/** + * Transmits a packet. + * + * @api private + */ + +Socket.prototype.packet = function (packet) { + if (this.flags.broadcast) { + this.log.debug('broadcasting packet'); + this.namespace.in(this.flags.room).except(this.id).packet(packet); + } else { + packet.endpoint = this.flags.endpoint; + packet = parser.encodePacket(packet); + + this.dispatch(packet, this.flags.volatile); + } + + this.setFlags(); + + return this; +}; + +/** + * Dispatches a packet + * + * @api private + */ + +Socket.prototype.dispatch = function (packet, volatile) { + if (this.manager.transports[this.id] && this.manager.transports[this.id].open) { + this.manager.transports[this.id].onDispatch(packet, volatile); + } else { + if (!volatile) { + this.manager.onClientDispatch(this.id, packet, volatile); + } + + this.manager.store.publish('dispatch:' + this.id, packet, volatile); + } +}; + +/** + * Stores data for the client. + * + * @api public + */ + +Socket.prototype.set = function (key, value, fn) { + this.store.set(key, value, fn); + return this; +}; + +/** + * Retrieves data for the client + * + * @api public + */ + +Socket.prototype.get = function (key, fn) { + this.store.get(key, fn); + return this; +}; + +/** + * Checks data for the client + * + * @api public + */ + +Socket.prototype.has = function (key, fn) { + this.store.has(key, fn); + return this; +}; + +/** + * Deletes data for the client + * + * @api public + */ + +Socket.prototype.del = function (key, fn) { + this.store.del(key, fn); + return this; +}; + +/** + * Kicks client + * + * @api public + */ + +Socket.prototype.disconnect = function () { + if (!this.disconnected) { + this.log.info('booting client'); + + if ('' === this.namespace.name) { + if (this.manager.transports[this.id] && this.manager.transports[this.id].open) { + this.manager.transports[this.id].onForcedDisconnect(); + } else { + this.manager.onClientDisconnect(this.id); + this.manager.store.publish('disconnect:' + this.id); + } + } else { + this.packet({type: 'disconnect'}); + this.manager.onLeave(this.id, this.namespace.name); + this.$emit('disconnect', 'booted'); + } + + } + + return this; +}; + +/** + * Send a message. + * + * @api public + */ + +Socket.prototype.send = function (data, fn) { + var packet = { + type: this.flags.json ? 'json' : 'message' + , data: data + }; + + if (fn) { + packet.id = ++this.ackPackets; + packet.ack = true; + this.acks[packet.id] = fn; + } + + return this.packet(packet); +}; + +/** + * Original emit function. + * + * @api private + */ + +Socket.prototype.$emit = EventEmitter.prototype.emit; + +/** + * Emit override for custom events. + * + * @api public + */ + +Socket.prototype.emit = function (ev) { + if (ev == 'newListener') { + return this.$emit.apply(this, arguments); + } + + var args = util.toArray(arguments).slice(1) + , lastArg = args[args.length - 1] + , packet = { + type: 'event' + , name: ev + }; + + if ('function' == typeof lastArg) { + packet.id = ++this.ackPackets; + packet.ack = lastArg.length ? 'data' : true; + this.acks[packet.id] = lastArg; + args = args.slice(0, args.length - 1); + } + + packet.args = args; + + return this.packet(packet); +}; diff --git a/networking/node_modules/socket.io/lib/static.js b/networking/node_modules/socket.io/lib/static.js new file mode 100644 index 0000000..e3117ed --- /dev/null +++ b/networking/node_modules/socket.io/lib/static.js @@ -0,0 +1,395 @@ + +/*! +* socket.io-node +* Copyright(c) 2011 LearnBoost +* MIT Licensed +*/ + +/** + * Module dependencies. + */ + +var client = require('socket.io-client') + , cp = require('child_process') + , fs = require('fs') + , util = require('./util'); + +/** + * File type details. + * + * @api private + */ + +var mime = { + js: { + type: 'application/javascript' + , encoding: 'utf8' + , gzip: true + } + , swf: { + type: 'application/x-shockwave-flash' + , encoding: 'binary' + , gzip: false + } +}; + +/** + * Regexp for matching custom transport patterns. Users can configure their own + * socket.io bundle based on the url structure. Different transport names are + * concatinated using the `+` char. /socket.io/socket.io+websocket.js should + * create a bundle that only contains support for the websocket. + * + * @api private + */ + +var bundle = /\+((?:\+)?[\w\-]+)*(?:\.v\d+\.\d+\.\d+)?(?:\.js)$/ + , versioning = /\.v\d+\.\d+\.\d+(?:\.js)$/; + +/** + * Export the constructor + */ + +exports = module.exports = Static; + +/** + * Static constructor + * + * @api public + */ + +function Static (manager) { + this.manager = manager; + this.cache = {}; + this.paths = {}; + + this.init(); +} + +/** + * Initialize the Static by adding default file paths. + * + * @api public + */ + +Static.prototype.init = function () { + /** + * Generates a unique id based the supplied transports array + * + * @param {Array} transports The array with transport types + * @api private + */ + function id (transports) { + var id = transports.join('').split('').map(function (char) { + return ('' + char.charCodeAt(0)).split('').pop(); + }).reduce(function (char, id) { + return char +id; + }); + + return client.version + ':' + id; + } + + /** + * Generates a socket.io-client file based on the supplied transports. + * + * @param {Array} transports The array with transport types + * @param {Function} callback Callback for the static.write + * @api private + */ + + function build (transports, callback) { + client.builder(transports, { + minify: self.manager.enabled('browser client minification') + }, function (err, content) { + callback(err, content ? new Buffer(content) : null, id(transports)); + } + ); + } + + var self = this; + + // add our default static files + this.add('/static/flashsocket/WebSocketMain.swf', { + file: client.dist + '/WebSocketMain.swf' + }); + + this.add('/static/flashsocket/WebSocketMainInsecure.swf', { + file: client.dist + '/WebSocketMainInsecure.swf' + }); + + // generates dedicated build based on the available transports + this.add('/socket.io.js', function (path, callback) { + build(self.manager.get('transports'), callback); + }); + + this.add('/socket.io.v', { mime: mime.js }, function (path, callback) { + build(self.manager.get('transports'), callback); + }); + + // allow custom builds based on url paths + this.add('/socket.io+', { mime: mime.js }, function (path, callback) { + var available = self.manager.get('transports') + , matches = path.match(bundle) + , transports = []; + + if (!matches) return callback('No valid transports'); + + // make sure they valid transports + matches[0].split('.')[0].split('+').slice(1).forEach(function (transport) { + if (!!~available.indexOf(transport)) { + transports.push(transport); + } + }); + + if (!transports.length) return callback('No valid transports'); + build(transports, callback); + }); + + // clear cache when transports change + this.manager.on('set:transports', function (key, value) { + delete self.cache['/socket.io.js']; + Object.keys(self.cache).forEach(function (key) { + if (bundle.test(key)) { + delete self.cache[key]; + } + }); + }); +}; + +/** + * Gzip compress buffers. + * + * @param {Buffer} data The buffer that needs gzip compression + * @param {Function} callback + * @api public + */ + +Static.prototype.gzip = function (data, callback) { + var gzip = cp.spawn('gzip', ['-9', '-c', '-f', '-n']) + , encoding = Buffer.isBuffer(data) ? 'binary' : 'utf8' + , buffer = [] + , err; + + gzip.stdout.on('data', function (data) { + buffer.push(data); + }); + + gzip.stderr.on('data', function (data) { + err = data +''; + buffer.length = 0; + }); + + gzip.on('exit', function () { + if (err) return callback(err); + + var size = 0 + , index = 0 + , i = buffer.length + , content; + + while (i--) { + size += buffer[i].length; + } + + content = new Buffer(size); + i = buffer.length; + + buffer.forEach(function (buffer) { + var length = buffer.length; + + buffer.copy(content, index, 0, length); + index += length; + }); + + buffer.length = 0; + callback(null, content); + }); + + gzip.stdin.end(data, encoding); +}; + +/** + * Is the path a static file? + * + * @param {String} path The path that needs to be checked + * @api public + */ + +Static.prototype.has = function (path) { + // fast case + if (this.paths[path]) return this.paths[path]; + + var keys = Object.keys(this.paths) + , i = keys.length; + + while (i--) { + if (-~path.indexOf(keys[i])) return this.paths[keys[i]]; + } + + return false; +}; + +/** + * Add new paths new paths that can be served using the static provider. + * + * @param {String} path The path to respond to + * @param {Options} options Options for writing out the response + * @param {Function} [callback] Optional callback if no options.file is + * supplied this would be called instead. + * @api public + */ + +Static.prototype.add = function (path, options, callback) { + var extension = /(?:\.(\w{1,4}))$/.exec(path); + + if (!callback && typeof options == 'function') { + callback = options; + options = {}; + } + + options.mime = options.mime || (extension ? mime[extension[1]] : false); + + if (callback) options.callback = callback; + if (!(options.file || options.callback) || !options.mime) return false; + + this.paths[path] = options; + + return true; +}; + +/** + * Writes a static response. + * + * @param {String} path The path for the static content + * @param {HTTPRequest} req The request object + * @param {HTTPResponse} res The response object + * @api public + */ + +Static.prototype.write = function (path, req, res) { + /** + * Write a response without throwing errors because can throw error if the + * response is no longer writable etc. + * + * @api private + */ + + function write (status, headers, content, encoding) { + try { + res.writeHead(status, headers || undefined); + + // only write content if it's not a HEAD request and we actually have + // some content to write (304's doesn't have content). + res.end( + req.method !== 'HEAD' && content ? content : '' + , encoding || undefined + ); + } catch (e) {} + } + + /** + * Answers requests depending on the request properties and the reply object. + * + * @param {Object} reply The details and content to reply the response with + * @api private + */ + + function answer (reply) { + var cached = req.headers['if-none-match'] === reply.etag; + if (cached && self.manager.enabled('browser client etag')) { + return write(304); + } + + var accept = req.headers['accept-encoding'] || '' + , gzip = !!~accept.toLowerCase().indexOf('gzip') + , mime = reply.mime + , versioned = reply.versioned + , headers = { + 'Content-Type': mime.type + }; + + // check if we can add a etag + if (self.manager.enabled('browser client etag') && reply.etag && !versioned) { + headers['Etag'] = reply.etag; + } + + // see if we need to set Expire headers because the path is versioned + if (versioned) { + var expires = self.manager.get('browser client expires'); + headers['Cache-Control'] = 'private, x-gzip-ok="", max-age=' + expires; + headers['Date'] = new Date().toUTCString(); + headers['Expires'] = new Date(Date.now() + (expires * 1000)).toUTCString(); + } + + if (gzip && reply.gzip) { + headers['Content-Length'] = reply.gzip.length; + headers['Content-Encoding'] = 'gzip'; + headers['Vary'] = 'Accept-Encoding'; + write(200, headers, reply.gzip.content, mime.encoding); + } else { + headers['Content-Length'] = reply.length; + write(200, headers, reply.content, mime.encoding); + } + + self.manager.log.debug('served static content ' + path); + } + + var self = this + , details; + + // most common case first + if (this.manager.enabled('browser client cache') && this.cache[path]) { + return answer(this.cache[path]); + } else if (this.manager.get('browser client handler')) { + return this.manager.get('browser client handler').call(this, req, res); + } else if ((details = this.has(path))) { + /** + * A small helper function that will let us deal with fs and dynamic files + * + * @param {Object} err Optional error + * @param {Buffer} content The data + * @api private + */ + + function ready (err, content, etag) { + if (err) { + self.manager.log.warn('Unable to serve file. ' + (err.message || err)); + return write(500, null, 'Error serving static ' + path); + } + + // store the result in the cache + var reply = self.cache[path] = { + content: content + , length: content.length + , mime: details.mime + , etag: etag || client.version + , versioned: versioning.test(path) + }; + + // check if gzip is enabled + if (details.mime.gzip && self.manager.enabled('browser client gzip')) { + self.gzip(content, function (err, content) { + if (!err) { + reply.gzip = { + content: content + , length: content.length + } + } + + answer(reply); + }); + } else { + answer(reply); + } + } + + if (details.file) { + fs.readFile(details.file, ready); + } else if(details.callback) { + details.callback.call(this, path, ready); + } else { + write(404, null, 'File handle not found'); + } + } else { + write(404, null, 'File not found'); + } +}; diff --git a/networking/node_modules/socket.io/lib/store.js b/networking/node_modules/socket.io/lib/store.js new file mode 100644 index 0000000..06c0389 --- /dev/null +++ b/networking/node_modules/socket.io/lib/store.js @@ -0,0 +1,98 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Expose the constructor. + */ + +exports = module.exports = Store; + +/** + * Module dependencies. + */ + +var EventEmitter = process.EventEmitter; + +/** + * Store interface + * + * @api public + */ + +function Store (options) { + this.options = options; + this.clients = {}; +}; + +/** + * Inherit from EventEmitter. + */ + +Store.prototype.__proto__ = EventEmitter.prototype; + +/** + * Initializes a client store + * + * @param {String} id + * @api public + */ + +Store.prototype.client = function (id) { + if (!this.clients[id]) { + this.clients[id] = new (this.constructor.Client)(this, id); + } + + return this.clients[id]; +}; + +/** + * Destroys a client + * + * @api {String} sid + * @param {Number} number of seconds to expire client data + * @api private + */ + +Store.prototype.destroyClient = function (id, expiration) { + if (this.clients[id]) { + this.clients[id].destroy(expiration); + delete this.clients[id]; + } + + return this; +}; + +/** + * Destroys the store + * + * @param {Number} number of seconds to expire client data + * @api private + */ + +Store.prototype.destroy = function (clientExpiration) { + var keys = Object.keys(this.clients) + , count = keys.length; + + for (var i = 0, l = count; i < l; i++) { + this.destroyClient(keys[i], clientExpiration); + } + + this.clients = {}; + + return this; +}; + +/** + * Client. + * + * @api public + */ + +Store.Client = function (store, id) { + this.store = store; + this.id = id; +}; diff --git a/networking/node_modules/socket.io/lib/stores/memory.js b/networking/node_modules/socket.io/lib/stores/memory.js new file mode 100644 index 0000000..8b731a7 --- /dev/null +++ b/networking/node_modules/socket.io/lib/stores/memory.js @@ -0,0 +1,143 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var crypto = require('crypto') + , Store = require('../store'); + +/** + * Exports the constructor. + */ + +exports = module.exports = Memory; +Memory.Client = Client; + +/** + * Memory store + * + * @api public + */ + +function Memory (opts) { + Store.call(this, opts); +}; + +/** + * Inherits from Store. + */ + +Memory.prototype.__proto__ = Store.prototype; + +/** + * Publishes a message. + * + * @api private + */ + +Memory.prototype.publish = function () { }; + +/** + * Subscribes to a channel + * + * @api private + */ + +Memory.prototype.subscribe = function () { }; + +/** + * Unsubscribes + * + * @api private + */ + +Memory.prototype.unsubscribe = function () { }; + +/** + * Client constructor + * + * @api private + */ + +function Client () { + Store.Client.apply(this, arguments); + this.data = {}; +}; + +/** + * Inherits from Store.Client + */ + +Client.prototype.__proto__ = Store.Client; + +/** + * Gets a key + * + * @api public + */ + +Client.prototype.get = function (key, fn) { + fn(null, this.data[key] === undefined ? null : this.data[key]); + return this; +}; + +/** + * Sets a key + * + * @api public + */ + +Client.prototype.set = function (key, value, fn) { + this.data[key] = value; + fn && fn(null); + return this; +}; + +/** + * Has a key + * + * @api public + */ + +Client.prototype.has = function (key, fn) { + fn(null, key in this.data); +}; + +/** + * Deletes a key + * + * @api public + */ + +Client.prototype.del = function (key, fn) { + delete this.data[key]; + fn && fn(null); + return this; +}; + +/** + * Destroys the client. + * + * @param {Number} number of seconds to expire data + * @api private + */ + +Client.prototype.destroy = function (expiration) { + if ('number' != typeof expiration) { + this.data = {}; + } else { + var self = this; + + setTimeout(function () { + self.data = {}; + }, expiration * 1000); + } + + return this; +}; diff --git a/networking/node_modules/socket.io/lib/stores/redis.js b/networking/node_modules/socket.io/lib/stores/redis.js new file mode 100644 index 0000000..8fea235 --- /dev/null +++ b/networking/node_modules/socket.io/lib/stores/redis.js @@ -0,0 +1,269 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var crypto = require('crypto') + , Store = require('../store') + , assert = require('assert'); + +/** + * Exports the constructor. + */ + +exports = module.exports = Redis; +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 + * - pack (fn) custom packing, defaults to JSON or msgpack if installed + * - unpack (fn) custom packing, defaults to JSON or msgpack if installed + * + * @api public + */ + +function Redis (opts) { + opts = opts || {}; + + // node id to uniquely identify this node + var nodeId = opts.nodeId || function () { + // by default, we generate a random id + return Math.abs(Math.random() * Math.random() * Date.now() | 0); + }; + + this.nodeId = nodeId(); + + // packing / unpacking mechanism + if (opts.pack) { + this.pack = opts.pack; + this.unpack = opts.unpack; + } else { + try { + var msgpack = require('msgpack'); + this.pack = msgpack.pack; + this.unpack = msgpack.unpack; + } catch (e) { + this.pack = JSON.stringify; + this.unpack = JSON.parse; + } + } + + var redis = opts.redis || require('redis') + , RedisClient = redis.RedisClient; + + // initialize a pubsub client and a regular client + if (opts.redisPub instanceof RedisClient) { + this.pub = opts.redisPub; + } else { + opts.redisPub || (opts.redisPub = {}); + this.pub = redis.createClient(opts.redisPub.port, opts.redisPub.host, opts.redisPub); + } + if (opts.redisSub instanceof RedisClient) { + this.sub = opts.redisSub; + } else { + opts.redisSub || (opts.redisSub = {}); + this.sub = redis.createClient(opts.redisSub.port, opts.redisSub.host, opts.redisSub); + } + if (opts.redisClient instanceof RedisClient) { + this.cmd = opts.redisClient; + } else { + opts.redisClient || (opts.redisClient = {}); + this.cmd = redis.createClient(opts.redisClient.port, opts.redisClient.host, opts.redisClient); + } + + Store.call(this, opts); + + this.sub.setMaxListeners(0); + this.setMaxListeners(0); +}; + +/** + * Inherits from Store. + */ + +Redis.prototype.__proto__ = Store.prototype; + +/** + * Publishes a message. + * + * @api private + */ + +Redis.prototype.publish = function (name) { + var args = Array.prototype.slice.call(arguments, 1); + this.pub.publish(name, this.pack({ nodeId: this.nodeId, args: args })); + this.emit.apply(this, ['publish', name].concat(args)); +}; + +/** + * Subscribes to a channel + * + * @api private + */ + +Redis.prototype.subscribe = function (name, consumer, fn) { + this.sub.subscribe(name); + + if (consumer || fn) { + var self = this; + + self.sub.on('subscribe', function subscribe (ch) { + if (name == ch) { + function message (ch, msg) { + if (name == ch) { + msg = self.unpack(msg); + + // we check that the message consumed wasnt emitted by this node + if (self.nodeId != msg.nodeId) { + consumer.apply(null, msg.args); + } + } + }; + + self.sub.on('message', message); + + self.on('unsubscribe', function unsubscribe (ch) { + if (name == ch) { + self.sub.removeListener('message', message); + self.removeListener('unsubscribe', unsubscribe); + } + }); + + self.sub.removeListener('subscribe', subscribe); + + fn && fn(); + } + }); + } + + this.emit('subscribe', name, consumer, fn); +}; + +/** + * Unsubscribes + * + * @api private + */ + +Redis.prototype.unsubscribe = function (name, fn) { + this.sub.unsubscribe(name); + + if (fn) { + var client = this.sub; + + client.on('unsubscribe', function unsubscribe (ch) { + if (name == ch) { + fn(); + client.removeListener('unsubscribe', unsubscribe); + } + }); + } + + this.emit('unsubscribe', name, fn); +}; + +/** + * Destroys the store + * + * @api public + */ + +Redis.prototype.destroy = function () { + Store.prototype.destroy.call(this); + + this.pub.end(); + this.sub.end(); + this.cmd.end(); +}; + +/** + * Client constructor + * + * @api private + */ + +function Client (store, id) { + Store.Client.call(this, store, id); +}; + +/** + * Inherits from Store.Client + */ + +Client.prototype.__proto__ = Store.Client; + +/** + * Redis hash get + * + * @api private + */ + +Client.prototype.get = function (key, fn) { + this.store.cmd.hget(this.id, key, fn); + return this; +}; + +/** + * Redis hash set + * + * @api private + */ + +Client.prototype.set = function (key, value, fn) { + this.store.cmd.hset(this.id, key, value, fn); + return this; +}; + +/** + * Redis hash del + * + * @api private + */ + +Client.prototype.del = function (key, fn) { + this.store.cmd.hdel(this.id, key, fn); + return this; +}; + +/** + * Redis hash has + * + * @api private + */ + +Client.prototype.has = function (key, fn) { + this.store.cmd.hexists(this.id, key, function (err, has) { + if (err) return fn(err); + fn(null, !!has); + }); + return this; +}; + +/** + * Destroys client + * + * @param {Number} number of seconds to expire data + * @api private + */ + +Client.prototype.destroy = function (expiration) { + if ('number' != typeof expiration) { + this.store.cmd.del(this.id); + } else { + this.store.cmd.expire(this.id, expiration); + } + + return this; +}; diff --git a/networking/node_modules/socket.io/lib/transport.js b/networking/node_modules/socket.io/lib/transport.js new file mode 100644 index 0000000..2e4c08b --- /dev/null +++ b/networking/node_modules/socket.io/lib/transport.js @@ -0,0 +1,534 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var parser = require('./parser'); + +/** + * Expose the constructor. + */ + +exports = module.exports = Transport; + +/** + * Transport constructor. + * + * @api public + */ + +function Transport (mng, data, req) { + this.manager = mng; + this.id = data.id; + this.disconnected = false; + this.drained = true; + this.handleRequest(req); +}; + +/** + * Access the logger. + * + * @api public + */ + +Transport.prototype.__defineGetter__('log', function () { + return this.manager.log; +}); + +/** + * Access the store. + * + * @api public + */ + +Transport.prototype.__defineGetter__('store', function () { + return this.manager.store; +}); + +/** + * Handles a request when it's set. + * + * @api private + */ + +Transport.prototype.handleRequest = function (req) { + this.log.debug('setting request', req.method, req.url); + this.req = req; + + if (req.method == 'GET') { + this.socket = req.socket; + this.open = true; + this.drained = true; + this.setHeartbeatInterval(); + + this.setHandlers(); + this.onSocketConnect(); + } +}; + +/** + * Called when a connection is first set. + * + * @api private + */ + +Transport.prototype.onSocketConnect = function () { }; + +/** + * Sets transport handlers + * + * @api private + */ + +Transport.prototype.setHandlers = function () { + var self = this; + + // we need to do this in a pub/sub way since the client can POST the message + // over a different socket (ie: different Transport instance) + this.store.subscribe('heartbeat-clear:' + this.id, function () { + self.onHeartbeatClear(); + }); + + this.store.subscribe('disconnect-force:' + this.id, function () { + self.onForcedDisconnect(); + }); + + this.store.subscribe('dispatch:' + this.id, function (packet, volatile) { + self.onDispatch(packet, volatile); + }); + + this.bound = { + end: this.onSocketEnd.bind(this) + , close: this.onSocketClose.bind(this) + , error: this.onSocketError.bind(this) + , drain: this.onSocketDrain.bind(this) + }; + + this.socket.on('end', this.bound.end); + this.socket.on('close', this.bound.close); + this.socket.on('error', this.bound.error); + this.socket.on('drain', this.bound.drain); + + this.handlersSet = true; +}; + +/** + * Removes transport handlers + * + * @api private + */ + +Transport.prototype.clearHandlers = function () { + if (this.handlersSet) { + this.store.unsubscribe('disconnect-force:' + this.id); + this.store.unsubscribe('heartbeat-clear:' + this.id); + this.store.unsubscribe('dispatch:' + this.id); + + this.socket.removeListener('end', this.bound.end); + this.socket.removeListener('close', this.bound.close); + this.socket.removeListener('error', this.bound.error); + this.socket.removeListener('drain', this.bound.drain); + } +}; + +/** + * Called when the connection dies + * + * @api private + */ + +Transport.prototype.onSocketEnd = function () { + this.end('socket end'); +}; + +/** + * Called when the connection dies + * + * @api private + */ + +Transport.prototype.onSocketClose = function (error) { + this.end(error ? 'socket error' : 'socket close'); +}; + +/** + * Called when the connection has an error. + * + * @api private + */ + +Transport.prototype.onSocketError = function (err) { + if (this.open) { + this.socket.destroy(); + this.onClose(); + } + + this.log.info('socket error ' + err.stack); +}; + +/** + * Called when the connection is drained. + * + * @api private + */ + +Transport.prototype.onSocketDrain = function () { + this.drained = true; +}; + +/** + * Called upon receiving a heartbeat packet. + * + * @api private + */ + +Transport.prototype.onHeartbeatClear = function () { + this.clearHeartbeatTimeout(); + this.setHeartbeatInterval(); +}; + +/** + * Called upon a forced disconnection. + * + * @api private + */ + +Transport.prototype.onForcedDisconnect = function () { + if (!this.disconnected) { + this.log.info('transport end by forced client disconnection'); + if (this.open) { + this.packet({ type: 'disconnect' }); + } + this.end('booted'); + } +}; + +/** + * Dispatches a packet. + * + * @api private + */ + +Transport.prototype.onDispatch = function (packet, volatile) { + if (volatile) { + this.writeVolatile(packet); + } else { + this.write(packet); + } +}; + +/** + * Sets the close timeout. + */ + +Transport.prototype.setCloseTimeout = function () { + if (!this.closeTimeout) { + var self = this; + + this.closeTimeout = setTimeout(function () { + self.log.debug('fired close timeout for client', self.id); + self.closeTimeout = null; + self.end('close timeout'); + }, this.manager.get('close timeout') * 1000); + + this.log.debug('set close timeout for client', this.id); + } +}; + +/** + * Clears the close timeout. + */ + +Transport.prototype.clearCloseTimeout = function () { + if (this.closeTimeout) { + clearTimeout(this.closeTimeout); + this.closeTimeout = null; + + this.log.debug('cleared close timeout for client', this.id); + } +}; + +/** + * Sets the heartbeat timeout + */ + +Transport.prototype.setHeartbeatTimeout = function () { + if (!this.heartbeatTimeout && this.manager.enabled('heartbeats')) { + var self = this; + + this.heartbeatTimeout = setTimeout(function () { + self.log.debug('fired heartbeat timeout for client', self.id); + self.heartbeatTimeout = null; + self.end('heartbeat timeout'); + }, this.manager.get('heartbeat timeout') * 1000); + + this.log.debug('set heartbeat timeout for client', this.id); + } +}; + +/** + * Clears the heartbeat timeout + * + * @param text + */ + +Transport.prototype.clearHeartbeatTimeout = function () { + if (this.heartbeatTimeout && this.manager.enabled('heartbeats')) { + clearTimeout(this.heartbeatTimeout); + this.heartbeatTimeout = null; + this.log.debug('cleared heartbeat timeout for client', this.id); + } +}; + +/** + * Sets the heartbeat interval. To be called when a connection opens and when + * a heartbeat is received. + * + * @api private + */ + +Transport.prototype.setHeartbeatInterval = function () { + if (!this.heartbeatInterval && this.manager.enabled('heartbeats')) { + var self = this; + + this.heartbeatInterval = setTimeout(function () { + self.heartbeat(); + self.heartbeatInterval = null; + }, this.manager.get('heartbeat interval') * 1000); + + this.log.debug('set heartbeat interval for client', this.id); + } +}; + +/** + * Clears all timeouts. + * + * @api private + */ + +Transport.prototype.clearTimeouts = function () { + this.clearCloseTimeout(); + this.clearHeartbeatTimeout(); + this.clearHeartbeatInterval(); +}; + +/** + * Sends a heartbeat + * + * @api private + */ + +Transport.prototype.heartbeat = function () { + if (this.open) { + this.log.debug('emitting heartbeat for client', this.id); + this.packet({ type: 'heartbeat' }); + this.setHeartbeatTimeout(); + } + + return this; +}; + +/** + * Handles a message. + * + * @param {Object} packet object + * @api private + */ + +Transport.prototype.onMessage = function (packet) { + var current = this.manager.transports[this.id]; + + if ('heartbeat' == packet.type) { + this.log.debug('got heartbeat packet'); + + if (current && current.open) { + current.onHeartbeatClear(); + } else { + this.store.publish('heartbeat-clear:' + this.id); + } + } else { + if ('disconnect' == packet.type && packet.endpoint == '') { + this.log.debug('got disconnection packet'); + + if (current) { + current.onForcedDisconnect(); + } else { + this.store.publish('disconnect-force:' + this.id); + } + + return; + } + + if (packet.id && packet.ack != 'data') { + this.log.debug('acknowledging packet automatically'); + + var ack = parser.encodePacket({ + type: 'ack' + , ackId: packet.id + , endpoint: packet.endpoint || '' + }); + + if (current && current.open) { + current.onDispatch(ack); + } else { + this.manager.onClientDispatch(this.id, ack); + this.store.publish('dispatch:' + this.id, ack); + } + } + + // handle packet locally or publish it + if (current) { + this.manager.onClientMessage(this.id, packet); + } else { + this.store.publish('message:' + this.id, packet); + } + } +}; + +/** + * Clears the heartbeat interval + * + * @api private + */ + +Transport.prototype.clearHeartbeatInterval = function () { + if (this.heartbeatInterval && this.manager.enabled('heartbeats')) { + clearTimeout(this.heartbeatInterval); + this.heartbeatInterval = null; + this.log.debug('cleared heartbeat interval for client', this.id); + } +}; + +/** + * Finishes the connection and makes sure client doesn't reopen + * + * @api private + */ + +Transport.prototype.disconnect = function (reason) { + this.packet({ type: 'disconnect' }); + this.end(reason); + + return this; +}; + +/** + * Closes the connection. + * + * @api private + */ + +Transport.prototype.close = function () { + if (this.open) { + this.doClose(); + this.onClose(); + } +}; + +/** + * Called upon a connection close. + * + * @api private + */ + +Transport.prototype.onClose = function () { + if (this.open) { + this.setCloseTimeout(); + this.clearHandlers(); + this.open = false; + this.manager.onClose(this.id); + this.store.publish('close', this.id); + } +}; + +/** + * Cleans up the connection, considers the client disconnected. + * + * @api private + */ + +Transport.prototype.end = function (reason) { + if (!this.disconnected) { + this.log.info('transport end (' + reason + ')'); + + var local = this.manager.transports[this.id]; + + this.close(); + this.clearTimeouts(); + this.disconnected = true; + + if (local) { + this.manager.onClientDisconnect(this.id, reason, true); + } else { + this.store.publish('disconnect:' + this.id, reason); + } + } +}; + +/** + * Signals that the transport should pause and buffer data. + * + * @api public + */ + +Transport.prototype.discard = function () { + this.log.debug('discarding transport'); + this.discarded = true; + this.clearTimeouts(); + this.clearHandlers(); + + return this; +}; + +/** + * Writes an error packet with the specified reason and advice. + * + * @param {Number} advice + * @param {Number} reason + * @api public + */ + +Transport.prototype.error = function (reason, advice) { + this.packet({ + type: 'error' + , reason: reason + , advice: advice + }); + + this.log.warn(reason, advice ? ('client should ' + advice) : ''); + this.end('error'); +}; + +/** + * Write a packet. + * + * @api public + */ + +Transport.prototype.packet = function (obj) { + return this.write(parser.encodePacket(obj)); +}; + +/** + * Writes a volatile message. + * + * @api private + */ + +Transport.prototype.writeVolatile = function (msg) { + if (this.open) { + if (this.drained) { + this.write(msg); + } else { + this.log.debug('ignoring volatile packet, buffer not drained'); + } + } else { + this.log.debug('ignoring volatile packet, transport not open'); + } +}; diff --git a/networking/node_modules/socket.io/lib/transports/flashsocket.js b/networking/node_modules/socket.io/lib/transports/flashsocket.js new file mode 100644 index 0000000..d79363d --- /dev/null +++ b/networking/node_modules/socket.io/lib/transports/flashsocket.js @@ -0,0 +1,106 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ +var WebSocket = require('./websocket'); + +/** + * Export the constructor. + */ + +exports = module.exports = FlashSocket; + +/** + * The FlashSocket transport is just a proxy + * for WebSocket connections. + * + * @api public + */ + +function FlashSocket (mng, data, req) { + return WebSocket.call(this, mng, data, req); +} + +/** + * Inherits from WebSocket. + */ + +FlashSocket.prototype.__proto__ = WebSocket.prototype; + +/** + * Transport name + * + * @api public + */ + +FlashSocket.prototype.name = 'flashsocket'; + +/** + * Listens for new configuration changes of the Manager + * this way we can enable and disable the flash server. + * + * @param {Manager} Manager instance. + * @api private + */ + + +FlashSocket.init = function (manager) { + var server; + function create () { + server = require('policyfile').createServer({ + log: function(msg){ + manager.log.info(msg.toLowerCase()); + } + }, manager.get('origins')); + + server.on('close', function (e) { + server = null; + }); + + server.listen(manager.get('flash policy port'), manager.server); + + manager.flashPolicyServer = server; + } + + // listen for origin changes, so we can update the server + manager.on('set:origins', function (value, key) { + if (!server) return; + + // update the origins and compile a new response buffer + server.origins = Array.isArray(value) ? value : [value]; + server.compile(); + }); + + // destory the server and create a new server + manager.on('set:flash policy port', function (value, key) { + var transports = manager.get('transports'); + if (~transports.indexOf('flashsocket')) { + if (server) { + if (server.port === value) return; + // destroy the server and rebuild it on a new port + try { + server.close(); + } + catch (e) { /* ignore exception. could e.g. be that the server isn't started yet */ } + } + create(); + } + }); + + // only start the server + manager.on('set:transports', function (value, key){ + if (!server && ~manager.get('transports').indexOf('flashsocket')) { + create(); + } + }); + // check if we need to initialize at start + if (~manager.get('transports').indexOf('flashsocket')){ + create(); + } +}; diff --git a/networking/node_modules/socket.io/lib/transports/htmlfile.js b/networking/node_modules/socket.io/lib/transports/htmlfile.js new file mode 100644 index 0000000..e8709a3 --- /dev/null +++ b/networking/node_modules/socket.io/lib/transports/htmlfile.js @@ -0,0 +1,82 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var HTTPTransport = require('./http'); + +/** + * Export the constructor. + */ + +exports = module.exports = HTMLFile; + +/** + * HTMLFile transport constructor. + * + * @api public + */ + +function HTMLFile (mng, data, req) { + HTTPTransport.call(this, mng, data, req); +}; + +/** + * Inherits from Transport. + */ + +HTMLFile.prototype.__proto__ = HTTPTransport.prototype; + +/** + * Transport name + * + * @api public + */ + +HTMLFile.prototype.name = 'htmlfile'; + +/** + * Handles the request. + * + * @api private + */ + +HTMLFile.prototype.handleRequest = function (req) { + HTTPTransport.prototype.handleRequest.call(this, req); + + if (req.method == 'GET') { + req.res.writeHead(200, { + 'Content-Type': 'text/html; charset=UTF-8' + , 'Connection': 'keep-alive' + , 'Transfer-Encoding': 'chunked' + }); + + req.res.write( + '' + + '' + + new Array(174).join(' ') + ); + } +}; + +/** + * Performs the write. + * + * @api private + */ + +HTMLFile.prototype.write = function (data) { + data = ''; + + if (this.response.write(data)) { + this.drained = true; + } + + this.log.debug(this.name + ' writing', data); +}; diff --git a/networking/node_modules/socket.io/lib/transports/http-polling.js b/networking/node_modules/socket.io/lib/transports/http-polling.js new file mode 100644 index 0000000..89b7e04 --- /dev/null +++ b/networking/node_modules/socket.io/lib/transports/http-polling.js @@ -0,0 +1,147 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var HTTPTransport = require('./http'); + +/** + * Exports the constructor. + */ + +exports = module.exports = HTTPPolling; + +/** + * HTTP polling constructor. + * + * @api public. + */ + +function HTTPPolling (mng, data, req) { + HTTPTransport.call(this, mng, data, req); +}; + +/** + * Inherits from HTTPTransport. + * + * @api public. + */ + +HTTPPolling.prototype.__proto__ = HTTPTransport.prototype; + +/** + * Transport name + * + * @api public + */ + +HTTPPolling.prototype.name = 'httppolling'; + +/** + * Override setHandlers + * + * @api private + */ + +HTTPPolling.prototype.setHandlers = function () { + HTTPTransport.prototype.setHandlers.call(this); + this.socket.removeListener('end', this.bound.end); + this.socket.removeListener('close', this.bound.close); +}; + +/** + * Removes heartbeat timeouts for polling. + */ + +HTTPPolling.prototype.setHeartbeatInterval = function () { + return this; +}; + +/** + * Handles a request + * + * @api private + */ + +HTTPPolling.prototype.handleRequest = function (req) { + HTTPTransport.prototype.handleRequest.call(this, req); + + if (req.method == 'GET') { + var self = this; + + this.pollTimeout = setTimeout(function () { + self.packet({ type: 'noop' }); + self.log.debug(self.name + ' closed due to exceeded duration'); + }, this.manager.get('polling duration') * 1000); + + this.log.debug('setting poll timeout'); + } +}; + +/** + * Clears polling timeout + * + * @api private + */ + +HTTPPolling.prototype.clearPollTimeout = function () { + if (this.pollTimeout) { + clearTimeout(this.pollTimeout); + this.pollTimeout = null; + this.log.debug('clearing poll timeout'); + } + + return this; +}; + +/** + * Override clear timeouts to clear the poll timeout + * + * @api private + */ + +HTTPPolling.prototype.clearTimeouts = function () { + HTTPTransport.prototype.clearTimeouts.call(this); + + this.clearPollTimeout(); +}; + +/** + * doWrite to clear poll timeout + * + * @api private + */ + +HTTPPolling.prototype.doWrite = function () { + this.clearPollTimeout(); +}; + +/** + * Performs a write. + * + * @api private. + */ + +HTTPPolling.prototype.write = function (data, close) { + this.doWrite(data); + this.response.end(); + this.onClose(); +}; + +/** + * Override end. + * + * @api private + */ + +HTTPPolling.prototype.end = function (reason) { + this.clearPollTimeout(); + return HTTPTransport.prototype.end.call(this, reason); +}; + diff --git a/networking/node_modules/socket.io/lib/transports/http.js b/networking/node_modules/socket.io/lib/transports/http.js new file mode 100644 index 0000000..237dac2 --- /dev/null +++ b/networking/node_modules/socket.io/lib/transports/http.js @@ -0,0 +1,119 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var Transport = require('../transport') + , parser = require('../parser') + , qs = require('querystring'); + +/** + * Export the constructor. + */ + +exports = module.exports = HTTPTransport; + +/** + * HTTP interface constructor. For all non-websocket transports. + * + * @api public + */ + +function HTTPTransport (mng, data, req) { + Transport.call(this, mng, data, req); +}; + +/** + * Inherits from Transport. + */ + +HTTPTransport.prototype.__proto__ = Transport.prototype; + +/** + * Handles a request. + * + * @api private + */ + +HTTPTransport.prototype.handleRequest = function (req) { + if (req.method == 'POST') { + var buffer = '' + , res = req.res + , origin = req.headers.origin + , headers = { 'Content-Length': 1, 'Content-Type': 'text/plain; charset=UTF-8' } + , self = this; + + req.on('data', function (data) { + buffer += data; + + if (Buffer.byteLength(buffer) >= self.manager.get('destroy buffer size')) { + buffer = ''; + req.connection.destroy(); + } + }); + + req.on('end', function () { + res.writeHead(200, headers); + res.end('1'); + + self.onData(self.postEncoded ? qs.parse(buffer).d : buffer); + }); + + // prevent memory leaks for uncompleted requests + req.on('close', function () { + buffer = ''; + self.onClose(); + }); + + if (origin) { + // https://developer.mozilla.org/En/HTTP_Access_Control + headers['Access-Control-Allow-Origin'] = origin; + headers['Access-Control-Allow-Credentials'] = 'true'; + } + } else { + this.response = req.res; + + Transport.prototype.handleRequest.call(this, req); + } +}; + +/** + * Handles data payload. + * + * @api private + */ + +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.onMessage(messages[i]); + } +}; + +/** + * Closes the request-response cycle + * + * @api private + */ + +HTTPTransport.prototype.doClose = function () { + this.response.end(); +}; + +/** + * Writes a payload of messages + * + * @api private + */ + +HTTPTransport.prototype.payload = function (msgs) { + this.write(parser.encodePayload(msgs)); +}; diff --git a/networking/node_modules/socket.io/lib/transports/index.js b/networking/node_modules/socket.io/lib/transports/index.js new file mode 100644 index 0000000..b865559 --- /dev/null +++ b/networking/node_modules/socket.io/lib/transports/index.js @@ -0,0 +1,12 @@ + +/** + * Export transports. + */ + +module.exports = { + websocket: require('./websocket') + , flashsocket: require('./flashsocket') + , htmlfile: require('./htmlfile') + , 'xhr-polling': require('./xhr-polling') + , 'jsonp-polling': require('./jsonp-polling') +}; diff --git a/networking/node_modules/socket.io/lib/transports/jsonp-polling.js b/networking/node_modules/socket.io/lib/transports/jsonp-polling.js new file mode 100644 index 0000000..ad7d5af --- /dev/null +++ b/networking/node_modules/socket.io/lib/transports/jsonp-polling.js @@ -0,0 +1,97 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var HTTPPolling = require('./http-polling'); +var jsonpolling_re = /^\d+$/ + +/** + * Export the constructor. + */ + +exports = module.exports = JSONPPolling; + +/** + * JSON-P polling transport. + * + * @api public + */ + +function JSONPPolling (mng, data, req) { + HTTPPolling.call(this, mng, data, req); + + this.head = 'io.j[0]('; + this.foot = ');'; + + if (data.query.i && jsonpolling_re.test(data.query.i)) { + this.head = 'io.j[' + data.query.i + ']('; + } +}; + +/** + * Inherits from Transport. + */ + +JSONPPolling.prototype.__proto__ = HTTPPolling.prototype; + +/** + * Transport name + * + * @api public + */ + +JSONPPolling.prototype.name = 'jsonppolling'; + +/** + * Make sure POST are decoded. + */ + +JSONPPolling.prototype.postEncoded = true; + +/** + * Handles incoming data. + * Due to a bug in \n handling by browsers, we expect a JSONified string. + * + * @api private + */ + +JSONPPolling.prototype.onData = function (data) { + try { + data = JSON.parse(data); + } catch (e) { + this.error('parse', 'reconnect'); + return; + } + + HTTPPolling.prototype.onData.call(this, data); +}; + +/** + * Performs the write. + * + * @api private + */ + +JSONPPolling.prototype.doWrite = function (data) { + HTTPPolling.prototype.doWrite.call(this); + + var data = data === undefined + ? '' : this.head + JSON.stringify(data) + this.foot; + + this.response.writeHead(200, { + 'Content-Type': 'text/javascript; charset=UTF-8' + , 'Content-Length': Buffer.byteLength(data) + , 'Connection': 'Keep-Alive' + , 'X-XSS-Protection': '0' + }); + + this.response.write(data); + this.log.debug(this.name + ' writing', data); +}; diff --git a/networking/node_modules/socket.io/lib/transports/websocket.js b/networking/node_modules/socket.io/lib/transports/websocket.js new file mode 100644 index 0000000..78a4304 --- /dev/null +++ b/networking/node_modules/socket.io/lib/transports/websocket.js @@ -0,0 +1,36 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var protocolVersions = require('./websocket/'); + +/** + * 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) { + var transport + , version = req.headers['sec-websocket-version']; + if (typeof version !== 'undefined' && typeof protocolVersions[version] !== 'undefined') { + transport = new protocolVersions[version](mng, data, req); + } + else transport = new protocolVersions['default'](mng, data, req); + if (typeof this.name !== 'undefined') transport.name = this.name; + return transport; +}; diff --git a/networking/node_modules/socket.io/lib/transports/websocket/default.js b/networking/node_modules/socket.io/lib/transports/websocket/default.js new file mode 100644 index 0000000..2e861a7 --- /dev/null +++ b/networking/node_modules/socket.io/lib/transports/websocket/default.js @@ -0,0 +1,360 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * 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'; + +/** + * Websocket draft version + * + * @api public + */ + +WebSocket.prototype.protocolVersion = 'hixie-76'; + +/** + * 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.manager.settings['match origin protocol'] ? + origin.match(/^https/) : 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/networking/node_modules/socket.io/lib/transports/websocket/hybi-07-12.js b/networking/node_modules/socket.io/lib/transports/websocket/hybi-07-12.js new file mode 100644 index 0000000..44f666a --- /dev/null +++ b/networking/node_modules/socket.io/lib/transports/websocket/hybi-07-12.js @@ -0,0 +1,622 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var Transport = require('../../transport') + , EventEmitter = process.EventEmitter + , crypto = require('crypto') + , url = require('url') + , 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.manager = mng; + this.parser = new Parser(); + this.parser.on('data', function (packet) { + self.onMessage(parser.decodePacket(packet)); + }); + this.parser.on('ping', function () { + // version 8 ping => pong + try { + self.socket.write('\u008a\u0000'); + } + catch (e) { + self.end(); + return; + } + }); + 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'; + +/** + * Websocket draft version + * + * @api public + */ + +WebSocket.prototype.protocolVersion = '07-12'; + +/** + * Called when the socket connects. + * + * @api private + */ + +WebSocket.prototype.onSocketConnect = function () { + var self = this; + + if (typeof this.req.headers.upgrade === 'undefined' || + this.req.headers.upgrade.toLowerCase() !== 'websocket') { + this.log.warn(this.name + ' connection invalid'); + this.end(); + return; + } + + var origin = this.req.headers['sec-websocket-origin'] + , location = ((this.manager.settings['match origin protocol'] ? + origin.match(/^https/) : this.socket.encrypted) ? + 'wss' : 'ws') + + '://' + this.req.headers.host + this.req.url; + + if (!this.verifyOrigin(origin)) { + this.log.warn(this.name + ' connection invalid: origin mismatch'); + this.end(); + return; + } + + 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); + }); +}; + +/** + * Verifies the origin of a request. + * + * @api private + */ + +WebSocket.prototype.verifyOrigin = function (origin) { + var origins = this.manager.get('origins'); + + if (origin === 'null') origin = '*'; + + if (origins.indexOf('*:*') !== -1) { + return true; + } + + if (origin) { + try { + var parts = url.parse(origin); + parts.port = parts.port || 80; + var ok = + ~origins.indexOf(parts.hostname + ':' + parts.port) || + ~origins.indexOf(parts.hostname + ':*') || + ~origins.indexOf('*:' + parts.port); + 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 websocket call, yet required by config'); + } + return false; +}; + +/** + * Writes to the socket. + * + * @api private + */ + +WebSocket.prototype.write = function (data) { + if (this.open) { + var buf = this.frame(0x81, data); + try { + this.socket.write(buf, 'binary'); + } + catch (e) { + this.end(); + return; + } + this.log.debug(this.name + ' writing', data); + } +}; + +/** + * 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; +}; + +/** + * 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)); + }); + } + }, + // binary + '2': function(data) { + var finish = function(mask, data) { + if (typeof self.currentMessage == 'string') self.currentMessage = []; // build a buffer list + self.currentMessage.push(self.unmask(mask, data, true)); + if (self.state.lastFragment) { + self.emit('binary', self.concatBuffers(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 must be 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 + this.state.opcode = this.state.activeFragmentedOperation; + if (!(this.state.opcode == 1 || this.state.opcode == 2)) { + this.error('continuation frame cannot follow current opcode') + return; + } + } + else { + this.state.opcode = opcode; + if (this.state.lastFragment === false) { + this.state.activeFragmentedOperation = opcode; + } + } + 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, binary) { + if (mask != null) { + for (var i = 0, ll = buf.length; i < ll; i++) { + buf[i] ^= mask[i % 4]; + } + } + if (binary) return buf; + return buf != null ? buf.toString('utf8') : ''; +} + +/** + * Concatenates a list of buffers. + * + * @api private + */ + +Parser.prototype.concatBuffers = function(buffers) { + var length = 0; + for (var i = 0, l = buffers.length; i < l; ++i) { + length += buffers[i].length; + } + var mergedBuffer = new Buffer(length); + var offset = 0; + for (var i = 0, l = buffers.length; i < l; ++i) { + buffers[i].copy(mergedBuffer, offset); + offset += buffers[i].length; + } + return mergedBuffer; +} + +/** + * Handles an error + * + * @api private + */ + +Parser.prototype.error = function (reason) { + this.reset(); + this.emit('error', reason); + return this; +}; diff --git a/networking/node_modules/socket.io/lib/transports/websocket/hybi-16.js b/networking/node_modules/socket.io/lib/transports/websocket/hybi-16.js new file mode 100644 index 0000000..69967da --- /dev/null +++ b/networking/node_modules/socket.io/lib/transports/websocket/hybi-16.js @@ -0,0 +1,622 @@ +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var Transport = require('../../transport') + , EventEmitter = process.EventEmitter + , crypto = require('crypto') + , url = require('url') + , 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.manager = mng; + this.parser = new Parser(); + this.parser.on('data', function (packet) { + self.onMessage(parser.decodePacket(packet)); + }); + this.parser.on('ping', function () { + // version 8 ping => pong + try { + self.socket.write('\u008a\u0000'); + } + catch (e) { + self.end(); + return; + } + }); + 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'; + +/** + * Websocket draft version + * + * @api public + */ + +WebSocket.prototype.protocolVersion = '16'; + +/** + * Called when the socket connects. + * + * @api private + */ + +WebSocket.prototype.onSocketConnect = function () { + var self = this; + + if (typeof this.req.headers.upgrade === 'undefined' || + this.req.headers.upgrade.toLowerCase() !== 'websocket') { + this.log.warn(this.name + ' connection invalid'); + this.end(); + return; + } + + var origin = this.req.headers['origin'] || '' + , location = ((this.manager.settings['match origin protocol'] ? + origin.match(/^https/) : this.socket.encrypted) ? + 'wss' : 'ws') + + '://' + this.req.headers.host + this.req.url; + + if (!this.verifyOrigin(origin)) { + this.log.warn(this.name + ' connection invalid: origin mismatch'); + this.end(); + return; + } + + 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); + }); +}; + +/** + * Verifies the origin of a request. + * + * @api private + */ + +WebSocket.prototype.verifyOrigin = function (origin) { + var origins = this.manager.get('origins'); + + if (origin === 'null') origin = '*'; + + if (origins.indexOf('*:*') !== -1) { + return true; + } + + if (origin) { + try { + var parts = url.parse(origin); + parts.port = parts.port || 80; + var ok = + ~origins.indexOf(parts.hostname + ':' + parts.port) || + ~origins.indexOf(parts.hostname + ':*') || + ~origins.indexOf('*:' + parts.port); + 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 websocket call, yet required by config'); + } + return false; +}; + +/** + * Writes to the socket. + * + * @api private + */ + +WebSocket.prototype.write = function (data) { + if (this.open) { + var buf = this.frame(0x81, data); + try { + this.socket.write(buf, 'binary'); + } + catch (e) { + this.end(); + return; + } + this.log.debug(this.name + ' writing', data); + } +}; + +/** + * 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; +}; + +/** + * 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)); + }); + } + }, + // binary + '2': function(data) { + var finish = function(mask, data) { + if (typeof self.currentMessage == 'string') self.currentMessage = []; // build a buffer list + self.currentMessage.push(self.unmask(mask, data, true)); + if (self.state.lastFragment) { + self.emit('binary', self.concatBuffers(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 must be empty'); + return; + } + this.state.lastFragment = (data[0] & 0x80) == 0x80; + this.state.masked = (data[1] & 0x80) == 0x80; + var opcode = data[0] & 0xf; + if (opcode == 0) { + // continuation frame + this.state.opcode = this.state.activeFragmentedOperation; + if (!(this.state.opcode == 1 || this.state.opcode == 2)) { + this.error('continuation frame cannot follow current opcode') + return; + } + } + else { + this.state.opcode = opcode; + if (this.state.lastFragment === false) { + this.state.activeFragmentedOperation = opcode; + } + } + 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, binary) { + if (mask != null) { + for (var i = 0, ll = buf.length; i < ll; i++) { + buf[i] ^= mask[i % 4]; + } + } + if (binary) return buf; + return buf != null ? buf.toString('utf8') : ''; +} + +/** + * Concatenates a list of buffers. + * + * @api private + */ + +Parser.prototype.concatBuffers = function(buffers) { + var length = 0; + for (var i = 0, l = buffers.length; i < l; ++i) { + length += buffers[i].length; + } + var mergedBuffer = new Buffer(length); + var offset = 0; + for (var i = 0, l = buffers.length; i < l; ++i) { + buffers[i].copy(mergedBuffer, offset); + offset += buffers[i].length; + } + return mergedBuffer; +} + +/** + * Handles an error + * + * @api private + */ + +Parser.prototype.error = function (reason) { + this.reset(); + this.emit('error', reason); + return this; +}; diff --git a/networking/node_modules/socket.io/lib/transports/websocket/index.js b/networking/node_modules/socket.io/lib/transports/websocket/index.js new file mode 100644 index 0000000..3a952b7 --- /dev/null +++ b/networking/node_modules/socket.io/lib/transports/websocket/index.js @@ -0,0 +1,11 @@ + +/** + * Export websocket versions. + */ + +module.exports = { + 7: require('./hybi-07-12'), + 8: require('./hybi-07-12'), + 13: require('./hybi-16'), + default: require('./default') +}; diff --git a/networking/node_modules/socket.io/lib/transports/xhr-polling.js b/networking/node_modules/socket.io/lib/transports/xhr-polling.js new file mode 100644 index 0000000..1db5aee --- /dev/null +++ b/networking/node_modules/socket.io/lib/transports/xhr-polling.js @@ -0,0 +1,69 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var HTTPPolling = require('./http-polling'); + +/** + * Export the constructor. + */ + +exports = module.exports = XHRPolling; + +/** + * Ajax polling transport. + * + * @api public + */ + +function XHRPolling (mng, data, req) { + HTTPPolling.call(this, mng, data, req); +}; + +/** + * Inherits from Transport. + */ + +XHRPolling.prototype.__proto__ = HTTPPolling.prototype; + +/** + * Transport name + * + * @api public + */ + +XHRPolling.prototype.name = 'xhr-polling'; + +/** + * Frames data prior to write. + * + * @api private + */ + +XHRPolling.prototype.doWrite = function (data) { + HTTPPolling.prototype.doWrite.call(this); + + var origin = this.req.headers.origin + , headers = { + 'Content-Type': 'text/plain; charset=UTF-8' + , 'Content-Length': data === undefined ? 0 : Buffer.byteLength(data) + , 'Connection': 'Keep-Alive' + }; + + if (origin) { + // https://developer.mozilla.org/En/HTTP_Access_Control + headers['Access-Control-Allow-Origin'] = origin; + headers['Access-Control-Allow-Credentials'] = 'true'; + } + + this.response.writeHead(200, headers); + this.response.write(data); + this.log.debug(this.name + ' writing', data); +}; diff --git a/networking/node_modules/socket.io/lib/util.js b/networking/node_modules/socket.io/lib/util.js new file mode 100644 index 0000000..f7d9f2b --- /dev/null +++ b/networking/node_modules/socket.io/lib/util.js @@ -0,0 +1,50 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +/** + * Converts an enumerable to an array. + * + * @api public + */ + +exports.toArray = function (enu) { + var arr = []; + + for (var i = 0, l = enu.length; i < l; i++) + arr.push(enu[i]); + + 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/networking/node_modules/socket.io/node_modules/policyfile/.npmignore b/networking/node_modules/socket.io/node_modules/policyfile/.npmignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/policyfile/.npmignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/networking/node_modules/socket.io/node_modules/policyfile/LICENSE b/networking/node_modules/socket.io/node_modules/policyfile/LICENSE new file mode 100644 index 0000000..bdb8f61 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/policyfile/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011 Arnout Kazemier,3rd-Eden + +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/networking/node_modules/socket.io/node_modules/policyfile/Makefile b/networking/node_modules/socket.io/node_modules/policyfile/Makefile new file mode 100644 index 0000000..1362d66 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/policyfile/Makefile @@ -0,0 +1,7 @@ +doc: + dox --title "FlashPolicyFileServer" lib/* > doc/index.html + +test: + expresso -I lib $(TESTFLAGS) tests/*.test.js + +.PHONY: test doc \ No newline at end of file diff --git a/networking/node_modules/socket.io/node_modules/policyfile/README.md b/networking/node_modules/socket.io/node_modules/policyfile/README.md new file mode 100644 index 0000000..527921e --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/policyfile/README.md @@ -0,0 +1,98 @@ +## LOL, WUT? +It basically allows you to allow or disallow Flash Player sockets from accessing your site. + +## Installation + +```bash +npm install policyfile +``` +## Usage + +The server is based on the regular and know `net` and `http` server patterns. So it you can just listen +for all the events that a `net` based server emits etc. But there is one extra event, the `connect_failed` +event. This event is triggered when we are unable to listen on the supplied port number. + +### createServer +Creates a new server instance and accepts 2 optional arguments: + +- `options` **Object** Options to configure the server instance + - `log` **Boolean** Enable logging to STDOUT and STDERR (defaults to true) +- `origins` **Array** An Array of origins that are allowed by the server (defaults to *:*) + +```js +var pf = require('policyfile'); +pf.createServer(); +pf.listen(); +``` + +#### server.listen +Start listening on the server and it takes 3 optional arguments + +- `port` **Number** On which port number should we listen? (defaults to 843, which is the first port number the FlashPlayer checks) +- `server` **Server** A http server, if we are unable to accept requests or run the server we can also answer the policy requests inline over the supplied HTTP server. +- `callback` **Function** A callback function that is called when listening to the server was successful. + +```js +var pf = require('policyfile'); +pf.createServer(); +pf.listen(1337, function(){ + console.log(':3 yay') +}); +``` + +Changing port numbers can be handy if you do not want to run your server as root and have port 843 forward to a non root port number (aka a number above 1024). + +```js +var pf = require('policyfile') + , http = require('http'); + +server = http.createServer(function(q,r){r.writeHead(200);r.end('hello world')}); +server.listen(80); + +pf.createServer(); +pf.listen(1337, server, function(){ + console.log(':3 yay') +}); +``` + +Support for serving inline requests over a existing HTTP connection as the FlashPlayer will first check port 843, but if it's unable to get a response there it will send a policy file request over port 80, which is usually your http server. + +#### server.add +Adds more origins to the policy file you can add as many arguments as you like. + +```js +var pf = require('policyfile'); +pf.createServer(['google.com:80']); +pf.listen(); +pf.add('blog.3rd-Eden.com:80', 'blog.3rd-Eden.com:8080'); // now has 3 origins +``` + +#### server.add +Adds more origins to the policy file you can add as many arguments as you like. + +```js +var pf = require('policyfile'); +pf.createServer(['blog.3rd-Eden.com:80', 'blog.3rd-Eden.com:8080']); +pf.listen(); +pf.remove('blog.3rd-Eden.com:8080'); // only contains the :80 version now +``` + +#### server.close +Shuts down the server + +```js +var pf = require('policyfile'); +pf.createServer(); +pf.listen(); +pf.close(); // OH NVM. +``` + +## API +http://3rd-eden.com/FlashPolicyFileServer/ + +## Examples +See https://github.com/3rd-Eden/FlashPolicyFileServer/tree/master/examples for examples + +## Licence + +MIT see LICENSE file in the repository \ No newline at end of file diff --git a/networking/node_modules/socket.io/node_modules/policyfile/doc/index.html b/networking/node_modules/socket.io/node_modules/policyfile/doc/index.html new file mode 100644 index 0000000..743fcda --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/policyfile/doc/index.html @@ -0,0 +1,375 @@ + + + FlashPolicyFileServer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

FlashPolicyFileServer

server

lib/server.js
+

Module dependencies and cached references. +

+
+
var slice = Array.prototype.slice
+  , net = require('net');
+
+

The server that does the Policy File severing

+ +

Options

+ +
  • log false or a function that can output log information, defaults to console.log?
+ +

+ +
  • param: Object options Options to customize the servers functionality.

  • param: Array origins The origins that are allowed on this server, defaults to *:*.

  • api: public

+
+
function Server(options, origins){
+  var me = this;
+  
+  this.origins = origins || ['*:*'];
+  this.port = 843;
+  this.log = console.log;
+  
+  // merge `this` with the options
+  Object.keys(options).forEach(function(key){
+    me[key] &amp;&amp; (me[key] = options[key])
+  });
+  
+  // create the net server
+  this.socket = net.createServer(function createServer(socket){
+    socket.on('error', function socketError(){ me.responder.call(me, socket) });
+    me.responder.call(me, socket);
+  });
+  
+  // Listen for errors as the port might be blocked because we do not have root priv.
+  this.socket.on('error', function serverError(err){
+    // Special and common case error handling
+    if (err.errno == 13){
+      me.log &amp;&amp; me.log(
+        'Unable to listen to port `' + me.port + '` as your Node.js instance does not have root privileges. ' +
+        (
+          me.server
+          ? 'The Flash Policy file will now be served inline over the supplied HTTP server, Flash Policy files request will suffer.'
+          : 'No fallback server supplied.'
+        )
+      );
+      
+      me.socket.removeAllListeners();
+      delete me.socket;
+
+      me.emit('connect_failed', err);
+    } else {
+      me.log &amp;&amp; me.log('FlashPolicyFileServer received a error event:\n' + (err.message ? err.message : err));
+    }
+  });
+  
+  this.socket.on('timeout', function serverTimeout(){});
+  this.socket.on('close', function serverClosed(err){
+    err &amp;&amp; me.log &amp;&amp; me.log('Server closing due to an error: \n' + (err.message ? err.message : err));
+    
+    if (me.server){
+      // not online anymore
+      delete me.server.online;
+      
+      // Remove the inline policy listener if we close down
+      // but only when the server was `online` (see listen prototype)
+      if( me.server['@'] &amp;&amp; me.server.online){
+        me.server.removeListener('connection', me.server['@']);
+      }
+    }
+    me.log &amp;&amp; me.log('Shutting down FlashPolicyFileServer');
+  });
+  
+  // Compile the initial `buffer`
+  this.compile();
+}
+
+

Start listening for requests

+ +

+ +
  • param: Number port The port number it should be listening to.

  • param: Server server A HTTP server instance, this will be used to listen for inline requests

  • param: Function cb The callback needs to be called once server is ready

  • api: public

+
+
Server.prototype.listen = function listen(port, server, cb){
+  var me = this
+    , args = slice.call(arguments, 0)
+    , callback;
+  
+  // assign the correct vars, for flexible arguments
+  args.forEach(function args(arg){
+    var type = typeof arg;
+    
+    if (type === 'number') me.port = arg;
+    if (type === 'function') callback = arg;
+    if (type === 'object') me.server = arg;
+  });
+  
+  if (this.server){
+    
+    // no one in their right mind would ever create a `@` prototype, so Im just gonna store
+    // my function on the server, so I can remove it later again once the server(s) closes
+    this.server['@'] = function connection(socket){
+      socket.once('data', function requestData(data){
+        // if it's a Flash policy request, and we can write to the 
+        if (
+             data
+          &amp;&amp; data[0] === 60
+          &amp;&amp; data.toString() === '<policy-file-request/>\0'
+          &amp;&amp; socket
+          &amp;&amp; (socket.readyState === 'open' || socket.readyState === 'writeOnly')
+        ){
+          // send the buffer
+          socket.end(me.buffer);
+        }
+      });
+    };
+    // attach it
+    this.server.on('connection', this.server['@']);
+  }
+  
+  // We add a callback method, so we can set a flag for when the server is `enabled` or `online`.
+  // this flag is needed because if a error occurs and the we cannot boot up the server the
+  // fallback functionality should not be removed during the `close` event
+  this.socket.listen(this.port, function serverListening(){
+   me.socket.online = true;
+   
+   if (callback) callback(), callback = undefined;
+   
+  });
+  
+  return this;
+};
+
+

Adds a new origin to the Flash Policy File.

+ +

+ +
  • param: Arguments The origins that need to be added.

  • api: public

+
+
Server.prototype.add = function add(){
+  var args = slice.call(arguments, 0)
+    , i = args.length;
+  
+  // flag duplicates
+  while (i--){
+    if (this.origins.indexOf(args[i]) &gt;= 0){
+      args[i] = null;
+    }
+  }
+  
+  // Add all the arguments to the array
+  // but first we want to remove all `falsy` values from the args
+  Array.prototype.push.apply(
+    this.origins
+  , args.filter(function(value){ return !!value })
+  );
+  
+  this.compile();
+  return this;
+};
+
+

Removes a origin from the Flash Policy File.

+ +

+ +
  • param: String origin The origin that needs to be removed from the server

  • api: public

+
+
Server.prototype.remove = function remove(origin){
+  var position = this.origins.indexOf(origin);
+  
+  // only remove and recompile if we have a match
+  if (position &gt; 0){
+    this.origins.splice(position,1);
+    this.compile();
+  }
+  
+  return this;
+};
+
+

Closes and cleans up the server

+ +
  • api: public

+
+
Server.prototype.close = function close(){
+  this.socket.removeAllListeners();
+  this.socket.close();
+  
+  return this;
+};
+
+

Proxy the event listener requests to the created Net server +

+
+
Object.keys(process.EventEmitter.prototype).forEach(function proxy(key){
+  Server.prototype[key] = Server.prototype[key] || function (){
+    if (this.socket) this.socket[key].apply(this.socket, arguments);
+    return this;
+  };
+});
+
+

Creates a new server instance.

+ +

+ +
  • param: Object options A options object to override the default config

  • param: Array origins The origins that should be allowed by the server

  • api: public

+
+
exports.createServer = function createServer(options, origins){
+  origins = Array.isArray(origins) ? origins : (Array.isArray(options) ? options : false);
+  options = !Array.isArray(options) &amp;&amp; options ? options : {};
+  
+  return new Server(options, origins);
+};
+
+

Provide a hook to the original server, so it can be extended if needed. +

+
+
exports.Server = Server;
+
+

Module version +

+
+
exports.version = '0.0.2';
+
+
\ No newline at end of file diff --git a/networking/node_modules/socket.io/node_modules/policyfile/examples/basic.fallback.js b/networking/node_modules/socket.io/node_modules/policyfile/examples/basic.fallback.js new file mode 100644 index 0000000..b439449 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/policyfile/examples/basic.fallback.js @@ -0,0 +1,8 @@ +var http = require('http') + , fspfs = require('../'); + +var server = http.createServer(function(q,r){ r.writeHead(200); r.end(':3') }) + , flash = fspfs.createServer(); + +server.listen(8080); +flash.listen(8081,server); \ No newline at end of file diff --git a/networking/node_modules/socket.io/node_modules/policyfile/examples/basic.js b/networking/node_modules/socket.io/node_modules/policyfile/examples/basic.js new file mode 100644 index 0000000..5e2290f --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/policyfile/examples/basic.js @@ -0,0 +1,5 @@ +var http = require('http') + , fspfs = require('../'); + +var flash = fspfs.createServer(); +flash.listen(); \ No newline at end of file diff --git a/networking/node_modules/socket.io/node_modules/policyfile/index.js b/networking/node_modules/socket.io/node_modules/policyfile/index.js new file mode 100644 index 0000000..60cf298 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/policyfile/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/server.js'); \ No newline at end of file diff --git a/networking/node_modules/socket.io/node_modules/policyfile/lib/server.js b/networking/node_modules/socket.io/node_modules/policyfile/lib/server.js new file mode 100644 index 0000000..a525772 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/policyfile/lib/server.js @@ -0,0 +1,289 @@ +/** + * Module dependencies and cached references. + */ + +var slice = Array.prototype.slice + , net = require('net'); + +/** + * The server that does the Policy File severing + * + * Options: + * - `log` false or a function that can output log information, defaults to console.log? + * + * @param {Object} options Options to customize the servers functionality. + * @param {Array} origins The origins that are allowed on this server, defaults to `*:*`. + * @api public + */ + +function Server (options, origins) { + var me = this; + + this.origins = origins || ['*:*']; + this.port = 843; + this.log = console.log; + + // merge `this` with the options + Object.keys(options).forEach(function (key) { + me[key] && (me[key] = options[key]) + }); + + // create the net server + this.socket = net.createServer(function createServer (socket) { + socket.on('error', function socketError () { + me.responder.call(me, socket); + }); + + me.responder.call(me, socket); + }); + + // Listen for errors as the port might be blocked because we do not have root priv. + this.socket.on('error', function serverError (err) { + // Special and common case error handling + if (err.errno == 13) { + me.log && me.log( + 'Unable to listen to port `' + me.port + '` as your Node.js instance does not have root privileges. ' + + ( + me.server + ? 'The Flash Policy File requests will only be served inline over the supplied HTTP server. Inline serving is slower than a dedicated server instance.' + : 'No fallback server supplied, we will be unable to answer Flash Policy File requests.' + ) + ); + + me.emit('connect_failed', err); + me.socket.removeAllListeners(); + delete me.socket; + } else { + me.log && me.log('FlashPolicyFileServer received an error event:\n' + (err.message ? err.message : err)); + } + }); + + this.socket.on('timeout', function serverTimeout () {}); + this.socket.on('close', function serverClosed (err) { + err && me.log && me.log('Server closing due to an error: \n' + (err.message ? err.message : err)); + + if (me.server) { + // Remove the inline policy listener if we close down + // but only when the server was `online` (see listen prototype) + if (me.server['@'] && me.server.online) { + me.server.removeListener('connection', me.server['@']); + } + + // not online anymore + delete me.server.online; + } + }); + + // Compile the initial `buffer` + this.compile(); +} + +/** + * Start listening for requests + * + * @param {Number} port The port number it should be listening to. + * @param {Server} server A HTTP server instance, this will be used to listen for inline requests + * @param {Function} cb The callback needs to be called once server is ready + * @api public + */ + +Server.prototype.listen = function listen (port, server, cb){ + var me = this + , args = slice.call(arguments, 0) + , callback; + + // assign the correct vars, for flexible arguments + args.forEach(function args (arg){ + var type = typeof arg; + + if (type === 'number') me.port = arg; + if (type === 'function') callback = arg; + if (type === 'object') me.server = arg; + }); + + if (this.server) { + + // no one in their right mind would ever create a `@` prototype, so Im just gonna store + // my function on the server, so I can remove it later again once the server(s) closes + this.server['@'] = function connection (socket) { + socket.once('data', function requestData (data) { + // if it's a Flash policy request, and we can write to the + if ( + data + && data[0] === 60 + && data.toString() === '\0' + && socket + && (socket.readyState === 'open' || socket.readyState === 'writeOnly') + ){ + // send the buffer + try { + socket.end(me.buffer); + } catch (e) {} + } + }); + }; + + // attach it + this.server.on('connection', this.server['@']); + } + + // We add a callback method, so we can set a flag for when the server is `enabled` or `online`. + // this flag is needed because if a error occurs and the we cannot boot up the server the + // fallback functionality should not be removed during the `close` event + this.port >= 0 && this.socket.listen(this.port, function serverListening () { + me.socket.online = true; + if (callback) { + callback.call(me); + callback = undefined; + } + }); + + return this; +}; + +/** + * Responds to socket connects and writes the compile policy file. + * + * @param {net.Socket} socket The socket that needs to receive the message + * @api private + */ + +Server.prototype.responder = function responder (socket){ + if (socket && socket.readyState == 'open' && socket.end) { + try { + socket.end(this.buffer); + } catch (e) {} + } +}; + +/** + * Compiles the supplied origins to a Flash Policy File format and stores it in a Node.js Buffer + * this way it can be send over the wire without any performance loss. + * + * @api private + */ + +Server.prototype.compile = function compile (){ + var xml = [ + '' + , '' + , '' + ]; + + // add the allow access element + this.origins.forEach(function origin (origin){ + var parts = origin.split(':'); + xml.push(''); + }); + + xml.push(''); + + // store the result in a buffer so we don't have to re-generate it all the time + this.buffer = new Buffer(xml.join(''), 'utf8'); + + return this; +}; + +/** + * Adds a new origin to the Flash Policy File. + * + * @param {Arguments} The origins that need to be added. + * @api public + */ + +Server.prototype.add = function add(){ + var args = slice.call(arguments, 0) + , i = args.length; + + // flag duplicates + while (i--) { + if (this.origins.indexOf(args[i]) >= 0){ + args[i] = null; + } + } + + // Add all the arguments to the array + // but first we want to remove all `falsy` values from the args + Array.prototype.push.apply( + this.origins + , args.filter(function filter (value) { + return !!value; + }) + ); + + this.compile(); + return this; +}; + +/** + * Removes a origin from the Flash Policy File. + * + * @param {String} origin The origin that needs to be removed from the server + * @api public + */ + +Server.prototype.remove = function remove (origin){ + var position = this.origins.indexOf(origin); + + // only remove and recompile if we have a match + if (position > 0) { + this.origins.splice(position,1); + this.compile(); + } + + return this; +}; + +/** + * Closes and cleans up the server + * + * @api public + */ + +Server.prototype.close = function close () { + this.socket.removeAllListeners(); + this.socket.close(); + + return this; +}; + +/** + * Proxy the event listener requests to the created Net server + */ + +Object.keys(process.EventEmitter.prototype).forEach(function proxy (key){ + Server.prototype[key] = Server.prototype[key] || function () { + if (this.socket) { + this.socket[key].apply(this.socket, arguments); + } + + return this; + }; +}); + +/** + * Creates a new server instance. + * + * @param {Object} options A options object to override the default config + * @param {Array} origins The origins that should be allowed by the server + * @api public + */ + +exports.createServer = function createServer(options, origins){ + origins = Array.isArray(origins) ? origins : (Array.isArray(options) ? options : false); + options = !Array.isArray(options) && options ? options : {}; + + return new Server(options, origins); +}; + +/** + * Provide a hook to the original server, so it can be extended if needed. + */ + +exports.Server = Server; + +/** + * Module version + */ + +exports.version = '0.0.4'; diff --git a/networking/node_modules/socket.io/node_modules/policyfile/package.json b/networking/node_modules/socket.io/node_modules/policyfile/package.json new file mode 100644 index 0000000..4351b94 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/policyfile/package.json @@ -0,0 +1,55 @@ +{ + "name": "policyfile", + "version": "0.0.4", + "author": { + "name": "Arnout Kazemier" + }, + "description": "Flash Socket Policy File Server. A server to respond to Flash Socket Policy requests, both inline and through a dedicated server instance.", + "main": "index", + "keywords": [ + "flash", + "socket", + "policy", + "file", + "server", + "Flash Socket Policy File Server", + "cross domain" + ], + "directories": { + "lib": "./lib" + }, + "maintainers": [ + { + "name": "Arnout Kazemier", + "email": "info@3rd-Eden.com", + "url": "http://blog.3rd-Eden.com" + } + ], + "licenses": [ + { + "type": "MIT", + "url": "https://github.com/3rd-Eden/FlashPolicyFileServer/blob/master/LICENSE" + } + ], + "repositories": [ + { + "type": "git", + "url": "https://github.com/3rd-Eden/FlashPolicyFileServer.git" + } + ], + "_id": "policyfile@0.0.4", + "dependencies": {}, + "devDependencies": {}, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "_engineSupported": true, + "_npmVersion": "1.1.4", + "_nodeVersion": "v0.6.12", + "_defaultsLoaded": true, + "dist": { + "shasum": "6abed755dc4c523bb66e1ad141721109483381d0" + }, + "_from": "policyfile@0.0.4" +} diff --git a/networking/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.crt b/networking/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.crt new file mode 100644 index 0000000..5883cd4 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.crt @@ -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/networking/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.private.key b/networking/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.private.key new file mode 100644 index 0000000..f31ff3d --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.private.key @@ -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/networking/node_modules/socket.io/node_modules/policyfile/tests/unit.test.js b/networking/node_modules/socket.io/node_modules/policyfile/tests/unit.test.js new file mode 100644 index 0000000..932b3c1 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/policyfile/tests/unit.test.js @@ -0,0 +1,231 @@ +var fspfs = require('../') + , fs = require('fs') + , http = require('http') + , https = require('https') + , net = require('net') + , should = require('should') + , assert = require('assert'); + +module.exports = { + // Library version should be Semver compatible + 'Library version': function(){ + fspfs.version.should.match(/^\d+\.\d+\.\d+$/); + } + + // Creating a server instace should not cause any problems + // either using the new Server or createServer method. +, 'Create Server instance': function(){ + var server = fspfs.createServer() + , server2 = new fspfs.Server({log:false}, ['blog.3rd-Eden.com:1337']); + + // server 2 options test + server2.log.should.be.false; + server2.origins.length.should.equal(1); + server2.origins[0].should.equal('blog.3rd-Eden.com:1337'); + + // server defaults + (typeof server.log).should.be.equal('function'); + server.origins.length.should.equal(1); + server.origins[0].should.equal('*:*'); + + // instance checking, sanity check + assert.ok(server instanceof fspfs.Server); + assert.ok(!!server.buffer); + + // more options testing + server = fspfs.createServer(['blog.3rd-Eden.com:80']); + server.origins.length.should.equal(1); + server.origins[0].should.equal('blog.3rd-Eden.com:80'); + + server = fspfs.createServer({log:false},['blog.3rd-Eden.com:80']); + server.log.should.be.false; + server.origins.length.should.equal(1); + server.origins[0].should.equal('blog.3rd-Eden.com:80'); + + } + +, 'Add origin': function(){ + var server = fspfs.createServer(); + server.add('google.com:80', 'blog.3rd-Eden.com:1337'); + + server.origins.length.should.equal(3); + server.origins.indexOf('google.com:80').should.be.above(0); + + // don't allow duplicates + server.add('google.com:80', 'google.com:80'); + + var i = server.origins.length + , count = 0; + + while(i--){ + if (server.origins[i] === 'google.com:80'){ + count++; + } + } + + count.should.equal(1); + } + +, 'Remove origin': function(){ + var server = fspfs.createServer(); + server.add('google.com:80', 'blog.3rd-Eden.com:1337'); + server.origins.length.should.equal(3); + + server.remove('google.com:80'); + server.origins.length.should.equal(2); + server.origins.indexOf('google.com:80').should.equal(-1); + } + +, 'Buffer': function(){ + var server = fspfs.createServer(); + + Buffer.isBuffer(server.buffer).should.be.true; + server.buffer.toString().indexOf('to-ports="*"').should.be.above(0); + server.buffer.toString().indexOf('domain="*"').should.be.above(0); + server.buffer.toString().indexOf('domain="google.com"').should.equal(-1); + + // The buffers should be rebuild when new origins are added + server.add('google.com:80'); + server.buffer.toString().indexOf('to-ports="80"').should.be.above(0); + server.buffer.toString().indexOf('domain="google.com"').should.be.above(0); + + server.remove('google.com:80'); + server.buffer.toString().indexOf('to-ports="80"').should.equal(-1); + server.buffer.toString().indexOf('domain="google.com"').should.equal(-1); + } + +, 'Responder': function(){ + var server = fspfs.createServer() + , calls = 0 + // dummy socket to emulate a `real` socket + , dummySocket = { + readyState: 'open' + , end: function(buffer){ + calls++; + Buffer.isBuffer(buffer).should.be.true; + buffer.toString().should.equal(server.buffer.toString()); + } + }; + + server.responder(dummySocket); + calls.should.equal(1); + } + +, 'Event proxy': function(){ + var server = fspfs.createServer() + , calls = 0; + + Object.keys(process.EventEmitter.prototype).forEach(function proxy(key){ + assert.ok(!!server[key] && typeof server[key] === 'function'); + }); + + // test if it works by calling a none default event + server.on('pew', function(){ + calls++; + }); + + server.emit('pew'); + calls.should.equal(1); + } + +, 'inline response http': function(){ + var port = 1335 + , httpserver = http.createServer(function(q,r){r.writeHead(200);r.end(':3')}) + , server = fspfs.createServer(); + + httpserver.listen(port, function(){ + server.listen(port + 1, httpserver, function(){ + var client = net.createConnection(port); + client.write('\0'); + client.on('error', function(err){ + assert.ok(!err, err) + }); + client.on('data', function(data){ + + var response = data.toString(); + console.log(response); + + response.indexOf('to-ports="*"').should.be.above(0); + response.indexOf('domain="*"').should.be.above(0); + response.indexOf('domain="google.com"').should.equal(-1); + + // clean up + client.destroy(); + server.close(); + httpserver.close(); + }); + }); + }); + } + +, 'server response': function(){ + var port = 1340 + , server = fspfs.createServer(); + + server.listen(port, function(){ + var client = net.createConnection(port); + client.write('\0'); + client.on('error', function(err){ + assert.ok(!err, err) + }); + client.on('data', function(data){ + + var response = data.toString(); + + response.indexOf('to-ports="*"').should.be.above(0); + response.indexOf('domain="*"').should.be.above(0); + response.indexOf('domain="google.com"').should.equal(-1); + + // clean up + client.destroy(); + server.close(); + }); + }); + } + +, 'inline response https': function(){ + var port = 1345 + , ssl = { + key: fs.readFileSync(__dirname + '/ssl/ssl.private.key').toString() + , cert: fs.readFileSync(__dirname + '/ssl/ssl.crt').toString() + } + , httpserver = https.createServer(ssl, function(q,r){r.writeHead(200);r.end(':3')}) + , server = fspfs.createServer(); + + httpserver.listen(port, function(){ + server.listen(port + 1, httpserver, function(){ + var client = net.createConnection(port); + client.write('\0'); + client.on('error', function(err){ + assert.ok(!err, err) + }); + client.on('data', function(data){ + + var response = data.toString(); + + response.indexOf('to-ports="*"').should.be.above(0); + response.indexOf('domain="*"').should.be.above(0); + response.indexOf('domain="google.com"').should.equal(-1); + + // clean up + client.destroy(); + server.close(); + httpserver.close(); + }); + }); + }); + } + +, 'connect_failed': function(){ + var server = fspfs.createServer(); + + server.on('connect_failed', function(){ + assert.ok(true); + }); + + server.listen(function(){ + assert.ok(false, 'Run this test without root access'); + server.close(); + }); + } +}; \ No newline at end of file diff --git a/networking/node_modules/socket.io/node_modules/redis/README.md b/networking/node_modules/socket.io/node_modules/redis/README.md new file mode 100644 index 0000000..02a873b --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/README.md @@ -0,0 +1,567 @@ +redis - a node.js redis client +=========================== + +This is a complete Redis client for node.js. It supports all Redis commands, including many recently added commands like EVAL from +experimental Redis server branches. + + +Install with: + + npm install redis + +Pieter Noordhuis has provided a binding to the official `hiredis` C library, which is non-blocking and fast. To use `hiredis`, do: + + npm install hiredis redis + +If `hiredis` is installed, `node_redis` will use it by default. Otherwise, a pure JavaScript parser will be used. + +If you use `hiredis`, be sure to rebuild it whenever you upgrade your version of node. There are mysterious failures that can +happen between node and native code modules after a node upgrade. + + +## Usage + +Simple example, included as `examples/simple.js`: + + var redis = require("redis"), + client = redis.createClient(); + + client.on("error", function (err) { + console.log("Error " + err); + }); + + client.set("string key", "string val", redis.print); + client.hset("hash key", "hashtest 1", "some value", redis.print); + client.hset(["hash key", "hashtest 2", "some other value"], redis.print); + client.hkeys("hash key", function (err, replies) { + console.log(replies.length + " replies:"); + replies.forEach(function (reply, i) { + console.log(" " + i + ": " + reply); + }); + client.quit(); + }); + +This will display: + + mjr:~/work/node_redis (master)$ node example.js + Reply: OK + Reply: 0 + Reply: 0 + 2 replies: + 0: hashtest 1 + 1: hashtest 2 + mjr:~/work/node_redis (master)$ + + +## Performance + +Here are typical results of `multi_bench.js` which is similar to `redis-benchmark` from the Redis distribution. +It uses 50 concurrent connections with no pipelining. + +JavaScript parser: + + PING: 20000 ops 42283.30 ops/sec 0/5/1.182 + SET: 20000 ops 32948.93 ops/sec 1/7/1.515 + GET: 20000 ops 28694.40 ops/sec 0/9/1.740 + INCR: 20000 ops 39370.08 ops/sec 0/8/1.269 + LPUSH: 20000 ops 36429.87 ops/sec 0/8/1.370 + LRANGE (10 elements): 20000 ops 9891.20 ops/sec 1/9/5.048 + LRANGE (100 elements): 20000 ops 1384.56 ops/sec 10/91/36.072 + +hiredis parser: + + PING: 20000 ops 46189.38 ops/sec 1/4/1.082 + SET: 20000 ops 41237.11 ops/sec 0/6/1.210 + GET: 20000 ops 39682.54 ops/sec 1/7/1.257 + INCR: 20000 ops 40080.16 ops/sec 0/8/1.242 + LPUSH: 20000 ops 41152.26 ops/sec 0/3/1.212 + LRANGE (10 elements): 20000 ops 36563.07 ops/sec 1/8/1.363 + LRANGE (100 elements): 20000 ops 21834.06 ops/sec 0/9/2.287 + +The performance of `node_redis` improves dramatically with pipelining, which happens automatically in most normal programs. + + +### Sending Commands + +Each Redis command is exposed as a function on the `client` object. +All functions take either take either an `args` Array plus optional `callback` Function or +a variable number of individual arguments followed by an optional callback. +Here is an example of passing an array of arguments and a callback: + + client.mset(["test keys 1", "test val 1", "test keys 2", "test val 2"], function (err, res) {}); + +Here is that same call in the second style: + + client.mset("test keys 1", "test val 1", "test keys 2", "test val 2", function (err, res) {}); + +Note that in either form the `callback` is optional: + + client.set("some key", "some val"); + client.set(["some other key", "some val"]); + +For a list of Redis commands, see [Redis Command Reference](http://redis.io/commands) + +The commands can be specified in uppercase or lowercase for convenience. `client.get()` is the same as `client.GET()`. + +Minimal parsing is done on the replies. Commands that return a single line reply return JavaScript Strings, +integer replies return JavaScript Numbers, "bulk" replies return node Buffers, and "multi bulk" replies return a +JavaScript Array of node Buffers. `HGETALL` returns an Object with Buffers keyed by the hash keys. + +# API + +## Connection Events + +`client` will emit some events about the state of the connection to the Redis server. + +### "ready" + +`client` will emit `ready` a connection is established to the Redis server and the server reports +that it is ready to receive commands. Commands issued before the `ready` event are queued, +then replayed just before this event is emitted. + +### "connect" + +`client` will emit `connect` at the same time as it emits `ready` unless `client.options.no_ready_check` +is set. If this options is set, `connect` will be emitted when the stream is connected, and then +you are free to try to send commands. + +### "error" + +`client` will emit `error` when encountering an error connecting to the Redis server. + +Note that "error" is a special event type in node. If there are no listeners for an +"error" event, node will exit. This is usually what you want, but it can lead to some +cryptic error messages like this: + + mjr:~/work/node_redis (master)$ node example.js + + node.js:50 + throw e; + ^ + Error: ECONNREFUSED, Connection refused + at IOWatcher.callback (net:870:22) + at node.js:607:9 + +Not very useful in diagnosing the problem, but if your program isn't ready to handle this, +it is probably the right thing to just exit. + +`client` will also emit `error` if an exception is thrown inside of `node_redis` for whatever reason. +It would be nice to distinguish these two cases. + +### "end" + +`client` will emit `end` when an established Redis server connection has closed. + +### "drain" + +`client` will emit `drain` when the TCP connection to the Redis server has been buffering, but is now +writable. This event can be used to stream commands in to Redis and adapt to backpressure. Right now, +you need to check `client.command_queue.length` to decide when to reduce your send rate. Then you can +resume sending when you get `drain`. + +### "idle" + +`client` will emit `idle` when there are no outstanding commands that are awaiting a response. + +## redis.createClient(port, host, options) + +Create a new client connection. `port` defaults to `6379` and `host` defaults +to `127.0.0.1`. If you have `redis-server` running on the same computer as node, then the defaults for +port and host are probably fine. `options` in an object with the following possible properties: + +* `parser`: which Redis protocol reply parser to use. Defaults to `hiredis` if that module is installed. +This may also be set to `javascript`. +* `return_buffers`: defaults to false. If set to `true`, then bulk data replies will be returned as node Buffer +objects instead of JavaScript Strings. + +`createClient()` returns a `RedisClient` object that is named `client` in all of the examples here. + +## client.auth(password, callback) + +When connecting to Redis servers that require authentication, the `AUTH` command must be sent as the +first command after connecting. This can be tricky to coordinate with reconnections, the ready check, +etc. To make this easier, `client.auth()` stashes `password` and will send it after each connection, +including reconnections. `callback` is invoked only once, after the response to the very first +`AUTH` command sent. + +## client.end() + +Forcibly close the connection to the Redis server. Note that this does not wait until all replies have been parsed. +If you want to exit cleanly, call `client.quit()` to send the `QUIT` command after you have handled all replies. + +This example closes the connection to the Redis server before the replies have been read. You probably don't +want to do this: + + var redis = require("redis"), + client = redis.createClient(); + + client.set("foo_rand000000000000", "some fantastic value"); + client.get("foo_rand000000000000", function (err, reply) { + console.log(reply.toString()); + }); + client.end(); + +`client.end()` is useful for timeout cases where something is stuck or taking too long and you want +to start over. + +## Friendlier hash commands + +Most Redis commands take a single String or an Array of Strings as arguments, and replies are sent back as a single String or an Array of Strings. When dealing with hash values, there are a couple of useful exceptions to this. + +### client.hgetall(hash) + +The reply from an HGETALL command will be converted into a JavaScript Object by `node_redis`. That way you can interact +with the responses using JavaScript syntax. + +Example: + + client.hmset("hosts", "mjr", "1", "another", "23", "home", "1234"); + client.hgetall("hosts", function (err, obj) { + console.dir(obj); + }); + +Output: + + { mjr: '1', another: '23', home: '1234' } + +### client.hmset(hash, obj, [callback]) + +Multiple values in a hash can be set by supplying an object: + + client.HMSET(key2, { + "0123456789": "abcdefghij", + "some manner of key": "a type of value" + }); + +The properties and values of this Object will be set as keys and values in the Redis hash. + +### client.hmset(hash, key1, val1, ... keyn, valn, [callback]) + +Multiple values may also be set by supplying a list: + + client.HMSET(key1, "0123456789", "abcdefghij", "some manner of key", "a type of value"); + + +## Publish / Subscribe + +Here is a simple example of the API for publish / subscribe. This program opens two +client connections, subscribes to a channel on one of them, and publishes to that +channel on the other: + + var redis = require("redis"), + client1 = redis.createClient(), client2 = redis.createClient(), + msg_count = 0; + + client1.on("subscribe", function (channel, count) { + client2.publish("a nice channel", "I am sending a message."); + client2.publish("a nice channel", "I am sending a second message."); + client2.publish("a nice channel", "I am sending my last message."); + }); + + client1.on("message", function (channel, message) { + console.log("client1 channel " + channel + ": " + message); + msg_count += 1; + if (msg_count === 3) { + client1.unsubscribe(); + client1.end(); + client2.end(); + } + }); + + client1.incr("did a thing"); + client1.subscribe("a nice channel"); + +When a client issues a `SUBSCRIBE` or `PSUBSCRIBE`, that connection is put into "pub/sub" mode. +At that point, only commands that modify the subscription set are valid. When the subscription +set is empty, the connection is put back into regular mode. + +If you need to send regular commands to Redis while in pub/sub mode, just open another connection. + +## Pub / Sub Events + +If a client has subscriptions active, it may emit these events: + +### "message" (channel, message) + +Client will emit `message` for every message received that matches an active subscription. +Listeners are passed the channel name as `channel` and the message Buffer as `message`. + +### "pmessage" (pattern, channel, message) + +Client will emit `pmessage` for every message received that matches an active subscription pattern. +Listeners are passed the original pattern used with `PSUBSCRIBE` as `pattern`, the sending channel +name as `channel`, and the message Buffer as `message`. + +### "subscribe" (channel, count) + +Client will emit `subscribe` in response to a `SUBSCRIBE` command. Listeners are passed the +channel name as `channel` and the new count of subscriptions for this client as `count`. + +### "psubscribe" (pattern, count) + +Client will emit `psubscribe` in response to a `PSUBSCRIBE` command. Listeners are passed the +original pattern as `pattern`, and the new count of subscriptions for this client as `count`. + +### "unsubscribe" (channel, count) + +Client will emit `unsubscribe` in response to a `UNSUBSCRIBE` command. Listeners are passed the +channel name as `channel` and the new count of subscriptions for this client as `count`. When +`count` is 0, this client has left pub/sub mode and no more pub/sub events will be emitted. + +### "punsubscribe" (pattern, count) + +Client will emit `punsubscribe` in response to a `PUNSUBSCRIBE` command. Listeners are passed the +channel name as `channel` and the new count of subscriptions for this client as `count`. When +`count` is 0, this client has left pub/sub mode and no more pub/sub events will be emitted. + +## client.multi([commands]) + +`MULTI` commands are queued up until an `EXEC` is issued, and then all commands are run atomically by +Redis. The interface in `node_redis` is to return an individual `Multi` object by calling `client.multi()`. + + var redis = require("./index"), + client = redis.createClient(), set_size = 20; + + client.sadd("bigset", "a member"); + client.sadd("bigset", "another member"); + + while (set_size > 0) { + client.sadd("bigset", "member " + set_size); + set_size -= 1; + } + + // multi chain with an individual callback + client.multi() + .scard("bigset") + .smembers("bigset") + .keys("*", function (err, replies) { + client.mget(replies, redis.print); + }) + .dbsize() + .exec(function (err, replies) { + console.log("MULTI got " + replies.length + " replies"); + replies.forEach(function (reply, index) { + console.log("Reply " + index + ": " + reply.toString()); + }); + }); + +`client.multi()` is a constructor that returns a `Multi` object. `Multi` objects share all of the +same command methods as `client` objects do. Commands are queued up inside the `Multi` object +until `Multi.exec()` is invoked. + +You can either chain together `MULTI` commands as in the above example, or you can queue individual +commands while still sending regular client command as in this example: + + var redis = require("redis"), + client = redis.createClient(), multi; + + // start a separate multi command queue + multi = client.multi(); + multi.incr("incr thing", redis.print); + multi.incr("incr other thing", redis.print); + + // runs immediately + client.mset("incr thing", 100, "incr other thing", 1, redis.print); + + // drains multi queue and runs atomically + multi.exec(function (err, replies) { + console.log(replies); // 101, 2 + }); + + // you can re-run the same transaction if you like + multi.exec(function (err, replies) { + console.log(replies); // 102, 3 + client.quit(); + }); + +In addition to adding commands to the `MULTI` queue individually, you can also pass an array +of commands and arguments to the constructor: + + var redis = require("redis"), + client = redis.createClient(), multi; + + client.multi([ + ["mget", "multifoo", "multibar", redis.print], + ["incr", "multifoo"], + ["incr", "multibar"] + ]).exec(function (err, replies) { + console.log(replies); + }); + + +## Monitor mode + +Redis supports the `MONITOR` command, which lets you see all commands received by the Redis server +across all client connections, including from other client libraries and other computers. + +After you send the `MONITOR` command, no other commands are valid on that connection. `node_redis` +will emit a `monitor` event for every new monitor message that comes across. The callback for the +`monitor` event takes a timestamp from the Redis server and an array of command arguments. + +Here is a simple example: + + var client = require("redis").createClient(), + util = require("util"); + + client.monitor(function (err, res) { + console.log("Entering monitoring mode."); + }); + + client.on("monitor", function (time, args) { + console.log(time + ": " + util.inspect(args)); + }); + + +# Extras + +Some other things you might like to know about. + +## client.server_info + +After the ready probe completes, the results from the INFO command are saved in the `client.server_info` +object. + +The `versions` key contains an array of the elements of the version string for easy comparison. + + > client.server_info.redis_version + '2.3.0' + > client.server_info.versions + [ 2, 3, 0 ] + +## redis.print() + +A handy callback function for displaying return values when testing. Example: + + var redis = require("redis"), + client = redis.createClient(); + + client.on("connect", function () { + client.set("foo_rand000000000000", "some fantastic value", redis.print); + client.get("foo_rand000000000000", redis.print); + }); + +This will print: + + Reply: OK + Reply: some fantastic value + +Note that this program will not exit cleanly because the client is still connected. + +## redis.debug_mode + +Boolean to enable debug mode and protocol tracing. + + var redis = require("redis"), + client = redis.createClient(); + + redis.debug_mode = true; + + client.on("connect", function () { + client.set("foo_rand000000000000", "some fantastic value"); + }); + +This will display: + + mjr:~/work/node_redis (master)$ node ~/example.js + send command: *3 + $3 + SET + $20 + foo_rand000000000000 + $20 + some fantastic value + + on_data: +OK + +`send command` is data sent into Redis and `on_data` is data received from Redis. + +## client.send_command(command_name, args, callback) + +Used internally to send commands to Redis. For convenience, nearly all commands that are published on the Redis +Wiki have been added to the `client` object. However, if I missed any, or if new commands are introduced before +this library is updated, you can use `send_command()` to send arbitrary commands to Redis. + +All commands are sent as multi-bulk commands. `args` can either be an Array of arguments, or individual arguments, +or omitted completely. + +## client.connected + +Boolean tracking the state of the connection to the Redis server. + +## client.command_queue.length + +The number of commands that have been sent to the Redis server but not yet replied to. You can use this to +enforce some kind of maximum queue depth for commands while connected. + +Don't mess with `client.command_queue` though unless you really know what you are doing. + +## client.offline_queue.length + +The number of commands that have been queued up for a future connection. You can use this to enforce +some kind of maximum queue depth for pre-connection commands. + +## client.retry_delay + +Current delay in milliseconds before a connection retry will be attempted. This starts at `250`. + +## client.retry_backoff + +Multiplier for future retry timeouts. This should be larger than 1 to add more time between retries. +Defaults to 1.7. The default initial connection retry is 250, so the second retry will be 425, followed by 723.5, etc. + + +## TODO + +Better tests for monitor mode, auth, disconnect/reconnect, and all combinations thereof. + +Stream large set/get values into and out of Redis. Otherwise the entire value must be in node's memory. + +Performance can be better for very large values. + +I think there are more performance improvements left in there for smaller values, especially for large lists of small values. + +## Contributors + +Some people have have added features and fixed bugs in `node_redis` other than me. + +In order of first contribution, they are: + +* [Tim Smart](https://github.com/Tim-Smart) +* [TJ Holowaychuk](https://github.com/visionmedia) +* [Rick Olson](https://github.com/technoweenie) +* [Orion Henry](https://github.com/orionz) +* [Hank Sims](https://github.com/hanksims) +* [Aivo Paas](https://github.com/aivopaas) +* [Paul Carey](https://github.com/paulcarey) +* [Pieter Noordhuis](https://github.com/pietern) +* [Vladimir Dronnikov](https://github.com/dvv) +* [Dave Hoover](https://github.com/redsquirrel) + +Thanks. + +## LICENSE - "MIT License" + +Copyright (c) 2010 Matthew Ranney, http://ranney.com/ + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 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. + +![spacer](http://ranney.com/1px.gif) diff --git a/networking/node_modules/socket.io/node_modules/redis/changelog.md b/networking/node_modules/socket.io/node_modules/redis/changelog.md new file mode 100644 index 0000000..f9a0b20 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/changelog.md @@ -0,0 +1,184 @@ +Changelog +========= + +## v0.6.7 - July 30, 2011 + +(accidentally skipped v0.6.6) + +Fix and test for [GH-123] + +Passing an Array as as the last argument should expand as users +expect. The old behavior was to coerce the arguments into Strings, +which did surprising things with Arrays. + +## v0.6.5 - July 6, 2011 + +Contributed changes: + +* Support SlowBuffers (Umair Siddique) +* Add Multi to exports (Louis-Philippe Perron) +* Fix for drain event calculation (Vladimir Dronnikov) + +Thanks! + +## v0.6.4 - June 30, 2011 + +Fix bug with optional callbacks for hmset. + +## v0.6.2 - June 30, 2011 + +Bugs fixed: + +* authentication retry while server is loading db (danmaz74) [GH-101] +* command arguments processing issue with arrays + +New features: + +* Auto update of new commands from redis.io (Dave Hoover) +* Performance improvements and backpressure controls. +* Commands now return the true/false value from the underlying socket write(s). +* Implement command_queue high water and low water for more better control of queueing. + +See `examples/backpressure_drain.js` for more information. + +## v0.6.1 - June 29, 2011 + +Add support and tests for Redis scripting through EXEC command. + +Bug fix for monitor mode. (forddg) + +Auto update of new commands from redis.io (Dave Hoover) + +## v0.6.0 - April 21, 2011 + +Lots of bugs fixed. + +* connection error did not properly trigger reconnection logic [GH-85] +* client.hmget(key, [val1, val2]) was not expanding properly [GH-66] +* client.quit() while in pub/sub mode would throw an error [GH-87] +* client.multi(['hmset', 'key', {foo: 'bar'}]) fails [GH-92] +* unsubscribe before subscribe would make things very confused [GH-88] +* Add BRPOPLPUSH [GH-79] + +## v0.5.11 - April 7, 2011 + +Added DISCARD + +I originally didn't think DISCARD would do anything here because of the clever MULTI interface, but somebody +pointed out to me that DISCARD can be used to flush the WATCH set. + +## v0.5.10 - April 6, 2011 + +Added HVALS + +## v0.5.9 - March 14, 2011 + +Fix bug with empty Array arguments - Andy Ray + +## v0.5.8 - March 14, 2011 + +Add `MONITOR` command and special monitor command reply parsing. + +## v0.5.7 - February 27, 2011 + +Add magical auth command. + +Authentication is now remembered by the client and will be automatically sent to the server +on every connection, including any reconnections. + +## v0.5.6 - February 22, 2011 + +Fix bug in ready check with `return_buffers` set to `true`. + +Thanks to Dean Mao and Austin Chau. + +## v0.5.5 - February 16, 2011 + +Add probe for server readiness. + +When a Redis server starts up, it might take a while to load the dataset into memory. +During this time, the server will accept connections, but will return errors for all non-INFO +commands. Now node_redis will send an INFO command whenever it connects to a server. +If the info command indicates that the server is not ready, the client will keep trying until +the server is ready. Once it is ready, the client will emit a "ready" event as well as the +"connect" event. The client will queue up all commands sent before the server is ready, just +like it did before. When the server is ready, all offline/non-ready commands will be replayed. +This should be backward compatible with previous versions. + +To disable this ready check behavior, set `options.no_ready_check` when creating the client. + +As a side effect of this change, the key/val params from the info command are available as +`client.server_options`. Further, the version string is decomposed into individual elements +in `client.server_options.versions`. + +## v0.5.4 - February 11, 2011 + +Fix excess memory consumption from Queue backing store. + +Thanks to Gustaf Sjöberg. + +## v0.5.3 - February 5, 2011 + +Fix multi/exec error reply callback logic. + +Thanks to Stella Laurenzo. + +## v0.5.2 - January 18, 2011 + +Fix bug where unhandled error replies confuse the parser. + +## v0.5.1 - January 18, 2011 + +Fix bug where subscribe commands would not handle redis-server startup error properly. + +## v0.5.0 - December 29, 2010 + +Some bug fixes: + +* An important bug fix in reconnection logic. Previously, reply callbacks would be invoked twice after + a reconnect. +* Changed error callback argument to be an actual Error object. + +New feature: + +* Add friendly syntax for HMSET using an object. + +## v0.4.1 - December 8, 2010 + +Remove warning about missing hiredis. You probably do want it though. + +## v0.4.0 - December 5, 2010 + +Support for multiple response parsers and hiredis C library from Pieter Noordhuis. +Return Strings instead of Buffers by default. +Empty nested mb reply bug fix. + +## v0.3.9 - November 30, 2010 + +Fix parser bug on failed EXECs. + +## v0.3.8 - November 10, 2010 + +Fix for null MULTI response when WATCH condition fails. + +## v0.3.7 - November 9, 2010 + +Add "drain" and "idle" events. + +## v0.3.6 - November 3, 2010 + +Add all known Redis commands from Redis master, even ones that are coming in 2.2 and beyond. + +Send a friendlier "error" event message on stream errors like connection refused / reset. + +## v0.3.5 - October 21, 2010 + +A few bug fixes. + +* Fixed bug with `nil` multi-bulk reply lengths that showed up with `BLPOP` timeouts. +* Only emit `end` once when connection goes away. +* Fixed bug in `test.js` where driver finished before all tests completed. + +## unversioned wasteland + +See the git history for what happened before. diff --git a/networking/node_modules/socket.io/node_modules/redis/eval_test.js b/networking/node_modules/socket.io/node_modules/redis/eval_test.js new file mode 100644 index 0000000..c1fbf8a --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/eval_test.js @@ -0,0 +1,9 @@ +var redis = require("./index"), + client = redis.createClient(); + +redis.debug_mode = true; + +client.eval("return 100.5", 0, function (err, res) { + console.dir(err); + console.dir(res); +}); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/auth.js b/networking/node_modules/socket.io/node_modules/redis/examples/auth.js new file mode 100644 index 0000000..6c0a563 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/auth.js @@ -0,0 +1,5 @@ +var redis = require("redis"), + client = redis.createClient(); + +// This command is magical. Client stashes the password and will issue on every connect. +client.auth("somepass"); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/backpressure_drain.js b/networking/node_modules/socket.io/node_modules/redis/examples/backpressure_drain.js new file mode 100644 index 0000000..3488ef4 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/backpressure_drain.js @@ -0,0 +1,33 @@ +var redis = require("../index"), + client = redis.createClient(null, null, { + command_queue_high_water: 5, + command_queue_low_water: 1 + }), + remaining_ops = 100000, paused = false; + +function op() { + if (remaining_ops <= 0) { + console.error("Finished."); + process.exit(0); + } + + remaining_ops--; + if (client.hset("test hash", "val " + remaining_ops, remaining_ops) === false) { + console.log("Pausing at " + remaining_ops); + paused = true; + } else { + process.nextTick(op); + } +} + +client.on("drain", function () { + if (paused) { + console.log("Resuming at " + remaining_ops); + paused = false; + process.nextTick(op); + } else { + console.log("Got drain while not paused at " + remaining_ops); + } +}); + +op(); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/extend.js b/networking/node_modules/socket.io/node_modules/redis/examples/extend.js new file mode 100644 index 0000000..488b8c2 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/extend.js @@ -0,0 +1,24 @@ +var redis = require("redis"), + client = redis.createClient(); + +// Extend the RedisClient prototype to add a custom method +// This one converts the results from "INFO" into a JavaScript Object + +redis.RedisClient.prototype.parse_info = function (callback) { + this.info(function (err, res) { + var lines = res.toString().split("\r\n").sort(); + var obj = {}; + lines.forEach(function (line) { + var parts = line.split(':'); + if (parts[1]) { + obj[parts[0]] = parts[1]; + } + }); + callback(obj) + }); +}; + +client.parse_info(function (info) { + console.dir(info); + client.quit(); +}); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/file.js b/networking/node_modules/socket.io/node_modules/redis/examples/file.js new file mode 100644 index 0000000..4d2b5d1 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/file.js @@ -0,0 +1,32 @@ +// Read a file from disk, store it in Redis, then read it back from Redis. + +var redis = require("redis"), + client = redis.createClient(), + fs = require("fs"), + filename = "kids_in_cart.jpg"; + +// Get the file I use for testing like this: +// curl http://ranney.com/kids_in_cart.jpg -o kids_in_cart.jpg +// or just use your own file. + +// Read a file from fs, store it in Redis, get it back from Redis, write it back to fs. +fs.readFile(filename, function (err, data) { + if (err) throw err + console.log("Read " + data.length + " bytes from filesystem."); + + client.set(filename, data, redis.print); // set entire file + client.get(filename, function (err, reply) { // get entire file + if (err) { + console.log("Get error: " + err); + } else { + fs.writeFile("duplicate_" + filename, reply, function (err) { + if (err) { + console.log("Error on write: " + err) + } else { + console.log("File written."); + } + client.end(); + }); + } + }); +}); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/mget.js b/networking/node_modules/socket.io/node_modules/redis/examples/mget.js new file mode 100644 index 0000000..936740d --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/mget.js @@ -0,0 +1,5 @@ +var client = require("redis").createClient(); + +client.mget(["sessions started", "sessions started", "foo"], function (err, res) { + console.dir(res); +}); \ No newline at end of file diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/monitor.js b/networking/node_modules/socket.io/node_modules/redis/examples/monitor.js new file mode 100644 index 0000000..2cb6a4e --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/monitor.js @@ -0,0 +1,10 @@ +var client = require("../index").createClient(), + util = require("util"); + +client.monitor(function (err, res) { + console.log("Entering monitoring mode."); +}); + +client.on("monitor", function (time, args) { + console.log(time + ": " + util.inspect(args)); +}); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/multi.js b/networking/node_modules/socket.io/node_modules/redis/examples/multi.js new file mode 100644 index 0000000..35c08e1 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/multi.js @@ -0,0 +1,46 @@ +var redis = require("redis"), + client = redis.createClient(), set_size = 20; + +client.sadd("bigset", "a member"); +client.sadd("bigset", "another member"); + +while (set_size > 0) { + client.sadd("bigset", "member " + set_size); + set_size -= 1; +} + +// multi chain with an individual callback +client.multi() + .scard("bigset") + .smembers("bigset") + .keys("*", function (err, replies) { + client.mget(replies, redis.print); + }) + .dbsize() + .exec(function (err, replies) { + console.log("MULTI got " + replies.length + " replies"); + replies.forEach(function (reply, index) { + console.log("Reply " + index + ": " + reply.toString()); + }); + }); + +client.mset("incr thing", 100, "incr other thing", 1, redis.print); + +// start a separate multi command queue +var multi = client.multi(); +multi.incr("incr thing", redis.print); +multi.incr("incr other thing", redis.print); + +// runs immediately +client.get("incr thing", redis.print); // 100 + +// drains multi queue and runs atomically +multi.exec(function (err, replies) { + console.log(replies); // 101, 2 +}); + +// you can re-run the same transaction if you like +multi.exec(function (err, replies) { + console.log(replies); // 102, 3 + client.quit(); +}); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/multi2.js b/networking/node_modules/socket.io/node_modules/redis/examples/multi2.js new file mode 100644 index 0000000..8be4d73 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/multi2.js @@ -0,0 +1,29 @@ +var redis = require("redis"), + client = redis.createClient(), multi; + +// start a separate command queue for multi +multi = client.multi(); +multi.incr("incr thing", redis.print); +multi.incr("incr other thing", redis.print); + +// runs immediately +client.mset("incr thing", 100, "incr other thing", 1, redis.print); + +// drains multi queue and runs atomically +multi.exec(function (err, replies) { + console.log(replies); // 101, 2 +}); + +// you can re-run the same transaction if you like +multi.exec(function (err, replies) { + console.log(replies); // 102, 3 + client.quit(); +}); + +client.multi([ + ["mget", "multifoo", "multibar", redis.print], + ["incr", "multifoo"], + ["incr", "multibar"] +]).exec(function (err, replies) { + console.log(replies.toString()); +}); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/psubscribe.js b/networking/node_modules/socket.io/node_modules/redis/examples/psubscribe.js new file mode 100644 index 0000000..c57117b --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/psubscribe.js @@ -0,0 +1,33 @@ +var redis = require("redis"), + client1 = redis.createClient(), + client2 = redis.createClient(), + client3 = redis.createClient(), + client4 = redis.createClient(), + msg_count = 0; + +redis.debug_mode = false; + +client1.on("psubscribe", function (pattern, count) { + console.log("client1 psubscribed to " + pattern + ", " + count + " total subscriptions"); + client2.publish("channeltwo", "Me!"); + client3.publish("channelthree", "Me too!"); + client4.publish("channelfour", "And me too!"); +}); + +client1.on("punsubscribe", function (pattern, count) { + console.log("client1 punsubscribed from " + pattern + ", " + count + " total subscriptions"); + client4.end(); + client3.end(); + client2.end(); + client1.end(); +}); + +client1.on("pmessage", function (pattern, channel, message) { + console.log("("+ pattern +")" + " client1 received message on " + channel + ": " + message); + msg_count += 1; + if (msg_count === 3) { + client1.punsubscribe(); + } +}); + +client1.psubscribe("channel*"); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/pub_sub.js b/networking/node_modules/socket.io/node_modules/redis/examples/pub_sub.js new file mode 100644 index 0000000..aa508d6 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/pub_sub.js @@ -0,0 +1,41 @@ +var redis = require("redis"), + client1 = redis.createClient(), msg_count = 0, + client2 = redis.createClient(); + +redis.debug_mode = false; + +// Most clients probably don't do much on "subscribe". This example uses it to coordinate things within one program. +client1.on("subscribe", function (channel, count) { + console.log("client1 subscribed to " + channel + ", " + count + " total subscriptions"); + if (count === 2) { + client2.publish("a nice channel", "I am sending a message."); + client2.publish("another one", "I am sending a second message."); + client2.publish("a nice channel", "I am sending my last message."); + } +}); + +client1.on("unsubscribe", function (channel, count) { + console.log("client1 unsubscribed from " + channel + ", " + count + " total subscriptions"); + if (count === 0) { + client2.end(); + client1.end(); + } +}); + +client1.on("message", function (channel, message) { + console.log("client1 channel " + channel + ": " + message); + msg_count += 1; + if (msg_count === 3) { + client1.unsubscribe(); + } +}); + +client1.on("ready", function () { + // if you need auth, do it here + client1.incr("did a thing"); + client1.subscribe("a nice channel", "another one"); +}); + +client2.on("ready", function () { + // if you need auth, do it here +}); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/simple.js b/networking/node_modules/socket.io/node_modules/redis/examples/simple.js new file mode 100644 index 0000000..b93c557 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/simple.js @@ -0,0 +1,17 @@ +var redis = require("redis"), + client = redis.createClient(); + +client.on("error", function (err) { + console.log("Redis connection error to " + client.host + ":" + client.port + " - " + err); +}); + +client.set("string key", "string val", redis.print); +client.hset("hash key", "hashtest 1", "some value", redis.print); +client.hset(["hash key", "hashtest 2", "some other value"], redis.print); +client.hkeys("hash key", function (err, replies) { + console.log(replies.length + " replies:"); + replies.forEach(function (reply, i) { + console.log(" " + i + ": " + reply); + }); + client.quit(); +}); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/subqueries.js b/networking/node_modules/socket.io/node_modules/redis/examples/subqueries.js new file mode 100644 index 0000000..560db24 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/subqueries.js @@ -0,0 +1,15 @@ +// Sending commands in response to other commands. +// This example runs "type" against every key in the database +// +var client = require("redis").createClient(); + +client.keys("*", function (err, keys) { + keys.forEach(function (key, pos) { + client.type(key, function (err, keytype) { + console.log(key + " is " + keytype); + if (pos === (keys.length - 1)) { + client.quit(); + } + }); + }); +}); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/subquery.js b/networking/node_modules/socket.io/node_modules/redis/examples/subquery.js new file mode 100644 index 0000000..861657e --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/subquery.js @@ -0,0 +1,19 @@ +var client = require("redis").createClient(); + +function print_results(obj) { + console.dir(obj); +} + +// build a map of all keys and their types +client.keys("*", function (err, all_keys) { + var key_types = {}; + + all_keys.forEach(function (key, pos) { // use second arg of forEach to get pos + client.type(key, function (err, type) { + key_types[key] = type; + if (pos === all_keys.length - 1) { // callbacks all run in order + print_results(key_types); + } + }); + }); +}); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/unix_socket.js b/networking/node_modules/socket.io/node_modules/redis/examples/unix_socket.js new file mode 100644 index 0000000..4a5e0bb --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/unix_socket.js @@ -0,0 +1,29 @@ +var redis = require("redis"), + client = redis.createClient("/tmp/redis.sock"), + profiler = require("v8-profiler"); + +client.on("connect", function () { + console.log("Got Unix socket connection.") +}); + +client.on("error", function (err) { + console.log(err.message); +}); + +client.set("space chars", "space value"); + +setInterval(function () { + client.get("space chars"); +}, 100); + +function done() { + client.info(function (err, reply) { + console.log(reply.toString()); + client.quit(); + }); +} + +setTimeout(function () { + console.log("Taking snapshot."); + var snap = profiler.takeSnapshot(); +}, 5000); diff --git a/networking/node_modules/socket.io/node_modules/redis/examples/web_server.js b/networking/node_modules/socket.io/node_modules/redis/examples/web_server.js new file mode 100644 index 0000000..9fd8592 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/examples/web_server.js @@ -0,0 +1,31 @@ +// A simple web server that generates dyanmic content based on responses from Redis + +var http = require("http"), server, + redis_client = require("redis").createClient(); + +server = http.createServer(function (request, response) { + response.writeHead(200, { + "Content-Type": "text/plain" + }); + + var redis_info, total_requests; + + redis_client.info(function (err, reply) { + redis_info = reply; // stash response in outer scope + }); + redis_client.incr("requests", function (err, reply) { + total_requests = reply; // stash response in outer scope + }); + redis_client.hincrby("ip", request.connection.remoteAddress, 1); + redis_client.hgetall("ip", function (err, reply) { + // This is the last reply, so all of the previous replies must have completed already + response.write("This page was generated after talking to redis.\n\n" + + "Redis info:\n" + redis_info + "\n" + + "Total requests: " + total_requests + "\n\n" + + "IP count: \n"); + Object.keys(reply).forEach(function (ip) { + response.write(" " + ip + ": " + reply[ip] + "\n"); + }); + response.end(); + }); +}).listen(80); diff --git a/networking/node_modules/socket.io/node_modules/redis/generate_commands.js b/networking/node_modules/socket.io/node_modules/redis/generate_commands.js new file mode 100644 index 0000000..e94d74e --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/generate_commands.js @@ -0,0 +1,40 @@ +var http = require("http"), + sys = require("sys"), + fs = require("fs"); + +function prettyCurrentTime() { + var date = new Date(); + return date.toLocaleString(); +} + +function write_file(commands, path) { + var file_contents, out_commands; + + console.log("Writing " + Object.keys(commands).length + " commands to " + path); + + file_contents = "// This file was generated by ./generate_commands.js on " + prettyCurrentTime() + "\n"; + + out_commands = Object.keys(commands).map(function (key) { + return key.toLowerCase(); + }); + + file_contents += "module.exports = " + JSON.stringify(out_commands, null, " ") + ";\n"; + + fs.writeFile(path, file_contents); +} + +http.get({host: "redis.io", path: "/commands.json"}, function (res) { + var body = ""; + + console.log("Response from redis.io/commands.json: " + res.statusCode); + + res.on('data', function (chunk) { + body += chunk; + }); + + res.on('end', function () { + write_file(JSON.parse(body), "lib/commands.js"); + }); +}).on('error', function (e) { + console.log("Error fetching command list from redis.io: " + e.message); +}); diff --git a/networking/node_modules/socket.io/node_modules/redis/index.js b/networking/node_modules/socket.io/node_modules/redis/index.js new file mode 100644 index 0000000..8728cea --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/index.js @@ -0,0 +1,860 @@ +/*global Buffer require exports console setTimeout */ + +var net = require("net"), + util = require("./lib/util").util, + Queue = require("./lib/queue").Queue, + to_array = require("./lib/to_array"), + events = require("events"), + parsers = [], commands, + default_port = 6379, + default_host = "127.0.0.1"; + +// can set this to true to enable for all connections +exports.debug_mode = false; + +// hiredis might not be installed +try { + require("./lib/parser/hiredis"); + parsers.push(require("./lib/parser/hiredis")); +} catch (err) { + if (exports.debug_mode) { + console.log("hiredis parser not installed."); + } +} + +parsers.push(require("./lib/parser/javascript")); + +function RedisClient(stream, options) { + this.stream = stream; + this.options = options || {}; + + this.connected = false; + this.ready = false; + this.connections = 0; + this.attempts = 1; + this.should_buffer = false; + this.command_queue_high_water = this.options.command_queue_high_water || 1000; + this.command_queue_low_water = this.options.command_queue_low_water || 0; + this.command_queue = new Queue(); // holds sent commands to de-pipeline them + this.offline_queue = new Queue(); // holds commands issued but not able to be sent + this.commands_sent = 0; + this.retry_delay = 250; // inital reconnection delay + this.current_retry_delay = this.retry_delay; + this.retry_backoff = 1.7; // each retry waits current delay * retry_backoff + this.subscriptions = false; + this.monitoring = false; + this.closing = false; + this.server_info = {}; + this.auth_pass = null; + + var parser_module, self = this; + + if (self.options.parser) { + if (! parsers.some(function (parser) { + if (parser.name === self.options.parser) { + parser_module = parser; + if (exports.debug_mode) { + console.log("Using parser module: " + parser_module.name); + } + return true; + } + })) { + throw new Error("Couldn't find named parser " + self.options.parser + " on this system"); + } + } else { + if (exports.debug_mode) { + console.log("Using default parser module: " + parsers[0].name); + } + parser_module = parsers[0]; + } + + parser_module.debug_mode = exports.debug_mode; + this.reply_parser = new parser_module.Parser({ + return_buffers: self.options.return_buffers || false + }); + + // "reply error" is an error sent back by Redis + this.reply_parser.on("reply error", function (reply) { + self.return_error(new Error(reply)); + }); + this.reply_parser.on("reply", function (reply) { + self.return_reply(reply); + }); + // "error" is bad. Somehow the parser got confused. It'll try to reset and continue. + this.reply_parser.on("error", function (err) { + self.emit("error", new Error("Redis reply parser error: " + err.stack)); + }); + + this.stream.on("connect", function () { + self.on_connect(); + }); + + this.stream.on("data", function (buffer_from_socket) { + self.on_data(buffer_from_socket); + }); + + this.stream.on("error", function (msg) { + if (this.closing) { + return; + } + + var message = "Redis connection to " + self.host + ":" + self.port + " failed - " + msg.message; + + if (exports.debug_mode) { + console.warn(message); + } + self.offline_queue.forEach(function (args) { + if (typeof args[2] === "function") { + args[2](message); + } + }); + self.offline_queue = new Queue(); + + self.command_queue.forEach(function (args) { + if (typeof args[2] === "function") { + args[2](message); + } + }); + self.command_queue = new Queue(); + + self.connected = false; + self.ready = false; + + self.emit("error", new Error(message)); + // "error" events get turned into exceptions if they aren't listened for. If the user handled this error + // then we should try to reconnect. + self.connection_gone("error"); + }); + + this.stream.on("close", function () { + self.connection_gone("close"); + }); + + this.stream.on("end", function () { + self.connection_gone("end"); + }); + + this.stream.on("drain", function () { + self.should_buffer = false; + self.emit("drain"); + }); + + events.EventEmitter.call(this); +} +util.inherits(RedisClient, events.EventEmitter); +exports.RedisClient = RedisClient; + +RedisClient.prototype.do_auth = function () { + var self = this; + + if (exports.debug_mode) { + console.log("Sending auth to " + self.host + ":" + self.port + " fd " + self.stream.fd); + } + self.send_anyway = true; + self.send_command("auth", [this.auth_pass], function (err, res) { + if (err) { + if (err.toString().match("LOADING")) { + // if redis is still loading the db, it will not authenticate and everything else will fail + console.log("Redis still loading, trying to authenticate later"); + setTimeout(function () { + self.do_auth(); + }, 2000); // TODO - magic number alert + return; + } else { + return self.emit("error", "Auth error: " + err); + } + } + if (res.toString() !== "OK") { + return self.emit("error", "Auth failed: " + res.toString()); + } + if (exports.debug_mode) { + console.log("Auth succeeded " + self.host + ":" + self.port + " fd " + self.stream.fd); + } + if (self.auth_callback) { + self.auth_callback(err, res); + self.auth_callback = null; + } + + // now we are really connected + self.emit("connect"); + if (self.options.no_ready_check) { + self.ready = true; + self.send_offline_queue(); + } else { + self.ready_check(); + } + }); + self.send_anyway = false; +}; + +RedisClient.prototype.on_connect = function () { + if (exports.debug_mode) { + console.log("Stream connected " + this.host + ":" + this.port + " fd " + this.stream.fd); + } + var self = this; + + this.connected = true; + this.ready = false; + this.attempts = 0; + this.connections += 1; + this.command_queue = new Queue(); + this.emitted_end = false; + this.retry_timer = null; + this.current_retry_delay = this.retry_time; + this.stream.setNoDelay(); + this.stream.setTimeout(0); + + if (this.auth_pass) { + this.do_auth(); + } else { + this.emit("connect"); + + if (this.options.no_ready_check) { + this.ready = true; + this.send_offline_queue(); + } else { + this.ready_check(); + } + } +}; + +RedisClient.prototype.ready_check = function () { + var self = this; + + function send_info_cmd() { + if (exports.debug_mode) { + console.log("checking server ready state..."); + } + + self.send_anyway = true; // secret flag to send_command to send something even if not "ready" + self.info(function (err, res) { + if (err) { + return self.emit("error", "Ready check failed: " + err); + } + + var lines = res.toString().split("\r\n"), obj = {}, retry_time; + + lines.forEach(function (line) { + var parts = line.split(':'); + if (parts[1]) { + obj[parts[0]] = parts[1]; + } + }); + + obj.versions = []; + obj.redis_version.split('.').forEach(function (num) { + obj.versions.push(+num); + }); + + // expose info key/vals to users + self.server_info = obj; + + if (!obj.loading || (obj.loading && obj.loading === "0")) { + if (exports.debug_mode) { + console.log("Redis server ready."); + } + self.ready = true; + + self.send_offline_queue(); + self.emit("ready"); + } else { + retry_time = obj.loading_eta_seconds * 1000; + if (retry_time > 1000) { + retry_time = 1000; + } + if (exports.debug_mode) { + console.log("Redis server still loading, trying again in " + retry_time); + } + setTimeout(send_info_cmd, retry_time); + } + }); + self.send_anyway = false; + } + + send_info_cmd(); +}; + +RedisClient.prototype.send_offline_queue = function () { + var command_obj, buffered_writes = 0; + while (this.offline_queue.length > 0) { + command_obj = this.offline_queue.shift(); + if (exports.debug_mode) { + console.log("Sending offline command: " + command_obj.command); + } + buffered_writes += !this.send_command(command_obj.command, command_obj.args, command_obj.callback); + } + this.offline_queue = new Queue(); + // Even though items were shifted off, Queue backing store still uses memory until next add, so just get a new Queue + + if (!buffered_writes) { + this.should_buffer = false; + this.emit("drain"); + } +}; + +RedisClient.prototype.connection_gone = function (why) { + var self = this; + + // If a retry is already in progress, just let that happen + if (this.retry_timer) { + return; + } + + // Note that this may trigger another "close" or "end" event + this.stream.destroy(); + + if (exports.debug_mode) { + console.warn("Redis connection is gone from " + why + " event."); + } + this.connected = false; + this.ready = false; + this.subscriptions = false; + this.monitoring = false; + + // since we are collapsing end and close, users don't expect to be called twice + if (! this.emitted_end) { + this.emit("end"); + this.emitted_end = true; + } + + this.command_queue.forEach(function (args) { + if (typeof args[2] === "function") { + args[2]("Server connection closed"); + } + }); + this.command_queue = new Queue(); + + // If this is a requested shutdown, then don't retry + if (this.closing) { + this.retry_timer = null; + return; + } + + this.current_retry_delay = this.retry_delay * this.retry_backoff; + + if (exports.debug_mode) { + console.log("Retry connection in " + this.current_retry_delay + " ms"); + } + this.attempts += 1; + this.emit("reconnecting", { + delay: this.current_retry_delay, + attempt: this.attempts + }); + this.retry_timer = setTimeout(function () { + if (exports.debug_mode) { + console.log("Retrying connection..."); + } + self.stream.connect(self.port, self.host); + self.retry_timer = null; + }, this.current_retry_delay); +}; + +RedisClient.prototype.on_data = function (data) { + if (exports.debug_mode) { + console.log("net read " + this.host + ":" + this.port + " fd " + this.stream.fd + ": " + data.toString()); + } + + try { + this.reply_parser.execute(data); + } catch (err) { + // This is an unexpected parser problem, an exception that came from the parser code itself. + // Parser should emit "error" events if it notices things are out of whack. + // Callbacks that throw exceptions will land in return_reply(), below. + // TODO - it might be nice to have a different "error" event for different types of errors + this.emit("error", err); + } +}; + +RedisClient.prototype.return_error = function (err) { + var command_obj = this.command_queue.shift(), queue_len = this.command_queue.getLength(); + + if (this.subscriptions === false && queue_len === 0) { + this.emit("idle"); + this.command_queue = new Queue(); + } + if (this.should_buffer && queue_len <= this.command_queue_low_water) { + this.emit("drain"); + this.should_buffer = false; + } + + if (command_obj && typeof command_obj.callback === "function") { + try { + command_obj.callback(err); + } catch (callback_err) { + // if a callback throws an exception, re-throw it on a new stack so the parser can keep going + process.nextTick(function () { + throw callback_err; + }); + } + } else { + console.log("node_redis: no callback to send error: " + err.message); + // this will probably not make it anywhere useful, but we might as well throw + process.nextTick(function () { + throw err; + }); + } +}; + +RedisClient.prototype.return_reply = function (reply) { + var command_obj = this.command_queue.shift(), + obj, i, len, key, val, type, timestamp, args, queue_len = this.command_queue.getLength(); + + if (this.subscriptions === false && queue_len === 0) { + this.emit("idle"); + this.command_queue = new Queue(); // explicitly reclaim storage from old Queue + } + if (this.should_buffer && queue_len <= this.command_queue_low_water) { + this.emit("drain"); + this.should_buffer = false; + } + + if (command_obj && !command_obj.sub_command) { + if (typeof command_obj.callback === "function") { + // HGETALL special case replies with keyed Buffers + if (reply && 'hgetall' === command_obj.command.toLowerCase()) { + obj = {}; + for (i = 0, len = reply.length; i < len; i += 2) { + key = reply[i].toString(); + val = reply[i + 1]; + obj[key] = val; + } + reply = obj; + } + + try { + command_obj.callback(null, reply); + } catch (err) { + // if a callback throws an exception, re-throw it on a new stack so the parser can keep going + process.nextTick(function () { + throw err; + }); + } + } else if (exports.debug_mode) { + console.log("no callback for reply: " + (reply && reply.toString && reply.toString())); + } + } else if (this.subscriptions || (command_obj && command_obj.sub_command)) { + if (Array.isArray(reply)) { + type = reply[0].toString(); + + if (type === "message") { + this.emit("message", reply[1].toString(), reply[2]); // channel, message + } else if (type === "pmessage") { + this.emit("pmessage", reply[1].toString(), reply[2].toString(), reply[3]); // pattern, channel, message + } else if (type === "subscribe" || type === "unsubscribe" || type === "psubscribe" || type === "punsubscribe") { + if (reply[2] === 0) { + this.subscriptions = false; + if (this.debug_mode) { + console.log("All subscriptions removed, exiting pub/sub mode"); + } + } + this.emit(type, reply[1].toString(), reply[2]); // channel, count + } else { + throw new Error("subscriptions are active but got unknown reply type " + type); + } + } else if (! this.closing) { + throw new Error("subscriptions are active but got an invalid reply: " + reply); + } + } else if (this.monitoring) { + len = reply.indexOf(" "); + timestamp = reply.slice(0, len); + // TODO - this de-quoting doesn't work correctly if you put JSON strings in your values. + args = reply.slice(len + 1).match(/"[^"]+"/g).map(function (elem) { + return elem.replace(/"/g, ""); + }); + this.emit("monitor", timestamp, args); + } else { + throw new Error("node_redis command queue state error. If you can reproduce this, please report it."); + } +}; + +// This Command constructor is ever so slightly faster than using an object literal +function Command(command, args, sub_command, callback) { + this.command = command; + this.args = args; + this.sub_command = sub_command; + this.callback = callback; +} + +RedisClient.prototype.send_command = function (command, args, callback) { + var arg, this_args, command_obj, i, il, elem_count, stream = this.stream, buffer_args, command_str = "", buffered_writes = 0; + + if (typeof command !== "string") { + throw new Error("First argument to send_command must be the command name string, not " + typeof command); + } + + if (Array.isArray(args)) { + if (typeof callback === "function") { + // probably the fastest way: + // client.command([arg1, arg2], cb); (straight passthrough) + // send_command(command, [arg1, arg2], cb); + } else if (! callback) { + // most people find this variable argument length form more convenient, but it uses arguments, which is slower + // client.command(arg1, arg2, cb); (wraps up arguments into an array) + // send_command(command, [arg1, arg2, cb]); + // client.command(arg1, arg2); (callback is optional) + // send_command(command, [arg1, arg2]); + if (typeof args[args.length - 1] === "function") { + callback = args[args.length - 1]; + args.length -= 1; + } + } else { + throw new Error("send_command: last argument must be a callback or undefined"); + } + } else { + throw new Error("send_command: second argument must be an array"); + } + + // if the last argument is an array, expand it out. This allows commands like this: + // client.command(arg1, [arg2, arg3, arg4], cb); + // and converts to: + // client.command(arg1, arg2, arg3, arg4, cb); + // which is convenient for some things like sadd + if (Array.isArray(args[args.length - 1])) { + args = args.slice(0, -1).concat(args[args.length - 1]); + } + + command_obj = new Command(command, args, false, callback); + + if ((!this.ready && !this.send_anyway) || !stream.writable) { + if (exports.debug_mode) { + if (!stream.writable) { + console.log("send command: stream is not writeable."); + } + + console.log("Queueing " + command + " for next server connection."); + } + this.offline_queue.push(command_obj); + this.should_buffer = true; + return false; + } + + if (command === "subscribe" || command === "psubscribe" || command === "unsubscribe" || command === "punsubscribe") { + if (this.subscriptions === false && exports.debug_mode) { + console.log("Entering pub/sub mode from " + command); + } + command_obj.sub_command = true; + this.subscriptions = true; + } else if (command === "monitor") { + this.monitoring = true; + } else if (command === "quit") { + this.closing = true; + } else if (this.subscriptions === true) { + throw new Error("Connection in pub/sub mode, only pub/sub commands may be used"); + } + this.command_queue.push(command_obj); + this.commands_sent += 1; + + elem_count = 1; + buffer_args = false; + + elem_count += args.length; + + // Always use "Multi bulk commands", but if passed any Buffer args, then do multiple writes, one for each arg + // This means that using Buffers in commands is going to be slower, so use Strings if you don't already have a Buffer. + // Also, why am I putting user documentation in the library source code? + + command_str = "*" + elem_count + "\r\n$" + command.length + "\r\n" + command + "\r\n"; + + for (i = 0, il = args.length, arg; i < il; i += 1) { + if (Buffer.isBuffer(args[i])) { + buffer_args = true; + } + } + + if (! buffer_args) { // Build up a string and send entire command in one write + for (i = 0, il = args.length, arg; i < il; i += 1) { + arg = args[i]; + if (typeof arg !== "string") { + arg = String(arg); + } + command_str += "$" + Buffer.byteLength(arg) + "\r\n" + arg + "\r\n"; + } + if (exports.debug_mode) { + console.log("send " + this.host + ":" + this.port + " fd " + this.stream.fd + ": " + command_str); + } + buffered_writes += !stream.write(command_str); + } else { + if (exports.debug_mode) { + console.log("send command (" + command_str + ") has Buffer arguments"); + } + buffered_writes += !stream.write(command_str); + + for (i = 0, il = args.length, arg; i < il; i += 1) { + arg = args[i]; + if (!(Buffer.isBuffer(arg) || arg instanceof String)) { + arg = String(arg); + } + + if (Buffer.isBuffer(arg)) { + if (arg.length === 0) { + if (exports.debug_mode) { + console.log("send_command: using empty string for 0 length buffer"); + } + buffered_writes += !stream.write("$0\r\n\r\n"); + } else { + buffered_writes += !stream.write("$" + arg.length + "\r\n"); + buffered_writes += !stream.write(arg); + buffered_writes += !stream.write("\r\n"); + if (exports.debug_mode) { + console.log("send_command: buffer send " + arg.length + " bytes"); + } + } + } else { + if (exports.debug_mode) { + console.log("send_command: string send " + Buffer.byteLength(arg) + " bytes: " + arg); + } + buffered_writes += !stream.write("$" + Buffer.byteLength(arg) + "\r\n" + arg + "\r\n"); + } + } + } + if (exports.debug_mode) { + console.log("send_command buffered_writes: " + buffered_writes, " should_buffer: " + this.should_buffer); + } + if (buffered_writes || this.command_queue.getLength() >= this.command_queue_high_water) { + this.should_buffer = true; + } + return !this.should_buffer; +}; + +RedisClient.prototype.end = function () { + this.stream._events = {}; + this.connected = false; + this.ready = false; + return this.stream.end(); +}; + +function Multi(client, args) { + this.client = client; + this.queue = [["MULTI"]]; + if (Array.isArray(args)) { + this.queue = this.queue.concat(args); + } +} + +exports.Multi = Multi; + +// take 2 arrays and return the union of their elements +function set_union(seta, setb) { + var obj = {}; + + seta.forEach(function (val) { + obj[val] = true; + }); + setb.forEach(function (val) { + obj[val] = true; + }); + return Object.keys(obj); +} + +// This static list of commands is updated from time to time. ./lib/commands.js can be updated with generate_commands.js +commands = set_union(["get", "set", "setnx", "setex", "append", "strlen", "del", "exists", "setbit", "getbit", "setrange", "getrange", "substr", + "incr", "decr", "mget", "rpush", "lpush", "rpushx", "lpushx", "linsert", "rpop", "lpop", "brpop", "brpoplpush", "blpop", "llen", "lindex", + "lset", "lrange", "ltrim", "lrem", "rpoplpush", "sadd", "srem", "smove", "sismember", "scard", "spop", "srandmember", "sinter", "sinterstore", + "sunion", "sunionstore", "sdiff", "sdiffstore", "smembers", "zadd", "zincrby", "zrem", "zremrangebyscore", "zremrangebyrank", "zunionstore", + "zinterstore", "zrange", "zrangebyscore", "zrevrangebyscore", "zcount", "zrevrange", "zcard", "zscore", "zrank", "zrevrank", "hset", "hsetnx", + "hget", "hmset", "hmget", "hincrby", "hdel", "hlen", "hkeys", "hvals", "hgetall", "hexists", "incrby", "decrby", "getset", "mset", "msetnx", + "randomkey", "select", "move", "rename", "renamenx", "expire", "expireat", "keys", "dbsize", "auth", "ping", "echo", "save", "bgsave", + "bgrewriteaof", "shutdown", "lastsave", "type", "multi", "exec", "discard", "sync", "flushdb", "flushall", "sort", "info", "monitor", "ttl", + "persist", "slaveof", "debug", "config", "subscribe", "unsubscribe", "psubscribe", "punsubscribe", "publish", "watch", "unwatch", "cluster", + "restore", "migrate", "dump", "object", "client", "eval", "evalsha"], require("./lib/commands")); + +commands.forEach(function (command) { + RedisClient.prototype[command] = function (args, callback) { + if (Array.isArray(args) && typeof callback === "function") { + return this.send_command(command, args, callback); + } else { + return this.send_command(command, to_array(arguments)); + } + }; + RedisClient.prototype[command.toUpperCase()] = RedisClient.prototype[command]; + + Multi.prototype[command] = function () { + this.queue.push([command].concat(to_array(arguments))); + return this; + }; + Multi.prototype[command.toUpperCase()] = Multi.prototype[command]; +}); + +// Stash auth for connect and reconnect. Send immediately if already connected. +RedisClient.prototype.auth = function () { + var args = to_array(arguments); + this.auth_pass = args[0]; + this.auth_callback = args[1]; + if (exports.debug_mode) { + console.log("Saving auth as " + this.auth_pass); + } + + if (this.connected) { + this.send_command("auth", args); + } +}; +RedisClient.prototype.AUTH = RedisClient.prototype.auth; + +RedisClient.prototype.hmget = function (arg1, arg2, arg3) { + if (Array.isArray(arg2) && typeof arg3 === "function") { + return this.send_command("hmget", [arg1].concat(arg2), arg3); + } else if (Array.isArray(arg1) && typeof arg2 === "function") { + return this.send_command("hmget", arg1, arg2); + } else { + return this.send_command("hmget", to_array(arguments)); + } +}; +RedisClient.prototype.HMGET = RedisClient.prototype.hmget; + +RedisClient.prototype.hmset = function (args, callback) { + var tmp_args, tmp_keys, i, il, key; + + if (Array.isArray(args) && typeof callback === "function") { + return this.send_command("hmset", args, callback); + } + + args = to_array(arguments); + if (typeof args[args.length - 1] === "function") { + callback = args[args.length - 1]; + args.length -= 1; + } else { + callback = null; + } + + if (args.length === 2 && typeof args[0] === "string" && typeof args[1] === "object") { + // User does: client.hmset(key, {key1: val1, key2: val2}) + tmp_args = [ args[0] ]; + tmp_keys = Object.keys(args[1]); + for (i = 0, il = tmp_keys.length; i < il ; i++) { + key = tmp_keys[i]; + tmp_args.push(key); + tmp_args.push(args[1][key]); + } + args = tmp_args; + } + + return this.send_command("hmset", args, callback); +}; +RedisClient.prototype.HMSET = RedisClient.prototype.hmset; + +Multi.prototype.hmset = function () { + var args = to_array(arguments), tmp_args; + if (args.length >= 2 && typeof args[0] === "string" && typeof args[1] === "object") { + tmp_args = [ "hmset", args[0] ]; + Object.keys(args[1]).map(function (key) { + tmp_args.push(key); + tmp_args.push(args[1][key]); + }); + if (args[2]) { + tmp_args.push(args[2]); + } + args = tmp_args; + } else { + args.unshift("hmset"); + } + + this.queue.push(args); + return this; +}; +Multi.prototype.HMSET = Multi.prototype.hmset; + +Multi.prototype.exec = function (callback) { + var self = this; + + // drain queue, callback will catch "QUEUED" or error + // TODO - get rid of all of these anonymous functions which are elegant but slow + this.queue.forEach(function (args, index) { + var command = args[0], obj; + if (typeof args[args.length - 1] === "function") { + args = args.slice(1, -1); + } else { + args = args.slice(1); + } + if (args.length === 1 && Array.isArray(args[0])) { + args = args[0]; + } + if (command === 'hmset' && typeof args[1] === 'object') { + obj = args.pop(); + Object.keys(obj).forEach(function (key) { + args.push(key); + args.push(obj[key]); + }); + } + this.client.send_command(command, args, function (err, reply) { + if (err) { + var cur = self.queue[index]; + if (typeof cur[cur.length - 1] === "function") { + cur[cur.length - 1](err); + } else { + throw new Error(err); + } + self.queue.splice(index, 1); + } + }); + }, this); + + // TODO - make this callback part of Multi.prototype instead of creating it each time + return this.client.send_command("EXEC", [], function (err, replies) { + if (err) { + if (callback) { + callback(new Error(err)); + return; + } else { + throw new Error(err); + } + } + + var i, il, j, jl, reply, args, obj, key, val; + + if (replies) { + for (i = 1, il = self.queue.length; i < il; i += 1) { + reply = replies[i - 1]; + args = self.queue[i]; + + // Convert HGETALL reply to object + if (reply && args[0].toLowerCase() === "hgetall") { + obj = {}; + for (j = 0, jl = reply.length; j < jl; j += 2) { + key = reply[j].toString(); + val = reply[j + 1]; + obj[key] = val; + } + replies[i - 1] = reply = obj; + } + + if (typeof args[args.length - 1] === "function") { + args[args.length - 1](null, reply); + } + } + } + + if (callback) { + callback(null, replies); + } + }); +}; + +RedisClient.prototype.multi = function (args) { + return new Multi(this, args); +}; +RedisClient.prototype.MULTI = function (args) { + return new Multi(this, args); +}; + +exports.createClient = function (port_arg, host_arg, options) { + var port = port_arg || default_port, + host = host_arg || default_host, + redis_client, net_client; + + net_client = net.createConnection(port, host); + + redis_client = new RedisClient(net_client, options); + + redis_client.port = port; + redis_client.host = host; + + return redis_client; +}; + +exports.print = function (err, reply) { + if (err) { + console.log("Error: " + err); + } else { + console.log("Reply: " + reply); + } +}; diff --git a/networking/node_modules/socket.io/node_modules/redis/lib/commands.js b/networking/node_modules/socket.io/node_modules/redis/lib/commands.js new file mode 100644 index 0000000..0293ae8 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/lib/commands.js @@ -0,0 +1,126 @@ +// This file was generated by ./generate_commands.js on Tue Jun 28 2011 22:37:02 GMT-0700 (PDT) +module.exports = [ + "append", + "auth", + "bgrewriteaof", + "bgsave", + "blpop", + "brpop", + "brpoplpush", + "config get", + "config set", + "config resetstat", + "dbsize", + "debug object", + "debug segfault", + "decr", + "decrby", + "del", + "discard", + "echo", + "exec", + "exists", + "expire", + "expireat", + "flushall", + "flushdb", + "get", + "getbit", + "getrange", + "getset", + "hdel", + "hexists", + "hget", + "hgetall", + "hincrby", + "hkeys", + "hlen", + "hmget", + "hmset", + "hset", + "hsetnx", + "hvals", + "incr", + "incrby", + "info", + "keys", + "lastsave", + "lindex", + "linsert", + "llen", + "lpop", + "lpush", + "lpushx", + "lrange", + "lrem", + "lset", + "ltrim", + "mget", + "monitor", + "move", + "mset", + "msetnx", + "multi", + "object", + "persist", + "ping", + "psubscribe", + "publish", + "punsubscribe", + "quit", + "randomkey", + "rename", + "renamenx", + "rpop", + "rpoplpush", + "rpush", + "rpushx", + "sadd", + "save", + "scard", + "sdiff", + "sdiffstore", + "select", + "set", + "setbit", + "setex", + "setnx", + "setrange", + "shutdown", + "sinter", + "sinterstore", + "sismember", + "slaveof", + "smembers", + "smove", + "sort", + "spop", + "srandmember", + "srem", + "strlen", + "subscribe", + "sunion", + "sunionstore", + "sync", + "ttl", + "type", + "unsubscribe", + "unwatch", + "watch", + "zadd", + "zcard", + "zcount", + "zincrby", + "zinterstore", + "zrange", + "zrangebyscore", + "zrank", + "zrem", + "zremrangebyrank", + "zremrangebyscore", + "zrevrange", + "zrevrangebyscore", + "zrevrank", + "zscore", + "zunionstore" +]; diff --git a/networking/node_modules/socket.io/node_modules/redis/lib/parser/hiredis.js b/networking/node_modules/socket.io/node_modules/redis/lib/parser/hiredis.js new file mode 100644 index 0000000..9dba8c9 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/lib/parser/hiredis.js @@ -0,0 +1,41 @@ +/*global Buffer require exports console setTimeout */ + +var events = require("events"), + util = require("../util").util, + hiredis = require("hiredis"); + +exports.debug_mode = false; +exports.name = "hiredis"; + +function HiredisReplyParser(options) { + this.name = exports.name; + this.options = options || {}; + this.reset(); + events.EventEmitter.call(this); +} + +util.inherits(HiredisReplyParser, events.EventEmitter); + +exports.Parser = HiredisReplyParser; + +HiredisReplyParser.prototype.reset = function () { + this.reader = new hiredis.Reader({ + return_buffers: this.options.return_buffers || false + }); +}; + +HiredisReplyParser.prototype.execute = function (data) { + var reply; + this.reader.feed(data); + try { + while ((reply = this.reader.get()) !== undefined) { + if (reply && reply.constructor === Error) { + this.emit("reply error", reply); + } else { + this.emit("reply", reply); + } + } + } catch (err) { + this.emit("error", err); + } +}; diff --git a/networking/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js b/networking/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js new file mode 100644 index 0000000..6f250c9 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js @@ -0,0 +1,316 @@ +/*global Buffer require exports console setTimeout */ + +// TODO - incorporate these V8 pro tips: +// pre-allocate Arrays if length is known in advance +// do not use delete +// use numbers for parser state + +var events = require("events"), + util = require("../util").util; + +exports.debug_mode = false; +exports.name = "javascript"; + +function RedisReplyParser(options) { + this.name = exports.name; + this.options = options || {}; + this.reset(); + events.EventEmitter.call(this); +} + +util.inherits(RedisReplyParser, events.EventEmitter); + +exports.Parser = RedisReplyParser; + +// Buffer.toString() is quite slow for small strings +function small_toString(buf, len) { + var tmp = "", i; + + for (i = 0; i < len; i += 1) { + tmp += String.fromCharCode(buf[i]); + } + + return tmp; +} + +// Reset parser to it's original state. +RedisReplyParser.prototype.reset = function () { + this.return_buffer = new Buffer(16384); // for holding replies, might grow + this.return_string = ""; + this.tmp_string = ""; // for holding size fields + + this.multi_bulk_length = 0; + this.multi_bulk_replies = null; + this.multi_bulk_pos = 0; + this.multi_bulk_nested_length = 0; + this.multi_bulk_nested_replies = null; + + this.states = { + TYPE: 1, + SINGLE_LINE: 2, + MULTI_BULK_COUNT: 3, + INTEGER_LINE: 4, + BULK_LENGTH: 5, + ERROR_LINE: 6, + BULK_DATA: 7, + UNKNOWN_TYPE: 8, + FINAL_CR: 9, + FINAL_LF: 10, + MULTI_BULK_COUNT_LF: 11 + }; + + this.state = this.states.TYPE; +}; + +RedisReplyParser.prototype.parser_error = function (message) { + this.emit("error", message); + this.reset(); +}; + +RedisReplyParser.prototype.execute = function (incoming_buf) { + var pos = 0, bd_tmp, bd_str, i, il, states = this.states; + //, state_times = {}, start_execute = new Date(), start_switch, end_switch, old_state; + //start_switch = new Date(); + + while (pos < incoming_buf.length) { + // old_state = this.state; + // console.log("execute: " + this.state + ", " + pos + "/" + incoming_buf.length + ", " + String.fromCharCode(incoming_buf[pos])); + + switch (this.state) { + case states.TYPE: + this.type = incoming_buf[pos]; + pos += 1; + + switch (this.type) { + case 43: // + + this.state = states.SINGLE_LINE; + this.return_buffer.end = 0; + this.return_string = ""; + break; + case 42: // * + this.state = states.MULTI_BULK_COUNT; + this.tmp_string = ""; + break; + case 58: // : + this.state = states.INTEGER_LINE; + this.return_buffer.end = 0; + this.return_string = ""; + break; + case 36: // $ + this.state = states.BULK_LENGTH; + this.tmp_string = ""; + break; + case 45: // - + this.state = states.ERROR_LINE; + this.return_buffer.end = 0; + this.return_string = ""; + break; + default: + this.state = states.UNKNOWN_TYPE; + } + break; + case states.INTEGER_LINE: + if (incoming_buf[pos] === 13) { + this.send_reply(+small_toString(this.return_buffer, this.return_buffer.end)); + this.state = states.FINAL_LF; + } else { + this.return_buffer[this.return_buffer.end] = incoming_buf[pos]; + this.return_buffer.end += 1; + } + pos += 1; + break; + case states.ERROR_LINE: + if (incoming_buf[pos] === 13) { + this.send_error(this.return_buffer.toString("ascii", 0, this.return_buffer.end)); + this.state = states.FINAL_LF; + } else { + this.return_buffer[this.return_buffer.end] = incoming_buf[pos]; + this.return_buffer.end += 1; + } + pos += 1; + break; + case states.SINGLE_LINE: + if (incoming_buf[pos] === 13) { + this.send_reply(this.return_string); + this.state = states.FINAL_LF; + } else { + this.return_string += String.fromCharCode(incoming_buf[pos]); + } + pos += 1; + break; + case states.MULTI_BULK_COUNT: + if (incoming_buf[pos] === 13) { // \r + this.state = states.MULTI_BULK_COUNT_LF; + } else { + this.tmp_string += String.fromCharCode(incoming_buf[pos]); + } + pos += 1; + break; + case states.MULTI_BULK_COUNT_LF: + if (incoming_buf[pos] === 10) { // \n + if (this.multi_bulk_length) { // nested multi-bulk + this.multi_bulk_nested_length = this.multi_bulk_length; + this.multi_bulk_nested_replies = this.multi_bulk_replies; + this.multi_bulk_nested_pos = this.multi_bulk_pos; + } + this.multi_bulk_length = +this.tmp_string; + this.multi_bulk_pos = 0; + this.state = states.TYPE; + if (this.multi_bulk_length < 0) { + this.send_reply(null); + this.multi_bulk_length = 0; + } else if (this.multi_bulk_length === 0) { + this.multi_bulk_pos = 0; + this.multi_bulk_replies = null; + this.send_reply([]); + } else { + this.multi_bulk_replies = new Array(this.multi_bulk_length); + } + } else { + this.parser_error(new Error("didn't see LF after NL reading multi bulk count")); + return; + } + pos += 1; + break; + case states.BULK_LENGTH: + if (incoming_buf[pos] === 13) { // \r + this.state = states.BULK_LF; + } else { + this.tmp_string += String.fromCharCode(incoming_buf[pos]); + } + pos += 1; + break; + case states.BULK_LF: + if (incoming_buf[pos] === 10) { // \n + this.bulk_length = +this.tmp_string; + if (this.bulk_length === -1) { + this.send_reply(null); + this.state = states.TYPE; + } else if (this.bulk_length === 0) { + this.send_reply(new Buffer("")); + this.state = states.FINAL_CR; + } else { + this.state = states.BULK_DATA; + if (this.bulk_length > this.return_buffer.length) { + if (exports.debug_mode) { + console.log("Growing return_buffer from " + this.return_buffer.length + " to " + this.bulk_length); + } + this.return_buffer = new Buffer(this.bulk_length); + } + this.return_buffer.end = 0; + } + } else { + this.parser_error(new Error("didn't see LF after NL while reading bulk length")); + return; + } + pos += 1; + break; + case states.BULK_DATA: + this.return_buffer[this.return_buffer.end] = incoming_buf[pos]; + this.return_buffer.end += 1; + pos += 1; + if (this.return_buffer.end === this.bulk_length) { + bd_tmp = new Buffer(this.bulk_length); + // When the response is small, Buffer.copy() is a lot slower. + if (this.bulk_length > 10) { + this.return_buffer.copy(bd_tmp, 0, 0, this.bulk_length); + } else { + for (i = 0, il = this.bulk_length; i < il; i += 1) { + bd_tmp[i] = this.return_buffer[i]; + } + } + this.send_reply(bd_tmp); + this.state = states.FINAL_CR; + } + break; + case states.FINAL_CR: + if (incoming_buf[pos] === 13) { // \r + this.state = states.FINAL_LF; + pos += 1; + } else { + this.parser_error(new Error("saw " + incoming_buf[pos] + " when expecting final CR")); + return; + } + break; + case states.FINAL_LF: + if (incoming_buf[pos] === 10) { // \n + this.state = states.TYPE; + pos += 1; + } else { + this.parser_error(new Error("saw " + incoming_buf[pos] + " when expecting final LF")); + return; + } + break; + default: + this.parser_error(new Error("invalid state " + this.state)); + } + // end_switch = new Date(); + // if (state_times[old_state] === undefined) { + // state_times[old_state] = 0; + // } + // state_times[old_state] += (end_switch - start_switch); + // start_switch = end_switch; + } + // console.log("execute ran for " + (Date.now() - start_execute) + " ms, on " + incoming_buf.length + " Bytes. "); + // Object.keys(state_times).forEach(function (state) { + // console.log(" " + state + ": " + state_times[state]); + // }); +}; + +RedisReplyParser.prototype.send_error = function (reply) { + if (this.multi_bulk_length > 0 || this.multi_bulk_nested_length > 0) { + // TODO - can this happen? Seems like maybe not. + this.add_multi_bulk_reply(reply); + } else { + this.emit("reply error", reply); + } +}; + +RedisReplyParser.prototype.send_reply = function (reply) { + if (this.multi_bulk_length > 0 || this.multi_bulk_nested_length > 0) { + if (!this.options.return_buffers && Buffer.isBuffer(reply)) { + this.add_multi_bulk_reply(reply.toString("utf8")); + } else { + this.add_multi_bulk_reply(reply); + } + } else { + if (!this.options.return_buffers && Buffer.isBuffer(reply)) { + this.emit("reply", reply.toString("utf8")); + } else { + this.emit("reply", reply); + } + } +}; + +RedisReplyParser.prototype.add_multi_bulk_reply = function (reply) { + if (this.multi_bulk_replies) { + this.multi_bulk_replies[this.multi_bulk_pos] = reply; + this.multi_bulk_pos += 1; + if (this.multi_bulk_pos < this.multi_bulk_length) { + return; + } + } else { + this.multi_bulk_replies = reply; + } + + if (this.multi_bulk_nested_length > 0) { + this.multi_bulk_nested_replies[this.multi_bulk_nested_pos] = this.multi_bulk_replies; + this.multi_bulk_nested_pos += 1; + + this.multi_bulk_length = 0; + this.multi_bulk_replies = null; + this.multi_bulk_pos = 0; + + if (this.multi_bulk_nested_length === this.multi_bulk_nested_pos) { + this.emit("reply", this.multi_bulk_nested_replies); + this.multi_bulk_nested_length = 0; + this.multi_bulk_nested_pos = 0; + this.multi_bulk_nested_replies = null; + } + } else { + this.emit("reply", this.multi_bulk_replies); + this.multi_bulk_length = 0; + this.multi_bulk_replies = null; + this.multi_bulk_pos = 0; + } +}; diff --git a/networking/node_modules/socket.io/node_modules/redis/lib/queue.js b/networking/node_modules/socket.io/node_modules/redis/lib/queue.js new file mode 100644 index 0000000..5cc3c42 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/lib/queue.js @@ -0,0 +1,58 @@ +var to_array = require("./to_array"); + +// Queue class adapted from Tim Caswell's pattern library +// http://github.com/creationix/pattern/blob/master/lib/pattern/queue.js + +function Queue() { + this.tail = []; + this.head = to_array(arguments); + this.offset = 0; +} + +Queue.prototype.shift = function () { + if (this.offset === this.head.length) { + var tmp = this.head; + tmp.length = 0; + this.head = this.tail; + this.tail = tmp; + this.offset = 0; + if (this.head.length === 0) { + return; + } + } + return this.head[this.offset++]; // sorry, JSLint +}; + +Queue.prototype.push = function (item) { + return this.tail.push(item); +}; + +Queue.prototype.forEach = function (fn, thisv) { + var array = this.head.slice(this.offset), i, il; + + array.push.apply(array, this.tail); + + if (thisv) { + for (i = 0, il = array.length; i < il; i += 1) { + fn.call(thisv, array[i], i, array); + } + } else { + for (i = 0, il = array.length; i < il; i += 1) { + fn(array[i], i, array); + } + } + + return array; +}; + +Queue.prototype.getLength = function () { + return this.head.length - this.offset + this.tail.length; +}; + +Object.defineProperty(Queue.prototype, 'length', { + get: function () { + return this.getLength(); + } +}); + +exports.Queue = Queue; diff --git a/networking/node_modules/socket.io/node_modules/redis/lib/to_array.js b/networking/node_modules/socket.io/node_modules/redis/lib/to_array.js new file mode 100644 index 0000000..88a57e1 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/lib/to_array.js @@ -0,0 +1,12 @@ +function to_array(args) { + var len = args.length, + arr = new Array(len), i; + + for (i = 0; i < len; i += 1) { + arr[i] = args[i]; + } + + return arr; +} + +module.exports = to_array; diff --git a/networking/node_modules/socket.io/node_modules/redis/lib/util.js b/networking/node_modules/socket.io/node_modules/redis/lib/util.js new file mode 100644 index 0000000..3dc41a5 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/lib/util.js @@ -0,0 +1,6 @@ +if (process.versions.node.match(/^0.3/)) { + exports.util = require("util"); +} else { + // This module is called "sys" in 0.2.x + exports.util = require("sys"); +} diff --git a/networking/node_modules/socket.io/node_modules/redis/multi_bench.js b/networking/node_modules/socket.io/node_modules/redis/multi_bench.js new file mode 100644 index 0000000..b78c126 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/multi_bench.js @@ -0,0 +1,135 @@ +var redis = require("./index"), + num_clients = parseInt(process.argv[2], 10) || 50, + active_clients = 0, + clients = new Array(num_clients), + num_requests = 20000, + issued_requests = 0, + latency = new Array(num_requests), + tests = [], + test_start, parser_logged = false, + client_options = { + return_buffers: false + }; + +redis.debug_mode = false; + +tests.push({ + descr: "PING", + command: ["ping"] +}); + +tests.push({ + descr: "SET", + command: ["set", "foo_rand000000000000", "bar"] +}); + +tests.push({ + descr: "GET", + command: ["get", "foo_rand000000000000"] +}); + +tests.push({ + descr: "INCR", + command: ["incr", "counter_rand000000000000"] +}); + +tests.push({ + descr: "LPUSH", + command: ["lpush", "mylist", new Array(8).join("-")] +}); + +tests.push({ + descr: "LRANGE (10 elements)", + command: ["lrange", "mylist", "0", "9"] +}); + +tests.push({ + descr: "LRANGE (100 elements)", + command: ["lrange", "mylist", "0", "99"] +}); + +function create_clients(callback) { + if (active_clients === num_clients) { + // common case is all clients are already created + console.log("create_clients: all clients already created " + num_clients); + callback(); + } else { + var client, connected = active_clients; + + while (active_clients < num_clients) { + client = clients[active_clients++] = redis.createClient(6379, "127.0.0.1", client_options); + if (! parser_logged) { + console.log("Using reply parser " + client.reply_parser.name); + parser_logged = true; + } + client.on("connect", function () { + // Fire callback when all clients are connected + connected += 1; + if (connected === num_clients) { + callback(); + } + }); + // TODO - need to check for client disconnect + client.on("error", function (msg) { + console.log("Connect problem:" + msg.stack); + }); + } + } +} + +function issue_request(client, test, cmd, args) { + var i = issued_requests++; + latency[i] = Date.now(); + + client[cmd](args, function() { + latency[i] = Date.now() - latency[i]; + if (issued_requests < num_requests) { + issue_request(client, test, cmd, args); + } else { + client.end(); + if (--active_clients == 0) + test_complete(test); + } + }); +} + +function test_run(test) { + create_clients(function() { + var i = num_clients, + cmd = test.command[0], + args = test.command.slice(1); + + test_start = Date.now(); + issued_requests = 0; + while(i-- && issued_requests < num_requests) { + issue_request(clients[i], test, cmd, args); + } + }); +} + +function test_complete(test) { + var min, max, sum, avg; + var total_time = Date.now() - test_start; + var op_rate = (issued_requests / (total_time / 1000.0)).toFixed(2); + var i; + + latency.sort(); + min = latency[0]; + max = latency[issued_requests-1]; + for (sum = 0, i = 0; i < issued_requests; i++) + sum += latency[i]; + avg = (sum / issued_requests).toFixed(3); + + console.log(test.descr + ": " + issued_requests + " ops " + op_rate + " ops/sec " + min + "/" + max + "/" + avg); + + next(); +} + +function next() { + var test = tests.shift(); + if (test) { + test_run(test); + } +} + +next(); diff --git a/networking/node_modules/socket.io/node_modules/redis/package.json b/networking/node_modules/socket.io/node_modules/redis/package.json new file mode 100644 index 0000000..f52aeb7 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/package.json @@ -0,0 +1,67 @@ +{ + "name": "redis", + "version": "0.6.7", + "description": "Redis client library", + "author": { + "name": "Matt Ranney", + "email": "mjr@ranney.com" + }, + "contributors": [ + { + "name": "Rick Olson" + }, + { + "name": "Tim-Smart" + }, + { + "name": "TJ Holowaychuk" + }, + { + "name": "Orion Henry" + }, + { + "name": "Hank Sims" + }, + { + "name": "Aivo Paas" + }, + { + "name": "Paul Carey" + }, + { + "name": "Pieter Noordhuis" + }, + { + "name": "Andy Ray" + }, + { + "name": "Vladimir Dronnikov" + }, + { + "name": "Dave Hoover" + } + ], + "main": "./index.js", + "scripts": { + "test": "node ./test.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/mranney/node_redis.git" + }, + "_id": "redis@0.6.7", + "dependencies": {}, + "devDependencies": {}, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "_engineSupported": true, + "_npmVersion": "1.1.4", + "_nodeVersion": "v0.6.12", + "_defaultsLoaded": true, + "dist": { + "shasum": "3313a943bacf1c0e958c315ce4578ef429a646c3" + }, + "_from": "redis@0.6.7" +} diff --git a/networking/node_modules/socket.io/node_modules/redis/simple_test.js b/networking/node_modules/socket.io/node_modules/redis/simple_test.js new file mode 100644 index 0000000..f32ab9d --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/simple_test.js @@ -0,0 +1,3 @@ +var client = require("./index").createClient(); + +client.hmset("test hash", "key 1", "val 1", "key 2", "val 2"); diff --git a/networking/node_modules/socket.io/node_modules/redis/test.js b/networking/node_modules/socket.io/node_modules/redis/test.js new file mode 100644 index 0000000..7489e0c --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/test.js @@ -0,0 +1,1248 @@ +/*global require console setTimeout process Buffer */ +var redis = require("./index"), + client = redis.createClient(), + client2 = redis.createClient(), + client3 = redis.createClient(), + client4 = redis.createClient(9006, "filefish.redistogo.com"), + assert = require("assert"), + util = require("./lib/util").util, + test_db_num = 15, // this DB will be flushed and used for testing + tests = {}, + connected = false, + ended = false, + next, cur_start, run_next_test, all_tests, all_start, test_count; + +// Set this to truthy to see the wire protocol and other debugging info +redis.debug_mode = process.argv[2]; + +function buffers_to_strings(arr) { + return arr.map(function (val) { + return val.toString(); + }); +} + +function require_number(expected, label) { + return function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(expected, results, label + " " + expected + " !== " + results); + assert.strictEqual(typeof results, "number", label); + return true; + }; +} + +function require_number_any(label) { + return function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(typeof results, "number", label + " " + results + " is not a number"); + return true; + }; +} + +function require_number_pos(label) { + return function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(true, (results > 0), label + " " + results + " is not a positive number"); + return true; + }; +} + +function require_string(str, label) { + return function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.equal(str, results, label + " " + str + " does not match " + results); + return true; + }; +} + +function require_null(label) { + return function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(null, results, label + ": " + results + " is not null"); + return true; + }; +} + +function require_error(label) { + return function (err, results) { + assert.notEqual(err, null, label + " err is null, but an error is expected here."); + return true; + }; +} + +function is_empty_array(obj) { + return Array.isArray(obj) && obj.length === 0; +} + +function last(name, fn) { + return function (err, results) { + fn(err, results); + next(name); + }; +} + +next = function next(name) { + console.log(" \x1b[33m" + (Date.now() - cur_start) + "\x1b[0m ms"); + run_next_test(); +}; + +// Tests are run in the order they are defined. So FLUSHDB should be stay first. + +tests.FLUSHDB = function () { + var name = "FLUSHDB"; + client.select(test_db_num, require_string("OK", name)); + client2.select(test_db_num, require_string("OK", name)); + client3.select(test_db_num, require_string("OK", name)); + client.mset("flush keys 1", "flush val 1", "flush keys 2", "flush val 2", require_string("OK", name)); + client.FLUSHDB(require_string("OK", name)); + client.dbsize(last(name, require_number(0, name))); +}; + +tests.MULTI_1 = function () { + var name = "MULTI_1", multi1, multi2; + + // Provoke an error at queue time + multi1 = client.multi(); + multi1.mset("multifoo", "10", "multibar", "20", require_string("OK", name)); + multi1.set("foo2", require_error(name)); + multi1.incr("multifoo", require_number(11, name)); + multi1.incr("multibar", require_number(21, name)); + multi1.exec(); + + // Confirm that the previous command, while containing an error, still worked. + multi2 = client.multi(); + multi2.incr("multibar", require_number(22, name)); + multi2.incr("multifoo", require_number(12, name)); + multi2.exec(function (err, replies) { + assert.strictEqual(22, replies[0]); + assert.strictEqual(12, replies[1]); + next(name); + }); +}; + +tests.MULTI_2 = function () { + var name = "MULTI_2"; + + // test nested multi-bulk replies + client.multi([ + ["mget", "multifoo", "multibar", function (err, res) { + assert.strictEqual(2, res.length, name); + assert.strictEqual("12", res[0].toString(), name); + assert.strictEqual("22", res[1].toString(), name); + }], + ["set", "foo2", require_error(name)], + ["incr", "multifoo", require_number(13, name)], + ["incr", "multibar", require_number(23, name)] + ]).exec(function (err, replies) { + assert.strictEqual(2, replies[0].length, name); + assert.strictEqual("12", replies[0][0].toString(), name); + assert.strictEqual("22", replies[0][1].toString(), name); + + assert.strictEqual("13", replies[1].toString()); + assert.strictEqual("23", replies[2].toString()); + next(name); + }); +}; + +tests.MULTI_3 = function () { + var name = "MULTI_3"; + + client.sadd("some set", "mem 1"); + client.sadd("some set", "mem 2"); + client.sadd("some set", "mem 3"); + client.sadd("some set", "mem 4"); + + // make sure empty mb reply works + client.del("some missing set"); + client.smembers("some missing set", function (err, reply) { + // make sure empty mb reply works + assert.strictEqual(true, is_empty_array(reply), name); + }); + + // test nested multi-bulk replies with empty mb elements. + client.multi([ + ["smembers", "some set"], + ["del", "some set"], + ["smembers", "some set"] + ]) + .scard("some set") + .exec(function (err, replies) { + assert.strictEqual(true, is_empty_array(replies[2]), name); + next(name); + }); +}; + +tests.MULTI_4 = function () { + var name = "MULTI_4"; + + client.multi() + .mset('some', '10', 'keys', '20') + .incr('some') + .incr('keys') + .mget('some', 'keys') + .exec(function (err, replies) { + assert.strictEqual(null, err); + assert.equal('OK', replies[0]); + assert.equal(11, replies[1]); + assert.equal(21, replies[2]); + assert.equal(11, replies[3][0].toString()); + assert.equal(21, replies[3][1].toString()); + next(name); + }); +}; + +tests.MULTI_5 = function () { + var name = "MULTI_5"; + + // test nested multi-bulk replies with nulls. + client.multi([ + ["mget", ["multifoo", "some", "random value", "keys"]], + ["incr", "multifoo"] + ]) + .exec(function (err, replies) { + assert.strictEqual(replies.length, 2, name); + assert.strictEqual(replies[0].length, 4, name); + next(name); + }); +}; + +tests.MULTI_6 = function () { + var name = "MULTI_6"; + + client.multi() + .hmset("multihash", "a", "foo", "b", 1) + .hmset("multihash", { + extra: "fancy", + things: "here" + }) + .hgetall("multihash") + .exec(function (err, replies) { + assert.strictEqual(null, err); + assert.equal("OK", replies[0]); + assert.equal(Object.keys(replies[2]).length, 4); + assert.equal("foo", replies[2].a); + assert.equal("1", replies[2].b); + assert.equal("fancy", replies[2].extra); + assert.equal("here", replies[2].things); + next(name); + }); +}; + +tests.EVAL_1 = function () { + var name = "EVAL_1"; + + if (client.server_info.versions[0] >= 2 && client.server_info.versions[1] >= 9) { + // test {EVAL - Lua integer -> Redis protocol type conversion} + client.eval("return 100.5", 0, require_number(100, name)); + // test {EVAL - Lua string -> Redis protocol type conversion} + client.eval("return 'hello world'", 0, require_string("hello world", name)); + // test {EVAL - Lua true boolean -> Redis protocol type conversion} + client.eval("return true", 0, require_number(1, name)); + // test {EVAL - Lua false boolean -> Redis protocol type conversion} + client.eval("return false", 0, require_null(name)); + // test {EVAL - Lua status code reply -> Redis protocol type conversion} + client.eval("return {ok='fine'}", 0, require_string("fine", name)); + // test {EVAL - Lua error reply -> Redis protocol type conversion} + client.eval("return {err='this is an error'}", 0, require_error(name)); + // test {EVAL - Lua table -> Redis protocol type conversion} + client.eval("return {1,2,3,'ciao',{1,2}}", 0, function (err, res) { + assert.strictEqual(5, res.length, name); + assert.strictEqual(1, res[0], name); + assert.strictEqual(2, res[1], name); + assert.strictEqual(3, res[2], name); + assert.strictEqual("ciao", res[3], name); + assert.strictEqual(2, res[4].length, name); + assert.strictEqual(1, res[4][0], name); + assert.strictEqual(2, res[4][1], name); + }); + // test {EVAL - Are the KEYS and ARGS arrays populated correctly?} + client.eval("return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", 2, "a", "b", "c", "d", function (err, res) { + assert.strictEqual(4, res.length, name); + assert.strictEqual("a", res[0], name); + assert.strictEqual("b", res[1], name); + assert.strictEqual("c", res[2], name); + assert.strictEqual("d", res[3], name); + }); + // test {EVAL - is Lua able to call Redis API?} + client.set("mykey", "myval"); + client.eval("return redis.call('get','mykey')", 0, require_string("myval", name)); + // test {EVALSHA - Can we call a SHA1 if already defined?} + client.evalsha("9bd632c7d33e571e9f24556ebed26c3479a87129", 0, require_string("myval", name)); + // test {EVALSHA - Do we get an error on non defined SHA1?} + client.evalsha("ffffffffffffffffffffffffffffffffffffffff", 0, require_error(name)); + // test {EVAL - Redis integer -> Lua type conversion} + client.set("x", 0); + client.eval("local foo = redis.call('incr','x')\n" + "return {type(foo),foo}", 0, function (err, res) { + assert.strictEqual(2, res.length, name); + assert.strictEqual("number", res[0], name); + assert.strictEqual(1, res[1], name); + }); + // test {EVAL - Redis bulk -> Lua type conversion} + client.eval("local foo = redis.call('get','mykey'); return {type(foo),foo}", 0, function (err, res) { + assert.strictEqual(2, res.length, name); + assert.strictEqual("string", res[0], name); + assert.strictEqual("myval", res[1], name); + }); + // test {EVAL - Redis multi bulk -> Lua type conversion} + client.del("mylist"); + client.rpush("mylist", "a"); + client.rpush("mylist", "b"); + client.rpush("mylist", "c"); + client.eval("local foo = redis.call('lrange','mylist',0,-1)\n" + "return {type(foo),foo[1],foo[2],foo[3],# foo}", 0, function (err, res) { + assert.strictEqual(5, res.length, name); + assert.strictEqual("table", res[0], name); + assert.strictEqual("a", res[1], name); + assert.strictEqual("b", res[2], name); + assert.strictEqual("c", res[3], name); + assert.strictEqual(3, res[4], name); + }); + // test {EVAL - Redis status reply -> Lua type conversion} + client.eval("local foo = redis.call('set','mykey','myval'); return {type(foo),foo['ok']}", 0, function (err, res) { + assert.strictEqual(2, res.length, name); + assert.strictEqual("table", res[0], name); + assert.strictEqual("OK", res[1], name); + }); + // test {EVAL - Redis error reply -> Lua type conversion} + client.set("mykey", "myval"); + client.eval("local foo = redis.call('incr','mykey'); return {type(foo),foo['err']}", 0, function (err, res) { + assert.strictEqual(2, res.length, name); + assert.strictEqual("table", res[0], name); + assert.strictEqual("ERR value is not an integer or out of range", res[1], name); + }); + // test {EVAL - Redis nil bulk reply -> Lua type conversion} + client.del("mykey"); + client.eval("local foo = redis.call('get','mykey'); return {type(foo),foo == false}", 0, function (err, res) { + assert.strictEqual(2, res.length, name); + assert.strictEqual("boolean", res[0], name); + assert.strictEqual(1, res[1], name); + }); + // test {EVAL - Script can't run more than configured time limit} { + client.config("set", "lua-time-limit", 1); + client.eval("local i = 0; while true do i=i+1 end", 0, last("name", require_error(name))); + } else { + console.log("Skipping " + name + " because server version isn't new enough."); + next(name); + } +}; + +tests.WATCH_MULTI = function () { + var name = 'WATCH_MULTI', multi; + + if (client.server_info.versions[0] >= 2 && client.server_info.versions[1] >= 1) { + client.watch(name); + client.incr(name); + multi = client.multi(); + multi.incr(name); + multi.exec(last(name, require_null(name))); + } else { + console.log("Skipping " + name + " because server version isn't new enough."); + next(name); + } +}; + +tests.reconnect = function () { + var name = "reconnect"; + + client.set("recon 1", "one"); + client.set("recon 2", "two", function (err, res) { + // Do not do this in normal programs. This is to simulate the server closing on us. + // For orderly shutdown in normal programs, do client.quit() + client.stream.destroy(); + }); + + client.on("reconnecting", function on_recon(params) { + client.on("connect", function on_connect() { + client.select(test_db_num, require_string("OK", name)); + client.get("recon 1", require_string("one", name)); + client.get("recon 1", require_string("one", name)); + client.get("recon 2", require_string("two", name)); + client.get("recon 2", require_string("two", name)); + client.removeListener("connect", on_connect); + client.removeListener("reconnecting", on_recon); + next(name); + }); + }); +}; + +tests.HSET = function () { + var key = "test hash", + field1 = new Buffer("0123456789"), + value1 = new Buffer("abcdefghij"), + field2 = new Buffer(0), + value2 = new Buffer(0), + name = "HSET"; + + client.HSET(key, field1, value1, require_number(1, name)); + client.HGET(key, field1, require_string(value1.toString(), name)); + + // Empty value + client.HSET(key, field1, value2, require_number(0, name)); + client.HGET([key, field1], require_string("", name)); + + // Empty key, empty value + client.HSET([key, field2, value1], require_number(1, name)); + client.HSET(key, field2, value2, last(name, require_number(0, name))); +}; + +tests.HMSET_BUFFER_AND_ARRAY = function () { + // Saving a buffer and an array to the same key should not error + var key = "test hash", + field1 = "buffer", + value1 = new Buffer("abcdefghij"), + field2 = "array", + value2 = ["array contents"], + name = "HSET"; + + client.HMSET(key, field1, value1, field2, value2, last(name, require_string("OK", name))); +}; + +// TODO - add test for HMSET. It is special. Test for all forms as well as optional callbacks + +tests.HMGET = function () { + var key1 = "test hash 1", key2 = "test hash 2", name = "HMGET"; + + // redis-like hmset syntax + client.HMSET(key1, "0123456789", "abcdefghij", "some manner of key", "a type of value", require_string("OK", name)); + + // fancy hmset syntax + client.HMSET(key2, { + "0123456789": "abcdefghij", + "some manner of key": "a type of value" + }, require_string("OK", name)); + + client.HMGET(key1, "0123456789", "some manner of key", function (err, reply) { + assert.strictEqual("abcdefghij", reply[0].toString(), name); + assert.strictEqual("a type of value", reply[1].toString(), name); + }); + + client.HMGET(key2, "0123456789", "some manner of key", function (err, reply) { + assert.strictEqual("abcdefghij", reply[0].toString(), name); + assert.strictEqual("a type of value", reply[1].toString(), name); + }); + + client.HMGET(key1, ["0123456789"], function (err, reply) { + assert.strictEqual("abcdefghij", reply[0], name); + }); + + client.HMGET(key1, ["0123456789", "some manner of key"], function (err, reply) { + assert.strictEqual("abcdefghij", reply[0], name); + assert.strictEqual("a type of value", reply[1], name); + }); + + client.HMGET(key1, "missing thing", "another missing thing", function (err, reply) { + assert.strictEqual(null, reply[0], name); + assert.strictEqual(null, reply[1], name); + next(name); + }); +}; + +tests.HINCRBY = function () { + var name = "HINCRBY"; + client.hset("hash incr", "value", 10, require_number(1, name)); + client.HINCRBY("hash incr", "value", 1, require_number(11, name)); + client.HINCRBY("hash incr", "value 2", 1, last(name, require_number(1, name))); +}; + +tests.SUBSCRIBE = function () { + var client1 = client, msg_count = 0, name = "SUBSCRIBE"; + + client1.on("subscribe", function (channel, count) { + if (channel === "chan1") { + client2.publish("chan1", "message 1", require_number(1, name)); + client2.publish("chan2", "message 2", require_number(1, name)); + client2.publish("chan1", "message 3", require_number(1, name)); + } + }); + + client1.on("unsubscribe", function (channel, count) { + if (count === 0) { + // make sure this connection can go into and out of pub/sub mode + client1.incr("did a thing", last(name, require_number(2, name))); + } + }); + + client1.on("message", function (channel, message) { + msg_count += 1; + assert.strictEqual("message " + msg_count, message.toString()); + if (msg_count === 3) { + client1.unsubscribe("chan1", "chan2"); + } + }); + + client1.set("did a thing", 1, require_string("OK", name)); + client1.subscribe("chan1", "chan2"); +}; + +tests.SUBSCRIBE_QUIT = function () { + var name = "SUBSCRIBE_QUIT"; + client3.on("end", function () { + next(name); + }); + client3.on("subscribe", function (channel, count) { + client3.quit(); + }); + client3.subscribe("chan3"); +}; + +tests.EXISTS = function () { + var name = "EXISTS"; + client.del("foo", "foo2", require_number_any(name)); + client.set("foo", "bar", require_string("OK", name)); + client.EXISTS("foo", require_number(1, name)); + client.EXISTS("foo2", last(name, require_number(0, name))); +}; + +tests.DEL = function () { + var name = "DEL"; + client.DEL("delkey", require_number_any(name)); + client.set("delkey", "delvalue", require_string("OK", name)); + client.DEL("delkey", require_number(1, name)); + client.exists("delkey", require_number(0, name)); + client.DEL("delkey", require_number(0, name)); + client.mset("delkey", "delvalue", "delkey2", "delvalue2", require_string("OK", name)); + client.DEL("delkey", "delkey2", last(name, require_number(2, name))); +}; + +tests.TYPE = function () { + var name = "TYPE"; + client.set(["string key", "should be a string"], require_string("OK", name)); + client.rpush(["list key", "should be a list"], require_number_pos(name)); + client.sadd(["set key", "should be a set"], require_number_any(name)); + client.zadd(["zset key", "10.0", "should be a zset"], require_number_any(name)); + client.hset(["hash key", "hashtest", "should be a hash"], require_number_any(0, name)); + + client.TYPE(["string key"], require_string("string", name)); + client.TYPE(["list key"], require_string("list", name)); + client.TYPE(["set key"], require_string("set", name)); + client.TYPE(["zset key"], require_string("zset", name)); + client.TYPE("not here yet", require_string("none", name)); + client.TYPE(["hash key"], last(name, require_string("hash", name))); +}; + +tests.KEYS = function () { + var name = "KEYS"; + client.mset(["test keys 1", "test val 1", "test keys 2", "test val 2"], require_string("OK", name)); + client.KEYS(["test keys*"], function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(2, results.length, name); + assert.strictEqual("test keys 1", results[0].toString(), name); + assert.strictEqual("test keys 2", results[1].toString(), name); + next(name); + }); +}; + +tests.MULTIBULK_ZERO_LENGTH = function () { + var name = "MULTIBULK_ZERO_LENGTH"; + client.KEYS(['users:*'], function (err, results) { + assert.strictEqual(null, err, 'error on empty multibulk reply'); + assert.strictEqual(true, is_empty_array(results), "not an empty array"); + next(name); + }); +}; + +tests.RANDOMKEY = function () { + var name = "RANDOMKEY"; + client.mset(["test keys 1", "test val 1", "test keys 2", "test val 2"], require_string("OK", name)); + client.RANDOMKEY([], function (err, results) { + assert.strictEqual(null, err, name + " result sent back unexpected error: " + err); + assert.strictEqual(true, /\w+/.test(results), name); + next(name); + }); +}; + +tests.RENAME = function () { + var name = "RENAME"; + client.set(['foo', 'bar'], require_string("OK", name)); + client.RENAME(["foo", "new foo"], require_string("OK", name)); + client.exists(["foo"], require_number(0, name)); + client.exists(["new foo"], last(name, require_number(1, name))); +}; + +tests.RENAMENX = function () { + var name = "RENAMENX"; + client.set(['foo', 'bar'], require_string("OK", name)); + client.set(['foo2', 'bar2'], require_string("OK", name)); + client.RENAMENX(["foo", "foo2"], require_number(0, name)); + client.exists(["foo"], require_number(1, name)); + client.exists(["foo2"], require_number(1, name)); + client.del(["foo2"], require_number(1, name)); + client.RENAMENX(["foo", "foo2"], require_number(1, name)); + client.exists(["foo"], require_number(0, name)); + client.exists(["foo2"], last(name, require_number(1, name))); +}; + +tests.DBSIZE = function () { + var name = "DBSIZE"; + client.set(['foo', 'bar'], require_string("OK", name)); + client.DBSIZE([], last(name, require_number_pos("DBSIZE"))); +}; + +tests.GET = function () { + var name = "GET"; + client.set(["get key", "get val"], require_string("OK", name)); + client.GET(["get key"], last(name, require_string("get val", name))); +}; + +tests.SET = function () { + var name = "SET"; + client.SET(["set key", "set val"], require_string("OK", name)); + client.get(["set key"], last(name, require_string("set val", name))); +}; + +tests.GETSET = function () { + var name = "GETSET"; + client.set(["getset key", "getset val"], require_string("OK", name)); + client.GETSET(["getset key", "new getset val"], require_string("getset val", name)); + client.get(["getset key"], last(name, require_string("new getset val", name))); +}; + +tests.MGET = function () { + var name = "MGET"; + client.mset(["mget keys 1", "mget val 1", "mget keys 2", "mget val 2", "mget keys 3", "mget val 3"], require_string("OK", name)); + client.MGET("mget keys 1", "mget keys 2", "mget keys 3", function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(3, results.length, name); + assert.strictEqual("mget val 1", results[0].toString(), name); + assert.strictEqual("mget val 2", results[1].toString(), name); + assert.strictEqual("mget val 3", results[2].toString(), name); + }); + client.MGET(["mget keys 1", "mget keys 2", "mget keys 3"], function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(3, results.length, name); + assert.strictEqual("mget val 1", results[0].toString(), name); + assert.strictEqual("mget val 2", results[1].toString(), name); + assert.strictEqual("mget val 3", results[2].toString(), name); + }); + client.MGET(["mget keys 1", "some random shit", "mget keys 2", "mget keys 3"], function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(4, results.length, name); + assert.strictEqual("mget val 1", results[0].toString(), name); + assert.strictEqual(null, results[1], name); + assert.strictEqual("mget val 2", results[2].toString(), name); + assert.strictEqual("mget val 3", results[3].toString(), name); + next(name); + }); +}; + +tests.SETNX = function () { + var name = "SETNX"; + client.set(["setnx key", "setnx value"], require_string("OK", name)); + client.SETNX(["setnx key", "new setnx value"], require_number(0, name)); + client.del(["setnx key"], require_number(1, name)); + client.exists(["setnx key"], require_number(0, name)); + client.SETNX(["setnx key", "new setnx value"], require_number(1, name)); + client.exists(["setnx key"], last(name, require_number(1, name))); +}; + +tests.SETEX = function () { + var name = "SETEX"; + client.SETEX(["setex key", "100", "setex val"], require_string("OK", name)); + client.exists(["setex key"], require_number(1, name)); + client.ttl(["setex key"], last(name, require_number_pos(name))); +}; + +tests.MSETNX = function () { + var name = "MSETNX"; + client.mset(["mset1", "val1", "mset2", "val2", "mset3", "val3"], require_string("OK", name)); + client.MSETNX(["mset3", "val3", "mset4", "val4"], require_number(0, name)); + client.del(["mset3"], require_number(1, name)); + client.MSETNX(["mset3", "val3", "mset4", "val4"], require_number(1, name)); + client.exists(["mset3"], require_number(1, name)); + client.exists(["mset4"], last(name, require_number(1, name))); +}; + +tests.HGETALL = function () { + var name = "HGETALL"; + client.hmset(["hosts", "mjr", "1", "another", "23", "home", "1234"], require_string("OK", name)); + client.HGETALL(["hosts"], function (err, obj) { + assert.strictEqual(null, err, name + " result sent back unexpected error: " + err); + assert.strictEqual(3, Object.keys(obj).length, name); + assert.strictEqual("1", obj.mjr.toString(), name); + assert.strictEqual("23", obj.another.toString(), name); + assert.strictEqual("1234", obj.home.toString(), name); + next(name); + }); +}; + +tests.HGETALL_NULL = function () { + var name = "HGETALL_NULL"; + + client.hgetall('missing', function (err, obj) { + assert.strictEqual(null, err); + assert.deepEqual([], obj); + next(name); + }); +}; + +tests.UTF8 = function () { + var name = "UTF8", + utf8_sample = "ಠ_ಠ"; + + client.set(["utf8test", utf8_sample], require_string("OK", name)); + client.get(["utf8test"], function (err, obj) { + assert.strictEqual(null, err); + assert.strictEqual(utf8_sample, obj); + next(name); + }); +}; + +// Set tests were adapted from Brian Hammond's redis-node-client.js, which has a comprehensive test suite + +tests.SADD = function () { + var name = "SADD"; + + client.del('set0'); + client.sadd('set0', 'member0', require_number(1, name)); + client.sadd('set0', 'member0', last(name, require_number(0, name))); +}; + +tests.SADD2 = function () { + var name = "SADD2"; + + client.del("set0"); + client.sadd("set0", ["member0", "member1", "member2"], require_number(3, name)); + client.smembers("set0", function (err, res) { + assert.strictEqual(res.length, 3); + assert.strictEqual(res[0], "member0"); + assert.strictEqual(res[1], "member1"); + assert.strictEqual(res[2], "member2"); + next(name); + }); +}; + +tests.SISMEMBER = function () { + var name = "SISMEMBER"; + + client.del('set0'); + client.sadd('set0', 'member0', require_number(1, name)); + client.sismember('set0', 'member0', require_number(1, name)); + client.sismember('set0', 'member1', last(name, require_number(0, name))); +}; + +tests.SCARD = function () { + var name = "SCARD"; + + client.del('set0'); + client.sadd('set0', 'member0', require_number(1, name)); + client.scard('set0', require_number(1, name)); + client.sadd('set0', 'member1', require_number(1, name)); + client.scard('set0', last(name, require_number(2, name))); +}; + +tests.SREM = function () { + var name = "SREM"; + + client.del('set0'); + client.sadd('set0', 'member0', require_number(1, name)); + client.srem('set0', 'foobar', require_number(0, name)); + client.srem('set0', 'member0', require_number(1, name)); + client.scard('set0', last(name, require_number(0, name))); +}; + +tests.SPOP = function () { + var name = "SPOP"; + + client.del('zzz'); + client.sadd('zzz', 'member0', require_number(1, name)); + client.scard('zzz', require_number(1, name)); + + client.spop('zzz', function (err, value) { + if (err) { + assert.fail(err); + } + assert.equal(value, 'member0', name); + }); + + client.scard('zzz', last(name, require_number(0, name))); +}; + +tests.SDIFF = function () { + var name = "SDIFF"; + + client.del('foo'); + client.sadd('foo', 'x', require_number(1, name)); + client.sadd('foo', 'a', require_number(1, name)); + client.sadd('foo', 'b', require_number(1, name)); + client.sadd('foo', 'c', require_number(1, name)); + + client.sadd('bar', 'c', require_number(1, name)); + + client.sadd('baz', 'a', require_number(1, name)); + client.sadd('baz', 'd', require_number(1, name)); + + client.sdiff('foo', 'bar', 'baz', function (err, values) { + if (err) { + assert.fail(err, name); + } + values.sort(); + assert.equal(values.length, 2, name); + assert.equal(values[0], 'b', name); + assert.equal(values[1], 'x', name); + next(name); + }); +}; + +tests.SDIFFSTORE = function () { + var name = "SDIFFSTORE"; + + client.del('foo'); + client.del('bar'); + client.del('baz'); + client.del('quux'); + + client.sadd('foo', 'x', require_number(1, name)); + client.sadd('foo', 'a', require_number(1, name)); + client.sadd('foo', 'b', require_number(1, name)); + client.sadd('foo', 'c', require_number(1, name)); + + client.sadd('bar', 'c', require_number(1, name)); + + client.sadd('baz', 'a', require_number(1, name)); + client.sadd('baz', 'd', require_number(1, name)); + + // NB: SDIFFSTORE returns the number of elements in the dstkey + + client.sdiffstore('quux', 'foo', 'bar', 'baz', require_number(2, name)); + + client.smembers('quux', function (err, values) { + if (err) { + assert.fail(err, name); + } + var members = buffers_to_strings(values).sort(); + + assert.deepEqual(members, [ 'b', 'x' ], name); + next(name); + }); +}; + +tests.SMEMBERS = function () { + var name = "SMEMBERS"; + + client.del('foo'); + client.sadd('foo', 'x', require_number(1, name)); + + client.smembers('foo', function (err, members) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(members), [ 'x' ], name); + }); + + client.sadd('foo', 'y', require_number(1, name)); + + client.smembers('foo', function (err, values) { + if (err) { + assert.fail(err, name); + } + assert.equal(values.length, 2, name); + var members = buffers_to_strings(values).sort(); + + assert.deepEqual(members, [ 'x', 'y' ], name); + next(name); + }); +}; + +tests.SMOVE = function () { + var name = "SMOVE"; + + client.del('foo'); + client.del('bar'); + + client.sadd('foo', 'x', require_number(1, name)); + client.smove('foo', 'bar', 'x', require_number(1, name)); + client.sismember('foo', 'x', require_number(0, name)); + client.sismember('bar', 'x', require_number(1, name)); + client.smove('foo', 'bar', 'x', last(name, require_number(0, name))); +}; + +tests.SINTER = function () { + var name = "SINTER"; + + client.del('sa'); + client.del('sb'); + client.del('sc'); + + client.sadd('sa', 'a', require_number(1, name)); + client.sadd('sa', 'b', require_number(1, name)); + client.sadd('sa', 'c', require_number(1, name)); + + client.sadd('sb', 'b', require_number(1, name)); + client.sadd('sb', 'c', require_number(1, name)); + client.sadd('sb', 'd', require_number(1, name)); + + client.sadd('sc', 'c', require_number(1, name)); + client.sadd('sc', 'd', require_number(1, name)); + client.sadd('sc', 'e', require_number(1, name)); + + client.sinter('sa', 'sb', function (err, intersection) { + if (err) { + assert.fail(err, name); + } + assert.equal(intersection.length, 2, name); + assert.deepEqual(buffers_to_strings(intersection).sort(), [ 'b', 'c' ], name); + }); + + client.sinter('sb', 'sc', function (err, intersection) { + if (err) { + assert.fail(err, name); + } + assert.equal(intersection.length, 2, name); + assert.deepEqual(buffers_to_strings(intersection).sort(), [ 'c', 'd' ], name); + }); + + client.sinter('sa', 'sc', function (err, intersection) { + if (err) { + assert.fail(err, name); + } + assert.equal(intersection.length, 1, name); + assert.equal(intersection[0], 'c', name); + }); + + // 3-way + + client.sinter('sa', 'sb', 'sc', function (err, intersection) { + if (err) { + assert.fail(err, name); + } + assert.equal(intersection.length, 1, name); + assert.equal(intersection[0], 'c', name); + next(name); + }); +}; + +tests.SINTERSTORE = function () { + var name = "SINTERSTORE"; + + client.del('sa'); + client.del('sb'); + client.del('sc'); + client.del('foo'); + + client.sadd('sa', 'a', require_number(1, name)); + client.sadd('sa', 'b', require_number(1, name)); + client.sadd('sa', 'c', require_number(1, name)); + + client.sadd('sb', 'b', require_number(1, name)); + client.sadd('sb', 'c', require_number(1, name)); + client.sadd('sb', 'd', require_number(1, name)); + + client.sadd('sc', 'c', require_number(1, name)); + client.sadd('sc', 'd', require_number(1, name)); + client.sadd('sc', 'e', require_number(1, name)); + + client.sinterstore('foo', 'sa', 'sb', 'sc', require_number(1, name)); + + client.smembers('foo', function (err, members) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(members), [ 'c' ], name); + next(name); + }); +}; + +tests.SUNION = function () { + var name = "SUNION"; + + client.del('sa'); + client.del('sb'); + client.del('sc'); + + client.sadd('sa', 'a', require_number(1, name)); + client.sadd('sa', 'b', require_number(1, name)); + client.sadd('sa', 'c', require_number(1, name)); + + client.sadd('sb', 'b', require_number(1, name)); + client.sadd('sb', 'c', require_number(1, name)); + client.sadd('sb', 'd', require_number(1, name)); + + client.sadd('sc', 'c', require_number(1, name)); + client.sadd('sc', 'd', require_number(1, name)); + client.sadd('sc', 'e', require_number(1, name)); + + client.sunion('sa', 'sb', 'sc', function (err, union) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(union).sort(), ['a', 'b', 'c', 'd', 'e'], name); + next(name); + }); +}; + +tests.SUNIONSTORE = function () { + var name = "SUNIONSTORE"; + + client.del('sa'); + client.del('sb'); + client.del('sc'); + client.del('foo'); + + client.sadd('sa', 'a', require_number(1, name)); + client.sadd('sa', 'b', require_number(1, name)); + client.sadd('sa', 'c', require_number(1, name)); + + client.sadd('sb', 'b', require_number(1, name)); + client.sadd('sb', 'c', require_number(1, name)); + client.sadd('sb', 'd', require_number(1, name)); + + client.sadd('sc', 'c', require_number(1, name)); + client.sadd('sc', 'd', require_number(1, name)); + client.sadd('sc', 'e', require_number(1, name)); + + client.sunionstore('foo', 'sa', 'sb', 'sc', function (err, cardinality) { + if (err) { + assert.fail(err, name); + } + assert.equal(cardinality, 5, name); + }); + + client.smembers('foo', function (err, members) { + if (err) { + assert.fail(err, name); + } + assert.equal(members.length, 5, name); + assert.deepEqual(buffers_to_strings(members).sort(), ['a', 'b', 'c', 'd', 'e'], name); + next(name); + }); +}; + +// SORT test adapted from Brian Hammond's redis-node-client.js, which has a comprehensive test suite + +tests.SORT = function () { + var name = "SORT"; + + client.del('y'); + client.del('x'); + + client.rpush('y', 'd', require_number(1, name)); + client.rpush('y', 'b', require_number(2, name)); + client.rpush('y', 'a', require_number(3, name)); + client.rpush('y', 'c', require_number(4, name)); + + client.rpush('x', '3', require_number(1, name)); + client.rpush('x', '9', require_number(2, name)); + client.rpush('x', '2', require_number(3, name)); + client.rpush('x', '4', require_number(4, name)); + + client.set('w3', '4', require_string("OK", name)); + client.set('w9', '5', require_string("OK", name)); + client.set('w2', '12', require_string("OK", name)); + client.set('w4', '6', require_string("OK", name)); + + client.set('o2', 'buz', require_string("OK", name)); + client.set('o3', 'foo', require_string("OK", name)); + client.set('o4', 'baz', require_string("OK", name)); + client.set('o9', 'bar', require_string("OK", name)); + + client.set('p2', 'qux', require_string("OK", name)); + client.set('p3', 'bux', require_string("OK", name)); + client.set('p4', 'lux', require_string("OK", name)); + client.set('p9', 'tux', require_string("OK", name)); + + // Now the data has been setup, we can test. + + // But first, test basic sorting. + + // y = [ d b a c ] + // sort y ascending = [ a b c d ] + // sort y descending = [ d c b a ] + + client.sort('y', 'asc', 'alpha', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), ['a', 'b', 'c', 'd'], name); + }); + + client.sort('y', 'desc', 'alpha', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), ['d', 'c', 'b', 'a'], name); + }); + + // Now try sorting numbers in a list. + // x = [ 3, 9, 2, 4 ] + + client.sort('x', 'asc', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), [2, 3, 4, 9], name); + }); + + client.sort('x', 'desc', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), [9, 4, 3, 2], name); + }); + + // Try sorting with a 'by' pattern. + + client.sort('x', 'by', 'w*', 'asc', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), [3, 9, 4, 2], name); + }); + + // Try sorting with a 'by' pattern and 1 'get' pattern. + + client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), ['foo', 'bar', 'baz', 'buz'], name); + }); + + // Try sorting with a 'by' pattern and 2 'get' patterns. + + client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux'], name); + }); + + // Try sorting with a 'by' pattern and 2 'get' patterns. + // Instead of getting back the sorted set/list, store the values to a list. + // Then check that the values are there in the expected order. + + client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*', 'store', 'bacon', function (err) { + if (err) { + assert.fail(err, name); + } + }); + + client.lrange('bacon', 0, -1, function (err, values) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(values), ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux'], name); + next(name); + }); + + // TODO - sort by hash value +}; + +tests.BLPOP = function () { + var name = "BLPOP"; + + client.rpush("blocking list", "initial value", function (err, res) { + client2.BLPOP("blocking list", 0, function (err, res) { + assert.strictEqual("blocking list", res[0].toString()); + assert.strictEqual("initial value", res[1].toString()); + + client.rpush("blocking list", "wait for this value"); + }); + client2.BLPOP("blocking list", 0, function (err, res) { + assert.strictEqual("blocking list", res[0].toString()); + assert.strictEqual("wait for this value", res[1].toString()); + next(name); + }); + }); +}; + +tests.BLPOP_TIMEOUT = function () { + var name = "BLPOP_TIMEOUT"; + + // try to BLPOP the list again, which should be empty. This should timeout and return null. + client2.BLPOP("blocking list", 1, function (err, res) { + if (err) { + throw err; + } + + assert.strictEqual(res, null); + next(name); + }); +}; + +tests.EXPIRE = function () { + var name = "EXPIRE"; + client.set(['expiry key', 'bar'], require_string("OK", name)); + client.EXPIRE(["expiry key", "1"], require_number_pos(name)); + setTimeout(function () { + client.exists(["expiry key"], last(name, require_number(0, name))); + }, 2000); +}; + +tests.TTL = function () { + var name = "TTL"; + client.set(["ttl key", "ttl val"], require_string("OK", name)); + client.expire(["ttl key", "100"], require_number_pos(name)); + setTimeout(function () { + client.TTL(["ttl key"], last(name, require_number_pos(0, name))); + }, 500); +}; + +all_tests = Object.keys(tests); +all_start = new Date(); +test_count = 0; + +run_next_test = function run_next_test() { + var test_name = all_tests.shift(); + if (typeof tests[test_name] === "function") { + util.print('- \x1b[1m' + test_name.toLowerCase() + '\x1b[0m:'); + cur_start = new Date(); + test_count += 1; + tests[test_name](); + } else { + console.log('\n completed \x1b[32m%d\x1b[0m tests in \x1b[33m%d\x1b[0m ms\n', test_count, new Date() - all_start); + client.quit(); + client2.quit(); + client4.quit(); + } +}; + +console.log("Using reply parser " + client.reply_parser.name); + +client.once("ready", function start_tests() { + console.log("Connected to " + client.host + ":" + client.port + ", Redis server version " + client.server_info.redis_version + "\n"); + + run_next_test(); + + connected = true; +}); + +client.on('end', function () { + ended = true; +}); + +// TODO - need a better way to test auth, maybe auto-config a local Redis server? Sounds hard. +// Yes, this is the real password. Please be nice, thanks. +client4.auth("664b1b6aaf134e1ec281945a8de702a9", function (err, res) { + var name = "AUTH_4"; + + if (err) { + assert.fail(err, name); + } + assert.strictEqual("OK", res.toString(), "auth"); +}); + +// Exit immediately on connection failure, which triggers "exit", below, which fails the test +client.on("error", function (err) { + console.error("client: " + err.stack); + process.exit(); +}); +client2.on("error", function (err) { + console.error("client2: " + err.stack); + process.exit(); +}); +client3.on("error", function (err) { + console.error("client3: " + err.stack); + process.exit(); +}); + +client.on("reconnecting", function (params) { +// console.log("reconnecting: " + util.inspect(params)); +}); + +process.on('uncaughtException', function (err) { + console.error("Uncaught exception: " + err.stack); + process.exit(1); +}); + +process.on('exit', function (code) { + assert.equal(true, connected); + assert.equal(true, ended); +}); diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/buffer_bench.js b/networking/node_modules/socket.io/node_modules/redis/tests/buffer_bench.js new file mode 100644 index 0000000..a504fbc --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/buffer_bench.js @@ -0,0 +1,89 @@ +var source = new Buffer(100), + dest = new Buffer(100), i, j, k, tmp, count = 1000000, bytes = 100; + +for (i = 99 ; i >= 0 ; i--) { + source[i] = 120; +} + +var str = "This is a nice String.", + buf = new Buffer("This is a lovely Buffer."); + +var start = new Date(); +for (i = count * 100; i > 0 ; i--) { + if (Buffer.isBuffer(str)) {} +} +var end = new Date(); +console.log("Buffer.isBuffer(str) " + (end - start) + " ms"); + +var start = new Date(); +for (i = count * 100; i > 0 ; i--) { + if (Buffer.isBuffer(buf)) {} +} +var end = new Date(); +console.log("Buffer.isBuffer(buf) " + (end - start) + " ms"); + +var start = new Date(); +for (i = count * 100; i > 0 ; i--) { + if (str instanceof Buffer) {} +} +var end = new Date(); +console.log("str instanceof Buffer " + (end - start) + " ms"); + +var start = new Date(); +for (i = count * 100; i > 0 ; i--) { + if (buf instanceof Buffer) {} +} +var end = new Date(); +console.log("buf instanceof Buffer " + (end - start) + " ms"); + +for (i = bytes ; i > 0 ; i --) { + var start = new Date(); + for (j = count ; j > 0; j--) { + tmp = source.toString("ascii", 0, bytes); + } + var end = new Date(); + console.log("toString() " + i + " bytes " + (end - start) + " ms"); +} + +for (i = bytes ; i > 0 ; i --) { + var start = new Date(); + for (j = count ; j > 0; j--) { + tmp = ""; + for (k = 0; k <= i ; k++) { + tmp += String.fromCharCode(source[k]); + } + } + var end = new Date(); + console.log("manual string " + i + " bytes " + (end - start) + " ms"); +} + +for (i = bytes ; i > 0 ; i--) { + var start = new Date(); + for (j = count ; j > 0 ; j--) { + for (k = i ; k > 0 ; k--) { + dest[k] = source[k]; + } + } + var end = new Date(); + console.log("Manual copy " + i + " bytes " + (end - start) + " ms"); +} + +for (i = bytes ; i > 0 ; i--) { + var start = new Date(); + for (j = count ; j > 0 ; j--) { + for (k = i ; k > 0 ; k--) { + dest[k] = 120; + } + } + var end = new Date(); + console.log("Direct assignment " + i + " bytes " + (end - start) + " ms"); +} + +for (i = bytes ; i > 0 ; i--) { + var start = new Date(); + for (j = count ; j > 0 ; j--) { + source.copy(dest, 0, 0, i); + } + var end = new Date(); + console.log("Buffer.copy() " + i + " bytes " + (end - start) + " ms"); +} diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/reconnect_test.js b/networking/node_modules/socket.io/node_modules/redis/tests/reconnect_test.js new file mode 100644 index 0000000..08a6ca6 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/reconnect_test.js @@ -0,0 +1,27 @@ +var redis = require("redis").createClient(); + +redis.on("error", function (err) { + console.log("Redis says: " + err); +}); + +redis.on("ready", function () { + console.log("Redis ready."); +}); + +redis.on("reconnecting", function (arg) { + console.log("Redis reconnecting: " + JSON.stringify(arg)); +}); +redis.on("connect", function () { + console.log("Redis connected."); +}); + +setInterval(function () { + var now = Date.now(); + redis.set("now", now, function (err, res) { + if (err) { + console.log(now + " Redis reply error: " + err); + } else { + console.log(now + " Redis reply: " + res); + } + }); +}, 200); diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/stress/codec.js b/networking/node_modules/socket.io/node_modules/redis/tests/stress/codec.js new file mode 100644 index 0000000..7d764f6 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/stress/codec.js @@ -0,0 +1,16 @@ +var json = { + encode: JSON.stringify, + decode: JSON.parse +}; + +var MsgPack = require('node-msgpack'); +msgpack = { + encode: MsgPack.pack, + decode: function(str) { return MsgPack.unpack(new Buffer(str)); } +}; + +bison = require('bison'); + +module.exports = json; +//module.exports = msgpack; +//module.exports = bison; diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/stress/pubsub/pub.js b/networking/node_modules/socket.io/node_modules/redis/tests/stress/pubsub/pub.js new file mode 100644 index 0000000..0acde7a --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/stress/pubsub/pub.js @@ -0,0 +1,38 @@ +'use strict'; + +var freemem = require('os').freemem; +var profiler = require('v8-profiler'); +var codec = require('../codec'); + +var sent = 0; + +var pub = require('redis').createClient(null, null, { + //command_queue_high_water: 5, + //command_queue_low_water: 1 +}) +.on('ready', function() { + this.emit('drain'); +}) +.on('drain', function() { + process.nextTick(exec); +}); + +var payload = '1'; for (var i = 0; i < 12; ++i) payload += payload; +console.log('Message payload length', payload.length); + +function exec() { + pub.publish('timeline', codec.encode({ foo: payload })); + ++sent; + if (!pub.should_buffer) { + process.nextTick(exec); + } +} + +profiler.takeSnapshot('s_0'); + +exec(); + +setInterval(function() { + profiler.takeSnapshot('s_' + sent); + console.error('sent', sent, 'free', freemem(), 'cmdqlen', pub.command_queue.length, 'offqlen', pub.offline_queue.length); +}, 2000); diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/stress/pubsub/run b/networking/node_modules/socket.io/node_modules/redis/tests/stress/pubsub/run new file mode 100755 index 0000000..bd9ac39 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/stress/pubsub/run @@ -0,0 +1,10 @@ +#!/bin/sh +node server.js & +node server.js & +node server.js & +node server.js & +node server.js & +node server.js & +node server.js & +node server.js & +node --debug pub.js diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/stress/pubsub/server.js b/networking/node_modules/socket.io/node_modules/redis/tests/stress/pubsub/server.js new file mode 100644 index 0000000..035e6b7 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/stress/pubsub/server.js @@ -0,0 +1,23 @@ +'use strict'; + +var freemem = require('os').freemem; +var codec = require('../codec'); + +var id = Math.random(); +var recv = 0; + +var sub = require('redis').createClient() + .on('ready', function() { + this.subscribe('timeline'); + }) + .on('message', function(channel, message) { + var self = this; + if (message) { + message = codec.decode(message); + ++recv; + } + }); + +setInterval(function() { + console.error('id', id, 'received', recv, 'free', freemem()); +}, 2000); diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/stress/rpushblpop/pub.js b/networking/node_modules/socket.io/node_modules/redis/tests/stress/rpushblpop/pub.js new file mode 100644 index 0000000..9caf1d0 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/stress/rpushblpop/pub.js @@ -0,0 +1,49 @@ +'use strict'; + +var freemem = require('os').freemem; +//var profiler = require('v8-profiler'); +var codec = require('../codec'); + +var sent = 0; + +var pub = require('redis').createClient(null, null, { + //command_queue_high_water: 5, + //command_queue_low_water: 1 +}) +.on('ready', function() { + this.del('timeline'); + this.emit('drain'); +}) +.on('drain', function() { + process.nextTick(exec); +}); + +var payload = '1'; for (var i = 0; i < 12; ++i) payload += payload; +console.log('Message payload length', payload.length); + +function exec() { + pub.rpush('timeline', codec.encode({ foo: payload })); + ++sent; + if (!pub.should_buffer) { + process.nextTick(exec); + } +} + +//profiler.takeSnapshot('s_0'); + +exec(); + +setInterval(function() { + //var ss = profiler.takeSnapshot('s_' + sent); + //console.error(ss.stringify()); + pub.llen('timeline', function(err, result) { + console.error('sent', sent, 'free', freemem(), + 'cmdqlen', pub.command_queue.length, 'offqlen', pub.offline_queue.length, + 'llen', result + ); + }); +}, 2000); + +/*setTimeout(function() { + process.exit(); +}, 30000);*/ diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/stress/rpushblpop/run b/networking/node_modules/socket.io/node_modules/redis/tests/stress/rpushblpop/run new file mode 100755 index 0000000..8045ae8 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/stress/rpushblpop/run @@ -0,0 +1,6 @@ +#!/bin/sh +node server.js & +#node server.js & +#node server.js & +#node server.js & +node --debug pub.js diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/stress/rpushblpop/server.js b/networking/node_modules/socket.io/node_modules/redis/tests/stress/rpushblpop/server.js new file mode 100644 index 0000000..9cbcdd9 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/stress/rpushblpop/server.js @@ -0,0 +1,30 @@ +'use strict'; + +var freemem = require('os').freemem; +var codec = require('../codec'); + +var id = Math.random(); +var recv = 0; + +var cmd = require('redis').createClient(); +var sub = require('redis').createClient() + .on('ready', function() { + this.emit('timeline'); + }) + .on('timeline', function() { + var self = this; + this.blpop('timeline', 0, function(err, result) { + var message = result[1]; + if (message) { + message = codec.decode(message); + ++recv; + } + self.emit('timeline'); + }); + }); + +setInterval(function() { + cmd.llen('timeline', function(err, result) { + console.error('id', id, 'received', recv, 'free', freemem(), 'llen', result); + }); +}, 2000); diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/00 b/networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/00 new file mode 100644 index 0000000..29d7bf7 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/00 @@ -0,0 +1,13 @@ +# size JSON msgpack bison +26602 2151.0170848180414 +25542 ? 2842.589272665782 +24835 ? ? 7280.4538397469805 +6104 6985.234528557929 +5045 ? 7217.461392841478 +4341 ? ? 14261.406335354604 +4180 15864.633685636572 +4143 ? 12954.806235781925 +4141 ? ? 44650.70733912719 +75 114227.07313350472 +40 ? 30162.440062810834 +39 ? ? 119815.66013519121 diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/plot b/networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/plot new file mode 100755 index 0000000..2563797 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/plot @@ -0,0 +1,13 @@ +#!/bin/sh + +gnuplot >size-rate.jpg << _EOF_ + +set terminal png nocrop enhanced font verdana 12 size 640,480 +set logscale x +set logscale y +set grid +set xlabel 'Serialized object size, octets' +set ylabel 'decode(encode(obj)) rate, 1/sec' +plot '00' using 1:2 title 'json' smooth bezier, '00' using 1:3 title 'msgpack' smooth bezier, '00' using 1:4 title 'bison' smooth bezier + +_EOF_ diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/size-rate.png b/networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/size-rate.png new file mode 100644 index 0000000000000000000000000000000000000000..c9c2bee6b076040ccf7e6bc337c307732c400463 GIT binary patch literal 6672 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 H#^C-7XAtZ( literal 0 HcmV?d00001 diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/speed.js b/networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/speed.js new file mode 100644 index 0000000..8e43cbc --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/stress/speed/speed.js @@ -0,0 +1,84 @@ +var msgpack = require('node-msgpack'); +var bison = require('bison'); +var codec = { + JSON: { + encode: JSON.stringify, + decode: JSON.parse + }, + msgpack: { + encode: msgpack.pack, + decode: msgpack.unpack + }, + bison: bison +}; + +var obj, l; + +var s = '0'; +for (var i = 0; i < 12; ++i) s += s; + +obj = { + foo: s, + arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333], + rand: [], + a: s, + ccc: s, + b: s + s + s +}; +for (i = 0; i < 100; ++i) obj.rand.push(Math.random()); +forObj(obj); + +obj = { + foo: s, + arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333], + rand: [] +}; +for (i = 0; i < 100; ++i) obj.rand.push(Math.random()); +forObj(obj); + +obj = { + foo: s, + arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333], + rand: [] +}; +forObj(obj); + +obj = { + arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333], + rand: [] +}; +forObj(obj); + +function run(obj, codec) { + var t1 = Date.now(); + var n = 10000; + for (var i = 0; i < n; ++i) { + codec.decode(l = codec.encode(obj)); + } + var t2 = Date.now(); + //console.log('DONE', n*1000/(t2-t1), 'codecs/sec, length=', l.length); + return [n*1000/(t2-t1), l.length]; +} + +function series(obj, cname, n) { + var rate = 0; + var len = 0; + for (var i = 0; i < n; ++i) { + var r = run(obj, codec[cname]); + rate += r[0]; + len += r[1]; + } + rate /= n; + len /= n; + console.log(cname + ' ' + rate + ' ' + len); + return [rate, len]; +} + +function forObj(obj) { + var r = { + JSON: series(obj, 'JSON', 20), + msgpack: series(obj, 'msgpack', 20), + bison: series(obj, 'bison', 20) + }; + return r; +} diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/sub_quit_test.js b/networking/node_modules/socket.io/node_modules/redis/tests/sub_quit_test.js new file mode 100644 index 0000000..ad1f413 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/sub_quit_test.js @@ -0,0 +1,18 @@ +var client = require("redis").createClient(), + client2 = require("redis").createClient(); + +client.subscribe("something"); +client.on("subscribe", function (channel, count) { + console.log("Got sub: " + channel); + client.unsubscribe("something"); +}); + +client.on("unsubscribe", function (channel, count) { + console.log("Got unsub: " + channel + ", quitting"); + client.quit(); +}); + +// exercise unsub before sub +client2.unsubscribe("something"); +client2.subscribe("another thing"); +client2.quit(); diff --git a/networking/node_modules/socket.io/node_modules/redis/tests/test_start_stop.js b/networking/node_modules/socket.io/node_modules/redis/tests/test_start_stop.js new file mode 100644 index 0000000..0770893 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/redis/tests/test_start_stop.js @@ -0,0 +1,17 @@ +var redis = require("./index"), + client = redis.createClient(); + +// This currently doesn't work, due to what I beleive to be a bug in redis 2.0.1. +// INFO and QUIT are pipelined together, and the socket closes before the INFO +// command gets a reply. + +redis.debug_mode = true; +client.info(redis.print); +client.quit(); + +// A workaround is: +// client.info(function (err, res) { +// console.log(res.toString()); +// client.quit(); +// }); + diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/.npmignore b/networking/node_modules/socket.io/node_modules/socket.io-client/.npmignore new file mode 100644 index 0000000..c27cb50 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/.npmignore @@ -0,0 +1,2 @@ +test/node_modules +support diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/History.md b/networking/node_modules/socket.io/node_modules/socket.io-client/History.md new file mode 100644 index 0000000..7315604 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/History.md @@ -0,0 +1,192 @@ + +0.9.6 / 2012-04-17 +================== + + * Don't position the jsonp form off the screen (android fix). + +0.9.5 / 2012-04-05 +================== + + * Bumped version. + +0.9.4 / 2012-04-01 +================== + + * Fixes polling loop upon reconnect advice (fixes #438). + +0.9.3 / 2012-03-28 +================== + + * Fix XHR.check, which was throwing an error transparently and causing non-IE browsers to fall back to JSONP [mikito] + * Fixed forced disconnect on window close [zzzaaa] + +0.9.2 / 2012-03-13 +================== + + * Transport order set by "options" [zzzaaa] + +0.9.1-1 / 2012-03-02 +==================== + + * Fixed active-x-obfuscator NPM dependency. + +0.9.1 / 2012-03-02 +================== + + * Misc corrections. + * Added warning within Firefox about webworker test in test runner. + * Update ws dependency [einaros] + * Implemented client side heartbeat checks. [felixge] + * Improved Firewall support with ActiveX obfuscation. [felixge] + * Fixed error handling during connection process. [Outsideris] + +0.9.0 / 2012-02-26 +================== + + * Added DS_Store to gitignore. + * Updated depedencies. + * Bumped uglify + * Tweaking code so it doesn't throw an exception when used inside a WebWorker in Firefox + * Do not rely on Array.prototype.indexOf as it breaks with pages that use the Prototype.js library. + * Windows support landed + * Use @einaros ws module instead of the old crap one + * Fix for broken closeTimeout and 'IE + xhr' goes into infinite loop on disconnection + * Disabled reconnection on error if reconnect option is set to false + * Set withCredentials to true before xhr to fix authentication + * Clears the timeout from reconnection attempt when there is a successful or failed reconnection. + This fixes the issue of setTimeout's carrying over from previous reconnection + and changing (skipping) values of self.reconnectionDelay in the newer reconnection. + * Removed decoding of parameters when chunking the query string. + This was used later on to construct the url to post to the socket.io server + for connection and if we're adding custom parameters of our own to this url + (for example for OAuth authentication) they were being sent decoded, which is wrong. + +0.8.7 / 2011-11-05 +================== + + * Bumped client + +0.8.6 / 2011-10-27 +================== + + * Added WebWorker support. + * Fixed swfobject and web_socket.js to not assume window. + * Fixed CORS detection for webworker. + * Fix `defer` for webkit in a webworker. + * Fixed io.util.request to not rely on window. + * FIxed; use global instead of window and dont rely on document. + * Fixed; JSON-P handshake if CORS is not available. + * Made underlying Transport disconnection trigger immediate socket.io disconnect. + * Fixed warning when compressing with Google Closure Compiler. + * Fixed builder's uglify utf-8 support. + * Added workaround for loading indicator in FF jsonp-polling. [3rd-Eden] + * Fixed host discovery lookup. [holic] + * Fixed close timeout when disconnected/reconnecting. [jscharlach] + * Fixed jsonp-polling feature detection. + * Fixed jsonp-polling client POSTing of \n. + * Fixed test runner on IE6/7 + +0.8.5 / 2011-10-07 +================== + + * Bumped client + +0.8.4 / 2011-09-06 +================== + + * Corrected build + +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 +================== + + * Added `SocketNamespace#of` shortcut. [3rd-Eden] + * Fixed a IE payload decoding bug. [3rd-Eden] + * Honor document protocol, unless overriden. [dvv] + * Fixed new builder dependencies. [3rd-Eden] + +0.7.3 / 2011-06-30 +================== + + * Fixed; acks don't depend on arity. They're automatic for `.send` and + callback based for `.emit`. [dvv] + * Added support for sub-sockets authorization. [3rd-Eden] + * Added BC support for `new io.connect`. [fat] + * Fixed double `connect` events. [3rd-Eden] + * Fixed reconnection with jsonp-polling maintaining old sessionid. [franck34] + +0.7.2 / 2011-06-22 +================== + + * Added `noop` message type. + +0.7.1 / 2011-06-21 +================== + + * Bumped socket.io dependency version for acceptance tests. + +0.7.0 / 2011-06-21 +================== + + * http://socket.io/announcement.html + diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/Makefile b/networking/node_modules/socket.io/node_modules/socket.io-client/Makefile new file mode 100644 index 0000000..f2d2f41 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/Makefile @@ -0,0 +1,20 @@ + +ALL_TESTS = $(shell find test/ -name '*.test.js') + +run-tests: + @./node_modules/.bin/expresso \ + -I lib \ + -I support \ + --serial \ + $(TESTS) + +test: + @$(MAKE) TESTS="$(ALL_TESTS)" run-tests + +test-acceptance: + @node support/test-runner/app $(TRANSPORT) + +build: + @node ./bin/builder.js + +.PHONY: test diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/README.md b/networking/node_modules/socket.io/node_modules/socket.io-client/README.md new file mode 100644 index 0000000..cdb7715 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/README.md @@ -0,0 +1,246 @@ +socket.io +========= + +#### Sockets for the rest of us + +The `socket.io` client is basically a simple HTTP Socket interface implementation. +It looks similar to WebSocket while providing additional features and +leveraging other transports when WebSocket is not supported by the user's +browser. + +```js +var socket = io.connect('http://domain.com'); +socket.on('connect', function () { + // socket connected +}); +socket.on('custom event', function () { + // server emitted a custom event +}); +socket.on('disconnect', function () { + // socket disconnected +}); +socket.send('hi there'); +``` + +### Recipes + +#### Utilizing namespaces (ie: multiple sockets) + +If you want to namespace all the messages and events emitted to a particular +endpoint, simply specify it as part of the `connect` uri: + +```js +var chat = io.connect('http://localhost/chat'); +chat.on('connect', function () { + // chat socket connected +}); + +var news = io.connect('/news'); // io.connect auto-detects host +news.on('connect', function () { + // news socket connected +}); +``` + +#### Emitting custom events + +To ease with the creation of applications, you can emit custom events outside +of the global `message` event. + +```js +var socket = io.connect(); +socket.emit('server custom event', { my: 'data' }); +``` + +#### Forcing disconnection + +```js +var socket = io.connect(); +socket.on('connect', function () { + socket.disconnect(); +}); +``` + +### Documentation + +#### io#connect + +```js +io.connect(uri, [options]); +``` + +##### Options: + +- *resource* + + socket.io + + The resource is what allows the `socket.io` server to identify incoming connections by `socket.io` clients. In other words, any HTTP server can implement socket.io and still serve other normal, non-realtime HTTP requests. + +- *transports* + +```js +['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', 'jsonp-polling'] +``` + + A list of the transports to attempt to utilize (in order of preference). + +- *'connect timeout'* + +```js +5000 +``` + + The amount of milliseconds a transport has to create a connection before we consider it timed out. + +- *'try multiple transports'* + +```js +true +``` + + A boolean indicating if we should try other transports when the connectTimeout occurs. + +- *reconnect* + +```js +true +``` + + A boolean indicating if we should automatically reconnect if a connection is disconnected. + +- *'reconnection delay'* + +```js +500 +``` + + The amount of milliseconds before we try to connect to the server again. We are using a exponential back off algorithm for the following reconnections, on each reconnect attempt this value will get multiplied (500 > 1000 > 2000 > 4000 > 8000). + + +- *'max reconnection attempts'* + +```js +10 +``` + + The amount of attempts should we make using the current transport to connect to the server? After this we will do one final attempt, and re-try with all enabled transport methods before we give up. + +##### Properties: + +- *options* + + The passed in options combined with the defaults. + +- *connected* + + Whether the socket is connected or not. + +- *connecting* + + Whether the socket is connecting or not. + +- *reconnecting* + + Whether we are reconnecting or not. + +- *transport* + + The transport instance. + +##### Methods: + +- *connect(λ)* + + Establishes a connection. If λ is supplied as argument, it will be called once the connection is established. + +- *send(message)* + + A string of data to send. + +- *disconnect* + + Closes the connection. + +- *on(event, λ)* + + Adds a listener for the event *event*. + +- *once(event, λ)* + + Adds a one time listener for the event *event*. The listener is removed after the first time the event is fired. + +- *removeListener(event, λ)* + + Removes the listener λ for the event *event*. + +##### Events: + +- *connect* + + Fired when the connection is established and the handshake successful. + +- *connecting(transport_type)* + + Fired when a connection is attempted, passing the transport name. + +- *connect_failed* + + Fired when the connection timeout occurs after the last connection attempt. + This only fires if the `connectTimeout` option is set. + If the `tryTransportsOnConnectTimeout` option is set, this only fires once all + possible transports have been tried. + +- *message(message)* + + Fired when a message arrives from the server + +- *close* + + Fired when the connection is closed. Be careful with using this event, as some transports will fire it even under temporary, expected disconnections (such as XHR-Polling). + +- *disconnect* + + Fired when the connection is considered disconnected. + +- *reconnect(transport_type,reconnectionAttempts)* + + Fired when the connection has been re-established. This only fires if the `reconnect` option is set. + +- *reconnecting(reconnectionDelay,reconnectionAttempts)* + + Fired when a reconnection is attempted, passing the next delay for the next reconnection. + +- *reconnect_failed* + + Fired when all reconnection attempts have failed and we where unsuccessful in reconnecting to the server. + +### Contributors + +Guillermo Rauch <guillermo@learnboost.com> + +Arnout Kazemier <info@3rd-eden.com> + +### License + +(The MIT License) + +Copyright (c) 2010 LearnBoost <dev@learnboost.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS 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/networking/node_modules/socket.io/node_modules/socket.io-client/bin/builder.js b/networking/node_modules/socket.io/node_modules/socket.io-client/bin/builder.js new file mode 100755 index 0000000..8870e51 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/bin/builder.js @@ -0,0 +1,281 @@ +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , socket = require('../lib/io') + , uglify = require('uglify-js') + , activeXObfuscator = require('active-x-obfuscator'); + +/** + * License headers. + * + * @api private + */ + +var template = '/*! Socket.IO.%ext% build:' + socket.version + ', %type%. Copyright(c) 2011 LearnBoost 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 + * + * @api private + */ + +var starttagIF = '// if node' + , endtagIF = '// end node'; + +/** + * The modules that are required to create a base build of Socket.IO. + * + * @const + * @type {Array} + * @api private + */ + +var base = [ + 'io.js' + , 'util.js' + , 'events.js' + , 'json.js' + , 'parser.js' + , 'transport.js' + , 'socket.js' + , 'namespace.js' + ]; + +/** + * The available transports for Socket.IO. These are mapped as: + * + * - `key` the name of the transport + * - `value` the dependencies for the transport + * + * @const + * @type {Object} + * @api public + */ + +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' + ] + , '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/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). + * + * @param {Array} transports The transports that needs to be bundled. + * @param {Object} [options] Options to configure the building 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 transports, options, callback, error = null + , 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) { + var type = Object.prototype.toString.call(arg) + .replace(/\[object\s(\w+)\]/gi , '$1' ).toLowerCase(); + + switch (type) { + case 'array': + return transports = arg; + case 'object': + return options = arg; + case '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. + var files = []; + base.forEach(function (file) { + files.push(__dirname + '/../lib/' + file); + }); + + transports.forEach(function (transport) { + var dependencies = baseTransports[transport]; + 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) { + 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) { + 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) { + code += results[file]; + }); + + // check if we need to add custom code + if (settings.custom.length) { + settings.custom.forEach(function (content) { + code += content; + }); + } + + code = activeXObfuscator(code); + + // 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; + } + + // stop ignoring the next line + if (end) { + ignore--; + } + + return ret == 0; + }).join('\n'); + } + + // check if we need to process it any further + if (settings.minify) { + 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, { ascii_only: true }); + } + + callback(error, code); + }) + }) +}; + +/** + * Builder version is also the current client version + * this way we don't have to do another include for the + * clients version number and we can just include the builder. + * + * @type {String} + * @api public + */ + +builder.version = socket.version; + +/** + * A list of all build in transport types. + * + * @type {Object} + * @api public + */ + +builder.transports = baseTransports; + +/** + * Command line support, this allows us to generate builds without having + * to load it as module. + */ + +if (!module.parent){ + // 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) { + if (err) return console.error(err); + + 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) { + if (err) return console.error(err); + + 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'); + }); +} diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/dist/WebSocketMain.swf b/networking/node_modules/socket.io/node_modules/socket.io-client/dist/WebSocketMain.swf new file mode 100644 index 0000000000000000000000000000000000000000..20a451f57ba342d27b1a485d2e3931ea79ed988b GIT binary patch literal 175830 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 z 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 literal 0 HcmV?d00001 diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/dist/WebSocketMainInsecure.swf b/networking/node_modules/socket.io/node_modules/socket.io-client/dist/WebSocketMainInsecure.swf new file mode 100644 index 0000000000000000000000000000000000000000..5949ff3d09e4dc669cb25144fa5775dba071b684 GIT binary patch literal 175953 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

6_4TzBh#=34(fx0_pa7FIaK3=>Pm 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±k#VeO;J63S6QrHJIUFH4_gkHxsAIz7p z`8-emA_wyq9nAmcV7{6EJ$W#{>0o}#!F-^cFy0pt_0m?a!b=qkH;+bTYai<8w}J6XHF+s#hLW(eLd!rb*?X?bsH1T29) zoxlrO7*me@h!QJm18?k|D5uEv@(y{o+d57d<^Sx~q3+geNkW%Oz_y@sb5v~7T)#@KH9~GjWJjI4HVE&Ha6W8Rk4|cPj}{=;CoJE zxM3fz+;^Xikjj~!t9-V)pw&w?$MXpXK5pQ{&N+N1cEC~)$Kf4Dn&J06pQJ;MLI(%A zTOD$@Ta}#Y=dQkq9Mw0A8Nr|nKW}vzaw$}qGb~g$+95-ESarL$Dr=@+-O|iGvjc3s zsBW=^DduBRMs0bk?N74XgL!taeahF#*%S_sc!yo&uW2mHz-V;rOyNJi)v!N85^BJX1%;&vU_82(HNykq3TC(`4^D=i?j$ z+hzx7Kt2$`#qrX9eL~{!OkbK(PK!2#FBcbwhMv5>_LDN+n(4yZXSuqMTpl}D+BtP0 z+ku9y2RRg$wC|K1lV()@|H^;o`+qM`XQ;2MGu2t@Z1oLwjyhMJN7(2XmqsnVVkwoQ z!YZO%Ri>hVM#njFJmk99xlmCcM@_gWDX-9FttRU|1 z^~HTnRq{cI`=?5lNy}NNKMhM3Lr-XQGPO_lsoUZTn81#m!B2$@7>m2=@PEe@Bi0XG z!lnV1MC_p_5YS-f4~7mta%io3+Nk~?Iig>}>F1}*dd9c;^{Z4A7PLJ7fkR#2Z{SWR z+kdAca&<#pJ4jX%+)lymhXng!wVV53;p<%;^?bIF5A+Tt89YlFJR4-dS4?RffPzNW zzS;*EJG{(wlw{qPSIK1in?nM(%WVJcQuHf}?F$9fYYf-E)+Z76XLt{VLbdk>P7!M% z=j(yf!mZNUHv*>}yNR4{22L5fj+|Qqr-S)K?Y6)fj$KL4?SYdgd$l_Prwa{t?ashi zhE;d%TY)o*a}2e22hL7~>!#jhuiOnE+c%#t7YFm-DEaqC{&)Mq{5Jk)=kwM1JjH`0 zloc%7@T_f-k=kNwp>||C|9a#~o-${#|9L4}pK!9d{`(w@Xto@m%lY#Ye15{8FXHn> z{(KpqFXOXp;4*wKqwm;IT#g3#64Iw1IQZ?rDVT$I1x|}O_?^IMGY7vLIQb+_?R$aK zDKt3D4Gz2V*pc~s_y_s?PxJX-=JS8Z=l`D1kI3goVsWyHN9xDWw$qCiH2MW5Gx`O# zHt6GXr~l_1^tjXiaeT!7P0eVleZNoEZv;B*F5e}%!>0N!i#u$J@3OhWcKa^L9rl6m zI=ueYv6HC&zsctZ=kx#Me^mLg`TQggZ%<2T;C|QvZXSQurffWz!N|eIU6#b6OV>jf zdr14hJ_CmZm>cGbT>n1&n%b9VoRj~m2_7v!PD4;C{^wNC(Sq5|{^qj=$*-kV?ie)o(JHu?GqvOE1x-c+K z_XoyPtCA04U|b^uW4UP=7|VT3R$o<{T!`RI$+(&2GerfvbW3D9n|vIRax!=~x#@A- z=jBI%>5C*tx@n25d)ET2UY5Azce7`=ix){8_>RRpRQS$#MpJl7Sh8BB1s>n8VN16( zEp3VBN)lIW&*u*}7UeyEb`q<(VPZMl)Dl%^&ZV@T$z^u`oZbG5Xvni-9VXv7&p<0S z!uTzZCA9kX&ACJpP7vyNcC|P-u=e751XxgmYx<{nG)TCVpk+Sv%n8>g3#}7*X1!ke z7S7VuAg2m>^lX#1XXmf>qdtC)81nH+teN7g9<^e4ib?Rk#g+%#3ku@<{2ta-$v$}6 zuA~PyN?iONDhfx3yqo|&x;Y6 zBK;p#DBZM5diEciRt6udWX9{?Ra{c=?ePSPgbV!+f>AO*_DYHTi{Hy-NrIJL0wOH8 zl=vjZe1gWNn^s7VQ~0d9ABTAbE?kQ*;g%KJ#JZgD7QRW;Fi}4 z+%m)GmeZ<|)p*RWAP%<6;K{_*Bo0jS6x`D-;ia7t=Uh7l(qIj$@|MIk=F`!WYgqZg z7jf6f8PkV&rWCpaFVSQN&5W}7gzQo8GDEyAVSoIe-lH$llMa+{2wO4m>_P7>+Joji znww@uDV(xBG02v^C^__PQYxE}F!Dwj?dy|G)$Z>DgYdO$-Bi&Yw@=H5zMPi(OK8b$ z{Jq92;pOXP{e+I&cCzDLaU>81^`y2n`< zgNLl=W4-Xnq?_6$8{3%^^$o{vkp4z3J_EzCR9e%X0={IIOydIVisNKV{_GLi*IRg@i=Ioj~Nw^}GLTRms!v4we%jX^i6| z>6%dWRc9m@z%;-u6e=Y`Z*zkA$xg!A*OOb(sbifY>)g)OI>uuiuj6;g43uB#%z*be zk2{M3+3cWs(Un##bw`H+lxHA5C=Fn{DFOC*F!FyxS+D&k9+VnL4$n`O- zrn|0Y+>kb!l%YZCy7y&hF6HRj-s5dsSU}y$-B1SR9I$~IaiUXVlNlvf_c+G~Nu^Kd z4hEX%1vuFy3kI5Z6>zdkmXfRpib+oJKE&NHel*z$#LfLaznxi?+|DmCl<>?HCrqOF z8a(egAzXW)Pwi*L2g3_DYdis6Gp`lfleN$E$)rZCXDMCHhl`YTAFi#@-?}}nrDC|a zHfVm7+^He3)5+?sftl>}xg~9y>$_dyfM>#W5ZBfuO~`$<1Z! zZsMzU)0_^AhI<3VUK8>Ncve+%Hwc(2A>eeU!wVW8Vk)^urgO=C5)V)8m);8+(;_1I zslmE$xq1l6B)dq(c<6*jnVdhd_iN6EO|)b zLwU$U3VWsZg2t8DY4YsEmd3g82oGy~EWKwH_%ECG^%MGep_Lzd_4J zyvC=p^m&cXWbnMk0ombsjsNhZ2GOu-zx>iCHM|1;_ny=^AcHqE4oL4wjRUgeNsZ46 z!Jod}G`wlF-{$}PfX098_mT%R ze8*uAXdKqlU{}9u3lC_3O5Qzoq7px#Q9`9KQ^^bdOa>2V%qU2r1->LYyDIqsIC^Gb z=$ji1eFO6}xP2peBF@<`96gxbPw4iHP%_MhIs~&}m}bp)@FX&iXv1J%k2^M*T-`w#V$HtmUwSWkbw&)U!Xqz2*K4Da>~L$Nt3wwinA zkD<^>yvG+#4{wabzUANGKW+pp0dI1N`2&47C!!vq-+A4S zXTLDb?^x7YTBRI6yzThm?Z*!X)8FEFJCxjl%K{q&!`reAi=2hsFZ9%>4@QT#=Nk0F z?!3v(ZURKZEfj-qq|nzW%89tK?t7sOt|8}?pjZtjj_QZ@w0iA<2JB%ccsS)D=BEh# zyXu^(s-%X!{}QHoq$AUe0@I8J(>z*alF?w2MMd{0xEDJ%xx1$Oa%WRIzq21>|62A3 z$%a;^5bTp|wD-}lTc%+?JfPVUCoq%xFjuz={k!U1s_sZs<#DGcjU_{6x^MkR7xrft z^{L&^=fv9eec%{YUE5x8Oc6g3SBToSJ{LaW{PLpEPb55tS9@k_Z>;uXJqr7^;wKiq zZ>lcI>od!Xxtxt>&Lk26m^>VR(!RHw}|)#q5i3a`ldQl{Wv~d#NQS14}=P< z9x4%^EtC`gNW_=J;;kASzg5I1i+Hn8r^Yvm_>)3?FFstv*9di7e5z1as`KJsi1^DQ z{<=^{sb8s!)gM%4e2h@N;@gGl9$zNZ58_XYc$`#2*$aqArL}5b>2l#o{*$)k&S8exZ)X+vhi^f$=FqT^+we zsMFO+>g($K_zNPwldbjcgCSpK(`;WIt@_3n3e_(@lTG<%M7&+7`uKREYU1|`bwzxx zh(9aTfcRrVogL4L_(Tz(A=JO(i-fv9{<%=UjlU`4cMCN{$@qstT@t@Xs6VQos$Z%< z#YYKM9Um#w&*JNZx+cCuD2?~sEp@DFP;nR#en7+@6!9e@{)te%Rh=57eyz?>7pi}& zuIeZ1()fKseI>p{sLSFDggPg_N~oX5KNazpMEr5KIJ`@!6IHFcTy<8zkB<=QCFLaIuABff|28!r~Bi)vC=#nU3bO~hvj z^%wQ$_$-!9_s3Drj(6Msd-?-KFbg!)?iUZJ|hZxpKM z6+^A$7_k3S9r<{9VJQZk%?hXEThA+<4o^X^a$wH!Ui+{old(V;(xzg(f{D$TKE!`W zH#US;FCx$dAd3k4jbR0GGbr#UJ8OD+-+JEZ5Tr_qt{I=P)N-*v|g;Y&QRisx{0CWfU^LRLITg=M_?T*iAO1ZTZcC51=0 z-1`gVp6(s)uBNi^&LRB?$}JYicc`cea25-G77KWvGH&d9evVOWPGQK7;(xCti88+d zcx9OKLq5@Qcx^bU`c|a#d71~iylzH>poH!f_m?*9`#4ChVtCs+3xz*A>gmE7^?j^S zpD75d#lEomW>sI(U!adDa4T#qzv%gNuExpfD5Ef5^r3lj1hQK4QdXnCLW z>aeEB=C@%UvbN~H748=t2YZa&2Q*uM;Q0O8d&F+-8GF|ZT8g4XjiS^ZrAAN{dnHC& zRP7ZMjZs_eRkZe~RZ2;0+8RM^9_M+^bN=Ul&M&`joRe2R-sf@?C+E1i_vUkNb(~U| z&}jXc)OU!}$mV!cmTY-qIqvU9+g#Bw8#L=Pzum2-w>XOwQT&&&Uq&DFP5EE!L4w#? z`<#uY^S;glwhjItR26LdJMUxJEP|3+U&gX!YVIe#Yq@$imD6)-P0h&ev+47k+9s`d zsnZ{NIiyAMO`X#cz+H=P(JP$KftO9y6&)8Q&9xiO|9GLLGgXaz7yobcpoGo-<8GZ7efZVP=DR;U0f+o`m83^HgcVx=^-g(Wrn)w z3mH}G6b_((ay{!ly^ZWiSb;)9Wq6$4y!}r3t)KDN3OaO7NH`D3_2tYSMix81PUuB( z`Zoi$Cw@o!V5w=&uw;cklwG1kH$lUbmEw29kDFUi&UU%@qi=Sf8;gj%q<@Yc`@L`a z^S#*0H+i_H8}U-c<3uzy$gxAl!x{vf(ZiV3Ka z{d#WTecPLQmKWhv$Q+rQX z#rzEr*a)DW_IrW}1?u~5FY3?5ZYza2`}(Lht582u4fj!9AHA@PD*#ye=*f@Zh18+O zMcELKBf~SHoytT0JNR#Yx<7o8U@TkKo*rjp@qVA%{V~o7LKaejYje>SX5A70@%Ai>10OyXV-=9-eU4{ zobeJ*n5#2&XaLuUl6$eRj8s?fCoEfZSuw@uvYOwb;xTrvepxL_PE+>6GhoCvBP&1O z+kKK;tl+1%RUeiALzB~os+|+$!jHX`Mv`V<*6$|aeV9crc^n!l_YIsp`S33!j&1hZ zDRN~J|A)$&@2|$P_Z6sU0{)zTnUi+B2lruNqoK&vVI_mKSahSs4uHPFkOB zCKo=v3(xrbhg)xALYCPYZ6p!XzF<@Z3Ctf{&r%V2ewmsaOz6kK_>JY2&wbWON{`{5 zFZr#KC(vFp;$Pp<@4x?D$N%!=gs`>mIP9H7T&pRt-H&3mti>Pf+Rgp}qe!Ux8 z))BGW^f@tQe{QZJL8*akx|G=F>kPz^YTl!SNpzFa>b78`>}6|NWm%bUGwC!dtGHW} zCk_1ptaV@EnnlSsE_pO0#{aCFD0PPJC93Jexl~hMjK>h!4~AHOVC=E^y*mD@nAguR z?U6j?nRR;u^4x6CKR@wS37YII7cW*4*J9tLw0Ypy#>vd><$W}wo(NbM^=;_T+_Z$B zMl1H^lzY(!ej0D22#Jy0$n?rO7$I6$S25V!SC^+yxxc9lM+gpUuG=4o9eDW0l};wZ z5Tb|A)WLwjvT=Wkki_vxSo74O%#zgQi2um(@bL)E@U4)laiIbv#V?-25cM(Iz>ni~ zFof94@^N3-X+iVwMZcA2sC%f-SNMQsHDNA`cp>q`p;*NRxi1_698Nt8wX2*sfQR0* zLJQ)IbXvyNduK~9z$U}UsV*g_wB=*%Y7a%q%Srl-E4BC)$_ufR zd9>G?&Yla81Aka2e^~3q-#!1^VKJx5gG+#`9avy$-^~6Oh}*O7+xWlfrdl4ro~Gx+ zeHtI!{w#h!DTq&rsNzisr;xD8r#A8-#Op^NK#!9?h{l}1*c*qq;T@t~$%|_;B29`s zOC3_1T69@O(m{7P;DiX}*M!>1tkzOceqrO21e9{Bf|6$H!ZgAA(;xCVpDeW-nLnVn;N^m_6uqKrr_OJ3@{e`iBn-iVWfqLJXFp`;>+nLom#;N8ach9?HK#H^qA--|M;9**ouioNRj5>XN@mw9{dEdzo4 zP|FBi_QWTq=3z7YhgJ@vL*v^@U)A)-wDuKF>b^HeA>xT!zfxuMEyCT*C1jfMMA(Nq z!%_zx-|}*wSn5tV5=Brq!pPRpK^Hw*qg`UPo^Sr_y%S|d9J=4xqi?XH-o0m}Sl?#7 zW}cHKKP1EDH+a6Lq;#J>*Lzc!#LxZsZJk357=AIV@WaG=GD!3@0bf8`To5N9-6jJm z{Ttz}{+YgDW5FK`xck}gkBa(&E*gD$iL0SQTXcHQJ(MfKK1g}++1y@6 zv*@!jB~A9KgeSikhN<#2{60MfmN=OBGZv?8lvR})m!@sp9C>rye&Cm*r0Z8;u_{0P zBlU^5X|b@0%Ua37)a|k-LerKDmXWctfgMx?~(m+ZvJ}9Fu}>h&3{$9##Kt^lue^_Na#m$X=vZ$ zX5{0`vMC*t^QUgP1xm-oKM|T@%2C?^SpDn)^dhe*}An9BKp^bo{Im)VFr&?)xJ5JwxhVgt}FJMEnr>LRI$jV)$Z# zl5Z^VfP#Fl?NGQNk7<2F*fA9S^)A&O%R|M-<1&%<^5dL7M&o0Gj7}4_+d|@(%~`c4 zLPRBQO<`ZY1Dv=v2EqiH2hZIIFC*RdjD3tRvwoeCc?Q={jqz-3z(P5~%vP$bc@Ljn zY3H2dE0Ym09Pt-ey#~K6|M7)pKv45(*QubY-~|zNn2zCti%N7#VlBNU7lg{?9Q2wC zX%?L23nk-D8E_l*5o3P8&Sw4KF$0E8z2u61;Y|5iE@0n|8NFm!P^W&gs?1>VBGDfd z7cb~%F=Sh>2vO^2@GckPmM3TV8T$pykA-1Y50YpRN5%oJy3(ZuUJ`eZn}!X{@JU~y zw!xFr^t65=!=v4ozk%-ws}G3_M_6#U-2z*+LseL!RrRw!Lnb#$iBUa2Nh=DL$=Z;PuT(5u{)5L_mBZ zzi(x02r2m-hQ^%gXrm-9JZt+k_c1vq6db=*HB{6#?AvJv`SuEZqCXI(1iTYb9R9Gq z1UFshwd=#YU96*C4*=$>N)@X6yO~+W6RZgmXP6vRgEvB6MntfyvAh?vUCh3d?G$ z6%X5Gyy)n8@6P9bDe3xTS&~4WdaXxE;2sb05bdX1$@&q7sT8cKEqbJK?#+=?b6G;6}xUF zitYRO+^jDPEqG3i99iVZf=za}5H1BqH#@Nnivz89z55) zZaMDOVrwKFjjploXDd2hE*&(9DdD<@)F>p@G=1`@Cv8tbRBp(G@{LJiOW5&FUaB`u z>dKpvfrL>A-{8^1H}MiFed))prr$Gt>2l{pl(IW!B|zD4Fz<~bA2U2PAe$npsII=h zkLCsBwJCVsrsnW9EepD0W&UYf!2PzaZnveF0^V&AA;|Q!gxM0mDo2OV|Max9>kT>P z@>67<BCK2>iSmh z5o|K|@9D5z71=@qweX4?ws+najtH3z z)b_m=yU$VYqVH0lqJrtX@=(ROhcrJc-uc%6|C;n{+6=f0jnox0N6s0wIJ#*bxel_W zaZO6y|Hy~OxRjzIdcVOT(p@J~l)s-njq8Wh{Yt+3m5z)5*hc1as<}G?zqkq-EcAb^ z5cYG{Mf#1U7p-*bIymd)Qn3qEms7l6V-Fw9inKq~j2^6`zUp+lb#$uqz{YZ7LxQbL zDKtrC&v44_se`S9io;4VmytHg&^FHA@0kLdU$+F&E%N#fqC@EV4-nSJh{_5CbNYpG5>Ne`M={Y552ej}UCn1=WcE7Cefq~ilW z6?-)fOB}JMakyl@ID`(#X5LH&Jj6FrHR4sdiO5-=0sD=3jqDy04q3ejt=g?0<{aic zdN6dM1Fjv;J95-pa?1ST9E-5uDoyK{m;SL8B!m`o)Om%3%_W8{vb0=hOK2tSOCnob~^T`k;b6|p#CqrOm@rK1&=+FY+FsYpu zxysT6jd@^1F=zduM%r!u!=5zj=b7K@o$C(^)0!EWS+(#bGu&n?EZOwr+I>Q(iJ z!g^{RnL^!<7|(9&slC|R5WQ?GHnR+jFaGg#-P3Lda7Lup`8?BAz0)x>2(CjW^DKj@ z;D^P!YQbdMsJYUMt(;<;hQmO;MvInT(lW42pr(4nY@~?vzGRr@rYgT4$7Ds^0k` z^JYKInDiLw!6(Tvvda!91heyJ$rmsSkztDNHo;-N?oafAjm2u!kDg|{9p`*1Ao9o{ zBOPub@hE#dNOV$snAlE^{4&W&j_k6=$r|8XHy$Kbr@09hJt&i`B0FdqKNmfSmh>WT zUz*5!dUmVgTI{mfsbS*v(gcZEZsV|ALCnv<437p1m4zAkpJxK|e`o_?71}?Yk&<3y z2Myze?sa;b-y1sSi8)Qrko;4$oZkUHBpJ(GRsoq%i$iv9! z3YR%&25$wtUO9QomgyN^ca*1w_Z{sJ;Y1iF1K*9;6e=VjAHBl4_pWrM=T>q1|%F z=4U#V5}%KxE!CWUuQgcP{Z4Jj)M~0enrvwPF)=oKW-(tRdh`2&)m&I3Pbi0ITk;x@ z+$^hVj-JjB*ABbub=v-B_Rz2e7L9$T{BprRzu>jy*I+QOy-Fy?vMMb5@Urg_>~vMs_r zGY<`xu)&F{xii0c+HXtMN7)UFZofSmxZA4ghlTB-dR~nqGHKiyyVXYqmYq)78?k@M zL>m^Je*3#?bcOwpgIylG*Ue1q&IdMDs8x?pqy>DR;QYDHueV!sq}^~eD@S-;?<5T) z9ishr{PT={zRf-JD2zZL_y~KBcMY4QMS~?o<(RcL{)7Jg;mPDz@2;UPs6mdt~`w$N6qSjmD z88OgX5nXmiSJ6jOP!JzqTMw543cJw?B`RCf#3`s*ynO2c-^<2L?LjI8cM73(|d zQW3`vdh&WI_qUac5rQMudf@l#^m^blXU=#sBXCmmJ7v@D*5VHBJCS>`uGHqyhQU=+ zLZwK(gXUt(B5s8x;1Ol1i>~jubif_zqT6n)-FG7b8>T8I7M^Ek#~u_TM2T;9CL zdgv?v1x9<{oQvzB#-@Ok8c_dDMP7PzzJ9ELLRFeGlimG0k-p^~>$B0-k7xx}D^t&i zT-WE<@#aOVsnExor8e)Q4KF0UJ3KgQj+9C#ja-UGbq`8Bm;ht*O2C^XoJxP_{Sp|V zQ-@8l7A*=M36$C-t$SN~r3Jo`g*oA4$|pqmxn|Gqx*~WOXqk#aHL@5REOa36oKrnW zr^aU2Eh3|*=8FPGXXcB!xpv<<->p&E2cgxonB5O}3N*GGi@8aw>Zs8E=~KH8lWV97 zG9>k$hnQ_27jX~MJzYxwm}`EsBjbp~C`|B(qg3s^GcUL1o$g)hWe@z=sq-Rk2Ctf< z&}9$HFkz}M|8CVZdXP5c>0CBX**pv}+-{Tg`srNmLHZSD)&0j%o5uGLqP?`q(!Hyn zz=38_mqPm&IgoZ2vZ?%(B3$)%wSpY7XfG{qTC!_ELYL%VYx8U>GkCN+-oKH}XRrEb zTh!{0*b_K5Hun?e9I_MLH8vMtutv%hK-J<&6S!|CyFbiLP`uZJM@621Slt{*xOug# zZ3-oD8*&zTN33>E8MB8pIz;PeG(uulHjV0Bu!7H_Pao*s&7H1x zmCxa1Lg+UsilWdNDZ<4Kw#zmLj`x9|Zyqs4G54^l@X?(<+NaEV?K4t|fINB!dPla) z4}~^9he~}Q?vZ3d+CExanS@a#rH##W_Vz`oq1b6M_M1OmgK}V$!;^;^g4X;alM^5f zTW`uQX}8Wn1>dA##`s%Lmm%u!97yA`*$?O<`oC8xIp@l{E<;>vjXKv^@VN?h{rWzo ze~iyx-IQl6k&UA0{3CN(2-@r+|5fS zzFO-ZZ!n%kLV)G=vxLx?le7o*vapZ-?3Wz-WmCJ#fsGEN#`oxJ1n~yH2eBP+lexL7 z@;EA4bNG+|JCP6pG5wL{6XlD;P2|oG^(~XYqRQ?zOc)*c=kef zka~*#&7G2ZikXsDz#8deIsdn{&5os=csCzc+pi;2t3tW>ZmEu?CAc;+90xQo{0nGE z*`#QASv0}=sMxGWVIf$YIyX{0wJv)`v;AMtYgwOo|98F;3%iTFaFdrH~cri}JUte5G-+@b z<4==g)llyE6&#drVMu3o+;lW?Uc5=>BK{c(c~JSaqAA7$gR)R|>3UJ0=3-yJ_uG9_ z<(2HgMl@G9G14xO8(%r=67i4MT{OPBhQ-d9*3Q@!rvH_+3PNZlOs-t{a))u)*3Xii z0%#=zO`Gy@8!=`((3wAV?=YxhkFgfC*; zJmJ4MH$V%#dzo6Mqr;BvN<_-0x7#4BP0wDb&%&6ahC8emX1)ZALjz~ zB^k&1dwnF8u8j4|^ZDEJkH=plLn=-Z%ijMTr~E7WU7?+E2XbmpVxvR8@*WleokK&T zQLhxVrMc7h_4`es0;{j!H~*c!B?znv7Q3jAc0N}4+WL5t_07=9zZG$zpNT^k+UMS> z*5bzH$}I0zL5{9`s}EOzCEh8oY0l*_(rGiYBN0F0gtN~pj(IJr9a^Z+E4KxEHLfY}bn!k7p?G2E zu>3VMN=bRA>H0SF1v7=!qSv>(2Qt${O^Vl%hAyavi&qinJ7JN<;ZJk$W$hN)e)W=j;OXVtWrWJ zod1?og(SQ#+byX!+TPet#rHqhWflf-_ND)6Bs-Ef=Z9LC)J=WfpNI5WU*38}9g3`s z4I7rfsCpchsK%AT8fI0}S=OYaf0Qsr*JOD8DYlc}meV$NyRhR8>qR4}`ID1ECAF&( zL;bS6TDzzDZ|)RzR93UGrxNXo(1OFQ&P_)$&$g$ex2um( zoicHjvCH5Bk{t&Enx2f=zY8AM5AwnYC>0q)z?YKblyXe$XCCjaOwqSF4b=oX5cdc* z=gpQKx8?2VmxCT?PU}2-^oer)Ji=$%)x^y0d|*nTxXbTHc^<&U7-&UtM(grbg@Wio zrcJl12HgV%@(VQrVy4(0lCl?FY%AZX!uW)*Xa%8(Vt3uucb}9f@oczfNOFbpBoNWN z+Xln$eFAplae;c#nxv z&q_PwA*7WdRz>Sl#}qJyKwn)D{E_D~Va5mGrH}iGzI|#{FbaGX$P{iE#!G4dK&`L2 zU!tqR`=_f#zsD%hY@XejRl~msV|@6x(w@)603Q>G!-XlzyD%7 zxpxUnIqpN|OT%%xg)bBN{{l%t)qiHu0hmAtqQ@1QtmnEIG)$4qb( zkOA1gE&5#afwDMvS}U7?c1Q zSaLM&yJ+bclQQCcX{#1*LH&_CO}e@F73SWm@>}QP3F+UQH*v%p-ik1{XM!d|Ul1AA zGpaiPDE`cI{ko=HFmMixzg5F^OcMT#?2qv+xM!~sjE8Q5WD>&*#h_*$pRN}Jx{J|rhmEg7f~&ffLJ zQlK&(`B+3InD_~Tuzx)&_2D~e?)!>2X9scSdrSCUH{H!tj;V-WP zyEoa6!qDne5qA$9h|;DeH#+j@+|i460dt$u2zgZG#Z1Sv8oFpO*%KK?lG9< zXi3)WcVya=r=7fJJ!bKA6bd3Q+7BSil6T!KM5Cl)6dLl4a_=-Glm zuvO>iWzzN5H&P`dP853evIVy%LNeTf2mi=WJABo-cQyw*h0|8>on4V;%Cgom+Us;b zy8DHThW460sy{TRR$%=X;r_YkN3QVgD9N5lD#4SRYXapGXyyE!X?^01dVf!4 z`Y|EK;dzNdLakZ^Y$|TskKhX=!sl>*d>(XAAvoZ6ToY8 z|88g2Epza25?8Q1p!_1bcV*Z0;zDMB=BPyC%kB~jbF>VTR;1hJnPujC|Ghu%_}S)J zlzg^U8Q*e$Myl>ByNFZV8iP#qEO5SQ`kr`D()xBT?xO|x;Lm0N6P?6fZ07puuOSez zyRD^hc7P-_m;av}<;M*DzxEDhy9cDLB>2RO2;2E?*Y|K z%-&0|wDL|NH|YGW@9mx48F@3t)1Z?2Ad(vo!$?;POhR4Wj*GXU?RjSK$cLZGe5p8Y z;8yp~M$(@23Bd!JJ3d}qagrIt+nuzOp?bAjG=z~_@9jHz>||1l``bbL&xyxwWg*%> zX3u?_@EHErWBw#y6h&J+f9vRTKSuun>z#_+45b`{ zqRNk>imzKV=6+|0So)8TtAa zn}(BW;j&OHvE)}MqW&T|W9ztA-3+jD1bn3&)ptt+AN8D$EO&gQ$|td-i#;Ix{EwLP z=eS{0c_|r{;o#)%u5$wWrJHwjSJCE2Rl&QZuOE=b=MYA8+=Iwy1hcI8ND=r86pm-> zS5iAW&Cg1jr*N6*2+* zuq7w!6&Yh7f#&tylQlBuj?)GD_YxL=*7RTa>&yD#F zqVbe?-tigvlORQ1pr54#7M<3WyQZ>+^;w5Pj!EfT;BkjUjr;67%aq6CzQfOD;ElDn z9(g)@enht=nE#D2m!dz{;DoRxb@4AF41Rrh&e9&A87BN@VQX0TO{UEc8G=vto@XW} z|9&+DJh=ttxAo(lNu-^$)^L~2P`Xf_((KGHUQ+#rW~D4NVhc+jEO)T&g1I?`!^RqDrXY0XDXna9KR?QiJAWT{7 zUtLMI>uqp1-=pzsewwdgyb&0&$SZIPN+hUVXE^7f`Ui=csl-^k4t>apyp$JReqfGN zklGtqoTzuSv_t#A#i>-!GQSpc{CpVj)ipcb7P);fMVtr+9tVYT#r z4)XS^6r@Jp_B~qoTT8L2l|>0Bs$JhlX9JTg97K*6kT=(Ok*aZ#-dO6Ethy_ z^WQ~9`VP4EqzSh8cP_7ywXNZm%cS!p9L@4%Up_ytLG3WSPFdcehI47YW)LzeYHGdt z`dr_XqE0CE^ya&susonno_yos`PGu*sqniOB8fku z5?eW`ZN&$_CdM+ergM8gZ7$rgLD_r1Thebl@z{r*wq@4&h;=>;U7k>-AG$;5ZF+BV z`eCnvfi@6=&-_wJpj=~fLI6 zQ-->Kq}pq$jEQr8dN;>;GlYFJJ`(JiT6b-sL=Eu2y`mHCkm(y#&{*hduJ0J7y_?wP zG}mR9+ik-6MK-R$wX6wm9Zn2-z@LxU?X_s#FPJQlV zh-t2D+14ZZ1$Ll6U1yWb_*P`C_Tu{lN8PHmJ&)CK?FH!$JH)f)!N&A4AoN9)a+~$& zOV_nWQd+VIu*jEa<|4P-r*N095k$iHR3+JklsMTkoagAdau_fgo} zH^*k9FyW1&7rZV%5B<}UneMYoii}B9&_L2`&}Bymy|3ir#+C|x0+6R~?RYAwpSK8b zVXm3{6ng+;7Gb)}kAa$oUs|NHtH_?W$Ste2dUVL;Z?*J~_~GgQ(DtmPdEUb9Gbm!Z7>N;1ZT!&o)TwWUDzOo?xCb5juYu~`N&gB# zVj}3j1{8@^ppLzh!Il3Qh(oO~O(^eymB>E+L<){{(El9J-a{+VePW5M9E~7P=mMtc ze+(pvd7#j}lYy207+me046V>4c7pz6Kz|Dy4#L|b?EkNU6e^AzObNB`rzb$LV0y!W z(I9Mz3lxDN?4}n4|Hq&g2K)$;LdOY#A3^O0>FE&}7;LEq6~_-2h1w6$Qy|PSy^+8) z5VqtFwI8BqMa*J)qk#>e8g!f(7+WGiC}4UcfC(UPR2(mu4Z7Sf2c))bf_x;IOQZVtD3kFyC z;J{Ll4q8VTYy^Ejn9P7E!eC1SC>;T?H1z#IG9|(h!xsh21Yt`)(Dy^hY=~71UktDr zG=SC-2V+b42nI}1I1mmJLg{dW$)QI5$=DJMSPT+E>j;5$p+jt2!gRCGQ=Z{VU+XkZ;E6Fndbc7{q1CErF2 zV;r$03)BD)m#gYP01H51kD5gJ|1OdXVMgS8**pf9AGnmYbXv3_+fmNUY^neH$TcSY( zV^*Vpd7x9&01&JS#SA24OEJJs&?$OA0vrm(3?*|SE-3ycRP?>D}Mz{fCz zBf~-1(tRlTpfN2X62kyP=7WgPLV{pyi4>uZVTeS&1Hn;3d|+-U`G7ID6pgF~!O=pZ zU^^)JkTDCQ8^eGl*>oMiLAauc65;^^ps)Ll2@yOPh6rRV2wQp#eLZN*fcSu6fFnyl znrIs2C;04;F&z4q!{cRAWCdxRMf$tOpgNg~Y(FP~9QpJBSGkw&a8o;sxJ^4)z-p zBcw4Y5y-b7Y{>#TIB3j-sKunfk)J?LXdw|WwnUBa!K6eXb3kh-As|>0IyhjAEyW<) zKx=3r32*>(aLAYgfx)C;NsOpcE-(>PxZfBLL5?vAM@E9MB~7UCpfLdP8e;-OegH9| zO9jE$5*b1lV-ksc4@yOq@`3rG!UM+GQZ%v_l!`7D1v^27hm3C{1~DdBk}0Z`2h0d9 z>o+Ds2xCklkgq}5k}0%o(3lZXhB1L7%Rr{+QeiN*M1^p}m_#A7K+~vF0q|XD*?=*& z6oYI5O`}W2!G6%PA!ByLHpT=?x{E6122(-Z`i%(?cQ8}o$Y>C@qz`o)G^R&nVWwcn zkD$BgQXw$5M1gpUnTkZFfj*;3`N3jPw*g~pDH_=T`iw3W1A9Q-hKyMeKQU8Sk{_y+ z7t9Xb?l&euC}E}|kO?4c=^1o;(3ly~f|-IND?xtfQV}q=M1u&#Ohq9Ppd(Z%5Uc{- z9x%q1Vvrr6BXp?*I0U*qWXy>;!%SgGR47+2Fah*V|Ku$MF-A5V83DqUG@y3|CutGU z7+Dyy07Qj$6$E2TqzEmHY$P%X6pwP{1M@=f3`}B6(a0K5Jla(h>;SzpG|7VahLOdR z^ii%nV0vg)|0E$o03#cLj00gy#?Y+6Ne0A6j4T{k3ercr3WKqv11iu`KdwwtBAhX@ zQOHct2+CCeECbCNz?x!^&7cvqt2o#fnl&`ZhFHhQVo6{22#4q?!PTJu7);_Lm@xI> zNH|Cg<;o4FfIjWVnqbIckQmxk2&@NvIygy(NW;`)Nfjtpey|Ai>A)m8;t8fc5}69Z zmR>-g4o%)c%wX!Hk)J^oXjd^XmUJKnS{lTaNn(T?ral505Ar~{@`72RKl`yJII;rd zfp!%ETS9*hPBI}HF!fl{Uz95ltPK4*FiDMgg{hB1=7O-LAn4DbNe;w6OnnTp9rPFN zDgnll4%k6U1GqAYhoHv13`a(R*ilCOEPj^bEZv3^s$d3{Em4Dlspyq+h5l0kAx@WnhvD;fZ+}h0F$F zOa9Q7p-Fbc4(4SHvK90Ty(JFDk`4$!YW=t}Nr2$M9EKxfKq{y$ZZHirupeuJA(0>z z^p+493=JHdq(>kyhgecOYKtE%0Sz3Oq(E3>4kMB2AZ*DC8aOn`ide)PMk5;zq+wp9PZq9j4b{%6rE`N>(;vS9sPiG=xKjkl2T z6hH#5e1y~k5^$ve@)nSQE5(pcfCOAAgyaAca0Llz10>*xK|UlBfHOsq4*&yP`2cwj zFu;|MkXnENt`tCC0}ODb7*Yl>z?DKs7Qg^kkdPLD0gjC3L!tpVQv~@47{!$jkTk$3 zu6%?v07h}80FnS0#g$@6C14a+3Lyx5mE>6 z#FYZb8-ORS6hq1Zp14v7$p(1h3KG%^@Whdwd`JucXNn+5zz(i_fTRO8o)X@@JC)lGWxj!o!SE?AU++dwX zC*^=EU38V!i3q&&4*GwIk594zS6XNIB@0TUNwLNR|@uG0UWqeyjKF?z>zBh z^sd&4GQ5)&y~}Xr3F|aIX$4@9(6`+VTDWpT0uN(Bb241n!NLqrVgOh7(VSZUOY|mB zWJTi&89A5*jU#rXaBeLYb-P$Vv>}Td0Hnxc-S2@_UIx6dI7_g4MC6#3}=Ku zUa$=uVHRw&h2e})+jAH*j-(5=Il^!y?D0uD;7Sv1qjkaz54(-FVYqUFVUN}y_i6z+ zQ?U0MV2vxqdu0G?Tq)ek0$Ah7l|Fh&>qH(N#)@8IxblF78J{!)ut#Wa_irtniRxz6 zg5pYYceWN3SKf46YC&-&yL(;>iYqbQ%34rdN$+meg5pYIcaRnoSMs{gwV*h165dUs zg){HEW3*0iCAM2z>jYOay8E}J+F z!Ik&j=~^ea^19nh>jYP_x_@Y$;7WA2yw(Y>q;)rHo#0ABx4+g2t{}RPwN7v)qMJtR z1Xq%}6SYooq9p6%JbqShDNA4ZX+ya4Jbq+bR)x1J53911S4z9-zx#9APBtkarmqVA z7|q4kS~{tvT$=pTp0ioIl|o>W5aC0aO7NK4L{VT+ig$3Wt&QX4^rUG4uI>|KvPX{g z``o;du+a3In#?0aG=Jo8$!p7)@vugcbq1nniwqY(e*C$=Hma10kXZ+JB+5fpK z$xpeM+~!Hn6F7~?=!LNq*;l5~C)L->Cz|bTk z-HiXjs4J5I#}T?v=2hZFTl+K5MwyrUgFyi*|9o4mb{5$lB7=67G=5yz-I7!9$#ICX zqR90=rb1`7m8p2269y>%O1pVvS_;eGd|Jece)2Y&f#l^ln%ZY&7ZhJ|C-_m5=8gY- z1TEs;FG%Fn=*gjnEmQUjk{rTd9M@`uFsTBKGL@GGn^THKDb!m_8wU4g92(7_$Dfj0 za^u2w=r_W)H-7*2;lw07To))6{)jmfVx&7WX(O}-xZb(*HR{G&g; zW@@37Xlh`E{z2=tTc~_lv#Z~(O~uY7eM;`H3-fyq-!Xr*dyuZ6iPY)Uy7OpIHlxf{ z(mRUldBZo;zwgzYH)PZrWm?*CTP$7;7yo!P<&0!+Owi` z)u<4P@SX|mwb%u?^dMJGwEvz|DIk7)zMAyL|L}_N!EW9xhj%b&@QTCR9x6KY*v=uy zs_&W!I4(2#G*RKV%Ch^(%bbk=v#K2P$IAAayPRH$3ZWcp88<%_6s)2NKl;~{a4lxQ zHm2}G<^OxQlitf(|Npw^y@#nDui77u=_l1WwjUn&c7R{?#h$6gb+~)PtG3Gr<%GWJ z+jBpwa%~n0%&Fk;mb-b1m@S2f$I2g;-7&Fs)4ZeW;J!H4&;L&VSOus0BPz}ok2sq= z;%xnN99Ps1SM>gIdt8T~N8Eo;%T3YaZ1sq<*(1)DPsfQ9wZj#?f7~9|;pY+8|6j}c z=IC*@c*NP{5ohbC;{-(Q2#DT4F+8p#&?D}@r{$*TakhHI+3XQ#%ctY`MC}NO-aj!s zt|QPRZp?oz>zkv;+2RprlSiDbpN7Gh!wqmVtZUi9FMqh|Fx`djvi-=N1RO_akl;|4xe;VL_H7jw##|q`RA^Sk37!& za~{W7x5H`pLnSvj}GSto~6UX=0}F-LuF9B#20w%Yd>G-wk=Lb z?(FkY2RUcD?Or(FdA5Dy=i}||8!sexE3am*+|69|Yo}^+)9ti>>pTMcx|~~ZXZxL> zud{w8jCd6i+UA)%B(zz&VQrqH-FrSN$Hd*>Gk4k3K3-1H4^B{*J7q*&wKG0m&Lh|} zJcm6uPhcPYe4IzhylC{?9a`;#%bTxKeu{HC42QKo@4~ZZ7~iRca&-?4i+mdW$=~H1 zT0SKAKSwwXLU3|E1v^KFH9zmt&Zu2JI8|7+5Ela;Q@{cK0LOJYXLcI2DI4bULhlUp z_voEEsoFfnRS)vVRY&yBV1HjDpG}!H_98Kjgr{CRvPO>^@Dto}~m3>Yc499Q` zhbvLkaO8CU)UTT=Rht(Wk`ew&*pdFot$a}l`^p`bCQ(8!uO`>sp=I~Dy((UJd;gT> zbi6<>uP|0rJLK{X32XBjaYp(7lhCi+*y)^jw7<*GM*G{e;a7AWhRFiK1^jzfc z$aj44GDVKDlWWeeuxhK3p0C{D=)GW9I65=f9X6k1$m>7x@nd9e2D>7Ya|};D))_L- zlj4Z5#X(*PV>{Qj+Bf^$G-2~AuJ-lz{l9AV{kH~J>`)H=GiUyBjrIR$mcMdW+waCK ze}!58+RXBCQ8SBb4COoy<#^ATRWDVWm+1ZpW*8^>yM29Koy|ONaxK7N1O=3R65taQ zuk5t|pK5!YMS|4LKN zsMh~9J@bD+PxHqc$+AvvM7)gT8}`U=)3P8G8wP@d}Tb1T*J67n}wN;DmU0QjS LboTr|Wyc*1(*E2! literal 0 HcmV?d00001 diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js b/networking/node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js new file mode 100644 index 0000000..f2c6a38 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js @@ -0,0 +1,3788 @@ +/*! Socket.IO.js build:0.9.6, development. Copyright(c) 2011 LearnBoost MIT Licensed */ + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, global) { + + /** + * IO namespace. + * + * @namespace + */ + + var io = exports; + + /** + * Socket.IO version + * + * @api public + */ + + io.version = '0.9.6'; + + /** + * Protocol implemented. + * + * @api public + */ + + io.protocol = 1; + + /** + * Available transports, these will be populated with the available transports + * + * @api public + */ + + io.transports = []; + + /** + * Keep track of jsonp callbacks. + * + * @api private + */ + + io.j = []; + + /** + * Keep track of our io.Sockets + * + * @api private + */ + io.sockets = {}; + + + /** + * Manages connections to hosts. + * + * @param {String} uri + * @Param {Boolean} force creation of new socket (defaults to false) + * @api public + */ + + io.connect = function (host, details) { + var uri = io.util.parseUri(host) + , uuri + , socket; + + if (global && global.location) { + uri.protocol = uri.protocol || global.location.protocol.slice(0, -1); + uri.host = uri.host || (global.document + ? global.document.domain : global.location.hostname); + uri.port = uri.port || global.location.port; + } + + uuri = io.util.uniqueUri(uri); + + var options = { + host: uri.host + , 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]) { + socket = new io.Socket(options); + } + + if (!options['force new connection'] && socket) { + io.sockets[uuri] = socket; + } + + socket = socket || io.sockets[uuri]; + + // if path is different from '' or / + return socket.of(uri.path.length > 1 ? uri.path : ''); + }; + +})('object' === typeof module ? module.exports : (this.io = {}), this); +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, global) { + + /** + * Utilities namespace. + * + * @namespace + */ + + var util = exports.util = {}; + + /** + * Parses an URI + * + * @author Steven Levithan (MIT license) + * @api public + */ + + var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; + + var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', + 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', + 'anchor']; + + util.parseUri = function (str) { + var m = re.exec(str || '') + , uri = {} + , i = 14; + + while (i--) { + uri[parts[i]] = m[i] || ''; + } + + return uri; + }; + + /** + * Produces a unique url that identifies a Socket.IO connection. + * + * @param {Object} uri + * @api public + */ + + util.uniqueUri = function (uri) { + var protocol = uri.protocol + , host = uri.host + , port = uri.port; + + if ('document' in global) { + host = host || document.domain; + port = port || (protocol == 'https' + && document.location.protocol !== 'https:' ? 443 : document.location.port); + } else { + host = host || 'localhost'; + + if (!port && protocol == 'https') { + port = 443; + } + } + + 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]] = kv[1]; + } + } + + return query; + }; + + /** + * Executes the given function when the page is loaded. + * + * io.util.load(function () { console.log('page loaded'); }); + * + * @param {Function} fn + * @api public + */ + + var pageLoaded = false; + + util.load = function (fn) { + if ('document' in global && document.readyState === 'complete' || pageLoaded) { + return fn(); + } + + util.on(global, 'load', fn, false); + }; + + /** + * Adds an event. + * + * @api private + */ + + util.on = function (element, event, fn, capture) { + if (element.attachEvent) { + element.attachEvent('on' + event, fn); + } else if (element.addEventListener) { + element.addEventListener(event, fn, capture); + } + }; + + /** + * Generates the correct `XMLHttpRequest` for regular and cross domain requests. + * + * @param {Boolean} [xdomain] Create a request that can be used cross domain. + * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest. + * @api private + */ + + util.request = function (xdomain) { + + if (xdomain && 'undefined' != typeof XDomainRequest) { + return new XDomainRequest(); + } + + if ('undefined' != typeof XMLHttpRequest && (!xdomain || util.ua.hasCORS)) { + return new XMLHttpRequest(); + } + + if (!xdomain) { + try { + return new window[(['Active'].concat('Object').join('X'))]('Microsoft.XMLHTTP'); + } catch(e) { } + } + + return null; + }; + + /** + * XHR based transport constructor. + * + * @constructor + * @api public + */ + + /** + * Change the internal pageLoaded value. + */ + + if ('undefined' != typeof window) { + util.load(function () { + pageLoaded = true; + }); + } + + /** + * Defers a function to ensure a spinner is not displayed by the browser + * + * @param {Function} fn + * @api public + */ + + util.defer = function (fn) { + if (!util.ua.webkit || 'undefined' != typeof importScripts) { + return fn(); + } + + util.load(function () { + setTimeout(fn, 100); + }); + }; + + /** + * Merges two objects. + * + * @api public + */ + + util.merge = function merge (target, additional, deep, lastseen) { + var seen = lastseen || [] + , depth = typeof deep == 'undefined' ? 2 : deep + , prop; + + for (prop in additional) { + if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) { + if (typeof target[prop] !== 'object' || !depth) { + target[prop] = additional[prop]; + seen.push(additional[prop]); + } else { + util.merge(target[prop], additional[prop], depth - 1, seen); + } + } + } + + return target; + }; + + /** + * Merges prototypes from objects + * + * @api public + */ + + util.mixin = function (ctor, ctor2) { + util.merge(ctor.prototype, ctor2.prototype); + }; + + /** + * Shortcut for prototypical and static inheritance. + * + * @api private + */ + + util.inherit = function (ctor, ctor2) { + function f() {}; + f.prototype = ctor2.prototype; + ctor.prototype = new f; + }; + + /** + * Checks if the given object is an Array. + * + * io.util.isArray([]); // true + * io.util.isArray({}); // false + * + * @param Object obj + * @api public + */ + + util.isArray = Array.isArray || function (obj) { + return Object.prototype.toString.call(obj) === '[object Array]'; + }; + + /** + * Intersects values of two arrays into a third + * + * @api public + */ + + util.intersect = function (arr, arr2) { + var ret = [] + , longest = arr.length > arr2.length ? arr : arr2 + , shortest = arr.length > arr2.length ? arr2 : arr; + + for (var i = 0, l = shortest.length; i < l; i++) { + if (~util.indexOf(longest, shortest[i])) + ret.push(shortest[i]); + } + + return ret; + } + + /** + * Array indexOf compatibility. + * + * @see bit.ly/a5Dxa2 + * @api public + */ + + util.indexOf = function (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; + }; + + /** + * Converts enumerables to array. + * + * @api public + */ + + util.toArray = function (enu) { + var arr = []; + + for (var i = 0, l = enu.length; i < l; i++) + arr.push(enu[i]); + + return arr; + }; + + /** + * UA / engines detection namespace. + * + * @namespace + */ + + util.ua = {}; + + /** + * Whether the UA supports CORS for XHR. + * + * @api public + */ + + util.ua.hasCORS = 'undefined' != typeof XMLHttpRequest && (function () { + try { + var a = new XMLHttpRequest(); + } catch (e) { + return false; + } + + return a.withCredentials != undefined; + })(); + + /** + * Detect webkit. + * + * @api public + */ + + util.ua.webkit = 'undefined' != typeof navigator + && /webkit/i.test(navigator.userAgent); + +})('undefined' != typeof io ? io : module.exports, this); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.EventEmitter = EventEmitter; + + /** + * Event emitter constructor. + * + * @api public. + */ + + function EventEmitter () {}; + + /** + * Adds a listener + * + * @api public + */ + + EventEmitter.prototype.on = function (name, fn) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = fn; + } else if (io.util.isArray(this.$events[name])) { + this.$events[name].push(fn); + } else { + this.$events[name] = [this.$events[name], fn]; + } + + return this; + }; + + EventEmitter.prototype.addListener = EventEmitter.prototype.on; + + /** + * Adds a volatile listener. + * + * @api public + */ + + EventEmitter.prototype.once = function (name, fn) { + var self = this; + + function on () { + self.removeListener(name, on); + fn.apply(this, arguments); + }; + + on.listener = fn; + this.on(name, on); + + return this; + }; + + /** + * Removes a listener. + * + * @api public + */ + + EventEmitter.prototype.removeListener = function (name, fn) { + if (this.$events && this.$events[name]) { + var list = this.$events[name]; + + if (io.util.isArray(list)) { + var pos = -1; + + for (var i = 0, l = list.length; i < l; i++) { + if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { + pos = i; + break; + } + } + + if (pos < 0) { + return this; + } + + list.splice(pos, 1); + + if (!list.length) { + delete this.$events[name]; + } + } else if (list === fn || (list.listener && list.listener === fn)) { + delete this.$events[name]; + } + } + + return this; + }; + + /** + * Removes all listeners for an event. + * + * @api public + */ + + EventEmitter.prototype.removeAllListeners = function (name) { + // TODO: enable this when node 0.5 is stable + //if (name === undefined) { + //this.$events = {}; + //return this; + //} + + if (this.$events && this.$events[name]) { + this.$events[name] = null; + } + + return this; + }; + + /** + * Gets all listeners for a certain event. + * + * @api publci + */ + + EventEmitter.prototype.listeners = function (name) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = []; + } + + if (!io.util.isArray(this.$events[name])) { + this.$events[name] = [this.$events[name]]; + } + + return this.$events[name]; + }; + + /** + * Emits an event. + * + * @api public + */ + + EventEmitter.prototype.emit = function (name) { + if (!this.$events) { + return false; + } + + var handler = this.$events[name]; + + if (!handler) { + return false; + } + + var args = Array.prototype.slice.call(arguments, 1); + + if ('function' == typeof handler) { + handler.apply(this, args); + } else if (io.util.isArray(handler)) { + var listeners = handler.slice(); + + for (var i = 0, l = listeners.length; i < l; i++) { + listeners[i].apply(this, args); + } + } else { + return false; + } + + return true; + }; + +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Based on JSON2 (http://www.JSON.org/js.html). + */ + +(function (exports, nativeJSON) { + "use strict"; + + // use native JSON if it's available + if (nativeJSON && nativeJSON.parse){ + return exports.JSON = { + parse: nativeJSON.parse + , stringify: nativeJSON.stringify + } + } + + var JSON = exports.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'); + }; + +})( + 'undefined' != typeof io ? io : module.exports + , typeof JSON !== 'undefined' ? JSON : undefined +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Parser namespace. + * + * @namespace + */ + + var parser = exports.parser = {}; + + /** + * Packet types. + */ + + var packets = parser.packets = [ + 'disconnect' + , 'connect' + , 'heartbeat' + , 'message' + , 'json' + , 'event' + , 'ack' + , 'error' + , 'noop' + ]; + + /** + * Errors reasons. + */ + + var reasons = parser.reasons = [ + 'transport not supported' + , 'client not handshaken' + , 'unauthorized' + ]; + + /** + * Errors advice. + */ + + var advice = parser.advice = [ + 'reconnect' + ]; + + /** + * Shortcuts. + */ + + var JSON = io.JSON + , indexOf = io.util.indexOf; + + /** + * Encodes a packet. + * + * @api private + */ + + parser.encodePacket = function (packet) { + var type = indexOf(packets, packet.type) + , id = packet.id || '' + , endpoint = packet.endpoint || '' + , ack = packet.ack + , data = null; + + switch (packet.type) { + case 'error': + var reason = packet.reason ? indexOf(reasons, packet.reason) : '' + , adv = packet.advice ? indexOf(advice, packet.advice) : ''; + + if (reason !== '' || adv !== '') + data = reason + (adv !== '' ? ('+' + adv) : ''); + + break; + + case 'message': + if (packet.data !== '') + data = packet.data; + break; + + case 'event': + var ev = { name: packet.name }; + + if (packet.args && packet.args.length) { + ev.args = packet.args; + } + + data = JSON.stringify(ev); + break; + + case 'json': + data = JSON.stringify(packet.data); + break; + + case 'connect': + if (packet.qs) + data = packet.qs; + break; + + case 'ack': + data = packet.ackId + + (packet.args && packet.args.length + ? '+' + JSON.stringify(packet.args) : ''); + break; + } + + // construct packet with required fragments + var encoded = [ + type + , id + (ack == 'data' ? '+' : '') + , endpoint + ]; + + // data fragment is optional + if (data !== null && data !== undefined) + encoded.push(data); + + return encoded.join(':'); + }; + + /** + * Encodes multiple messages (payload). + * + * @param {Array} messages + * @api private + */ + + parser.encodePayload = function (packets) { + var decoded = ''; + + if (packets.length == 1) + return packets[0]; + + for (var i = 0, l = packets.length; i < l; i++) { + var packet = packets[i]; + decoded += '\ufffd' + packet.length + '\ufffd' + packets[i]; + } + + return decoded; + }; + + /** + * Decodes a packet + * + * @api private + */ + + var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/; + + parser.decodePacket = function (data) { + var pieces = data.match(regexp); + + if (!pieces) return {}; + + var id = pieces[2] || '' + , data = pieces[5] || '' + , packet = { + type: packets[pieces[1]] + , endpoint: pieces[4] || '' + }; + + // whether we need to acknowledge the packet + if (id) { + packet.id = id; + if (pieces[3]) + packet.ack = 'data'; + else + packet.ack = true; + } + + // handle different packet types + switch (packet.type) { + case 'error': + var pieces = data.split('+'); + packet.reason = reasons[pieces[0]] || ''; + packet.advice = advice[pieces[1]] || ''; + break; + + case 'message': + packet.data = data || ''; + break; + + case 'event': + try { + var opts = JSON.parse(data); + packet.name = opts.name; + packet.args = opts.args; + } catch (e) { } + + packet.args = packet.args || []; + break; + + case 'json': + try { + packet.data = JSON.parse(data); + } catch (e) { } + break; + + case 'connect': + packet.qs = data || ''; + break; + + case 'ack': + var pieces = data.match(/^([0-9]+)(\+)?(.*)/); + if (pieces) { + packet.ackId = pieces[1]; + packet.args = []; + + if (pieces[3]) { + try { + packet.args = pieces[3] ? JSON.parse(pieces[3]) : []; + } catch (e) { } + } + } + break; + + case 'disconnect': + case 'heartbeat': + break; + }; + + return packet; + }; + + /** + * Decodes data payload. Detects multiple messages + * + * @return {Array} messages + * @api public + */ + + parser.decodePayload = function (data) { + // IE doesn't like data[i] for unicode chars, charAt works fine + if (data.charAt(0) == '\ufffd') { + var ret = []; + + for (var i = 1, length = ''; i < data.length; i++) { + if (data.charAt(i) == '\ufffd') { + ret.push(parser.decodePacket(data.substr(i + 1).substr(0, length))); + i += Number(length) + 1; + length = ''; + } else { + length += data.charAt(i); + } + } + + return ret; + } else { + return [parser.decodePacket(data)]; + } + }; + +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.Transport = Transport; + + /** + * This is the transport template for all supported transport methods. + * + * @constructor + * @api public + */ + + function Transport (socket, sessid) { + this.socket = socket; + this.sessid = sessid; + }; + + /** + * Apply EventEmitter mixin. + */ + + io.util.mixin(Transport, io.EventEmitter); + + /** + * Handles the response from the server. When a new response is received + * it will automatically update the timeout, decode the message and + * forwards the response to the onMessage function for further processing. + * + * @param {String} data Response from the server. + * @api private + */ + + Transport.prototype.onData = function (data) { + this.clearCloseTimeout(); + + // If the connection in currently open (or in a reopening state) reset the close + // timeout since we have just received data. This check is necessary so + // that we don't reset the timeout on an explicitly disconnected connection. + if (this.socket.connected || this.socket.connecting || this.socket.reconnecting) { + this.setCloseTimeout(); + } + + if (data !== '') { + // todo: we should only do decodePayload for xhr transports + var msgs = io.parser.decodePayload(data); + + if (msgs && msgs.length) { + for (var i = 0, l = msgs.length; i < l; i++) { + this.onPacket(msgs[i]); + } + } + } + + return this; + }; + + /** + * Handles packets. + * + * @api private + */ + + Transport.prototype.onPacket = function (packet) { + this.socket.setHeartbeatTimeout(); + + if (packet.type == 'heartbeat') { + return this.onHeartbeat(); + } + + if (packet.type == 'connect' && packet.endpoint == '') { + this.onConnect(); + } + + if (packet.type == 'error' && packet.advice == 'reconnect') { + this.open = false; + } + + this.socket.onPacket(packet); + + return this; + }; + + /** + * Sets close timeout + * + * @api private + */ + + Transport.prototype.setCloseTimeout = function () { + if (!this.closeTimeout) { + var self = this; + + this.closeTimeout = setTimeout(function () { + self.onDisconnect(); + }, this.socket.closeTimeout); + } + }; + + /** + * Called when transport disconnects. + * + * @api private + */ + + Transport.prototype.onDisconnect = function () { + if (this.close && this.open) this.close(); + this.clearTimeouts(); + this.socket.onDisconnect(); + return this; + }; + + /** + * Called when transport connects + * + * @api private + */ + + Transport.prototype.onConnect = function () { + this.socket.onConnect(); + return this; + } + + /** + * Clears close timeout + * + * @api private + */ + + Transport.prototype.clearCloseTimeout = function () { + if (this.closeTimeout) { + clearTimeout(this.closeTimeout); + this.closeTimeout = null; + } + }; + + /** + * Clear timeouts + * + * @api private + */ + + Transport.prototype.clearTimeouts = function () { + this.clearCloseTimeout(); + + if (this.reopenTimeout) { + clearTimeout(this.reopenTimeout); + } + }; + + /** + * Sends a packet + * + * @param {Object} packet object. + * @api private + */ + + Transport.prototype.packet = function (packet) { + this.send(io.parser.encodePacket(packet)); + }; + + /** + * Send the received heartbeat message back to server. So the server + * knows we are still connected. + * + * @param {String} heartbeat Heartbeat response from the server. + * @api private + */ + + Transport.prototype.onHeartbeat = function (heartbeat) { + this.packet({ type: 'heartbeat' }); + }; + + /** + * Called when the transport opens. + * + * @api private + */ + + Transport.prototype.onOpen = function () { + this.open = true; + this.clearCloseTimeout(); + this.socket.onOpen(); + }; + + /** + * Notifies the base when the connection with the Socket.IO server + * has been disconnected. + * + * @api private + */ + + Transport.prototype.onClose = function () { + var self = this; + + /* FIXME: reopen delay causing a infinit loop + this.reopenTimeout = setTimeout(function () { + self.open(); + }, this.socket.options['reopen delay']);*/ + + this.open = false; + this.socket.onClose(); + this.onDisconnect(); + }; + + /** + * Generates a connection url based on the Socket.IO URL Protocol. + * See for more details. + * + * @returns {String} Connection url + * @api private + */ + + Transport.prototype.prepareUrl = function () { + var options = this.socket.options; + + return this.scheme() + '://' + + options.host + ':' + options.port + '/' + + 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 +); +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io, global) { + + /** + * Expose constructor. + */ + + exports.Socket = Socket; + + /** + * Create a new `Socket.IO client` which can establish a persistent + * connection with a Socket.IO enabled server. + * + * @api public + */ + + function Socket (options) { + this.options = { + port: 80 + , secure: false + , 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.connected = false; + this.open = false; + this.connecting = false; + this.reconnecting = false; + this.namespaces = {}; + this.buffer = []; + this.doBuffer = false; + + if (this.options['sync disconnect on unload'] && + (!this.isXDomain() || io.util.ua.hasCORS)) { + var self = this; + + io.util.on(global, 'unload', function () { + self.disconnectSync(); + }, false); + } + + if (this.options['auto connect']) { + this.connect(); + } +}; + + /** + * Apply EventEmitter mixin. + */ + + io.util.mixin(Socket, io.EventEmitter); + + /** + * Returns a namespace listener/emitter for this socket + * + * @api public + */ + + Socket.prototype.of = function (name) { + if (!this.namespaces[name]) { + this.namespaces[name] = new io.SocketNamespace(this, name); + + if (name !== '') { + this.namespaces[name].packet({ type: 'connect' }); + } + } + + return this.namespaces[name]; + }; + + /** + * Emits the given event to the Socket and all namespaces + * + * @api private + */ + + Socket.prototype.publish = function () { + this.emit.apply(this, arguments); + + var nsp; + + for (var i in this.namespaces) { + if (this.namespaces.hasOwnProperty(i)) { + nsp = this.of(i); + nsp.$emit.apply(nsp, arguments); + } + } + }; + + /** + * Performs the handshake + * + * @api private + */ + + function empty () { }; + + Socket.prototype.handshake = function (fn) { + var self = this + , options = this.options; + + function complete (data) { + if (data instanceof Error) { + self.onError(data.message); + } else { + fn.apply(null, data.split(':')); + } + }; + + var url = [ + 'http' + (options.secure ? 's' : '') + ':/' + , options.host + ':' + options.port + , options.resource + , io.protocol + , io.util.query(this.options.query, 't=' + +new Date) + ].join('/'); + + if (this.isXDomain() && !io.util.ua.hasCORS) { + var insertAt = document.getElementsByTagName('script')[0] + , script = document.createElement('script'); + + script.src = url + '&jsonp=' + io.j.length; + insertAt.parentNode.insertBefore(script, insertAt); + + io.j.push(function (data) { + complete(data); + script.parentNode.removeChild(script); + }); + } else { + var xhr = io.util.request(); + + xhr.open('GET', url, true); + xhr.withCredentials = true; + xhr.onreadystatechange = function () { + if (xhr.readyState == 4) { + xhr.onreadystatechange = empty; + + if (xhr.status == 200) { + complete(xhr.responseText); + } else { + !self.reconnecting && self.onError(xhr.responseText); + } + } + }; + xhr.send(null); + } + }; + + /** + * Find an available transport based on the options supplied in the constructor. + * + * @api private + */ + + Socket.prototype.getTransport = function (override) { + var transports = override || this.transports, match; + + for (var i = 0, transport; transport = transports[i]; i++) { + if (io.Transport[transport] + && io.Transport[transport].check(this) + && (!this.isXDomain() || io.Transport[transport].xdomainCheck())) { + return new io.Transport[transport](this, this.sessionid); + } + } + + return null; + }; + + /** + * Connects to the server. + * + * @param {Function} [fn] Callback. + * @returns {io.Socket} + * @api public + */ + + Socket.prototype.connect = function (fn) { + if (this.connecting) { + return this; + } + + var self = this; + + this.handshake(function (sid, heartbeat, close, transports) { + self.sessionid = sid; + self.closeTimeout = close * 1000; + self.heartbeatTimeout = heartbeat * 1000; + self.transports = transports ? io.util.intersect( + transports.split(',') + , self.options.transports + ) : self.options.transports; + + self.setHeartbeatTimeout(); + + function connect (transports){ + if (self.transport) self.transport.clearTimeouts(); + + self.transport = self.getTransport(transports); + if (!self.transport) return self.publish('connect_failed'); + + // 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['try multiple transports']) { + if (!self.remainingTransports) { + self.remainingTransports = self.transports.slice(0); + } + + var remaining = self.remainingTransports; + + while (remaining.length > 0 && remaining.splice(0,1)[0] != + self.transport.name) {} + + if (remaining.length){ + connect(remaining); + } else { + self.publish('connect_failed'); + } + } + } + }, self.options['connect timeout']); + } + }); + } + + connect(self.transports); + + self.once('connect', function (){ + clearTimeout(self.connectTimeoutTimer); + + fn && typeof fn == 'function' && fn(); + }); + }); + + return this; + }; + + /** + * Clears and sets a new heartbeat timeout using the value given by the + * server during the handshake. + * + * @api private + */ + + Socket.prototype.setHeartbeatTimeout = function () { + clearTimeout(this.heartbeatTimeoutTimer); + + var self = this; + this.heartbeatTimeoutTimer = setTimeout(function () { + self.transport.onClose(); + }, this.heartbeatTimeout); + }; + + /** + * Sends a message. + * + * @param {Object} data packet. + * @returns {io.Socket} + * @api public + */ + + Socket.prototype.packet = function (data) { + if (this.connected && !this.doBuffer) { + this.transport.packet(data); + } else { + this.buffer.push(data); + } + + return this; + }; + + /** + * Sets buffer state + * + * @api private + */ + + Socket.prototype.setBuffer = function (v) { + this.doBuffer = v; + + if (!v && this.connected && this.buffer.length) { + this.transport.payload(this.buffer); + this.buffer = []; + } + }; + + /** + * Disconnect the established connect. + * + * @returns {io.Socket} + * @api public + */ + + Socket.prototype.disconnect = function () { + if (this.connected || this.connecting) { + if (this.open) { + this.of('').packet({ type: 'disconnect' }); + } + + // handle disconnection immediately + this.onDisconnect('booted'); + } + + return this; + }; + + /** + * Disconnects the socket with a sync XHR. + * + * @api private + */ + + Socket.prototype.disconnectSync = function () { + // ensure disconnection + var xhr = io.util.request() + , uri = this.resource + '/' + io.protocol + '/' + this.sessionid; + + xhr.open('GET', uri, true); + + // handle disconnection immediately + this.onDisconnect('booted'); + }; + + /** + * Check if we need to use cross domain enabled transports. Cross domain would + * be a different port or different domain name. + * + * @returns {Boolean} + * @api private + */ + + Socket.prototype.isXDomain = function () { + + var port = global.location.port || + ('https:' == global.location.protocol ? 443 : 80); + + return this.options.host !== global.location.hostname + || this.options.port != port; + }; + + /** + * Called upon handshake. + * + * @api private + */ + + Socket.prototype.onConnect = function () { + if (!this.connected) { + this.connected = true; + this.connecting = false; + if (!this.doBuffer) { + // make sure to flush the buffer + this.setBuffer(false); + } + this.emit('connect'); + } + }; + + /** + * Called when the transport opens + * + * @api private + */ + + Socket.prototype.onOpen = function () { + this.open = true; + }; + + /** + * Called when the transport closes. + * + * @api private + */ + + Socket.prototype.onClose = function () { + this.open = false; + clearTimeout(this.heartbeatTimeoutTimer); + }; + + /** + * Called when the transport first opens a connection + * + * @param text + */ + + Socket.prototype.onPacket = function (packet) { + this.of(packet.endpoint).onPacket(packet); + }; + + /** + * Handles an error. + * + * @api private + */ + + Socket.prototype.onError = function (err) { + if (err && err.advice) { + if (err.advice === 'reconnect' && (this.connected || this.connecting)) { + this.disconnect(); + if (this.options.reconnect) { + this.reconnect(); + } + } + } + + this.publish('error', err && err.reason ? err.reason : err); + }; + + /** + * Called when the transport disconnects. + * + * @api private + */ + + Socket.prototype.onDisconnect = function (reason) { + var wasConnected = this.connected + , wasConnecting = this.connecting; + + this.connected = false; + this.connecting = false; + this.open = false; + + if (wasConnected || wasConnecting) { + this.transport.close(); + this.transport.clearTimeouts(); + if (wasConnected) { + this.publish('disconnect', reason); + + if ('booted' != reason && this.options.reconnect && !this.reconnecting) { + this.reconnect(); + } + } + } + }; + + /** + * Called upon reconnection. + * + * @api private + */ + + Socket.prototype.reconnect = function () { + this.reconnecting = true; + this.reconnectionAttempts = 0; + this.reconnectionDelay = this.options['reconnection delay']; + + 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); + } + + clearTimeout(self.reconnectionTimer); + + self.removeListener('connect_failed', maybeReconnect); + self.removeListener('connect', maybeReconnect); + + self.reconnecting = false; + + delete self.reconnectionAttempts; + delete self.reconnectionDelay; + delete self.reconnectionTimer; + delete self.redoTransports; + + self.options['try multiple transports'] = tryMultiple; + }; + + function maybeReconnect () { + if (!self.reconnecting) { + return; + } + + if (self.connected) { + return reset(); + }; + + if (self.connecting && self.reconnecting) { + return self.reconnectionTimer = setTimeout(maybeReconnect, 1000); + } + + if (self.reconnectionAttempts++ >= maxAttempts) { + if (!self.redoTransports) { + self.on('connect_failed', maybeReconnect); + self.options['try multiple transports'] = true; + self.transport = self.getTransport(); + self.redoTransports = true; + self.connect(); + } else { + self.publish('reconnect_failed'); + reset(); + } + } else { + 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); + } + }; + + this.options['try multiple transports'] = false; + this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay); + + this.on('connect', maybeReconnect); + }; + +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports + , this +); +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.SocketNamespace = SocketNamespace; + + /** + * Socket namespace constructor. + * + * @constructor + * @api public + */ + + function SocketNamespace (socket, name) { + this.socket = socket; + this.name = name || ''; + this.flags = {}; + this.json = new Flag(this, 'json'); + this.ackPackets = 0; + this.acks = {}; + }; + + /** + * Apply EventEmitter mixin. + */ + + io.util.mixin(SocketNamespace, io.EventEmitter); + + /** + * Copies emit since we override it + * + * @api private + */ + + SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit; + + /** + * Creates a new namespace, by proxying the request to the socket. This + * allows us to use the synax as we do on the server. + * + * @api public + */ + + SocketNamespace.prototype.of = function () { + return this.socket.of.apply(this.socket, arguments); + }; + + /** + * Sends a packet. + * + * @api private + */ + + SocketNamespace.prototype.packet = function (packet) { + packet.endpoint = this.name; + this.socket.packet(packet); + this.flags = {}; + return this; + }; + + /** + * Sends a message + * + * @api public + */ + + SocketNamespace.prototype.send = function (data, fn) { + var packet = { + type: this.flags.json ? 'json' : 'message' + , data: data + }; + + if ('function' == typeof fn) { + packet.id = ++this.ackPackets; + packet.ack = true; + this.acks[packet.id] = fn; + } + + return this.packet(packet); + }; + + /** + * Emits an event + * + * @api public + */ + + SocketNamespace.prototype.emit = function (name) { + var args = Array.prototype.slice.call(arguments, 1) + , lastArg = args[args.length - 1] + , packet = { + type: 'event' + , name: name + }; + + if ('function' == typeof lastArg) { + packet.id = ++this.ackPackets; + packet.ack = 'data'; + this.acks[packet.id] = lastArg; + args = args.slice(0, args.length - 1); + } + + packet.args = args; + + return this.packet(packet); + }; + + /** + * Disconnects the namespace + * + * @api private + */ + + SocketNamespace.prototype.disconnect = function () { + if (this.name === '') { + this.socket.disconnect(); + } else { + this.packet({ type: 'disconnect' }); + this.$emit('disconnect'); + } + + return this; + }; + + /** + * Handles a packet + * + * @api private + */ + + SocketNamespace.prototype.onPacket = function (packet) { + var self = this; + + function ack () { + self.packet({ + type: 'ack' + , args: io.util.toArray(arguments) + , ackId: packet.id + }); + }; + + switch (packet.type) { + case 'connect': + this.$emit('connect'); + break; + + case 'disconnect': + if (this.name === '') { + this.socket.onDisconnect(packet.reason || 'booted'); + } else { + this.$emit('disconnect', packet.reason); + } + break; + + case 'message': + case 'json': + var params = ['message', packet.data]; + + if (packet.ack == 'data') { + params.push(ack); + } else if (packet.ack) { + this.packet({ type: 'ack', ackId: packet.id }); + } + + this.$emit.apply(this, params); + break; + + case 'event': + var params = [packet.name].concat(packet.args); + + if (packet.ack == 'data') + params.push(ack); + + this.$emit.apply(this, params); + break; + + case 'ack': + if (this.acks[packet.ackId]) { + this.acks[packet.ackId].apply(this, packet.args); + delete this.acks[packet.ackId]; + } + break; + + case 'error': + if (packet.advice){ + this.socket.onError(packet); + } else { + if (packet.reason == 'unauthorized') { + this.$emit('connect_failed', packet.reason); + } else { + this.$emit('error', packet.reason); + } + } + break; + } + }; + + /** + * Flag interface. + * + * @api private + */ + + function Flag (nsp, name) { + this.namespace = nsp; + this.name = name; + }; + + /** + * Send a message + * + * @api public + */ + + Flag.prototype.send = function () { + this.namespace.flags[this.name] = true; + this.namespace.send.apply(this.namespace, arguments); + }; + + /** + * Emit an event + * + * @api public + */ + + Flag.prototype.emit = function () { + this.namespace.flags[this.name] = true; + this.namespace.emit.apply(this.namespace, arguments); + }; + +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io, global) { + + /** + * Expose constructor. + */ + + exports.websocket = WS; + + /** + * The WebSocket transport uses the HTML5 WebSocket API to establish an + * persistent connection with the Socket.IO server. This transport will also + * be inherited by the FlashSocket fallback as it provides a API compatible + * polyfill for the WebSockets. + * + * @constructor + * @extends {io.Transport} + * @api public + */ + + function WS (socket) { + io.Transport.apply(this, arguments); + }; + + /** + * Inherits from Transport. + */ + + io.util.inherit(WS, io.Transport); + + /** + * Transport name + * + * @api public + */ + + WS.prototype.name = 'websocket'; + + /** + * Initializes a new `WebSocket` connection with the Socket.IO server. We attach + * all the appropriate listeners to handle the responses from the server. + * + * @returns {Transport} + * @api public + */ + + WS.prototype.open = function () { + var query = io.util.query(this.socket.options.query) + , self = this + , Socket + + + if (!Socket) { + Socket = global.MozWebSocket || global.WebSocket; + } + + this.websocket = new Socket(this.prepareUrl() + query); + + this.websocket.onopen = function () { + self.onOpen(); + self.socket.setBuffer(false); + }; + this.websocket.onmessage = function (ev) { + self.onData(ev.data); + }; + this.websocket.onclose = function () { + self.onClose(); + self.socket.setBuffer(true); + }; + this.websocket.onerror = function (e) { + self.onError(e); + }; + + return this; + }; + + /** + * Send a message to the Socket.IO server. The message will automatically be + * encoded in the correct message format. + * + * @returns {Transport} + * @api public + */ + + WS.prototype.send = function (data) { + this.websocket.send(data); + return this; + }; + + /** + * Payload + * + * @api private + */ + + WS.prototype.payload = function (arr) { + for (var i = 0, l = arr.length; i < l; i++) { + this.packet(arr[i]); + } + return this; + }; + + /** + * Disconnect the established `WebSocket` connection. + * + * @returns {Transport} + * @api public + */ + + WS.prototype.close = function () { + this.websocket.close(); + return this; + }; + + /** + * Handle the errors that `WebSocket` might be giving when we + * are attempting to connect or send messages. + * + * @param {Error} e The error. + * @api private + */ + + WS.prototype.onError = function (e) { + this.socket.onError(e); + }; + + /** + * Returns the appropriate scheme for the URI generation. + * + * @api private + */ + WS.prototype.scheme = function () { + return this.socket.options.secure ? 'wss' : 'ws'; + }; + + /** + * Checks if the browser has support for native `WebSockets` and that + * it's not the polyfill created for the FlashSocket transport. + * + * @return {Boolean} + * @api public + */ + + WS.check = function () { + return ('WebSocket' in global && !('__addTask' in WebSocket)) + || 'MozWebSocket' in global; + }; + + /** + * Check if the `WebSocket` transport support cross domain communications. + * + * @returns {Boolean} + * @api public + */ + + WS.xdomainCheck = function () { + return true; + }; + + /** + * Add the transport to your public io.transports array. + * + * @api private + */ + + io.transports.push('websocket'); + +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports + , this +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.flashsocket = Flashsocket; + + /** + * 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 + * about this can be found on the github page. + * + * @constructor + * @extends {io.Transport.websocket} + * @api public + */ + + function Flashsocket () { + io.Transport.websocket.apply(this, arguments); + }; + + /** + * Inherits from Transport. + */ + + io.util.inherit(Flashsocket, io.Transport.websocket); + + /** + * Transport name + * + * @api public + */ + + 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` + * transport. + * + * @returns {Transport} + * @api public + */ + + Flashsocket.prototype.open = function () { + var self = this + , args = arguments; + + WebSocket.__addTask(function () { + io.Transport.websocket.prototype.open.apply(self, args); + }); + return this; + }; + + /** + * 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` + * transport. + * + * @returns {Transport} + * @api public + */ + + Flashsocket.prototype.send = function () { + var self = this, args = arguments; + WebSocket.__addTask(function () { + io.Transport.websocket.prototype.send.apply(self, args); + }); + return this; + }; + + /** + * Disconnects the established `FlashSocket` connection. + * + * @returns {Transport} + * @api public + */ + + Flashsocket.prototype.close = function () { + WebSocket.__tasks.length = 0; + io.Transport.websocket.prototype.close.call(this); + return this; + }; + + /** + * 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 () { + if ( + typeof WebSocket == 'undefined' + || !('__initialize' in WebSocket) || !swfobject + ) return false; + + return swfobject.getFlashPlayerVersion().major >= 10; + }; + + /** + * 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. + * + * @returns {Boolean} + * @api public + */ + + Flashsocket.xdomainCheck = function () { + return true; + }; + + /** + * Disable AUTO_INITIALIZATION + */ + + if (typeof window != 'undefined') { + WEB_SOCKET_DISABLE_AUTO_INITIALIZATION = true; + } + + /** + * Add the transport to your public io.transports array. + * + * @api private + */ + + io.transports.push('flashsocket'); +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); +/* SWFObject v2.2 + is released under the MIT License +*/ +if ('undefined' != typeof window) { +var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O[(['Active'].concat('Object').join('X'))]!=D){try{var ad=new window[(['Active'].concat('Object').join('X'))](W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='"+af+"";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab +// License: New BSD License +// Reference: http://dev.w3.org/html5/websockets/ +// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol + +(function() { + + if ('undefined' == typeof window || window.WebSocket) return; + + var console = window.console; + if (!console || !console.log || !console.error) { + console = {log: function(){ }, error: function(){ }}; + } + + if (!swfobject.hasFlashPlayerVersion("10.0.0")) { + console.error("Flash Player >= 10.0.0 is required."); + return; + } + if (location.protocol == "file:") { + console.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://..."); + } + + /** + * This class represents a faux web socket. + * @param {string} url + * @param {array or string} protocols + * @param {string} proxyHost + * @param {int} proxyPort + * @param {string} headers + */ + WebSocket = function(url, protocols, proxyHost, proxyPort, headers) { + var self = this; + self.__id = WebSocket.__nextId++; + WebSocket.__instances[self.__id] = self; + self.readyState = WebSocket.CONNECTING; + self.bufferedAmount = 0; + self.__events = {}; + if (!protocols) { + protocols = []; + } else if (typeof protocols == "string") { + protocols = [protocols]; + } + // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc. + // Otherwise, when onopen fires immediately, onopen is called before it is set. + setTimeout(function() { + WebSocket.__addTask(function() { + WebSocket.__flash.create( + self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null); + }); + }, 0); + }; + + /** + * Send data to the web socket. + * @param {string} data The data to send to the socket. + * @return {boolean} True for success, false for failure. + */ + WebSocket.prototype.send = function(data) { + if (this.readyState == WebSocket.CONNECTING) { + throw "INVALID_STATE_ERR: Web Socket connection has not been established"; + } + // We use encodeURIComponent() here, because FABridge doesn't work if + // the argument includes some characters. We don't use escape() here + // because of this: + // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions + // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't + // preserve all Unicode characters either e.g. "\uffff" in Firefox. + // Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require + // additional testing. + var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data)); + if (result < 0) { // success + return true; + } else { + this.bufferedAmount += result; + return false; + } + }; + + /** + * Close this web socket gracefully. + */ + WebSocket.prototype.close = function() { + if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) { + return; + } + this.readyState = WebSocket.CLOSING; + WebSocket.__flash.close(this.__id); + }; + + /** + * Implementation of {@link DOM 2 EventTarget Interface} + * + * @param {string} type + * @param {function} listener + * @param {boolean} useCapture + * @return void + */ + WebSocket.prototype.addEventListener = function(type, listener, useCapture) { + if (!(type in this.__events)) { + this.__events[type] = []; + } + this.__events[type].push(listener); + }; + + /** + * Implementation of {@link DOM 2 EventTarget Interface} + * + * @param {string} type + * @param {function} listener + * @param {boolean} useCapture + * @return void + */ + WebSocket.prototype.removeEventListener = function(type, listener, useCapture) { + if (!(type in this.__events)) return; + var events = this.__events[type]; + for (var i = events.length - 1; i >= 0; --i) { + if (events[i] === listener) { + events.splice(i, 1); + break; + } + } + }; + + /** + * Implementation of {@link DOM 2 EventTarget Interface} + * + * @param {Event} event + * @return void + */ + WebSocket.prototype.dispatchEvent = function(event) { + var events = this.__events[event.type] || []; + for (var i = 0; i < events.length; ++i) { + events[i](event); + } + var handler = this["on" + event.type]; + if (handler) handler(event); + }; + + /** + * Handles an event from Flash. + * @param {Object} flashEvent + */ + WebSocket.prototype.__handleEvent = function(flashEvent) { + if ("readyState" in flashEvent) { + this.readyState = flashEvent.readyState; + } + if ("protocol" in flashEvent) { + this.protocol = flashEvent.protocol; + } + + var jsEvent; + if (flashEvent.type == "open" || flashEvent.type == "error") { + jsEvent = this.__createSimpleEvent(flashEvent.type); + } else if (flashEvent.type == "close") { + // TODO implement jsEvent.wasClean + jsEvent = this.__createSimpleEvent("close"); + } else if (flashEvent.type == "message") { + var data = decodeURIComponent(flashEvent.message); + jsEvent = this.__createMessageEvent("message", data); + } else { + throw "unknown event type: " + flashEvent.type; + } + + this.dispatchEvent(jsEvent); + }; + + WebSocket.prototype.__createSimpleEvent = function(type) { + if (document.createEvent && window.Event) { + var event = document.createEvent("Event"); + event.initEvent(type, false, false); + return event; + } else { + return {type: type, bubbles: false, cancelable: false}; + } + }; + + WebSocket.prototype.__createMessageEvent = function(type, data) { + if (document.createEvent && window.MessageEvent && !window.opera) { + var event = document.createEvent("MessageEvent"); + event.initMessageEvent("message", false, false, data, null, null, window, null); + return event; + } else { + // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes. + return {type: type, data: data, bubbles: false, cancelable: false}; + } + }; + + /** + * Define the WebSocket readyState enumeration. + */ + WebSocket.CONNECTING = 0; + WebSocket.OPEN = 1; + WebSocket.CLOSING = 2; + WebSocket.CLOSED = 3; + + WebSocket.__flash = null; + WebSocket.__instances = {}; + WebSocket.__tasks = []; + WebSocket.__nextId = 0; + + /** + * Load a new flash security policy file. + * @param {string} url + */ + WebSocket.loadFlashPolicyFile = function(url){ + WebSocket.__addTask(function() { + WebSocket.__flash.loadManualPolicyFile(url); + }); + }; + + /** + * Loads WebSocketMain.swf and creates WebSocketMain object in Flash. + */ + WebSocket.__initialize = function() { + if (WebSocket.__flash) return; + + if (WebSocket.__swfLocation) { + // For backword compatibility. + window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation; + } + if (!window.WEB_SOCKET_SWF_LOCATION) { + console.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf"); + return; + } + var container = document.createElement("div"); + container.id = "webSocketContainer"; + // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents + // Flash from loading at least in IE. So we move it out of the screen at (-100, -100). + // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash + // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is + // the best we can do as far as we know now. + container.style.position = "absolute"; + if (WebSocket.__isFlashLite()) { + container.style.left = "0px"; + container.style.top = "0px"; + } else { + container.style.left = "-100px"; + container.style.top = "-100px"; + } + var holder = document.createElement("div"); + holder.id = "webSocketFlash"; + container.appendChild(holder); + document.body.appendChild(container); + // See this article for hasPriority: + // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html + swfobject.embedSWF( + WEB_SOCKET_SWF_LOCATION, + "webSocketFlash", + "1" /* width */, + "1" /* height */, + "10.0.0" /* SWF version */, + null, + null, + {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"}, + null, + function(e) { + if (!e.success) { + console.error("[WebSocket] swfobject.embedSWF failed"); + } + }); + }; + + /** + * Called by Flash to notify JS that it's fully loaded and ready + * for communication. + */ + WebSocket.__onFlashInitialized = function() { + // We need to set a timeout here to avoid round-trip calls + // to flash during the initialization process. + setTimeout(function() { + WebSocket.__flash = document.getElementById("webSocketFlash"); + WebSocket.__flash.setCallerUrl(location.href); + WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG); + for (var i = 0; i < WebSocket.__tasks.length; ++i) { + WebSocket.__tasks[i](); + } + WebSocket.__tasks = []; + }, 0); + }; + + /** + * Called by Flash to notify WebSockets events are fired. + */ + WebSocket.__onFlashEvent = function() { + setTimeout(function() { + try { + // Gets events using receiveEvents() instead of getting it from event object + // of Flash event. This is to make sure to keep message order. + // It seems sometimes Flash events don't arrive in the same order as they are sent. + var events = WebSocket.__flash.receiveEvents(); + for (var i = 0; i < events.length; ++i) { + WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]); + } + } catch (e) { + console.error(e); + } + }, 0); + return true; + }; + + // Called by Flash. + WebSocket.__log = function(message) { + console.log(decodeURIComponent(message)); + }; + + // Called by Flash. + WebSocket.__error = function(message) { + console.error(decodeURIComponent(message)); + }; + + WebSocket.__addTask = function(task) { + if (WebSocket.__flash) { + task(); + } else { + WebSocket.__tasks.push(task); + } + }; + + /** + * Test if the browser is running flash lite. + * @return {boolean} True if flash lite is running, false otherwise. + */ + WebSocket.__isFlashLite = function() { + if (!window.navigator || !window.navigator.mimeTypes) { + return false; + } + var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"]; + if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) { + return false; + } + return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false; + }; + + if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) { + if (window.addEventListener) { + window.addEventListener("load", function(){ + WebSocket.__initialize(); + }, false); + } else { + window.attachEvent("onload", function(){ + WebSocket.__initialize(); + }); + } + } + +})(); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io, global) { + + /** + * Expose constructor. + * + * @api public + */ + + exports.XHR = XHR; + + /** + * XHR constructor + * + * @costructor + * @api public + */ + + function XHR (socket) { + if (!socket) return; + + io.Transport.apply(this, arguments); + this.sendBuffer = []; + }; + + /** + * Inherits from Transport. + */ + + io.util.inherit(XHR, io.Transport); + + /** + * Establish a connection + * + * @returns {Transport} + * @api public + */ + + XHR.prototype.open = function () { + this.socket.setBuffer(false); + this.onOpen(); + this.get(); + + // we need to make sure the request succeeds since we have no indication + // whether the request opened or not until it succeeded. + this.setCloseTimeout(); + + return this; + }; + + /** + * Check if we need to send data to the Socket.IO server, if we have data in our + * buffer we encode it and forward it to the `post` method. + * + * @api private + */ + + XHR.prototype.payload = function (payload) { + var msgs = []; + + for (var i = 0, l = payload.length; i < l; i++) { + msgs.push(io.parser.encodePacket(payload[i])); + } + + this.send(io.parser.encodePayload(msgs)); + }; + + /** + * Send data to the Socket.IO server. + * + * @param data The message + * @returns {Transport} + * @api public + */ + + XHR.prototype.send = function (data) { + this.post(data); + return this; + }; + + /** + * Posts a encoded message to the Socket.IO server. + * + * @param {String} data A encoded message. + * @api private + */ + + function empty () { }; + + XHR.prototype.post = function (data) { + var self = this; + this.socket.setBuffer(true); + + function stateChange () { + if (this.readyState == 4) { + this.onreadystatechange = empty; + self.posting = false; + + if (this.status == 200){ + self.socket.setBuffer(false); + } else { + self.onClose(); + } + } + } + + function onload () { + this.onload = empty; + self.socket.setBuffer(false); + }; + + this.sendXHR = this.request('POST'); + + if (global.XDomainRequest && this.sendXHR instanceof XDomainRequest) { + this.sendXHR.onload = this.sendXHR.onerror = onload; + } else { + this.sendXHR.onreadystatechange = stateChange; + } + + this.sendXHR.send(data); + }; + + /** + * Disconnects the established `XHR` connection. + * + * @returns {Transport} + * @api public + */ + + XHR.prototype.close = function () { + this.onClose(); + return this; + }; + + /** + * Generates a configured XHR request + * + * @param {String} url The url that needs to be requested. + * @param {String} method The method the request should use. + * @returns {XMLHttpRequest} + * @api private + */ + + XHR.prototype.request = function (method) { + 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 { + if (req.setRequestHeader) { + req.setRequestHeader('Content-type', 'text/plain;charset=UTF-8'); + } else { + // XDomainRequest + req.contentType = 'text/plain'; + } + } catch (e) {} + } + + return req; + }; + + /** + * Returns the scheme to use for the transport URLs. + * + * @api private + */ + + XHR.prototype.scheme = function () { + return this.socket.options.secure ? 'https' : 'http'; + }; + + /** + * Check if the XHR transports are supported + * + * @param {Boolean} xdomain Check if we support cross domain requests. + * @returns {Boolean} + * @api public + */ + + XHR.check = function (socket, xdomain) { + try { + var request = io.util.request(xdomain), + usesXDomReq = (global.XDomainRequest && request instanceof XDomainRequest), + socketProtocol = (socket && socket.options && socket.options.secure ? 'https:' : 'http:'), + isXProtocol = (socketProtocol != global.location.protocol); + if (request && !(usesXDomReq && isXProtocol)) { + return true; + } + } catch(e) {} + + return false; + }; + + /** + * Check if the XHR transport supports cross domain requests. + * + * @returns {Boolean} + * @api public + */ + + XHR.xdomainCheck = function () { + return XHR.check(null, true); + }; + +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports + , this +); +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.htmlfile = HTMLFile; + + /** + * The HTMLFile transport creates a `forever iframe` based transport + * for Internet Explorer. Regular forever iframe implementations will + * continuously trigger the browsers buzy indicators. If the forever iframe + * is created inside a `htmlfile` these indicators will not be trigged. + * + * @constructor + * @extends {io.Transport.XHR} + * @api public + */ + + function HTMLFile (socket) { + io.Transport.XHR.apply(this, arguments); + }; + + /** + * Inherits from XHR transport. + */ + + io.util.inherit(HTMLFile, io.Transport.XHR); + + /** + * Transport name + * + * @api public + */ + + HTMLFile.prototype.name = 'htmlfile'; + + /** + * Creates a new Ac...eX `htmlfile` with a forever loading iframe + * that can be used to listen to messages. Inside the generated + * `htmlfile` a reference will be made to the HTMLFile transport. + * + * @api private + */ + + HTMLFile.prototype.get = function () { + this.doc = new window[(['Active'].concat('Object').join('X'))]('htmlfile'); + this.doc.open(); + this.doc.write(''); + this.doc.close(); + this.doc.parentWindow.s = this; + + var iframeC = this.doc.createElement('div'); + iframeC.className = 'socketio'; + + this.doc.body.appendChild(iframeC); + this.iframe = this.doc.createElement('iframe'); + + iframeC.appendChild(this.iframe); + + var self = this + , query = io.util.query(this.socket.options.query, 't='+ +new Date); + + this.iframe.src = this.prepareUrl() + query; + + io.util.on(window, 'unload', function () { + self.destroy(); + }); + }; + + /** + * The Socket.IO server will write script tags inside the forever + * iframe, this function will be used as callback for the incoming + * information. + * + * @param {String} data The message + * @param {document} doc Reference to the context + * @api private + */ + + HTMLFile.prototype._ = function (data, doc) { + this.onData(data); + try { + var script = doc.getElementsByTagName('script')[0]; + script.parentNode.removeChild(script); + } catch (e) { } + }; + + /** + * Destroy the established connection, iframe and `htmlfile`. + * And calls the `CollectGarbage` function of Internet Explorer + * to release the memory. + * + * @api private + */ + + HTMLFile.prototype.destroy = function () { + if (this.iframe){ + try { + this.iframe.src = 'about:blank'; + } catch(e){} + + this.doc = null; + this.iframe.parentNode.removeChild(this.iframe); + this.iframe = null; + + CollectGarbage(); + } + }; + + /** + * Disconnects the established connection. + * + * @returns {Transport} Chaining. + * @api public + */ + + HTMLFile.prototype.close = function () { + this.destroy(); + return io.Transport.XHR.prototype.close.call(this); + }; + + /** + * Checks if the browser supports this transport. The browser + * must have an `Ac...eXObject` implementation. + * + * @return {Boolean} + * @api public + */ + + HTMLFile.check = function () { + if (typeof window != "undefined" && (['Active'].concat('Object').join('X')) in window){ + try { + var a = new window[(['Active'].concat('Object').join('X'))]('htmlfile'); + return a && io.Transport.XHR.check(); + } catch(e){} + } + return false; + }; + + /** + * Check if cross domain requests are supported. + * + * @returns {Boolean} + * @api public + */ + + HTMLFile.xdomainCheck = function () { + // we can probably do handling for sub-domains, we should + // test that it's cross domain but a subdomain here + return false; + }; + + /** + * Add the transport to your public io.transports array. + * + * @api private + */ + + io.transports.push('htmlfile'); + +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io, global) { + + /** + * Expose constructor. + */ + + exports['xhr-polling'] = XHRPolling; + + /** + * The XHR-polling transport uses long polling XHR requests to create a + * "persistent" connection with the server. + * + * @constructor + * @api public + */ + + function XHRPolling () { + io.Transport.XHR.apply(this, arguments); + }; + + /** + * Inherits from XHR transport. + */ + + io.util.inherit(XHRPolling, io.Transport.XHR); + + /** + * Merge the properties from XHR transport + */ + + io.util.merge(XHRPolling, io.Transport.XHR); + + /** + * Transport name + * + * @api public + */ + + XHRPolling.prototype.name = 'xhr-polling'; + + /** + * Establish a connection, for iPhone and Android this will be done once the page + * is loaded. + * + * @returns {Transport} Chaining. + * @api public + */ + + XHRPolling.prototype.open = function () { + var self = this; + + io.Transport.XHR.prototype.open.call(self); + return false; + }; + + /** + * Starts a XHR request to wait for incoming messages. + * + * @api private + */ + + function empty () {}; + + XHRPolling.prototype.get = function () { + if (!this.open) return; + + var self = this; + + function stateChange () { + if (this.readyState == 4) { + this.onreadystatechange = empty; + + if (this.status == 200) { + self.onData(this.responseText); + self.get(); + } else { + self.onClose(); + } + } + }; + + function onload () { + this.onload = empty; + this.onerror = empty; + self.onData(this.responseText); + self.get(); + }; + + function onerror () { + self.onClose(); + }; + + this.xhr = this.request(); + + if (global.XDomainRequest && this.xhr instanceof XDomainRequest) { + this.xhr.onload = onload; + this.xhr.onerror = onerror; + } else { + this.xhr.onreadystatechange = stateChange; + } + + this.xhr.send(null); + }; + + /** + * Handle the unclean close behavior. + * + * @api private + */ + + XHRPolling.prototype.onClose = function () { + io.Transport.XHR.prototype.onClose.call(this); + + if (this.xhr) { + this.xhr.onreadystatechange = this.xhr.onload = this.xhr.onerror = empty; + try { + this.xhr.abort(); + } catch(e){} + this.xhr = null; + } + }; + + /** + * 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. + * + * @api private + */ + + io.transports.push('xhr-polling'); + +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports + , this +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io, global) { + /** + * There is a way to hide the loading indicator in Firefox. If you create and + * remove a iframe it will stop showing the current loading indicator. + * Unfortunately we can't feature detect that and UA sniffing is evil. + * + * @api private + */ + + var indicator = global.document && "MozAppearance" in + global.document.documentElement.style; + + /** + * Expose constructor. + */ + + exports['jsonp-polling'] = JSONPPolling; + + /** + * The JSONP transport creates an persistent connection by dynamically + * inserting a script tag in the page. This script tag will receive the + * information of the Socket.IO server. When new information is received + * it creates a new script tag for the new data stream. + * + * @constructor + * @extends {io.Transport.xhr-polling} + * @api public + */ + + function JSONPPolling (socket) { + io.Transport['xhr-polling'].apply(this, arguments); + + this.index = io.j.length; + + var self = this; + + io.j.push(function (msg) { + self._(msg); + }); + }; + + /** + * Inherits from XHR polling transport. + */ + + io.util.inherit(JSONPPolling, io.Transport['xhr-polling']); + + /** + * Transport name + * + * @api public + */ + + JSONPPolling.prototype.name = 'jsonp-polling'; + + /** + * Posts a encoded message to the Socket.IO server using an iframe. + * The iframe is used because script tags can create POST based requests. + * The iframe is positioned outside of the view so the user does not + * notice it's existence. + * + * @param {String} data A encoded message. + * @api private + */ + + JSONPPolling.prototype.post = function (data) { + 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') + , id = this.iframeId = 'socketio_iframe_' + this.index + , iframe; + + form.className = 'socketio'; + form.style.position = 'absolute'; + form.style.top = '0px'; + form.style.left = '0px'; + form.style.display = 'none'; + form.target = id; + form.method = 'POST'; + form.setAttribute('accept-charset', 'utf-8'); + area.name = 'd'; + form.appendChild(area); + document.body.appendChild(form); + + this.form = form; + this.area = area; + } + + this.form.action = this.prepareUrl() + query; + + function complete () { + initIframe(); + self.socket.setBuffer(false); + }; + + function initIframe () { + if (self.iframe) { + self.form.removeChild(self.iframe); + } + + try { + // ie6 dynamic iframes with target="" support (thanks Chris Lambacher) + iframe = document.createElement(''; +html += '

'; +html += '
'; +html += '
Upload File
'; +html += '
Want to upload multiple files at once? Please upgrade to the latest Flash Player, then reload this page. For some reason our Flash based uploader did not load, so you are currently using our single file uploader.
'; +html += spacer(1,20) + '
'; +var url = zero_client.targetURL; +if (url.indexOf('?') > -1) url += '&'; else url += '?'; +url += 'format=jshtml&onafter=' + escape('window.parent.upload_basic_finish(response);'); +Debug.trace('upload', "Prepping basic upload: " + url); +html += '
'; +html += '
'; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "hide_popup_dialog()") + ' ' + large_icon_button('page_white_get.png', 'Upload', "upload_basic_go()") + '
'; +html += '
'; +html += ''; +html += '
'; +html += ''; +session.hooks.keys[ESC_KEY] = 'hide_popup_dialog'; +show_popup_dialog(528, 200, html); +} +function upload_basic_go() { +$('f_upload_basic').submit(); +$('d_upload_form').hide(); +$('d_upload_progress').show(); +} +function upload_basic_finish(response) { +Debug.trace('upload', "Basic upload complete: " + dumper(response)); +setTimeout( 'upload_basic_finish_2()', 100 ); +} +function upload_basic_finish_2() { +$('i_upload_basic').src = 'blank.html'; +setTimeout( 'upload_basic_finish_3()', 100 ); +} +function upload_basic_finish_3() { +hide_popup_dialog(); +delete session.progress; +show_progress_dialog( 0, 'Finishing Upload...', true ); +fire_callback( session.upload_callback ); +} +function upload_destroy() { +if (zero_client) { +zero_client.destroy(); +delete ZeroUpload.clients[ zero_client.id ]; +zero_client = null; +} +} +function prep_upload(dom_id, url, callback, types) { +session.upload_callback = callback; +if (url) { +if (url.indexOf('?') > -1) url += '&'; else url += '?'; +url += 'session=' + session.cookie.get('effect_session_id'); +} +upload_destroy(); +zero_client = new ZeroUpload.Client(); +if (url) zero_client.setURL( url ); +zero_client.setHandCursor( true ); +if (types) zero_client.setFileTypes( types[0], types[1] ); +zero_client.addEventListener( 'queueStart', uploadQueueStart ); +zero_client.addEventListener( 'fileStart', uploadFileStart ); +zero_client.addEventListener( 'progress', uploadProgress ); +zero_client.addEventListener( 'fileComplete', uploadFileComplete ); +zero_client.addEventListener( 'queueComplete', uploadQueueComplete ); +zero_client.addEventListener( 'error', uploadError ); +zero_client.addEventListener( 'debug', function(client, eventName, args) { +Debug.trace('upload', "Caught event: " + eventName); +} ); +if (dom_id) { +Debug.trace('upload', "Gluing ZeroUpload to: " + dom_id); +zero_client.glue( dom_id ); +} +} +Class.create( 'Debug', { +__static: { +enabled: false, +categories: { all: 1 }, +buffer: [], +max_rows: 5000, +win: null, +ie: !!navigator.userAgent.match(/MSIE/), +ie6: !!navigator.userAgent.match(/MSIE\D+6/), +init: function() { +Debug.enabled = true; +Debug.trace( 'debug', 'Debug log start' ); +var html = '

'; +if (Debug.ie) { +setTimeout( function() { +document.body.insertAdjacentHTML('beforeEnd', +'
' + html + '
' +); +}, 1000 ); +} +else { +var div = document.createElement('DIV'); +div.id = 'd_debug'; +div.setAttribute('id', 'd_debug'); +div.style.position = Debug.ie6 ? 'absolute' : 'fixed'; +div.style.zIndex = '101'; +div.style.left = '0px'; +div.style.top = '0px'; +div.style.width = '100%'; +div.innerHTML = html; +document.getElementsByTagName('body')[0].appendChild(div); +} +}, +show: function() { +if (!Debug.win || Debug.win.closed) { +Debug.trace('debug', "Opening debug window"); +Debug.win = window.open( '', 'DebugWindow', 'width=600,height=500,menubar=no,resizable=yes,scrollbars=yes,location=no,status=no,toolbar=no,directories=no' ); +if (!Debug.win) return alert("Failed to open window. Popup blocker maybe?"); +var doc = Debug.win.document; +doc.open(); +doc.writeln( 'Debug Log' ); +doc.writeln( '
' ); +doc.writeln( '
' ); +doc.writeln( '
' ); +doc.writeln( '' ); +doc.writeln( '' ); +doc.writeln( '
' ); +doc.writeln( '' ); +doc.close(); +} +Debug.win.focus(); +}, +console_execute: function() { +var cmd = Debug.win.document.getElementById('fe_command'); +if (cmd.value.length) { +Debug.trace( 'console', cmd.value ); +try { +Debug.trace( 'console', '' + eval(cmd.value) ); +} +catch (e) { +Debug.trace( 'error', 'JavaScript Interpreter Exception: ' + e.toString() ); +} +} +}, +get_time_stamp: function(now) { +var date = new Date( now * 1000 ); +var hh = date.getHours(); if (hh < 10) hh = "0" + hh; +var mi = date.getMinutes(); if (mi < 10) mi = "0" + mi; +var ss = date.getSeconds(); if (ss < 10) ss = "0" + ss; +var sss = '' + date.getMilliseconds(); while (sss.length < 3) sss = "0" + sss; +return '' + hh + ':' + mi + ':' + ss + '.' + sss; +}, +refresh_console: function() { +if (!Debug.win || Debug.win.closed) return; +var div = Debug.win.document.getElementById('d_debug_log'); +if (div) { +var row = null; +while ( row = Debug.buffer.shift() ) { +var time_stamp = Debug.get_time_stamp(row.time); +var msg = row.msg; +msg = msg.replace(/\t/g, "    "); +msg = msg.replace(//g, ">"); +msg = msg.replace(/\n/g, "
\n"); +var html = ''; +var sty = 'float:left; font-family: Consolas, Courier, mono; font-size: 12px; cursor:default; margin-right:10px; margin-bottom:1px; padding:2px;'; +html += '
' + time_stamp + '
'; +html += '
' + row.cat + '
'; +html += '
' + msg + '
'; +html += '
'; +var chunk = Debug.win.document.createElement('DIV'); +chunk.style['float'] = 'none'; +chunk.innerHTML = html; +div.appendChild(chunk); +} +var cmd = Debug.win.document.getElementById('fe_command'); +cmd.focus(); +} +Debug.dirty = 0; +Debug.win.scrollTo(0, 99999); +}, +hires_time_now: function() { +var now = new Date(); +return ( now.getTime() / 1000 ); +}, +trace: function(cat, msg) { +if (arguments.length == 1) { +msg = cat; +cat = 'debug'; +} +if (Debug.categories.all || Debug.categories[cat]) { +Debug.buffer.push({ cat: cat, msg: msg, time: Debug.hires_time_now() }); +if (Debug.buffer.length > Debug.max_rows) Debug.buffer.shift(); +if (!Debug.dirty) { +Debug.dirty = 1; +setTimeout( 'Debug.refresh_console();', 1 ); +} +} +} +} +} ); +var session = { +inited: false, +api_mod_cache: {}, +query: parseQueryString( ''+location.search ), +cookie: new CookieTree({ path: '/effect/' }), +storage: {}, +storage_dirty: false, +hooks: { +keys: {} +}, +username: '', +em_width: 11, +audioResourceMatch: /\.mp3$/i, +imageResourceMatch: /\.(jpe|jpeg|jpg|png|gif)$/i, +textResourceMatch: /\.xml$/i, +movieResourceMatch: /\.(flv|mp4|mp4v|mov|3gp|3g2)$/i, +imageResourceMatchString: '\.(jpe|jpeg|jpg|png|gif)$' +}; +session.debug = session.query.debug ? true : false; +var page_manager = null; +var preload_icons = []; +var preload_images = [ +'loading.gif', +'aquaprogressbar.gif', +'aquaprogressbar_bkgnd.gif' +]; +function get_base_url() { +return protocol + '://' + location.hostname + session.config.BaseURI; +} +function effect_init() { +if (session.inited) return; +session.inited = true; +assert( window.config, "Config not loaded" ); +session.config = window.config; +Debug.trace("Starting up"); +rendering_page = false; +preload(); +window.$R = {}; +for (var key in config.RegExpShortcuts) { +$R[key] = new RegExp( config.RegExpShortcuts[key] ); +} +ww_precalc_font("body", "effect_precalc_font_finish"); +page_manager = new Effect.PageManager( config.Pages.Page ); +var session_id = session.cookie.get('effect_session_id'); +if (session_id && session_id.match(/^login/)) { +do_session_recover(); +} +else { +show_default_login_status(); +Nav.init(); +} +Blog.search({ +stag: 'sidebar_docs', +limit: 20, +title_only: true, +sort_by: 'seq', +sort_dir: -1, +target: 'd_sidebar_documents', +outer_div_class: 'sidebar_blog_row', +title_class: 'sidebar_blog_title', +after: '' +}); +Blog.search({ +stag: 'sidebar_tutorials', +limit: 5, +title_only: true, +sort_by: 'seq', +sort_dir: -1, +target: 'd_sidebar_tutorials', +outer_div_class: 'sidebar_blog_row', +title_class: 'sidebar_blog_title', +after: '' +}); +Blog.search({ +stag: 'sidebar_plugins', +limit: 5, +title_only: true, +sort_by: 'seq', +sort_dir: -1, +target: 'd_sidebar_plugins', +outer_div_class: 'sidebar_blog_row', +title_class: 'sidebar_blog_title', +after: '' +}); +$('fe_search_bar').onkeydown = delay_onChange_input_text; +user_storage_idle(); +} +function effect_precalc_font_finish(width, height) { +session.em_width = width; +} +function preload() { +for (var idx = 0, len = preload_icons.length; idx < len; idx++) { +var url = images_uri + '/icons/' + preload_icons[idx] + '.gif'; +preload_icons[idx] = new Image(); +preload_icons[idx].src = url; +} +for (var idx = 0, len = preload_images.length; idx < len; idx++) { +var url = images_uri + '/' + preload_images[idx]; +preload_images[idx] = new Image(); +preload_images[idx].src = url; +} +} +function $P(id) { +if (!id) id = page_manager.current_page_id; +var page = page_manager.find(id); +assert( !!page, "Failed to locate page: " + id ); +return page; +} +function get_pref(name) { +if (!session.user || !session.user.Preferences) return alert("ASSERT FAILURE! Tried to lookup pref " + name + " and user is not yet loaded!"); +return session.user.Preferences[name]; +} +function get_bool_pref(name) { +return (get_pref(name) == 1); +} +function set_pref(name, value) { +session.user.Preferences[name] = value; +} +function set_bool_pref(name, value) { +set_pref(name, value ? '1' : '0'); +} +function save_prefs() { +var prefs_to_save = {}; +if (arguments.length) { +for (var idx = 0, len = arguments.length; idx < len; idx++) { +var key = arguments[idx]; +prefs_to_save[key] = get_pref(key); +} +} +else prefs_to_save = session.user.Preferences; +effect_api_mod_touch('user_get'); +effect_api_send('user_update', { +Username: session.username, +Preferences: prefs_to_save +}, 'save_prefs_2'); +} +function save_prefs_2(response) { +do_message('success', 'Preferences saved.'); +} + +function get_full_name(username) { +var user = session.users[username]; +if (!user) return username; +return user.FullName; +} +function get_buddy_icon_url(username, size) { +var mod = session.api_mod_cache.get_buddy_icon || 0; +if (!size) size = 32; +var url = '/effect/api/get_buddy_icon?username='+username + '&mod=' + mod + '&size=' + size; +return url; +} +function get_buddy_icon_display(username, show_icon, show_name) { +if ((typeof(show_icon) == 'undefined') && get_bool_pref('show_user_icons')) show_icon = 1; +if ((typeof(show_name) == 'undefined') && get_bool_pref('show_user_names')) show_name = 1; +var html = ''; +if (show_icon) html += ''; +if (show_icon && show_name) html += '
'; +if (show_name) html += username; +return html; +} +function do_session_recover() { +session.hooks.after_error = 'do_logout'; +effect_api_send('session_recover', {}, 'do_login_2', { _from_recover: 1 } ); +} +function require_login() { +if (session.user) return true; +Debug.trace('Page requires login, showing login page'); +session.nav_after_login = Nav.currentAnchor(); +setTimeout( function() { +Nav.go( 'Login' ); +}, 1 ); +return false; +} +function popup_window(url, name) { +if (!url) url = ''; +if (!name) name = ''; +var win = window.open(url, name); +if (!win) return alert('Failed to open popup window. If you have a popup blocker, please disable it for this website and try again.'); +return win; +} +function do_login_prompt() { +hide_popup_dialog(); +delete session.progress; +if (!session.temp_password) session.temp_password = ''; +if (!session.username) session.username = ''; +var temp_username = session.open_id || session.username || ''; +var html = ''; +html += '
'; +html += '
'; +html += '
Effect Developer Login
'; +html += '
'; +html += '
Effect Username  or  '+icon('openid', 'OpenID', 'popup_window(\'http://openid.net/\')', 'What is OpenID?')+'


'; +html += '
'; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "clear_login()") + ' ' + large_icon_button('check', 'Login', 'do_login()') + '
'; +html += '
'; +html += ''; +session.hooks.keys[ENTER_KEY] = 'do_login'; +session.hooks.keys[ESC_KEY] = 'clear_login'; +safe_focus( 'fe_username' ); +show_popup_dialog(450, 225, html); +} +function do_openid_reg(title, auto_login_button) { +hide_popup_dialog(); +delete session.progress; +if (!title) title = 'Register Account Using OpenID'; +if (typeof(auto_login_button) == 'undefined') auto_login_button = 1; +var html = ''; +html += '
'; +html += '
'; +html += '
'+title+'
'; +html += '
'; +html += '
'+icon('openid', 'Enter Your OpenID URL:')+'
'; +if (auto_login_button) html += '


'; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "hide_popup_dialog()") + ' ' + large_icon_button('check', title.match(/login/i) ? 'Login' : 'Register', 'do_openid_login()') + '
'; +html += '
'; +html += ''; +session.hooks.keys[ENTER_KEY] = 'do_openid_login'; +session.hooks.keys[ESC_KEY] = 'hide_popup_dialog'; +safe_focus( 'fe_username' ); +show_popup_dialog(450, 225, html); +} +function do_login_prompt_2() { +hide_popup_dialog(); +delete session.progress; +if (!session.temp_password) session.temp_password = ''; +if (!session.username) session.username = ''; +var html = ''; +html += '
'; +html += '
'; +html += '
Enter Your Password
'; +html += '
'; +html += '
Password:


'; +html += '
'; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "clear_login()") + ' ' + large_icon_button('check', 'Login', 'do_effect_login()') + '
'; +html += '
'; +html += ''; +session.hooks.keys[ENTER_KEY] = 'do_effect_login'; +session.hooks.keys[ESC_KEY] = 'clear_login'; +safe_focus( 'fe_lp_password' ); +show_popup_dialog(450, 225, html); +} +function clear_login() { +hide_popup_dialog(); +Nav.prev(); +} +function do_login() { +if ($('fe_username').value.match(/^\w+$/)) { +session.username = $('fe_username').value; +session.auto_login = $('fe_auto_login').checked; +do_login_prompt_2(); +return; +} +else { +do_openid_login(); +} +} +function do_openid_login() { +if (!$('fe_username').value) return; +session.openid_win = popup_window(''); +if (!session.openid_win) return; +session.open_id = $('fe_username').value; +session.auto_login = $('fe_auto_login') && $('fe_auto_login').checked; +hide_popup_dialog(); +show_progress_dialog(1, "Logging in..."); +session.hooks.before_error = 'close_openid_window'; +session.hooks.after_error = 'do_login_prompt'; +effect_api_send('openid_login', { +OpenID: session.open_id, +Infinite: session.auto_login ? 1 : 0 +}, 'do_openid_login_2'); +} +function close_openid_window() { +if (session.openid_win) { +session.openid_win.close(); +delete session.openid_win; +} +} +function do_openid_login_2(response) { +if (response.CheckURL) { +Debug.trace('openid', "Redirecting popup window to OpenID Check URL: " + response.CheckURL); +show_progress_dialog(1, "Waiting for popup window...", false, ['x', 'Cancel', 'do_login_prompt()']); +session.openid_win.location = response.CheckURL; +session.openid_win.focus(); +} +} +function receive_openid_response(iframe_response) { +var response = deep_copy_object(iframe_response); +Debug.trace('openid', "Received OpenID Response: " + dumper(response)); +hide_popup_dialog(); +if (response.Code) { +close_openid_window(); +return do_error( response.Description ); +} +delete session.hooks.before_error; +delete session.hooks.after_error; +if (response.SessionID) { +session.cookie.set( 'effect_session_id', response.SessionID ); +session.cookie.save(); +} +switch (response.Action) { +case 'popup': +show_progress_dialog(1, "Waiting for popup window...", false, ['x', 'Cancel', 'do_login_prompt()']); +Debug.trace('openid', "Redirecting popup window to OpenID Setup URL: " + response.SetupURL); +session.openid_win.location = response.SetupURL; +session.openid_win.focus(); +break; +case 'login': +close_openid_window(); +do_login_2(response); +break; +case 'register': +if (!response.Info) response.Info = {}; +close_openid_window(); +Debug.trace('openid', 'Original OpenID: ' + response.OpenID_Login); +Debug.trace('openid', 'Clean OpenID: ' + response.OpenID_Unique); +Debug.trace('openid', 'Registration Info: ' + dumper(response.Info)); +session.prereg = response.Info; +session.prereg.open_id_login = response.OpenID_Login; +session.prereg.open_id = response.OpenID_Unique; +if (session.user) { +if (!session.user.OpenIDs) session.user.OpenIDs = {}; +if (!session.user.OpenIDs.OpenID) session.user.OpenIDs.OpenID = []; +var dupe = find_object( session.user.OpenIDs.OpenID, { Unique: session.prereg.open_id } ); +if (dupe) return do_error("That OpenID is already registered and attached to your account. No need to add it again."); +session.user.OpenIDs.OpenID.push({ +Login: session.prereg.open_id_login, +Unique: session.prereg.open_id +}); +setTimeout( function() { +Nav.go('MyAccount', true); +do_message('success', 'Added new OpenID URL to account.'); +}, 1 ); +} +else { +setTimeout( function() { Nav.go('CreateAccount', true); }, 1 ); +} +break; +} +} +function do_effect_login() { +var password = $('fe_lp_password').value; +session.auto_login = $('fe_auto_login').checked; +hide_popup_dialog(); +show_progress_dialog(1, "Logging in..."); +session.hooks.after_error = 'do_login_prompt'; +effect_api_send('user_login', { +Username: session.username, +Password: password, +Infinite: session.auto_login ? 1 : 0 +}, 'do_login_2'); +} +function do_logout() { +effect_api_send('user_logout', {}, 'do_logout_2'); +} +function do_logout_2(response) { +hide_popup_dialog(); +show_default_login_status(); +delete session.hooks.after_error; +delete session.cookie.tree.effect_session_id; +session.cookie.save(); +session.storage = {}; +session.storage_dirty = false; +delete session.user; +delete session.first_login; +var old_username = session.username; +session.username = ''; +if (Nav.inited) { +Nav.go('Main'); +if (old_username) $GR.growl('success', "Logged out of account: " + old_username); +} +else { +Nav.init(); +} +} +function do_login_2(response, tx) { +if (response.FirstLogin) session.first_login = 1; +if (response.User.UserStorage) { +Debug.trace('Recovering site storage blob: session.storage = ' + response.User.UserStorage + ';'); +try { +eval( 'session.storage = ' + response.User.UserStorage + ';' ); +} +catch (e) { +Debug.trace("SITE STORAGE RECOVERY FAILED: " + e); +session.storage = {}; +} +delete response.User.UserStorage; +session.storage_dirty = false; +} +session.user = response.User; +session.username = session.user.Username; +hide_popup_dialog(); +delete session.hooks.after_error; +update_header(); +if (!tx || !tx._from_recover) $GR.growl('success', "Logged in as: " + session.username); +if (session.nav_after_login) { +Nav.go( session.nav_after_login ); +delete session.nav_after_login; +} +else if (Nav.currentAnchor().match(/^Login/)) { +Nav.go('Home'); +} +else { +Nav.refresh(); +} +Nav.init(); +} +function user_storage_mark() { +Debug.trace("Marking user storage as dirty"); +session.storage_dirty = true; +} +function user_storage_idle() { +if (session.storage_dirty && !session.mouseIsDown) { +user_storage_save(); +session.storage_dirty = false; +} +setTimeout( 'user_storage_idle()', 5000 ); +} +function user_storage_save() { +if (session.user) { +Debug.trace("Committing user storage blob"); +effect_api_send('update_user_storage', { Data: serialize(session.storage) }, 'user_storage_save_finish', { _silent: 1 } ); +} +} +function user_storage_save_finish(response, tx) { +} +function show_default_login_status() { +$('d_sidebar_wrapper_recent_games').hide(); +$('d_login_status').innerHTML = '
' + +'
' + +large_icon_button('key', "Login", '#Home') + '' + spacer(1,1) + '' + +'' + large_icon_button('user_add.png', "Signup", '#CreateAccount') + '
' + +'
'; +$('d_tagline').innerHTML = +'Login' + ' | ' + +'Create Account'; +} +function update_header() { +var html = ''; +html += '
'; +html += ''; +html += ''; +html += ''; +html += ''+spacer(2,2)+''; +html += session.user.FullName + '
'; +html += spacer(1,5) + '
'; +html += 'My Home  |  '; +html += 'Logout'; +html += '
'; +$('d_login_status').innerHTML = html; +$('d_tagline').innerHTML = +'Welcome '+session.user.FirstName+'' + ' | ' + +'My Home' + ' | ' + +'Logout'; +effect_api_get( 'get_user_games', { limit:5, offset:0 }, 'receive_sidebar_recent_games', { } ); +} +function receive_sidebar_recent_games(response, tx) { +var html = ''; +if (response.Rows && response.Rows.Row) { +var games = always_array( response.Rows.Row ); +for (var idx = 0, len = games.length; idx < len; idx++) { +var game = games[idx]; +html += ''; +} +html += ''; +$('d_sidebar_recent_games').innerHTML = html; +$('d_sidebar_wrapper_recent_games').show(); +} +else { +$('d_sidebar_wrapper_recent_games').hide(); +} +} +function check_privilege(key) { +if (!session.user) return false; +if (session.user.Privileges.admin == 1) return true; +if (!key.toString().match(/^\//)) key = '/' + key; +var value = lookup_path(key, session.user.Privileges); +return( value && (value != 0) ); +} +function is_admin() { +return check_privilege('admin'); +} +function upgrade_flash_error() { +return alert("Sorry, file upload requires Adobe Flash Player 9 or higher."); +} +function cancel_user_image_manager() { +upload_destroy(); +hide_popup_dialog(); +delete session.hooks.keys[DELETE_KEY]; +} +function do_user_image_manager(callback) { +if (callback) session.uim_callback = callback; +else session.uim_callback = null; +session.temp_last_user_img = null; +session.temp_last_user_image_filename = ''; +var html = '
'; +html += '
Image Manager
'; +html += '
'; +html += ''; +html += '
'; +html += '
'; +html += ''; +html += ''; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', 'cancel_user_image_manager()') + ' ' + large_icon_button('bullet_upload.png', 'Upload Files...', 'upload_basic()', 'b_upload_user_image') + ' ' + large_icon_button('check', 'Choose', 'do_choose_user_image()', 'btn_choose_user_image', '', 'disabled') + '
'; +html += '
'; +session.hooks.keys[ENTER_KEY] = 'do_choose_user_image'; +session.hooks.keys[ESC_KEY] = 'cancel_user_image_manager'; +session.hooks.keys[DELETE_KEY] = 'do_delete_selected_user_image'; +show_popup_dialog(500, 300, html); +var self = this; +setTimeout( function() { +prep_upload('b_upload_user_image', '/effect/api/upload_user_image', [self, 'do_upload_user_image_2'], ['Image Files', '*.jpg;*.jpe;*.jpeg;*.gif;*.png']); +}, 1 ); +var args = { +limit: 50, +offset: 0, +random: Math.random() +}; +effect_api_get( 'user_images_get', args, 'uim_populate_images', { } ); +} +function do_upload_user_image_2() { +effect_api_mod_touch('user_images_get'); +effect_api_send('user_get', { +Username: session.username +}, [this, 'do_upload_user_image_3']); +} +function do_upload_user_image_3(response) { +if (response.User.LastUploadError) return do_error( "Failed to upload image: " + response.User.LastUploadError ); +do_user_image_manager( session.uim_callback ); +} +function uim_populate_images(response, tx) { +var html = ''; +var base_url = '/effect/api/view/users/' + session.username + '/images'; +if (response.Rows && response.Rows.Row) { +var imgs = always_array( response.Rows.Row ); +for (var idx = 0, len = imgs.length; idx < len; idx++) { +var img = imgs[idx]; +var class_name = ((img.Filename == session.temp_last_user_image_filename) ? 'choose_item_selected' : 'choose_item'); +html += ''; +} +} +else { +html = ''; +} +$('d_user_image_list').innerHTML = html; +} +function do_select_user_image(img, filename) { +if (session.temp_last_user_img) session.temp_last_user_img.className = 'choose_item'; +img.className = 'choose_item_selected'; +$('btn_choose_user_image').removeClass('disabled'); +session.temp_last_user_img = img; +session.temp_last_user_image_filename = filename; +} +function do_delete_selected_user_image() { +if (session.temp_last_user_image_filename) { +effect_api_send('user_image_delete', { Filename: session.temp_last_user_image_filename }, 'do_delete_selected_user_image_finish', {}); +} +} +function do_delete_selected_user_image_finish(response, tx) { +try { $('d_user_image_list').removeChild( session.temp_last_user_img ); } catch(e) {;} +session.temp_last_user_img = null; +session.temp_last_user_image_filename = null; +} +function do_choose_user_image() { +if (!session.temp_last_user_image_filename) return; +if (session.uim_callback) { +fire_callback( session.uim_callback, session.temp_last_user_image_filename ); +} +cancel_user_image_manager(); +} +function user_image_thumbnail(filename, width, height, attribs) { +var username = session.username; +if (filename.match(/^(\w+)\/(.+)$/)) { +username = RegExp.$1; +filename = RegExp.$2; +} +var url = '/effect/api/view/users/' + username + '/images/' + filename.replace(/\.(\w+)$/, '_thumb.jpg'); +return ''; +} +function get_user_display(username, full_name, base_url) { +if (!base_url) base_url = ''; +return icon('user', full_name || username, base_url + '#User/' + username); +} +function get_game_tab_bar(game_id, cur_page_name) { +return tab_bar([ +['#Game/' + game_id, 'Game', 'controller.png'], +['#GameDisplay/' + game_id, 'Display', 'monitor.png'], +['#GameAssets/' + game_id, 'Assets', 'folder_page_white.png'], +['#GameObjects/' + game_id, 'Objects', 'bricks.png'], +['#GameAudio/' + game_id, 'Audio', 'sound.gif'], +['#GameKeys/' + game_id, 'Keyboard', 'keyboard.png'], +['#GameLevels/' + game_id, 'Levels', 'world.png'], +['#GamePublisher/' + game_id, 'Publish', 'cd.png'] +], cur_page_name); +} +function get_user_tab_bar(cur_page_name) { +var tabs = [ +['#Home', 'My Home', 'house.png'] +]; +tabs.push( ['#MyAccount', 'Edit Account', 'user_edit.png'] ); +tabs.push( ['#ArticleEdit', 'Post Article', 'page_white_edit.png'] ); +if (config.ProEnabled) { +tabs.push( ['#UserPayments', 'Payments', 'money.png'] ); +} +tabs.push( ['#UserLog', 'Security Log', 'application_view_detail.png'] ); +return tab_bar(tabs, cur_page_name); +} +function get_admin_tab_bar(cur_page_name) { +var tabs = []; +tabs.push( ['#Admin', 'Admin', 'lock.png'] ); +tabs.push( ['#TicketSearch/bugs', 'Bug Tracker', 'bug.png'] ); +tabs.push( ['#TicketSearch/helpdesk', 'Help Desk', 'telephone.png'] ); +tabs.push( ['#AdminReport', 'Reports', 'chart_pie.png'] ); +return tab_bar(tabs, cur_page_name); +} +function get_string(path, args) { +assert(window.config, "get_string() called before config loaded"); +if (!args) args = {}; +args.config = config; +args.session = session; +args.query = session.query; +var value = lookup_path(path, config.Strings); +return (typeof(value) == 'string') ? substitute(value, args) : value; +} +function normalize_dir_path(path) { +if (!path.match(/^\//)) path = '/' + path; +if (!path.match(/\/$/)) path += '/'; +return path; +} +function textedit_window_save(storage_key, filename, content, callback) { +if (!callback) callback = null; +effect_api_mod_touch('textedit'); +if (storage_key.match(/^\/games\/([a-z0-9][a-z0-9\-]*[a-z0-9])\/assets(.+)$/)) { +var game_id = RegExp.$1; +var path = RegExp.$2; +show_progress_dialog(1, "Saving file..."); +effect_api_send('asset_save_file_contents', { +GameID: game_id, +Path: path, +Filename: filename, +Content: content +}, 'textedit_window_save_finish', { _mode: 'asset', _game_id: game_id, _filename: filename, _callback: callback } ); +} +else { +show_progress_dialog(1, "Saving data..."); +effect_api_send('admin_save_file_contents', { +Path: storage_key, +Filename: filename, +Content: content +}, 'textedit_window_save_finish', { _mode: 'admin', _storage_key: storage_key, _filename: filename, _callback: callback } ); +} +} +function textedit_window_save_finish(response, tx) { +hide_progress_dialog(); +if (tx._mode == 'asset') { +do_message('success', "Saved asset: \""+tx._filename+"\""); +show_glog_widget(); +} +else { +do_message('success', "Saved data: \""+tx._storage_key+'/'+tx._filename+"\""); +} +if (tx._callback) tx._callback(); +} +function do_buy(args) { +$P().hide(); +$('d_page_loading').show(); +effect_api_send('create_order', args, 'do_buy_redirect', { _buy_args: args } ); +} +function do_buy_redirect(response, tx) { +var args = tx._buy_args; +$('fe_gco_title').value = args.Title || ''; +$('fe_gco_desc').value = args.Desc || ''; +$('fe_gco_price').value = args.Price || ''; +$('fe_gco_after').value = args.After || ''; +$('fe_gco_unique_id').value = response.OrderID; +Debug.trace('payment', "Redirecting to Google Checkout"); +setTimeout( function() { $('BB_BuyButtonForm').submit(); }, 1 ); +} +function show_glog_widget(game_id) { +if (!game_id) game_id = session.glog_game_id; +if (!game_id) { +$('glog_widget').hide(); +return; +} +if (game_id != session.glog_game_id) { +$('glog_widget').hide(); +session.glog_game_id = game_id; +update_glog_widget(game_id); +} +else { +$('glog_widget').show(); +setTimeout( function() { update_glog_widget(game_id); }, 500 ); +} +} +function update_glog_widget(game_id) { +effect_api_get('game_get_log', { +id: game_id, +offset: 0, +limit: 1, +rand: Math.random() +}, 'receive_glog_data', { _game_id: game_id }); +} +function receive_glog_data(response, tx) { +var game_id = tx._game_id; +if (response && response.Rows && response.Rows.Row) { +var rows = always_array( response.Rows.Row ); +var row = rows[0]; +var html = ''; +html += '
'; +html += '
Latest Game Activity
'; +html += ''; +html += ''; +html += '
'; +html += '
'; +html += ''; +html += ''; +html += ''; +html += '
' + get_buddy_icon_display(row.Username, 1, 0) + ''; +html += '
' + icon( get_icon_for_glog_type(row.Type), ''+row.Message+'' ) + '
'; +html += '
' + get_relative_date(row.Date, true) + '
'; +html += '
'; +$('glog_widget').innerHTML = html; +$('glog_widget').show(); +} +} +function show_glog_post_dialog(game_id) { +hide_popup_dialog(); +delete session.progress; +var html = ''; +html += '
'; +html += '"; + second_cell = ""; + row = $("").attr("id", "s" + index).attr("class", "location_row").html(first_cell + second_cell); + $locationsDiv.append(row); + } + if (index === this.numSearchToDisplay) { + $locationsDiv.append(""); + return $locationsDiv.append(""); + } + }, this); + return this.geocoder.geocode({ + address: address + }, __bind(function(result, status) { + if (status !== "OK") { + $('.error_message').html(t("Search Address Failed")).fadeIn(); + return; + } + _.each(result, showResults); + $("#search_results").html($locationsDiv); + this.locationChange("search"); + this.searchResults = result; + return this.displaySearchLoc(); + }, this)); + }; + ClientsRequestView.prototype.mouseoverLocation = function(e) { + var $el, id, marker; + $el = $(e.currentTarget); + id = $el.attr("id").substring(1); + marker = this.markers[id]; + return marker.setAnimation(google.maps.Animation.BOUNCE); + }; + ClientsRequestView.prototype.mouseoutLocation = function(e) { + var $el, id, marker; + $el = $(e.currentTarget); + id = $el.attr("id").substring(1); + marker = this.markers[id]; + return marker.setAnimation(null); + }; + ClientsRequestView.prototype.searchLocation = function(e) { + e.preventDefault(); + $("#address").val($(e.currentTarget).html()); + return this.searchAddress(); + }; + ClientsRequestView.prototype.favoriteClick = function(e) { + var index, location; + e.preventDefault(); + $(".favorites").attr("href", ""); + index = $(e.currentTarget).removeAttr("href").attr("id"); + location = new google.maps.LatLng(USER.locations[index].latitude, USER.locations[index].longitude); + return this.panToLocation(location); + }; + ClientsRequestView.prototype.clickLocation = function(e) { + var id; + id = $(e.currentTarget).attr("id").substring(1); + return this.panToLocation(this.markers[id].getPosition()); + }; + ClientsRequestView.prototype.panToLocation = function(location) { + this.map.panTo(location); + this.map.setZoom(16); + return this.pickup_icon.setPosition(location); + }; + ClientsRequestView.prototype.locationLinkHandle = function(e) { + var panelName; + e.preventDefault(); + panelName = $(e.currentTarget).attr("id"); + return this.locationChange(panelName); + }; + ClientsRequestView.prototype.locationChange = function(type) { + $(".locations_link").attr("href", "").css("font-weight", "normal"); + switch (type) { + case "favorite": + $(".search_results").attr("href", ""); + $(".locations_link#favorite").removeAttr("href").css("font-weight", "bold"); + $("#search_results").hide(); + $("#favorite_results").fadeIn(); + return this.displayFavLoc(); + case "search": + $(".favorites").attr("href", ""); + $(".locations_link#search").removeAttr("href").css("font-weight", "bold"); + $("#favorite_results").hide(); + $("#search_results").fadeIn(); + return this.displaySearchLoc(); + } + }; + ClientsRequestView.prototype.rateTrip = function(e) { + var rating; + rating = $(e.currentTarget).attr("id"); + $(".stars").attr("src", "/web/img/star_inactive.png"); + return _(rating).times(function(index) { + return $(".stars#" + (index + 1)).attr("src", "/web/img/star_active.png"); + }); + }; + ClientsRequestView.prototype.pickupHandle = function(e) { + var $el, callback, message; + e.preventDefault(); + $el = $(e.currentTarget).find("span"); + switch ($el.html()) { + case t("Request Pickup"): + _.delay(this.requestRide, 3000); + $("#status_message").html(t("Sending pickup request...")); + $el.html(t("Cancel Pickup")).parent().attr("class", "button_red"); + this.pickup_icon.setDraggable(false); + this.map.panTo(this.pickup_icon.getPosition()); + return this.map.setZoom(18); + case t("Cancel Pickup"): + if (this.status === "ready") { + $el.html(t("Request Pickup")).parent().attr("class", "button_green"); + return this.pickup_icon.setDraggable(true); + } else { + callback = __bind(function(v, m, f) { + if (v) { + this.AskDispatch("PickupCanceledClient"); + return this.setStatus("ready"); + } + }, this); + message = t("Cancel Request Prompt"); + if (this.status === "arriving") { + message = 'Cancel Request Arrived Prompt'; + } + return $.prompt(message, { + buttons: { + Ok: true, + Cancel: false + }, + callback: callback + }); + } + } + }; + ClientsRequestView.prototype.requestRide = function() { + if ($("#pickupHandle").find("span").html() === t("Cancel Pickup")) { + this.AskDispatch("Pickup"); + return this.setStatus("searching"); + } + }; + ClientsRequestView.prototype.removeCabs = function() { + _.each(this.cabs, __bind(function(point) { + return point.setMap(null); + }, this)); + return this.cabs = []; + }; + ClientsRequestView.prototype.addToFavLoc = function(e) { + var $el, lat, lng, nickname; + e.preventDefault(); + $el = $(e.currentTarget); + $el.find(".error_message").html(""); + nickname = $el.find("#favLocNickname").val().toString(); + lat = $el.find("#pickupLat").val().toString(); + lng = $el.find("#pickupLng").val().toString(); + if (nickname.length < 3) { + $el.find(".error_message").html(t("Favorite Location Nickname Length Error")); + return; + } + this.ShowSpinner("submit"); + return $.ajax({ + type: 'POST', + url: API + "/locations", + dataType: 'json', + data: { + token: USER.token, + nickname: nickname, + latitude: lat, + longitude: lng + }, + success: __bind(function(data, textStatus, jqXHR) { + return $el.html(t("Favorite Location Save Succeeded")); + }, this), + error: __bind(function(jqXHR, textStatus, errorThrown) { + return $el.find(".error_message").html(t("Favorite Location Save Failed")); + }, this), + complete: __bind(function(data) { + return this.HideSpinner(); + }, this) + }); + }; + ClientsRequestView.prototype.showFavLoc = function(e) { + $(e.currentTarget).fadeOut(); + return $("#favLoc_form").fadeIn(); + }; + ClientsRequestView.prototype.selectInputText = function(e) { + e.currentTarget.focus(); + return e.currentTarget.select(); + }; + ClientsRequestView.prototype.displayFavLoc = function() { + var alphabet, bounds; + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + this.removeMarkers(); + bounds = new google.maps.LatLngBounds(); + _.each(USER.locations, __bind(function(location, index) { + var marker; + marker = new google.maps.Marker({ + position: new google.maps.LatLng(location.latitude, location.longitude), + map: this.map, + title: t("Favorite Location Title", { + id: alphabet != null ? alphabet[index] : void 0 + }), + icon: "https://www.google.com/mapfiles/marker" + alphabet[index] + ".png" + }); + this.markers.push(marker); + bounds.extend(marker.getPosition()); + return google.maps.event.addListener(marker, 'click', __bind(function() { + return this.pickup_icon.setPosition(marker.getPosition()); + }, this)); + }, this)); + this.pickup_icon.setPosition(_.first(this.markers).getPosition()); + return this.map.fitBounds(bounds); + }; + ClientsRequestView.prototype.displaySearchLoc = function() { + var alphabet; + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + this.removeMarkers(); + return _.each(this.searchResults, __bind(function(result, index) { + var marker; + if (index < this.numSearchToDisplay) { + marker = new google.maps.Marker({ + position: result.geometry.location, + map: this.map, + title: t("Search Location Title", { + id: alphabet != null ? alphabet[index] : void 0 + }), + icon: "https://www.google.com/mapfiles/marker" + alphabet[index] + ".png" + }); + this.markers.push(marker); + return this.panToLocation(result.geometry.location); + } + }, this)); + }; + ClientsRequestView.prototype.removeMarkers = function() { + _.each(this.markers, __bind(function(marker) { + return marker.setMap(null); + }, this)); + return this.markers = []; + }; + ClientsRequestView.prototype.AskDispatch = function(ask, options) { + var attrs, lowestETA, processData, showCab; + if (ask == null) { + ask = ""; + } + if (options == null) { + options = {}; + } + switch (ask) { + case "NearestCab": + attrs = { + latitude: this.pickup_icon.getPosition().lat(), + longitude: this.pickup_icon.getPosition().lng() + }; + lowestETA = 99999; + showCab = __bind(function(cab) { + var point; + point = new google.maps.Marker({ + position: new google.maps.LatLng(cab.latitude, cab.longitude), + map: this.map, + icon: this.cabMarker, + title: t("ETA Message", { + minutes: app.helpers.FormatSeconds(cab != null ? cab.eta : void 0, true) + }) + }); + if (cab.eta < lowestETA) { + lowestETA = cab.eta; + } + return this.cabs.push(point); + }, this); + processData = __bind(function(data, textStatus, jqXHR) { + if (this.status === "ready") { + this.removeCabs(); + if (data.sorry) { + $("#status_message").html(data.sorry).fadeIn(); + } else { + _.each(data.driverLocations, showCab); + $("#status_message").html(t("Nearest Cab Message", { + minutes: app.helpers.FormatSeconds(lowestETA, true) + })).fadeIn(); + } + if (Backbone.history.fragment === "!/request") { + return _.delay(this.showCabs, this.pollInterval); + } + } + }, this); + return this.AjaxCall(ask, processData, attrs); + case "StatusClient": + processData = __bind(function(data, textStatus, jqXHR) { + var bounds, cabLocation, locationSaved, point, userLocation; + if (data.messageType === "OK") { + switch (data.status) { + case "completed": + this.removeCabs(); + this.setStatus("rate"); + return this.fetchTripDetails(data.tripID); + case "open": + return this.setStatus("ready"); + case "begintrip": + this.setStatus("riding"); + cabLocation = new google.maps.LatLng(data.latitude, data.longitude); + this.removeCabs(); + this.pickup_icon.setMap(null); + point = new google.maps.Marker({ + position: cabLocation, + map: this.map, + icon: this.cabMarker + }); + this.cabs.push(point); + this.map.panTo(point.getPosition()); + $("#rideName").html(data.driverName); + $("#ridePhone").html(data.driverMobile); + $("#ride_address_wrapper").hide(); + if (Backbone.history.fragment === "!/request") { + return _.delay(this.AskDispatch, this.pollInterval, "StatusClient"); + } + break; + case "pending": + this.setStatus("searching"); + if (Backbone.history.fragment === "!/request") { + return _.delay(this.AskDispatch, this.pollInterval, "StatusClient"); + } + break; + case "accepted": + case "arrived": + if (data.status === "accepted") { + this.setStatus("waiting"); + $("#status_message").html(t("Arrival ETA Message", { + minutes: app.helpers.FormatSeconds(data.eta, true) + })); + } else { + this.setStatus("arriving"); + $("#status_message").html(t("Arriving Now Message")); + } + userLocation = new google.maps.LatLng(data.pickupLocation.latitude, data.pickupLocation.longitude); + cabLocation = new google.maps.LatLng(data.latitude, data.longitude); + this.pickup_icon.setPosition(userLocation); + this.removeCabs(); + $("#rideName").html(data.driverName); + $("#ridePhone").html(data.driverMobile); + if ($("#rideAddress").html() === "") { + locationSaved = false; + _.each(USER.locations, __bind(function(location) { + if (parseFloat(location.latitude) === parseFloat(data.pickupLocation.latitude) && parseFloat(location.longitude) === parseFloat(data.pickupLocation.longitude)) { + return locationSaved = true; + } + }, this)); + if (locationSaved) { + $("#addToFavButton").hide(); + } + $("#pickupLat").val(data.pickupLocation.latitude); + $("#pickupLng").val(data.pickupLocation.longitude); + this.geocoder.geocode({ + location: userLocation + }, __bind(function(result, status) { + $("#rideAddress").html(result[0].formatted_address); + return $("#favLocNickname").val("" + result[0].address_components[0].short_name + " " + result[0].address_components[1].short_name); + }, this)); + } + point = new google.maps.Marker({ + position: cabLocation, + map: this.map, + icon: this.cabMarker + }); + this.cabs.push(point); + bounds = bounds = new google.maps.LatLngBounds(); + bounds.extend(cabLocation); + bounds.extend(userLocation); + this.map.fitBounds(bounds); + if (Backbone.history.fragment === "!/request") { + return _.delay(this.AskDispatch, this.pollInterval, "StatusClient"); + } + } + } + }, this); + return this.AjaxCall(ask, processData); + case "Pickup": + attrs = { + latitude: this.pickup_icon.getPosition().lat(), + longitude: this.pickup_icon.getPosition().lng() + }; + processData = __bind(function(data, textStatus, jqXHR) { + if (data.messageType === "Error") { + return $("#status_message").html(data.description); + } else { + return this.AskDispatch("StatusClient"); + } + }, this); + return this.AjaxCall(ask, processData, attrs); + case "PickupCanceledClient": + processData = __bind(function(data, textStatus, jqXHR) { + if (data.messageType === "OK") { + return this.setStatus("ready"); + } else { + return $("#status_message").html(data.description); + } + }, this); + return this.AjaxCall(ask, processData, attrs); + case "RatingDriver": + attrs = { + rating: options.rating + }; + processData = __bind(function(data, textStatus, jqXHR) { + if (data.messageType === "OK") { + this.setStatus("init"); + } else { + $("status_message").html(t("Rating Driver Failed")); + } + return this.HideSpinner(); + }, this); + return this.AjaxCall(ask, processData, attrs); + case "Feedback": + attrs = { + message: options.message + }; + processData = __bind(function(data, textStatus, jqXHR) { + if (data.messageType === "OK") { + return alert("rated"); + } + }, this); + return this.AjaxCall(ask, processData, attrs); + } + }; + ClientsRequestView.prototype.AjaxCall = function(type, successCallback, attrs) { + if (attrs == null) { + attrs = {}; + } + _.extend(attrs, { + token: USER.token, + messageType: type, + app: "client", + version: "1.0.60", + device: "web" + }); + return $.ajax({ + type: 'POST', + url: DISPATCH + "/", + processData: false, + data: JSON.stringify(attrs), + success: successCallback, + dataType: 'json', + error: __bind(function(jqXHR, textStatus, errorThrown) { + $("#status_message").html(errorThrown); + return this.HideSpinner(); + }, this) + }); + }; + return ClientsRequestView; + })(); +}).call(this); +}, "views/clients/settings": function(exports, require, module) {(function() { + var clientsSettingsTemplate; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsSettingsTemplate = require('templates/clients/settings'); + exports.ClientsSettingsView = (function() { + __extends(ClientsSettingsView, UberView); + function ClientsSettingsView() { + this.render = __bind(this.render, this); + this.initialize = __bind(this.initialize, this); + ClientsSettingsView.__super__.constructor.apply(this, arguments); + } + ClientsSettingsView.prototype.id = 'settings_view'; + ClientsSettingsView.prototype.className = 'view_container'; + ClientsSettingsView.prototype.events = { + 'submit #profile_pic_form': 'processPicUpload', + 'click #submit_pic': 'processPicUpload', + 'click a.setting_change': "changeTab", + 'submit #edit_info_form': "submitInfo", + 'click #change_password': 'changePass' + }; + ClientsSettingsView.prototype.divs = { + 'info_div': "Information", + 'pic_div': "Picture" + }; + ClientsSettingsView.prototype.pageTitle = t("Settings") + " | " + t("Uber"); + ClientsSettingsView.prototype.tabTitle = { + 'info_div': t("Information"), + 'pic_div': t("Picture") + }; + ClientsSettingsView.prototype.initialize = function() { + return this.mixin(require('web-lib/mixins/i18n_phone_form').i18nPhoneForm); + }; + ClientsSettingsView.prototype.render = function(type) { + if (type == null) { + type = "info"; + } + this.RefreshUserInfo(__bind(function() { + var $el, alphabet; + this.delegateEvents(); + this.HideSpinner(); + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + $el = $(this.el); + $(this.el).html(clientsSettingsTemplate({ + type: type + })); + $el.find("#" + type + "_div").show(); + $el.find("a[href='" + type + "_div']").parent().addClass("active"); + return document.title = "" + this.tabTitle[type + '_div'] + " " + this.pageTitle; + }, this)); + this.delegateEvents(); + return this; + }; + ClientsSettingsView.prototype.changeTab = function(e) { + var $eTarget, $el, div, link, pageDiv, _i, _j, _len, _len2, _ref, _ref2; + e.preventDefault(); + $eTarget = $(e.currentTarget); + this.ClearGlobalStatus(); + $el = $(this.el); + _ref = $el.find(".setting_change"); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + link = _ref[_i]; + $(link).parent().removeClass("active"); + } + $eTarget.parent().addClass("active"); + _ref2 = _.keys(this.divs); + for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) { + div = _ref2[_j]; + $el.find("#" + div).hide(); + } + pageDiv = $eTarget.attr('href'); + $el.find("#" + pageDiv).show(); + Backbone.history.navigate("!/settings/" + (this.divs[pageDiv].toLowerCase().replace(" ", "-")), false); + document.title = "" + this.tabTitle[pageDiv] + " " + this.pageTitle; + if (pageDiv === "loc_div") { + try { + google.maps.event.trigger(this.map, 'resize'); + return this.map.fitBounds(this.bounds); + } catch (_e) {} + } + }; + ClientsSettingsView.prototype.submitInfo = function(e) { + var $e, attrs, client, options; + $('#global_status').find('.success_message').text(''); + $('#global_status').find('.error_message').text(''); + $('.error_message').text(''); + e.preventDefault(); + $e = $(e.currentTarget); + attrs = $e.serializeToJson(); + attrs['mobile_country_id'] = this.$('#mobile_country_id').val(); + if (attrs['password'] === '') { + delete attrs['password']; + } + options = { + success: __bind(function(response) { + this.ShowSuccess(t("Information Update Succeeded")); + return this.RefreshUserInfo(); + }, this), + error: __bind(function(model, data) { + var errors; + if (data.status === 406) { + errors = JSON.parse(data.responseText); + return _.each(_.keys(errors), function(field) { + return $("#" + field).parent().find('span.error_message').text(errors[field]); + }); + } else { + return this.ShowError(t("Information Update Failed")); + } + }, this), + type: "PUT" + }; + client = new app.models.client({ + id: USER.id + }); + return client.save(attrs, options); + }; + ClientsSettingsView.prototype.changePass = function(e) { + e.preventDefault(); + $(e.currentTarget).hide(); + return $("#password").show(); + }; + ClientsSettingsView.prototype.processPicUpload = function(e) { + e.preventDefault(); + this.ShowSpinner("submit"); + return $.ajaxFileUpload({ + url: API + '/user_pictures', + secureuri: false, + fileElementId: 'picture', + data: { + token: USER.token + }, + dataType: 'json', + complete: __bind(function(data, status) { + this.HideSpinner(); + if (status === 'success') { + this.ShowSuccess(t("Picture Update Succeeded")); + return this.RefreshUserInfo(__bind(function() { + return $("#settingsProfPic").attr("src", USER.picture_url + ("?" + (Math.floor(Math.random() * 1000)))); + }, this)); + } else { + if (data.error) { + return this.ShowError(data.error); + } else { + return this.ShowError("Picture Update Failed"); + } + } + }, this) + }); + }; + return ClientsSettingsView; + })(); +}).call(this); +}, "views/clients/sign_up": function(exports, require, module) {(function() { + var clientsSignUpTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + clientsSignUpTemplate = require('templates/clients/sign_up'); + exports.ClientsSignUpView = (function() { + __extends(ClientsSignUpView, UberView); + function ClientsSignUpView() { + ClientsSignUpView.__super__.constructor.apply(this, arguments); + } + ClientsSignUpView.prototype.id = 'signup_view'; + ClientsSignUpView.prototype.className = 'view_container'; + ClientsSignUpView.prototype.initialize = function() { + this.mixin(require('web-lib/mixins/i18n_phone_form').i18nPhoneForm); + return $('#location_country').live('change', function() { + if (!$('#mobile').val()) { + return $('#mobile_country').find("option[value=" + ($(this).val()) + "]").attr('selected', 'selected').end().trigger('change'); + } + }); + }; + ClientsSignUpView.prototype.events = { + 'submit form': 'signup', + 'click button': 'signup', + 'change #card_number': 'showCardType', + 'change #location_country': 'countryChange' + }; + ClientsSignUpView.prototype.render = function(invite) { + this.HideSpinner(); + $(this.el).html(clientsSignUpTemplate({ + invite: invite + })); + return this; + }; + ClientsSignUpView.prototype.signup = function(e) { + var $el, attrs, client, error_messages, options; + e.preventDefault(); + $el = $("form"); + $el.find('#terms_error').hide(); + if (!$el.find('#signup_terms input[type=checkbox]').attr('checked')) { + $('#spinner.submit').hide(); + $el.find('#terms_error').show(); + return; + } + error_messages = $el.find('.error_message').html(""); + attrs = { + first_name: $el.find('#first_name').val(), + last_name: $el.find('#last_name').val(), + email: $el.find('#email').val(), + password: $el.find('#password').val(), + location_country: $el.find('#location_country option:selected').attr('data-iso2'), + location: $el.find('#location').val(), + language: $el.find('#language').val(), + mobile_country: $el.find('#mobile_country option:selected').attr('data-iso2'), + mobile: $el.find('#mobile').val(), + card_number: $el.find('#card_number').val(), + card_expiration_month: $el.find('#card_expiration_month').val(), + card_expiration_year: $el.find('#card_expiration_year').val(), + card_code: $el.find('#card_code').val(), + use_case: $el.find('#use_case').val(), + promotion_code: $el.find('#promotion_code').val() + }; + options = { + statusCode: { + 200: function(response) { + $.cookie('token', response.token); + amplify.store('USERjson', response); + app.refreshMenu(); + return app.routers.clients.navigate('!/dashboard', true); + }, + 406: function(e) { + var error, errors, _i, _len, _ref, _results; + errors = JSON.parse(e.responseText); + _ref = _.keys(errors); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + error = _ref[_i]; + _results.push($('#' + error).parent().find('span').html($('#' + error).parent().find('span').html() + " " + errors[error])); + } + return _results; + } + }, + complete: __bind(function(response) { + return this.HideSpinner(); + }, this) + }; + client = new app.models.client; + $('.spinner#submit').show(); + return client.save(attrs, options); + }; + ClientsSignUpView.prototype.countryChange = function(e) { + var $e; + $e = $(e.currentTarget); + return $("#mobile_country").val($e.val()).trigger('change'); + }; + ClientsSignUpView.prototype.showCardType = function(e) { + var $el, reAmerica, reDiscover, reMaster, reVisa, validCard; + reVisa = /^4\d{3}-?\d{4}-?\d{4}-?\d{4}$/; + reMaster = /^5[1-5]\d{2}-?\d{4}-?\d{4}-?\d{4}$/; + reAmerica = /^6011-?\d{4}-?\d{4}-?\d{4}$/; + reDiscover = /^3[4,7]\d{13}$/; + $el = $("#card_logos_signup"); + validCard = false; + if (e.currentTarget.value.match(reVisa)) { + $el.find("#overlay_left").css('width', "0px"); + return $el.find("#overlay_right").css('width', "75%"); + } else if (e.currentTarget.value.match(reMaster)) { + $el.find("#overlay_left").css('width', "25%"); + return $el.find("#overlay_right").css('width', "50%"); + } else if (e.currentTarget.value.match(reAmerica)) { + $el.find("#overlay_left").css('width', "75%"); + $el.find("#overlay_right").css('width', "0px"); + return console.log("amex"); + } else if (e.currentTarget.value.match(reDiscover)) { + $el.find("#overlay_left").css('width', "50%"); + return $el.find("#overlay_right").css('width', "25%"); + } else { + $el.find("#overlay_left").css('width', "0px"); + return $el.find("#overlay_right").css('width', "0px"); + } + }; + return ClientsSignUpView; + })(); +}).call(this); +}, "views/clients/trip_detail": function(exports, require, module) {(function() { + var clientsTripDetailTemplate; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsTripDetailTemplate = require('templates/clients/trip_detail'); + exports.TripDetailView = (function() { + __extends(TripDetailView, UberView); + function TripDetailView() { + this.resendReceipt = __bind(this.resendReceipt, this); + TripDetailView.__super__.constructor.apply(this, arguments); + } + TripDetailView.prototype.id = 'trip_detail_view'; + TripDetailView.prototype.className = 'view_container'; + TripDetailView.prototype.events = { + 'click a#fare_review': 'showFareReview', + 'click #fare_review_hide': 'hideFareReview', + 'submit #form_review_form': 'submitFareReview', + 'click #submit_fare_review': 'submitFareReview', + 'click .resendReceipt': 'resendReceipt' + }; + TripDetailView.prototype.render = function(id) { + if (id == null) { + id = 'invalid'; + } + this.ReadUserInfo(); + this.HideSpinner(); + this.model = new app.models.trip({ + id: id + }); + this.model.fetch({ + data: { + relationships: 'points,driver,city.country' + }, + dataType: 'json', + success: __bind(function() { + var trip; + trip = this.model; + $(this.el).html(clientsTripDetailTemplate({ + trip: trip + })); + this.RequireMaps(__bind(function() { + var bounds, endPos, map, myOptions, path, polyline, startPos; + bounds = new google.maps.LatLngBounds(); + path = []; + _.each(this.model.get('points'), __bind(function(point) { + path.push(new google.maps.LatLng(point.lat, point.lng)); + return bounds.extend(_.last(path)); + }, this)); + myOptions = { + zoom: 12, + center: path[0], + mapTypeId: google.maps.MapTypeId.ROADMAP, + zoomControl: false, + rotateControl: false, + panControl: false, + mapTypeControl: false, + scrollwheel: false + }; + map = new google.maps.Map(document.getElementById("trip_details_map"), myOptions); + map.fitBounds(bounds); + startPos = new google.maps.Marker({ + position: _.first(path), + map: map, + title: t("Trip started here"), + icon: 'https://uber-static.s3.amazonaws.com/marker_start.png' + }); + endPos = new google.maps.Marker({ + position: _.last(path), + map: map, + title: t("Trip ended here"), + icon: 'https://uber-static.s3.amazonaws.com/marker_end.png' + }); + startPos.setMap(map); + endPos.setMap(map); + polyline = new google.maps.Polyline({ + path: path, + strokeColor: '#003F87', + strokeOpacity: 1, + strokeWeight: 5 + }); + return polyline.setMap(map); + }, this)); + return this.HideSpinner(); + }, this) + }); + this.ShowSpinner('load'); + this.delegateEvents(); + return this; + }; + TripDetailView.prototype.showFareReview = function(e) { + e.preventDefault(); + $('#fare_review_box').slideDown(); + return $('#fare_review').hide(); + }; + TripDetailView.prototype.hideFareReview = function(e) { + e.preventDefault(); + $('#fare_review_box').slideUp(); + return $('#fare_review').show(); + }; + TripDetailView.prototype.submitFareReview = function(e) { + var attrs, errorMessage, id, options; + e.preventDefault(); + errorMessage = $(".error_message"); + errorMessage.hide(); + id = $("#tripid").val(); + this.model = new app.models.trip({ + id: id + }); + attrs = { + note: $('#form_review_message').val(), + note_type: 'client_fare_review' + }; + options = { + success: __bind(function(response) { + $(".success_message").fadeIn(); + return $("#fare_review_form_wrapper").slideUp(); + }, this), + error: __bind(function(error) { + return errorMessage.fadeIn(); + }, this) + }; + return this.model.save(attrs, options); + }; + TripDetailView.prototype.resendReceipt = function(e) { + var $e; + e.preventDefault(); + $e = $(e.currentTarget); + this.$(".resendReceiptSuccess").empty().show(); + this.$(".resentReceiptError").empty().show(); + e.preventDefault(); + $('#spinner').show(); + return $.ajax('/api/trips/func/resend_receipt', { + data: { + token: $.cookie('token'), + trip_id: this.model.id + }, + type: 'POST', + complete: __bind(function(xhr) { + var response; + response = JSON.parse(xhr.responseText); + $('#spinner').hide(); + switch (xhr.status) { + case 200: + this.$(".resendReceiptSuccess").html("Receipt has been emailed"); + return this.$(".resendReceiptSuccess").fadeOut(2000); + default: + this.$(".resendReceiptError").html("Receipt has failed to be emailed"); + return this.$(".resendReceiptError").fadeOut(2000); + } + }, this) + }); + }; + return TripDetailView; + })(); +}).call(this); +}, "views/shared/menu": function(exports, require, module) {(function() { + var menuTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + menuTemplate = require('templates/shared/menu'); + exports.SharedMenuView = (function() { + __extends(SharedMenuView, Backbone.View); + function SharedMenuView() { + SharedMenuView.__super__.constructor.apply(this, arguments); + } + SharedMenuView.prototype.id = 'menu_view'; + SharedMenuView.prototype.render = function() { + var type; + if ($.cookie('token') === null) { + type = 'guest'; + } else { + type = 'client'; + } + $(this.el).html(menuTemplate({ + type: type + })); + return this; + }; + return SharedMenuView; + })(); +}).call(this); +}, "web-lib/collections/countries": function(exports, require, module) {(function() { + var UberCollection; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + UberCollection = require('web-lib/uber_collection').UberCollection; + exports.CountriesCollection = (function() { + __extends(CountriesCollection, UberCollection); + function CountriesCollection() { + CountriesCollection.__super__.constructor.apply(this, arguments); + } + CountriesCollection.prototype.model = app.models.country; + CountriesCollection.prototype.url = '/countries'; + return CountriesCollection; + })(); +}).call(this); +}, "web-lib/collections/vehicle_types": function(exports, require, module) {(function() { + var UberCollection, vehicleType, _ref; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + UberCollection = require('web-lib/uber_collection').UberCollection; + vehicleType = (typeof app !== "undefined" && app !== null ? (_ref = app.models) != null ? _ref.vehicleType : void 0 : void 0) || require('models/vehicle_type').VehicleType; + exports.VehicleTypesCollection = (function() { + __extends(VehicleTypesCollection, UberCollection); + function VehicleTypesCollection() { + VehicleTypesCollection.__super__.constructor.apply(this, arguments); + } + VehicleTypesCollection.prototype.model = vehicleType; + VehicleTypesCollection.prototype.url = '/vehicle_types'; + VehicleTypesCollection.prototype.defaultColumns = ['id', 'created_at', 'updated_at', 'deleted_at', 'created_by_user_id', 'updated_by_user_id', 'city_id', 'type', 'make', 'model', 'capacity', 'minimum_year', 'actions']; + VehicleTypesCollection.prototype.tableColumns = function(cols) { + var actions, c, capacity, city_id, columnValues, created_at, created_by_user_id, deleted_at, headerRow, id, make, minimum_year, model, type, updated_at, updated_by_user_id, _i, _len; + id = { + sTitle: 'Id' + }; + created_at = { + sTitle: 'Created At (UTC)', + 'sType': 'string' + }; + updated_at = { + sTitle: 'Updated At (UTC)', + 'sType': 'string' + }; + deleted_at = { + sTitle: 'Deleted At (UTC)', + 'sType': 'string' + }; + created_by_user_id = { + sTitle: 'Created By' + }; + updated_by_user_id = { + sTitle: 'Updated By' + }; + city_id = { + sTitle: 'City' + }; + type = { + sTitle: 'Type' + }; + make = { + sTitle: 'Make' + }; + model = { + sTitle: 'Model' + }; + capacity = { + sTitle: 'Capacity' + }; + minimum_year = { + sTitle: 'Min. Year' + }; + actions = { + sTitle: 'Actions' + }; + columnValues = { + id: id, + created_at: created_at, + updated_at: updated_at, + deleted_at: deleted_at, + created_by_user_id: created_by_user_id, + updated_by_user_id: updated_by_user_id, + city_id: city_id, + type: type, + make: make, + model: model, + capacity: capacity, + minimum_year: minimum_year, + actions: actions + }; + headerRow = []; + for (_i = 0, _len = cols.length; _i < _len; _i++) { + c = cols[_i]; + if (columnValues[c]) { + headerRow.push(columnValues[c]); + } + } + return headerRow; + }; + return VehicleTypesCollection; + })(); +}).call(this); +}, "web-lib/helpers": function(exports, require, module) {(function() { + var __indexOf = Array.prototype.indexOf || function(item) { + for (var i = 0, l = this.length; i < l; i++) { + if (this[i] === item) return i; + } + return -1; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + exports.helpers = { + pin: function(num, color) { + if (color == null) { + color = 'FF0000'; + } + return ""; + }, + reverseGeocode: function(latitude, longitude) { + if (latitude && longitude) { + return "" + latitude + ", " + longitude + ""; + } else { + return ''; + } + }, + linkedName: function(model) { + var first_name, id, last_name, role, url; + role = model.role || model.get('role'); + id = model.id || model.get('id'); + first_name = model.first_name || model.get('first_name'); + last_name = model.last_name || model.get('last_name'); + url = "/" + role + "s/" + id; + return "" + first_name + " " + last_name + ""; + }, + linkedVehicle: function(vehicle, vehicleType) { + return " " + (vehicleType != null ? vehicleType.get('make') : void 0) + " " + (vehicleType != null ? vehicleType.get('model') : void 0) + " " + (vehicle.get('year')) + " "; + }, + linkedUserId: function(userType, userId) { + return "" + userType + " " + userId + ""; + }, + timeDelta: function(start, end) { + var delta; + if (typeof start === 'string') { + start = this.parseDate(start); + } + if (typeof end === 'string') { + end = this.parseDate(end); + } + if (end && start) { + delta = end.getTime() - start.getTime(); + return this.formatSeconds(delta / 1000); + } else { + return '00:00'; + } + }, + formatSeconds: function(s) { + var minutes, seconds; + s = Math.floor(s); + minutes = Math.floor(s / 60); + seconds = s - minutes * 60; + return "" + (this.leadingZero(minutes)) + ":" + (this.leadingZero(seconds)); + }, + formatCurrency: function(strValue, reverseSign, currency) { + var currency_locale, lc, mf; + if (reverseSign == null) { + reverseSign = false; + } + if (currency == null) { + currency = null; + } + strValue = String(strValue); + if (reverseSign) { + strValue = ~strValue.indexOf('-') ? strValue.split('-').join('') : ['-', strValue].join(''); + } + currency_locale = i18n.currencyToLocale[currency]; + try { + if (!(currency_locale != null) || currency_locale === i18n.locale) { + return i18n.jsworld.mf.format(strValue); + } else { + lc = new jsworld.Locale(POSIX_LC[currency_locale]); + mf = new jsworld.MonetaryFormatter(lc); + return mf.format(strValue); + } + } catch (error) { + i18n.log(error); + return strValue; + } + }, + formatTripFare: function(trip, type) { + var _ref, _ref2; + if (type == null) { + type = "fare"; + } + if (!trip.get('fare')) { + return 'n/a'; + } + if (((_ref = trip.get('fare_breakdown_local')) != null ? _ref.currency : void 0) != null) { + return app.helpers.formatCurrency(trip.get("" + type + "_local"), false, (_ref2 = trip.get('fare_breakdown_local')) != null ? _ref2.currency : void 0); + } else if (trip.get("" + type + "_string") != null) { + return trip.get("" + type + "_string"); + } else if (trip.get("" + type + "_local") != null) { + return trip.get("" + type + "_local"); + } else { + return 'n/a'; + } + }, + formatPhoneNumber: function(phoneNumber, countryCode) { + if (countryCode == null) { + countryCode = "+1"; + } + if (phoneNumber != null) { + phoneNumber = String(phoneNumber); + switch (countryCode) { + case '+1': + return countryCode + ' ' + phoneNumber.substring(0, 3) + '-' + phoneNumber.substring(3, 6) + '-' + phoneNumber.substring(6, 10); + case '+33': + return countryCode + ' ' + phoneNumber.substring(0, 1) + ' ' + phoneNumber.substring(1, 3) + ' ' + phoneNumber.substring(3, 5) + ' ' + phoneNumber.substring(5, 7) + ' ' + phoneNumber.substring(7, 9); + default: + countryCode + phoneNumber; + } + } + return "" + countryCode + " " + phoneNumber; + }, + parseDate: function(d, cityTime, tz) { + var city_filter, parsed, _ref; + if (cityTime == null) { + cityTime = true; + } + if (tz == null) { + tz = null; + } + if (((_ref = !d.substr(-6, 1)) === '+' || _ref === '-') || d.length === 19) { + d += '+00:00'; + } + if (/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})/.test(d)) { + parsed = d.match(/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/); + d = new Date(); + d.setUTCFullYear(parsed[1]); + d.setUTCMonth(parsed[2] - 1); + d.setUTCDate(parsed[3]); + d.setUTCHours(parsed[4]); + d.setUTCMinutes(parsed[5]); + d.setUTCSeconds(parsed[6]); + } else { + d = Date.parse(d); + } + if (typeof d === 'number') { + d = new Date(d); + } + d = new timezoneJS.Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), 'Etc/UTC'); + if (tz) { + d.convertToTimezone(tz); + } else if (cityTime) { + city_filter = $.cookie('city_filter'); + if (city_filter) { + tz = $("#city_filter option[value=" + city_filter + "]").attr('data-timezone'); + if (tz) { + d.convertToTimezone(tz); + } + } + } + return d; + }, + dateToTimezone: function(d) { + var city_filter, tz; + d = new timezoneJS.Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), 'Etc/UTC'); + city_filter = $.cookie('city_filter'); + if (city_filter) { + tz = $("#city_filter option[value=" + city_filter + "]").attr('data-timezone'); + d.convertToTimezone(tz); + } + return d; + }, + fixAMPM: function(d, formatted) { + if (d.hours >= 12) { + return formatted.replace(/\b[AP]M\b/, 'PM'); + } else { + return formatted.replace(/\b[AP]M\b/, 'AM'); + } + }, + formatDate: function(d, time, timezone) { + var formatted; + if (time == null) { + time = true; + } + if (timezone == null) { + timezone = null; + } + d = this.parseDate(d, true, timezone); + formatted = time ? ("" + (i18n.jsworld.dtf.formatDate(d)) + " ") + this.formatTime(d, d.getTimezoneInfo()) : i18n.jsworld.dtf.formatDate(d); + return this.fixAMPM(d, formatted); + }, + formatDateLong: function(d, time, timezone) { + if (time == null) { + time = true; + } + if (timezone == null) { + timezone = null; + } + d = this.parseDate(d, true, timezone); + timezone = d.getTimezoneInfo().tzAbbr; + if (time) { + return (i18n.jsworld.dtf.formatDateTime(d)) + (" " + timezone); + } else { + return i18n.jsworld.dtf.formatDate(d); + } + }, + formatTimezoneJSDate: function(d) { + var day, hours, jsDate, minutes, month, year; + year = d.getFullYear(); + month = this.leadingZero(d.getMonth()); + day = this.leadingZero(d.getDate()); + hours = this.leadingZero(d.getHours()); + minutes = this.leadingZero(d.getMinutes()); + jsDate = new Date(year, month, day, hours, minutes, 0); + return jsDate.toDateString(); + }, + formatTime: function(d, timezone) { + var formatted; + if (timezone == null) { + timezone = null; + } + formatted = ("" + (i18n.jsworld.dtf.formatTime(d))) + (timezone != null ? " " + (timezone != null ? timezone.tzAbbr : void 0) : ""); + return this.fixAMPM(d, formatted); + }, + formatISODate: function(d) { + var pad; + pad = function(n) { + if (n < 10) { + return '0' + n; + } + return n; + }; + return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + 'Z'; + }, + formatExpDate: function(d) { + var month, year; + d = this.parseDate(d); + year = d.getFullYear(); + month = this.leadingZero(d.getMonth() + 1); + return "" + year + "-" + month; + }, + formatLatLng: function(lat, lng, precision) { + if (precision == null) { + precision = 8; + } + return parseFloat(lat).toFixed(precision) + ',' + parseFloat(lng).toFixed(precision); + }, + leadingZero: function(num) { + if (num < 10) { + return "0" + num; + } else { + return num; + } + }, + roundNumber: function(num, dec) { + return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec); + }, + notesToHTML: function(notes) { + var i, note, notesHTML, _i, _len; + notesHTML = ''; + i = 1; + if (notes) { + for (_i = 0, _len = notes.length; _i < _len; _i++) { + note = notes[_i]; + notesHTML += "" + note['userid'] + "     " + (this.formatDate(note['created_at'])) + "

" + note['note'] + "

"; + notesHTML += "
"; + } + } + return notesHTML.replace("'", '"e'); + }, + formatPhone: function(n) { + var parts, phone, regexObj; + n = "" + n; + regexObj = /^(?:\+?1[-. ]?)?(?:\(?([0-9]{3})\)?[-. ]?)?([0-9]{3})[-. ]?([0-9]{4})$/; + if (regexObj.test(n)) { + parts = n.match(regexObj); + phone = ""; + if (parts[1]) { + phone += "(" + parts[1] + ") "; + } + phone += "" + parts[2] + "-" + parts[3]; + } else { + phone = n; + } + return phone; + }, + usStates: ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'District of Columbia', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Carolina', 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming'], + onboardingPages: ['applied', 'ready_to_interview', 'pending_interview', 'interviewed', 'accepted', 'ready_to_onboard', 'pending_onboarding', 'active', 'waitlisted', 'rejected'], + driverBreadCrumb: function(loc, model) { + var onboardingPage, out, _i, _len, _ref; + out = "Drivers > "; + if (!(model != null)) { + out += ""; + } else { + out += "" + (this.onboardingUrlToName(model.get('driver_status'))) + ""; + out += " > " + (this.linkedName(model)) + " (" + (model.get('role')) + ") #" + (model.get('id')); + } + return out; + }, + onboardingUrlToName: function(url) { + return url != null ? url.replace(/_/g, " ").replace(/(^|\s)([a-z])/g, function(m, p1, p2) { + return p1 + p2.toUpperCase(); + }) : void 0; + }, + formatVehicle: function(vehicle) { + if (vehicle.get('make') && vehicle.get('model') && vehicle.get('license_plate')) { + return "" + (vehicle.get('make')) + " " + (vehicle.get('model')) + " (" + (vehicle.get('license_plate')) + ")"; + } + }, + docArbitraryFields: function(docName, cityDocs) { + var doc, field, out, _i, _j, _len, _len2, _ref; + out = ""; + for (_i = 0, _len = cityDocs.length; _i < _len; _i++) { + doc = cityDocs[_i]; + if (doc.name === docName && __indexOf.call(_.keys(doc), "metaFields") >= 0) { + _ref = doc.metaFields; + for (_j = 0, _len2 = _ref.length; _j < _len2; _j++) { + field = _ref[_j]; + out += "" + field.label + ":
"; + } + } + } + return out; + }, + capitaliseFirstLetter: function(string) { + return string.charAt(0).toUpperCase() + string.slice(1); + }, + createDocUploadForm: function(docName, driverId, vehicleId, cityMeta, vehicleName, expirationRequired) { + var ddocs, expDropdowns, pdocs, vdocs; + if (driverId == null) { + driverId = "None"; + } + if (vehicleId == null) { + vehicleId = "None"; + } + if (cityMeta == null) { + cityMeta = []; + } + if (vehicleName == null) { + vehicleName = false; + } + if (expirationRequired == null) { + expirationRequired = false; + } + ddocs = cityMeta["driverRequiredDocs"] || []; + pdocs = cityMeta["partnerRequiredDocs"] || []; + vdocs = cityMeta["vehicleRequiredDocs"] || []; + expDropdowns = "Expiration Date:\n -\n"; + return " \n
\n \n \n \n\n
\n " + (vehicleName ? vehicleName : "") + " " + docName + "\n
\n\n
\n \n
\n\n
\n " + (expirationRequired ? expDropdowns : "") + "\n
\n\n
\n " + (app.helpers.docArbitraryFields(docName, _.union(ddocs, pdocs, vdocs))) + "\n
\n\n
\n \n
\n\n
\n"; + }, + countrySelector: function(name, options) { + var countries, countryCodePrefix, defaultOptions; + if (options == null) { + options = {}; + } + defaultOptions = { + selectedKey: 'telephone_code', + selectedValue: '+1', + silent: false + }; + _.extend(defaultOptions, options); + options = defaultOptions; + countries = new app.collections.countries(); + countries.fetch({ + data: { + limit: 300 + }, + success: function(countries) { + var $option, $select, country, selected, _i, _len, _ref; + selected = false; + _ref = countries.models || []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + country = _ref[_i]; + $select = $("select[name=" + name + "]"); + $option = $('').val(country.id).attr('data-iso2', country.get('iso2')).attr('data-prefix', country.get('telephone_code')).html(country.get('name')); + if (country.get(options.selectedKey) === options.selectedValue && !selected) { + selected = true; + $option.attr('selected', 'selected'); + } + $select.append($option); + } + if (selected && !options.silent) { + return $select.val(options.selected).trigger('change'); + } + } + }); + countryCodePrefix = options.countryCodePrefix ? "data-country-code-prefix='" + options.countryCodePrefix + "'" : ''; + return ""; + }, + missingDocsOnDriver: function(driver) { + var city, docsReq, documents, partnerDocs; + city = driver.get('city'); + documents = driver.get('documents'); + if ((city != null) && (documents != null)) { + docsReq = _.pluck(city != null ? city.get('meta')["driverRequiredDocs"] : void 0, "name"); + if (driver.get('role') === "partner") { + partnerDocs = _.pluck(city != null ? city.get('meta')["partnerRequiredDocs"] : void 0, "name"); + docsReq = _.union(docsReq, partnerDocs); + } + return _.reject(docsReq, __bind(function(doc) { + return __indexOf.call((documents != null ? documents.pluck("name") : void 0) || [], doc) >= 0; + }, this)); + } else { + return []; + } + } + }; +}).call(this); +}, "web-lib/i18n": function(exports, require, module) {(function() { + exports.i18n = { + defaultLocale: 'en_US', + cookieName: '_LOCALE_', + locales: { + 'en_US': "English (US)", + 'fr_FR': "Français" + }, + currencyToLocale: { + 'USD': 'en_US', + 'EUR': 'fr_FR' + }, + logglyKey: 'd2d5a9bc-7ebe-4538-a180-81e62c705b1b', + logglyHost: 'https://logs.loggly.com', + init: function() { + this.castor = new window.loggly({ + url: this.logglyHost + '/inputs/' + this.logglyKey + '?rt=1', + level: 'error' + }); + this.setLocale($.cookie(this.cookieName) || this.defaultLocale); + window.t = _.bind(this.t, this); + this.loadLocaleTranslations(this.locale); + if (!(this[this.defaultLocale] != null)) { + return this.loadLocaleTranslations(this.defaultLocale); + } + }, + loadLocaleTranslations: function(locale) { + var loadPaths, path, _i, _len, _results; + loadPaths = ['web-lib/translations/' + locale, 'web-lib/translations/' + locale.slice(0, 2), 'translations/' + locale, 'translations/' + locale.slice(0, 2)]; + _results = []; + for (_i = 0, _len = loadPaths.length; _i < _len; _i++) { + path = loadPaths[_i]; + locale = path.substring(path.lastIndexOf('/') + 1); + if (this[locale] == null) { + this[locale] = {}; + } + _results.push((function() { + try { + return _.extend(this[locale], require(path).translations); + } catch (error) { + + } + }).call(this)); + } + return _results; + }, + getLocale: function() { + return this.locale; + }, + setLocale: function(locale) { + var message, parts, _ref; + parts = locale.split('_'); + this.locale = parts[0].toLowerCase(); + if (parts.length > 1) { + this.locale += "_" + (parts[1].toUpperCase()); + } + if (this.locale) { + $.cookie(this.cookieName, this.locale, { + path: '/', + domain: '.uber.com' + }); + } + try { + ((_ref = this.jsworld) != null ? _ref : this.jsworld = {}).lc = new jsworld.Locale(POSIX_LC[this.locale]); + this.jsworld.mf = new jsworld.MonetaryFormatter(this.jsworld.lc); + this.jsworld.nf = new jsworld.NumericFormatter(this.jsworld.lc); + this.jsworld.dtf = new jsworld.DateTimeFormatter(this.jsworld.lc); + this.jsworld.np = new jsworld.NumericParser(this.jsworld.lc); + this.jsworld.mp = new jsworld.MonetaryParser(this.jsworld.lc); + return this.jsworld.dtp = new jsworld.DateTimeParser(this.jsworld.lc); + } catch (error) { + message = 'JsWorld error with locale: ' + this.locale; + return this.log({ + message: message, + error: error + }); + } + }, + getTemplate: function(id) { + var _ref, _ref2; + return ((_ref = this[this.locale]) != null ? _ref[id] : void 0) || ((_ref2 = this[this.locale.slice(0, 2)]) != null ? _ref2[id] : void 0); + }, + getTemplateDefault: function(id) { + var _ref, _ref2; + return ((_ref = this[this.defaultLocale]) != null ? _ref[id] : void 0) || ((_ref2 = this[this.defaultLocale.slice(0, 2)]) != null ? _ref2[id] : void 0); + }, + getTemplateOrDefault: function(id) { + return this.getTemplate(id) || this.getTemplateDefault(id); + }, + t: function(id, vars) { + var errStr, locale, template; + if (vars == null) { + vars = {}; + } + locale = this.getLocale(); + template = this.getTemplate(id); + if (template == null) { + if (/dev|test/.test(window.location.host)) { + template = "(?) " + id; + } else { + template = this.getTemplateDefault(id); + } + errStr = "Missing [" + locale + "] translation for [" + id + "] at [" + window.location.hash + "] - Default template is [" + template + "]"; + this.log({ + error: errStr, + locale: locale, + id: id, + defaultTemplate: template + }); + } + if (template) { + return _.template(template, vars); + } else { + return id; + } + }, + log: function(error) { + if (/dev/.test(window.location.host)) { + if ((typeof console !== "undefined" && console !== null ? console.log : void 0) != null) { + return console.log(error); + } + } else { + _.extend(error, { + host: window.location.host, + hash: window.location.hash + }); + return this.castor.error(JSON.stringify(error)); + } + } + }; +}).call(this); +}, "web-lib/mixins/i18n_phone_form": function(exports, require, module) {(function() { + exports.i18nPhoneForm = { + _events: { + 'change select[data-country-code-prefix]': 'setCountryCodePrefix' + }, + setCountryCodePrefix: function(e) { + var $el, prefix; + $el = $(e.currentTarget); + prefix = $el.find('option:selected').attr('data-prefix'); + return $("#" + ($el.attr('data-country-code-prefix'))).text(prefix); + } + }; +}).call(this); +}, "web-lib/models/country": function(exports, require, module) {(function() { + var UberModel; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + UberModel = require('web-lib/uber_model').UberModel; + exports.Country = (function() { + __extends(Country, UberModel); + function Country() { + Country.__super__.constructor.apply(this, arguments); + } + Country.prototype.url = function() { + if (this.id) { + return "/countries/" + this.id; + } else { + return '/countries'; + } + }; + return Country; + })(); +}).call(this); +}, "web-lib/models/vehicle_type": function(exports, require, module) {(function() { + var UberModel; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + UberModel = require('web-lib/uber_model').UberModel; + exports.VehicleType = (function() { + __extends(VehicleType, UberModel); + function VehicleType() { + this.toString = __bind(this.toString, this); + VehicleType.__super__.constructor.apply(this, arguments); + } + VehicleType.prototype.endpoint = 'vehicle_types'; + VehicleType.prototype.toTableRow = function(cols) { + var actions, c, capacity, city_id, columnValues, created_at, created_by_user_id, deleted_at, id, make, minimum_year, model, rows, type, updated_at, updated_by_user_id, _i, _len, _ref; + id = "" + (this.get('id')) + ""; + if (this.get('created_at')) { + created_at = app.helpers.formatDate(this.get('created_at')); + } + if (this.get('updated_at')) { + updated_at = app.helpers.formatDate(this.get('updated_at')); + } + if (this.get('deleted_at')) { + deleted_at = app.helpers.formatDate(this.get('deleted_at')); + } + created_by_user_id = "" + (this.get('created_by_user_id')) + ""; + updated_by_user_id = "" + (this.get('updated_by_user_id')) + ""; + city_id = (_ref = this.get('city')) != null ? _ref.get('display_name') : void 0; + type = this.get('type'); + make = this.get('make'); + model = this.get('model'); + capacity = this.get('capacity'); + minimum_year = this.get('minimum_year'); + actions = "Show"; + if (!this.get('deleted_at')) { + actions += " Edit"; + actions += " Delete"; + } + columnValues = { + id: id, + created_at: created_at, + updated_at: updated_at, + deleted_at: deleted_at, + created_by_user_id: created_by_user_id, + updated_by_user_id: updated_by_user_id, + city_id: city_id, + type: type, + make: make, + model: model, + capacity: capacity, + minimum_year: minimum_year, + actions: actions + }; + rows = []; + for (_i = 0, _len = cols.length; _i < _len; _i++) { + c = cols[_i]; + rows.push(columnValues[c] ? columnValues[c] : '-'); + } + return rows; + }; + VehicleType.prototype.toString = function() { + return this.get('make') + ' ' + this.get('model') + ' ' + this.get('type') + (" (" + (this.get('capacity')) + ")"); + }; + return VehicleType; + })(); +}).call(this); +}, "web-lib/templates/footer": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + var locale, title, _ref; + __out.push('\n\n\n\n\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "web-lib/translations/en": function(exports, require, module) {(function() { + exports.translations = { + "Info": "Info", + "Learn More": "Learn More", + "Pricing": "Pricing", + "FAQ": "FAQ", + "Support": "Support", + "Support & FAQ": "Support & FAQ", + "Contact Us": "Contact Us", + "Jobs": "Jobs", + "Phones": "Phones", + "Text Message": "Text Message", + "iPhone": "iPhone", + "Android": "Android", + "Drivers": "Drivers", + "Apply": "Apply", + "Sign In": "Sign In", + "Social": "Social", + "Twitter": "Twitter", + "Facebook": "Facebook", + "Blog": "Blog", + "Legal": "Legal", + "Company_Footer": "Company", + "Privacy Policy": "Privacy Policy", + "Terms": "Terms", + "Copyright © Uber Technologies, Inc.": "Copyright © Uber Technologies, Inc.", + "Language:": "Language:", + "Apply to Drive": "Apply to Drive", + "Expiration": "Expiration", + "Fare": "Fare", + "Driver": "Driver ", + "Dashboard": "Dashboard", + "Forgot Password": "Forgot Password", + "Trip Details": "Trip Details", + "Save": "Save", + "Cancel": "Cancel", + "Edit": "Edit", + "Password": "Password", + "First Name": "First Name", + "Last Name": "Last Name", + "Email Address": "Email Address", + "Submit": "Submit", + "Mobile Number": "Mobile Number", + "Zip Code": "Zip Code", + "Sign Out": "Sign Out", + "Confirm Email Message": "Attempting to confirm email...", + "Upload": "Upload", + "Rating": "Rating", + "Pickup Time": "Pickup Time", + "2011": "2011", + "2012": "2012", + "2013": "2013", + "2014": "2014", + "2015": "2015", + "2016": "2016", + "2017": "2017", + "2018": "2018", + "2019": "2019", + "2020": "2020", + "2021": "2021", + "2022": "2022", + "01": "01", + "02": "02", + "03": "03", + "04": "04", + "05": "05", + "06": "06", + "07": "07", + "08": "08", + "09": "09", + "10": "10", + "11": "11", + "12": "12" + }; +}).call(this); +}, "web-lib/translations/fr": function(exports, require, module) {(function() { + exports.translations = { + "Info": "Info", + "Learn More": "En Savoir Plus", + "Pricing": "Calcul du Prix", + "Support & FAQ": "Aide & FAQ", + "Contact Us": "Contactez Nous", + "Jobs": "Emplois", + "Phones": "Téléphones", + "Text Message": "SMS", + "iPhone": "iPhone", + "Android": "Android", + "Apply to Drive": "Candidature Chauffeur", + "Sign In": "Connexion", + "Social": "Contact", + "Twitter": "Twitter", + "Facebook": "Facebook", + "Blog": "Blog", + "Privacy Policy": "Protection des Données Personelles", + "Terms": "Conditions Générales", + "Copyright © Uber Technologies, Inc.": "© Uber, Inc.", + "Language:": "Langue:", + "Forgot Password": "Mot de passe oublié", + "Company_Footer": "À Propos d'Uber", + "Expiration": "Expiration", + "Fare": "Tarif", + "Driver": "Chauffeur", + "Drivers": "Chauffeurs", + "Dashboard": "Tableau de bord", + "Forgot Password": "Mot de passe oublié", + "Forgot Password?": "Mot de passe oublié?", + "Trip Details": "Détails de la course", + "Save": "Enregistrer", + "Cancel": "Annuler", + "Edit": "Modifier", + "Password": "Mot de passe", + "First Name": "Prénom", + "Last Name": "Nom", + "Email Address": "E-mail", + "Submit": "Soumettre", + "Mobile Number": "Téléphone Portable", + "Zip Code": "Code Postal", + "Sign Out": "Se déconnecter", + "Confirm Email Message": "E-mail de confirmation", + "Upload": "Télécharger", + "Rating": "Notation", + "Pickup Time": "Heure de prise en charge", + "2011": "2011", + "2012": "2012", + "2013": "2013", + "2014": "2014", + "2015": "2015", + "2016": "2016", + "2017": "2017", + "2018": "2018", + "2019": "2019", + "2020": "2020", + "2021": "2021", + "2022": "2022", + "01": "01", + "02": "02", + "03": "03", + "04": "04", + "05": "05", + "06": "06", + "07": "07", + "08": "08", + "09": "09", + "10": "10", + "11": "11", + "12": "12" + }; +}).call(this); +}, "web-lib/uber_collection": function(exports, require, module) {(function() { + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + exports.UberCollection = (function() { + __extends(UberCollection, Backbone.Collection); + function UberCollection() { + UberCollection.__super__.constructor.apply(this, arguments); + } + UberCollection.prototype.parse = function(data) { + var model, tmp, _i, _in, _len, _out; + _in = data.resources || data; + _out = []; + if (data.meta) { + this.meta = data.meta; + } + for (_i = 0, _len = _in.length; _i < _len; _i++) { + model = _in[_i]; + tmp = new this.model; + tmp.set(tmp.parse(model)); + _out.push(tmp); + } + return _out; + }; + UberCollection.prototype.isRenderable = function() { + if (this.models.length) { + return true; + } + }; + UberCollection.prototype.toTableRows = function(cols) { + var tableRows; + tableRows = []; + _.each(this.models, function(model) { + return tableRows.push(model.toTableRow(cols)); + }); + return tableRows; + }; + return UberCollection; + })(); +}).call(this); +}, "web-lib/uber_model": function(exports, require, module) {(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __indexOf = Array.prototype.indexOf || function(item) { + for (var i = 0, l = this.length; i < l; i++) { + if (this[i] === item) return i; + } + return -1; + }; + exports.UberModel = (function() { + __extends(UberModel, Backbone.Model); + function UberModel() { + this.refetch = __bind(this.refetch, this); + this.fetch = __bind(this.fetch, this); + this.save = __bind(this.save, this); + this.parse = __bind(this.parse, this); + UberModel.__super__.constructor.apply(this, arguments); + } + UberModel.prototype.endpoint = 'set_api_endpoint_in_subclass'; + UberModel.prototype.refetchOptions = {}; + UberModel.prototype.url = function(type) { + var endpoint_path; + endpoint_path = "/" + this.endpoint; + if (this.get('id')) { + return endpoint_path + ("/" + (this.get('id'))); + } else { + return endpoint_path; + } + }; + UberModel.prototype.isRenderable = function() { + var i, key, value, _ref; + i = 0; + _ref = this.attributes; + for (key in _ref) { + if (!__hasProp.call(_ref, key)) continue; + value = _ref[key]; + if (this.attributes.hasOwnProperty(key)) { + i += 1; + } + if (i > 1) { + return true; + } + } + return !(i === 1); + }; + UberModel.prototype.parse = function(response) { + var attrs, key, model, models, _i, _j, _k, _len, _len2, _len3, _ref, _ref2; + if (typeof response === 'object') { + _ref = _.intersection(_.keys(app.models), _.keys(response)); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + if (response[key]) { + attrs = this.parse(response[key]); + if (typeof attrs === 'object') { + response[key] = new app.models[key](attrs); + } + } + } + _ref2 = _.intersection(_.keys(app.collections), _.keys(response)); + for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) { + key = _ref2[_j]; + models = response[key]; + if (_.isArray(models)) { + response[key] = new app.collections[key]; + for (_k = 0, _len3 = models.length; _k < _len3; _k++) { + model = models[_k]; + attrs = app.collections[key].prototype.model.prototype.parse(model); + response[key].add(new response[key].model(attrs)); + } + } + } + } + return response; + }; + UberModel.prototype.save = function(attributes, options) { + var attr, _i, _j, _len, _len2, _ref, _ref2; + if (options == null) { + options = {}; + } + _ref = _.intersection(_.keys(app.models), _.keys(this.attributes)); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + attr = _ref[_i]; + if (typeof this.get(attr) === "object") { + this.unset(attr, { + silent: true + }); + } + } + _ref2 = _.intersection(_.keys(app.collections), _.keys(this.attributes)); + for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) { + attr = _ref2[_j]; + if (typeof this.get(attr) === "object") { + this.unset(attr, { + silent: true + }); + } + } + if ((options != null) && options.diff && (attributes != null) && attributes !== {}) { + attributes['id'] = this.get('id'); + attributes['token'] = this.get('token'); + this.clear({ + 'silent': true + }); + this.set(attributes, { + silent: true + }); + } + if (__indexOf.call(_.keys(options), "data") < 0 && __indexOf.call(_.keys(this.refetchOptions || {}), "data") >= 0) { + options.data = this.refetchOptions.data; + } + return Backbone.Model.prototype.save.call(this, attributes, options); + }; + UberModel.prototype.fetch = function(options) { + this.refetchOptions = options; + return Backbone.Model.prototype.fetch.call(this, options); + }; + UberModel.prototype.refetch = function() { + return this.fetch(this.refetchOptions); + }; + return UberModel; + })(); +}).call(this); +}, "web-lib/uber_router": function(exports, require, module) {(function() { + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + exports.UberRouter = (function() { + __extends(UberRouter, Backbone.Router); + function UberRouter() { + UberRouter.__super__.constructor.apply(this, arguments); + } + UberRouter.prototype.datePickers = function(format) { + if (format == null) { + format = "%Z-%m-%dT%H:%i:%s%:"; + } + $('.datepicker').AnyTime_noPicker(); + return $('.datepicker').AnyTime_picker({ + 'format': format, + 'formatUtcOffset': '%@' + }); + }; + UberRouter.prototype.autoGrowInput = function() { + return $('.editable input').autoGrowInput(); + }; + UberRouter.prototype.windowTitle = function(title) { + return $(document).attr('title', title); + }; + return UberRouter; + })(); +}).call(this); +}, "web-lib/uber_show_view": function(exports, require, module) {(function() { + var UberView; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + UberView = require('web-lib/uber_view').UberView; + exports.UberShowView = (function() { + __extends(UberShowView, UberView); + function UberShowView() { + UberShowView.__super__.constructor.apply(this, arguments); + } + UberShowView.prototype.view = 'show'; + UberShowView.prototype.events = { + 'click #edit': 'edit', + 'submit form': 'save', + 'click .cancel': 'cancel' + }; + UberShowView.prototype.errors = null; + UberShowView.prototype.showTemplate = null; + UberShowView.prototype.editTemplate = null; + UberShowView.prototype.initialize = function() { + if (this.init_hook) { + this.init_hook(); + } + _.bindAll(this, 'render'); + return this.model.bind('change', this.render); + }; + UberShowView.prototype.render = function() { + var $el; + $el = $(this.el); + this.selectView(); + if (this.view === 'show') { + $el.html(this.showTemplate({ + model: this.model + })); + } else if (this.view === 'edit') { + $el.html(this.editTemplate({ + model: this.model, + errors: this.errors || {}, + collections: this.collections || {} + })); + } else { + $el.html(this.newTemplate({ + model: this.model, + errors: this.errors || {}, + collections: this.collections || {} + })); + } + if (this.render_hook) { + this.render_hook(); + } + this.errors = null; + this.userIdsToLinkedNames(); + this.datePickers(); + return this.place(); + }; + UberShowView.prototype.selectView = function() { + var url; + if (this.options.urlRendering) { + url = window.location.hash; + if (url.match(/\/new/)) { + return this.view = 'new'; + } else if (url.match(/\/edit/)) { + return this.view = 'edit'; + } else { + return this.view = 'show'; + } + } + }; + UberShowView.prototype.edit = function(e) { + e.preventDefault(); + if (this.options.urlRendering) { + window.location.hash = '#/' + this.model.endpoint + '/' + this.model.get('id') + '/edit'; + } else { + this.view = 'edit'; + } + return this.model.change(); + }; + UberShowView.prototype.save = function(e) { + var attributes, ele, form_attrs, _i, _len, _ref; + e.preventDefault(); + attributes = $(e.currentTarget).serializeToJson(); + form_attrs = {}; + _ref = $('input[type="radio"]'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + ele = _ref[_i]; + if ($(ele).is(':checked')) { + form_attrs[$(ele).attr('name')] = $(ele).attr('value'); + } + } + attributes = _.extend(attributes, form_attrs); + if (this.relationships) { + attributes = _.extend(attributes, { + relationships: this.relationships + }); + } + if (this.filter_attributes != null) { + this.filter_attributes(attributes); + } + return this.model.save(attributes, { + silent: true, + success: __bind(function(model) { + if (this.options.urlRendering) { + window.location.hash = '#/' + this.model.endpoint + '/' + this.model.get('id'); + } else { + this.view = 'show'; + } + return this.flash('success', "Uber save!"); + }, this), + statusCode: { + 406: __bind(function(xhr) { + this.errors = JSON.parse(xhr.responseText); + return this.flash('error', 'That was not Uber.'); + }, this) + }, + error: __bind(function(model, xhr) { + var code, message, responseJSON, responseText; + code = xhr.status; + responseText = xhr.responseText; + if (responseText) { + responseJSON = JSON.parse(responseText); + } + if (responseJSON && (typeof responseJSON === 'object') && (responseJSON.hasOwnProperty('error'))) { + message = responseJSON.error; + } + return this.flash('error', (code || 'Unknown') + ' error' + (': ' + message || '')); + }, this), + complete: __bind(function() { + return this.model.change(); + }, this) + }); + }; + UberShowView.prototype.cancel = function(e) { + e.preventDefault(); + if (this.options.urlRendering) { + window.location.hash = '#/' + this.model.endpoint + '/' + this.model.get('id'); + } else { + this.view = 'show'; + } + return this.model.fetch({ + silent: true, + complete: __bind(function() { + return this.model.change(); + }, this) + }); + }; + return UberShowView; + })(); +}).call(this); +}, "web-lib/uber_sync": function(exports, require, module) {(function() { + var methodType; + var __indexOf = Array.prototype.indexOf || function(item) { + for (var i = 0, l = this.length; i < l; i++) { + if (this[i] === item) return i; + } + return -1; + }; + methodType = { + create: 'POST', + update: 'PUT', + "delete": 'DELETE', + read: 'GET' + }; + exports.UberSync = function(method, model, options) { + var token; + options.type = methodType[method]; + options.url = _.isString(this.url) ? '/api' + this.url : '/api' + this.url(options.type); + options.data = _.extend({}, options.data); + if (__indexOf.call(_.keys(options.data), "city_id") < 0) { + if ($.cookie('city_filter')) { + _.extend(options.data, { + city_id: $.cookie('city_filter') + }); + } + } else { + delete options.data['city_id']; + } + if (options.type === 'POST' || options.type === 'PUT') { + _.extend(options.data, model.toJSON()); + } + token = $.cookie('token') ? $.cookie('token') : typeof USER !== "undefined" && USER !== null ? USER.get('token') : ""; + _.extend(options.data, { + token: token + }); + if (method === "delete") { + options.contentType = 'application/json'; + options.data = JSON.stringify(options.data); + } + return $.ajax(options); + }; +}).call(this); +}, "web-lib/uber_view": function(exports, require, module) {(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + exports.UberView = (function() { + __extends(UberView, Backbone.View); + function UberView() { + this.processDocumentUpload = __bind(this.processDocumentUpload, this); + UberView.__super__.constructor.apply(this, arguments); + } + UberView.prototype.className = 'view_container'; + UberView.prototype.hashId = function() { + return parseInt(location.hash.split('/')[2]); + }; + UberView.prototype.place = function(content) { + var $target; + $target = this.options.scope ? this.options.scope.find(this.options.selector) : $(this.options.selector); + $target[this.options.method || 'html'](content || this.el); + this.delegateEvents(); + $('#spinner').hide(); + return this; + }; + UberView.prototype.mixin = function(m, args) { + var events, self; + if (args == null) { + args = {}; + } + self = this; + events = m._events; + _.extend(this, m); + if (m.initialize) { + m.initialize(self, args); + } + return _.each(_.keys(events), function(key) { + var event, func, selector, split; + split = key.split(' '); + event = split[0]; + selector = split[1]; + func = events[key]; + return $(self.el).find(selector).live(event, function(e) { + return self[func](e); + }); + }); + }; + UberView.prototype.datePickers = function(format) { + if (format == null) { + format = "%Z-%m-%dT%H:%i:%s%:"; + } + $('.datepicker').AnyTime_noPicker(); + return $('.datepicker').AnyTime_picker({ + 'format': format, + 'formatUtcOffset': '%@' + }); + }; + UberView.prototype.dataTable = function(collection, selector, options, params, cols) { + var defaults; + if (selector == null) { + selector = 'table'; + } + if (options == null) { + options = {}; + } + if (params == null) { + params = {}; + } + if (cols == null) { + cols = []; + } + $(selector).empty(); + if (!cols.length) { + cols = collection.defaultColumns; + } + defaults = { + aoColumns: collection.tableColumns(cols), + bDestroy: true, + bSort: false, + bProcessing: true, + bFilter: false, + bServerSide: true, + bPaginate: true, + bScrollInfinite: true, + bScrollCollapse: true, + sScrollY: '600px', + iDisplayLength: 50, + fnServerData: function(source, data, callback) { + var defaultParams; + defaultParams = { + limit: data[4].value, + offset: data[3].value + }; + return collection.fetch({ + data: _.extend(defaultParams, params), + success: function() { + return callback({ + aaData: collection.toTableRows(cols), + iTotalRecords: collection.meta.count, + iTotalDisplayRecords: collection.meta.count + }); + }, + error: function() { + return new Error({ + message: 'Loading error.' + }); + } + }); + }, + fnRowCallback: function(nRow, aData, iDisplayIndex, iDisplayIndexFull) { + $('[data-tooltip]', nRow).qtip({ + content: { + attr: 'data-tooltip' + }, + style: { + classes: "ui-tooltip-light ui-tooltip-rounded ui-tooltip-shadow" + } + }); + return nRow; + } + }; + return $(this.el).find(selector).dataTable(_.extend(defaults, options)); + }; + UberView.prototype.dataTableLocal = function(collection, selector, options, params, cols) { + var $dataTable, defaults; + if (selector == null) { + selector = 'table'; + } + if (options == null) { + options = {}; + } + if (params == null) { + params = {}; + } + if (cols == null) { + cols = []; + } + $(selector).empty(); + if (!cols.length || cols.length === 0) { + cols = collection.defaultColumns; + } + defaults = { + aaData: collection.toTableRows(cols), + aoColumns: collection.tableColumns(cols), + bDestroy: true, + bSort: false, + bProcessing: true, + bFilter: false, + bScrollInfinite: true, + bScrollCollapse: true, + sScrollY: '600px', + iDisplayLength: -1 + }; + $dataTable = $(this.el).find(selector).dataTable(_.extend(defaults, options)); + _.delay(__bind(function() { + if ($dataTable && $dataTable.length > 0) { + return $dataTable.fnAdjustColumnSizing(); + } + }, this), 1); + return $dataTable; + }; + UberView.prototype.reverseGeocode = function() { + var $el; + return ''; + $el = $(this.el); + return this.requireMaps(function() { + var geocoder; + geocoder = new google.maps.Geocoder(); + return $el.find('[data-point]').each(function() { + var $this, latLng, point; + $this = $(this); + point = JSON.parse($this.attr('data-point')); + latLng = new google.maps.LatLng(point.latitude, point.longitude); + return geocoder.geocode({ + latLng: latLng + }, function(data, status) { + if (status === google.maps.GeocoderStatus.OK) { + return $this.text(data[0].formatted_address); + } + }); + }); + }); + }; + UberView.prototype.userIdsToLinkedNames = function() { + var $el; + $el = $(this.el); + return $el.find('a[data-user-id][data-user-type]').each(function() { + var $this, user, userType; + $this = $(this); + userType = $this.attr('data-user-type') === 'user' ? 'client' : $this.attr('data-user-type'); + user = new app.models[userType]({ + id: $this.attr('data-user-id') + }); + return user.fetch({ + success: function(user) { + return $this.html(app.helpers.linkedName(user)).attr('href', "!/" + user.role + "s/" + user.id); + }, + error: function() { + if ($this.attr('data-user-type') === 'user') { + user = new app.models['driver']({ + id: $this.attr('data-user-id') + }); + return user.fetch({ + success: function(user) { + return $this.html(app.helpers.linkedName(user)).attr('href', "!/driver/" + user.id); + } + }); + } + } + }); + }); + }; + UberView.prototype.selectedCity = function() { + var $selected, city, cityFilter; + cityFilter = $.cookie('city_filter'); + $selected = $("#city_filter option[value=" + cityFilter + "]"); + if (city_filter && $selected.length) { + return city = { + lat: parseFloat($selected.attr('data-lat')), + lng: parseFloat($selected.attr('data-lng')), + timezone: $selected.attr('data-timezone') + }; + } else { + return city = { + lat: 37.775, + lng: -122.45, + timezone: 'Etc/UTC' + }; + } + }; + UberView.prototype.updateModel = function(e, success) { + var $el, attrs, model, self; + e.preventDefault(); + $el = $(e.currentTarget); + self = this; + model = new this.model.__proto__.constructor({ + id: this.model.id + }); + attrs = {}; + $el.find('[name]').each(function() { + var $this; + $this = $(this); + return attrs["" + ($this.attr('name'))] = $this.val(); + }); + self.model.set(attrs); + $el.find('span.error').text(''); + return model.save(attrs, { + complete: function(xhr) { + var response; + response = JSON.parse(xhr.responseText); + switch (xhr.status) { + case 200: + self.model = model; + $el.find('[name]').val(''); + if (success) { + return success(); + } + break; + case 406: + return _.each(response, function(error, field) { + return $el.find("[name=" + field + "]").parent().find('span.error').text(error); + }); + default: + return this.unanticipatedError(response); + } + } + }); + }; + UberView.prototype.autoUpdateModel = function(e) { + var $el, arg, model, self, val; + $el = $(e.currentTarget); + val = $el.val(); + self = this; + if (val !== this.model.get($el.attr('id'))) { + arg = {}; + arg[$el.attr('id')] = $el.is(':checkbox') ? $el.is(':checked') ? 1 : 0 : val; + $('.editable span').empty(); + this.model.set(arg); + model = new this.model.__proto__.constructor({ + id: this.model.id + }); + return model.save(arg, { + complete: function(xhr) { + var key, response, _i, _len, _ref, _results; + response = JSON.parse(xhr.responseText); + switch (xhr.status) { + case 200: + self.flash('success', 'Saved!'); + return $el.blur(); + case 406: + self.flash('error', 'That was not Uber.'); + _ref = _.keys(response); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + _results.push($el.parent().find('span').html(response[key])); + } + return _results; + break; + default: + return self.unanticipatedError; + } + } + }); + } + }; + UberView.prototype.unanticipatedError = function(response) { + return self.flash('error', response); + }; + UberView.prototype.flash = function(type, text) { + var $banner; + $banner = $("." + type); + $banner.find('p').text(text).end().css('border', '1px solid #999').animate({ + top: 0 + }, 500); + return setTimeout(function() { + return $banner.animate({ + top: -$banner.outerHeight() + }, 500); + }, 3000); + }; + UberView.prototype.requireMaps = function(callback) { + if (typeof google !== 'undefined' && google.maps) { + return callback(); + } else { + return $.getScript("https://www.google.com/jsapi?key=" + CONFIG.googleJsApiKey, function() { + return google.load('maps', 3, { + callback: callback, + other_params: 'sensor=false&language=en' + }); + }); + } + }; + UberView.prototype.select_drop_down = function(model, key) { + var value; + value = model.get(key); + if (value) { + return $("select[id='" + key + "'] option[value='" + value + "']").attr('selected', 'selected'); + } + }; + UberView.prototype.processDocumentUpload = function(e) { + var $fi, $form, arbData, curDate, data, expDate, expM, expY, expiration, fileElementId, invalid; + e.preventDefault(); + $form = $(e.currentTarget); + $fi = $("input[type=file]", $form); + $(".validationError").removeClass("validationError"); + if (!$fi.val()) { + return $fi.addClass("validationError"); + } else { + fileElementId = $fi.attr('id'); + expY = $("select[name=expiration-year]", $form).val(); + expM = $("select[name=expiration-month]", $form).val(); + invalid = false; + if (expY && expM) { + expDate = new Date(expY, expM, 28); + curDate = new Date(); + if (expDate < curDate) { + invalid = true; + $(".expiration", $form).addClass("validationError"); + } + expiration = "" + expY + "-" + expM + "-28T23:59:59Z"; + } + arbData = {}; + $(".arbitraryField", $form).each(__bind(function(i, e) { + arbData[$(e).attr('name')] = $(e).val(); + if ($(e).val() === "") { + invalid = true; + return $(e).addClass("validationError"); + } + }, this)); + if (!invalid) { + data = { + token: $.cookie('token') || USER.get('token'), + name: $("input[name=fileName]", $form).val(), + meta: escape(JSON.stringify(arbData)), + user_id: $("input[name=driver_id]", $form).val(), + vehicle_id: $("input[name=vehicle_id]", $form).val() + }; + if (expiration) { + data['expiration'] = expiration; + } + $("#spinner").show(); + return $.ajaxFileUpload({ + url: '/api/documents', + secureuri: false, + fileElementId: fileElementId, + data: data, + complete: __bind(function(resp, status) { + var key, _i, _len, _ref, _results; + $("#spinner").hide(); + if (status === "success") { + if (this.model) { + this.model.refetch(); + } else { + USER.refetch(); + } + } + if (status === "error") { + _ref = _.keys(resp); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + _results.push($("*[name=" + key + "]", $form).addClass("validationError")); + } + return _results; + } + }, this) + }); + } + } + }; + return UberView; + })(); +}).call(this); +}, "web-lib/views/footer": function(exports, require, module) {(function() { + var footerTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + footerTemplate = require('web-lib/templates/footer'); + exports.SharedFooterView = (function() { + __extends(SharedFooterView, Backbone.View); + function SharedFooterView() { + SharedFooterView.__super__.constructor.apply(this, arguments); + } + SharedFooterView.prototype.id = 'footer_view'; + SharedFooterView.prototype.events = { + 'click .language': 'intl_set_cookie_locale' + }; + SharedFooterView.prototype.render = function() { + $(this.el).html(footerTemplate()); + this.delegateEvents(); + return this; + }; + SharedFooterView.prototype.intl_set_cookie_locale = function(e) { + var _ref; + i18n.setLocale(e != null ? (_ref = e.srcElement) != null ? _ref.id : void 0 : void 0); + return location.reload(); + }; + return SharedFooterView; + })(); +}).call(this); +}}); diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/embed-tokens.js b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/embed-tokens.js new file mode 100755 index 0000000..61307ee --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/embed-tokens.js @@ -0,0 +1,15 @@ +#! /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("embed-tokens.js", "utf8").replace(/^#.*$/mg, ""); +var ast = jsp.parse(code, null, true); + +// trololo +function fooBar() {} + +console.log(sys.inspect(ast, null, null)); diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto.js b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto.js new file mode 100644 index 0000000..945960c --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto.js @@ -0,0 +1,26 @@ +function unique(arqw) { + var a = [], i, j + outer: for (i = 0; i < arqw.length; i++) { + for (j = 0; j < a.length; j++) { + if (a[j] == arqw[i]) { + continue outer + } + } + a[a.length] = arqw[i] + } + return a +} + + +function unique(arqw) { + var crap = [], i, j + outer: for (i = 0; i < arqw.length; i++) { + for (j = 0; j < crap.length; j++) { + if (crap[j] == arqw[i]) { + continue outer + } + } + crap[crap.length] = arqw[i] + } + return crap +} diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto2.js b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto2.js new file mode 100644 index 0000000..d13b2bc --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/goto2.js @@ -0,0 +1,8 @@ +function q(qooo) { + var a; + foo: for(;;) { + a++; + if (something) break foo; + return qooo; + } +} diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/hoist.js b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/hoist.js new file mode 100644 index 0000000..4bf2b94 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/hoist.js @@ -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/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument.js b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument.js new file mode 100644 index 0000000..c6a9d79 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument.js @@ -0,0 +1,97 @@ +// 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/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument2.js b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument2.js new file mode 100644 index 0000000..6aee5f3 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument2.js @@ -0,0 +1,138 @@ +// 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/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/liftvars.js b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/liftvars.js new file mode 100644 index 0000000..2f4b7fe --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/liftvars.js @@ -0,0 +1,8 @@ +var UNUSED_VAR1 = 19; + +function main() { + var unused_var2 = 20; + alert(100); +} + +main(); diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/test.js b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/test.js new file mode 100755 index 0000000..f295fba --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/test.js @@ -0,0 +1,30 @@ +#! /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); + +var w = pro.ast_walker(); +ast = w.with_walkers({ + "function": function() { + var node = w.dive(this); // walk depth first + console.log(pro.gen_code(node, { beautify: true })); + return node; + }, + "name": function(name) { + return [ this[0], "X" ]; + } +}, function(){ + return w.walk(ast); +}); + +console.log(pro.gen_code(ast, { + beautify: true +})); diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/uglify-hangs.js b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/uglify-hangs.js new file mode 100644 index 0000000..0d5b7e0 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/uglify-hangs.js @@ -0,0 +1,3930 @@ +/** + * @fileoverview + * + * JsWorld + * + *

Javascript library for localised formatting and parsing of: + *

    + *
  • Numbers + *
  • Dates and times + *
  • Currency + *
+ * + *

The library classes are configured with standard POSIX locale definitions + * derived from Unicode's Common Locale Data Repository (CLDR). + * + *

Website: JsWorld + * + * @author Vladimir Dzhuvinov + * @version 2.5 (2011-12-23) + */ + + + +/** + * @namespace Namespace container for the JsWorld library objects. + */ +jsworld = {}; + + +/** + * @function + * + * @description Formats a JavaScript Date object as an ISO-8601 date/time + * string. + * + * @param {Date} [d] A valid JavaScript Date object. If undefined the + * current date/time will be used. + * @param {Boolean} [withTZ] Include timezone offset, default false. + * + * @returns {String} The date/time formatted as YYYY-MM-DD HH:MM:SS. + */ +jsworld.formatIsoDateTime = function(d, withTZ) { + + if (typeof d === "undefined") + d = new Date(); // now + + if (typeof withTZ === "undefined") + withTZ = false; + + var s = jsworld.formatIsoDate(d) + " " + jsworld.formatIsoTime(d); + + if (withTZ) { + + var diff = d.getHours() - d.getUTCHours(); + var hourDiff = Math.abs(diff); + + var minuteUTC = d.getUTCMinutes(); + var minute = d.getMinutes(); + + if (minute != minuteUTC && minuteUTC < 30 && diff < 0) + hourDiff--; + + if (minute != minuteUTC && minuteUTC > 30 && diff > 0) + hourDiff--; + + var minuteDiff; + if (minute != minuteUTC) + minuteDiff = ":30"; + else + minuteDiff = ":00"; + + var timezone; + if (hourDiff < 10) + timezone = "0" + hourDiff + minuteDiff; + + else + timezone = "" + hourDiff + minuteDiff; + + if (diff < 0) + timezone = "-" + timezone; + + else + timezone = "+" + timezone; + + s = s + timezone; + } + + return s; +}; + + +/** + * @function + * + * @description Formats a JavaScript Date object as an ISO-8601 date string. + * + * @param {Date} [d] A valid JavaScript Date object. If undefined the current + * date will be used. + * + * @returns {String} The date formatted as YYYY-MM-DD. + */ +jsworld.formatIsoDate = function(d) { + + if (typeof d === "undefined") + d = new Date(); // now + + var year = d.getFullYear(); + var month = d.getMonth() + 1; + var day = d.getDate(); + + return year + "-" + jsworld._zeroPad(month, 2) + "-" + jsworld._zeroPad(day, 2); +}; + + +/** + * @function + * + * @description Formats a JavaScript Date object as an ISO-8601 time string. + * + * @param {Date} [d] A valid JavaScript Date object. If undefined the current + * time will be used. + * + * @returns {String} The time formatted as HH:MM:SS. + */ +jsworld.formatIsoTime = function(d) { + + if (typeof d === "undefined") + d = new Date(); // now + + var hour = d.getHours(); + var minute = d.getMinutes(); + var second = d.getSeconds(); + + return jsworld._zeroPad(hour, 2) + ":" + jsworld._zeroPad(minute, 2) + ":" + jsworld._zeroPad(second, 2); +}; + + +/** + * @function + * + * @description Parses an ISO-8601 formatted date/time string to a JavaScript + * Date object. + * + * @param {String} isoDateTimeVal An ISO-8601 formatted date/time string. + * + *

Accepted formats: + * + *

    + *
  • YYYY-MM-DD HH:MM:SS + *
  • YYYYMMDD HHMMSS + *
  • YYYY-MM-DD HHMMSS + *
  • YYYYMMDD HH:MM:SS + *
+ * + * @returns {Date} The corresponding Date object. + * + * @throws Error on a badly formatted date/time string or on a invalid date. + */ +jsworld.parseIsoDateTime = function(isoDateTimeVal) { + + if (typeof isoDateTimeVal != "string") + throw "Error: The parameter must be a string"; + + // First, try to match "YYYY-MM-DD HH:MM:SS" format + var matches = isoDateTimeVal.match(/^(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d):(\d\d):(\d\d)/); + + // If unsuccessful, try to match "YYYYMMDD HHMMSS" format + if (matches === null) + matches = isoDateTimeVal.match(/^(\d\d\d\d)(\d\d)(\d\d)[T ](\d\d)(\d\d)(\d\d)/); + + // ... try to match "YYYY-MM-DD HHMMSS" format + if (matches === null) + matches = isoDateTimeVal.match(/^(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d)(\d\d)(\d\d)/); + + // ... try to match "YYYYMMDD HH:MM:SS" format + if (matches === null) + matches = isoDateTimeVal.match(/^(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d):(\d\d):(\d\d)/); + + // Report bad date/time string + if (matches === null) + throw "Error: Invalid ISO-8601 date/time string"; + + // Force base 10 parse int as some values may have leading zeros! + // (to avoid implicit octal base conversion) + var year = parseInt(matches[1], 10); + var month = parseInt(matches[2], 10); + var day = parseInt(matches[3], 10); + + var hour = parseInt(matches[4], 10); + var mins = parseInt(matches[5], 10); + var secs = parseInt(matches[6], 10); + + // Simple value range check, leap years not checked + // Note: the originial ISO time spec for leap hours (24:00:00) and seconds (00:00:60) is not supported + if (month < 1 || month > 12 || + day < 1 || day > 31 || + hour < 0 || hour > 23 || + mins < 0 || mins > 59 || + secs < 0 || secs > 59 ) + + throw "Error: Invalid ISO-8601 date/time value"; + + var d = new Date(year, month - 1, day, hour, mins, secs); + + // Check if the input date was valid + // (JS Date does automatic forward correction) + if (d.getDate() != day || d.getMonth() +1 != month) + throw "Error: Invalid date"; + + return d; +}; + + +/** + * @function + * + * @description Parses an ISO-8601 formatted date string to a JavaScript + * Date object. + * + * @param {String} isoDateVal An ISO-8601 formatted date string. + * + *

Accepted formats: + * + *

    + *
  • YYYY-MM-DD + *
  • YYYYMMDD + *
+ * + * @returns {Date} The corresponding Date object. + * + * @throws Error on a badly formatted date string or on a invalid date. + */ +jsworld.parseIsoDate = function(isoDateVal) { + + if (typeof isoDateVal != "string") + throw "Error: The parameter must be a string"; + + // First, try to match "YYYY-MM-DD" format + var matches = isoDateVal.match(/^(\d\d\d\d)-(\d\d)-(\d\d)/); + + // If unsuccessful, try to match "YYYYMMDD" format + if (matches === null) + matches = isoDateVal.match(/^(\d\d\d\d)(\d\d)(\d\d)/); + + // Report bad date/time string + if (matches === null) + throw "Error: Invalid ISO-8601 date string"; + + // Force base 10 parse int as some values may have leading zeros! + // (to avoid implicit octal base conversion) + var year = parseInt(matches[1], 10); + var month = parseInt(matches[2], 10); + var day = parseInt(matches[3], 10); + + // Simple value range check, leap years not checked + if (month < 1 || month > 12 || + day < 1 || day > 31 ) + + throw "Error: Invalid ISO-8601 date value"; + + var d = new Date(year, month - 1, day); + + // Check if the input date was valid + // (JS Date does automatic forward correction) + if (d.getDate() != day || d.getMonth() +1 != month) + throw "Error: Invalid date"; + + return d; +}; + + +/** + * @function + * + * @description Parses an ISO-8601 formatted time string to a JavaScript + * Date object. + * + * @param {String} isoTimeVal An ISO-8601 formatted time string. + * + *

Accepted formats: + * + *

    + *
  • HH:MM:SS + *
  • HHMMSS + *
+ * + * @returns {Date} The corresponding Date object, with year, month and day set + * to zero. + * + * @throws Error on a badly formatted time string. + */ +jsworld.parseIsoTime = function(isoTimeVal) { + + if (typeof isoTimeVal != "string") + throw "Error: The parameter must be a string"; + + // First, try to match "HH:MM:SS" format + var matches = isoTimeVal.match(/^(\d\d):(\d\d):(\d\d)/); + + // If unsuccessful, try to match "HHMMSS" format + if (matches === null) + matches = isoTimeVal.match(/^(\d\d)(\d\d)(\d\d)/); + + // Report bad date/time string + if (matches === null) + throw "Error: Invalid ISO-8601 date/time string"; + + // Force base 10 parse int as some values may have leading zeros! + // (to avoid implicit octal base conversion) + var hour = parseInt(matches[1], 10); + var mins = parseInt(matches[2], 10); + var secs = parseInt(matches[3], 10); + + // Simple value range check, leap years not checked + if (hour < 0 || hour > 23 || + mins < 0 || mins > 59 || + secs < 0 || secs > 59 ) + + throw "Error: Invalid ISO-8601 time value"; + + return new Date(0, 0, 0, hour, mins, secs); +}; + + +/** + * @private + * + * @description Trims leading and trailing whitespace from a string. + * + *

Used non-regexp the method from http://blog.stevenlevithan.com/archives/faster-trim-javascript + * + * @param {String} str The string to trim. + * + * @returns {String} The trimmed string. + */ +jsworld._trim = function(str) { + + var whitespace = ' \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000'; + + for (var i = 0; i < str.length; i++) { + + if (whitespace.indexOf(str.charAt(i)) === -1) { + str = str.substring(i); + break; + } + } + + for (i = str.length - 1; i >= 0; i--) { + if (whitespace.indexOf(str.charAt(i)) === -1) { + str = str.substring(0, i + 1); + break; + } + } + + return whitespace.indexOf(str.charAt(0)) === -1 ? str : ''; +}; + + + +/** + * @private + * + * @description Returns true if the argument represents a decimal number. + * + * @param {Number|String} arg The argument to test. + * + * @returns {Boolean} true if the argument represents a decimal number, + * otherwise false. + */ +jsworld._isNumber = function(arg) { + + if (typeof arg == "number") + return true; + + if (typeof arg != "string") + return false; + + // ensure string + var s = arg + ""; + + return (/^-?(\d+|\d*\.\d+)$/).test(s); +}; + + +/** + * @private + * + * @description Returns true if the argument represents a decimal integer. + * + * @param {Number|String} arg The argument to test. + * + * @returns {Boolean} true if the argument represents an integer, otherwise + * false. + */ +jsworld._isInteger = function(arg) { + + if (typeof arg != "number" && typeof arg != "string") + return false; + + // convert to string + var s = arg + ""; + + return (/^-?\d+$/).test(s); +}; + + +/** + * @private + * + * @description Returns true if the argument represents a decimal float. + * + * @param {Number|String} arg The argument to test. + * + * @returns {Boolean} true if the argument represents a float, otherwise false. + */ +jsworld._isFloat = function(arg) { + + if (typeof arg != "number" && typeof arg != "string") + return false; + + // convert to string + var s = arg + ""; + + return (/^-?\.\d+?$/).test(s); +}; + + +/** + * @private + * + * @description Checks if the specified formatting option is contained + * within the options string. + * + * @param {String} option The option to search for. + * @param {String} optionsString The options string. + * + * @returns {Boolean} true if the flag is found, else false + */ +jsworld._hasOption = function(option, optionsString) { + + if (typeof option != "string" || typeof optionsString != "string") + return false; + + if (optionsString.indexOf(option) != -1) + return true; + else + return false; +}; + + +/** + * @private + * + * @description String replacement function. + * + * @param {String} s The string to work on. + * @param {String} target The string to search for. + * @param {String} replacement The replacement. + * + * @returns {String} The new string. + */ +jsworld._stringReplaceAll = function(s, target, replacement) { + + var out; + + if (target.length == 1 && replacement.length == 1) { + // simple char/char case somewhat faster + out = ""; + + for (var i = 0; i < s.length; i++) { + + if (s.charAt(i) == target.charAt(0)) + out = out + replacement.charAt(0); + else + out = out + s.charAt(i); + } + + return out; + } + else { + // longer target and replacement strings + out = s; + + var index = out.indexOf(target); + + while (index != -1) { + + out = out.replace(target, replacement); + + index = out.indexOf(target); + } + + return out; + } +}; + + +/** + * @private + * + * @description Tests if a string starts with the specified substring. + * + * @param {String} testedString The string to test. + * @param {String} sub The string to match. + * + * @returns {Boolean} true if the test succeeds. + */ +jsworld._stringStartsWith = function (testedString, sub) { + + if (testedString.length < sub.length) + return false; + + for (var i = 0; i < sub.length; i++) { + if (testedString.charAt(i) != sub.charAt(i)) + return false; + } + + return true; +}; + + +/** + * @private + * + * @description Gets the requested precision from an options string. + * + *

Example: ".3" returns 3 decimal places precision. + * + * @param {String} optionsString The options string. + * + * @returns {integer Number} The requested precision, -1 if not specified. + */ +jsworld._getPrecision = function (optionsString) { + + if (typeof optionsString != "string") + return -1; + + var m = optionsString.match(/\.(\d)/); + if (m) + return parseInt(m[1], 10); + else + return -1; +}; + + +/** + * @private + * + * @description Takes a decimal numeric amount (optionally as string) and + * returns its integer and fractional parts packed into an object. + * + * @param {Number|String} amount The amount, e.g. "123.45" or "-56.78" + * + * @returns {object} Parsed amount object with properties: + * {String} integer : the integer part + * {String} fraction : the fraction part + */ +jsworld._splitNumber = function (amount) { + + if (typeof amount == "number") + amount = amount + ""; + + var obj = {}; + + // remove negative sign + if (amount.charAt(0) == "-") + amount = amount.substring(1); + + // split amount into integer and decimal parts + var amountParts = amount.split("."); + if (!amountParts[1]) + amountParts[1] = ""; // we need "" instead of null + + obj.integer = amountParts[0]; + obj.fraction = amountParts[1]; + + return obj; +}; + + +/** + * @private + * + * @description Formats the integer part using the specified grouping + * and thousands separator. + * + * @param {String} intPart The integer part of the amount, as string. + * @param {String} grouping The grouping definition. + * @param {String} thousandsSep The thousands separator. + * + * @returns {String} The formatted integer part. + */ +jsworld._formatIntegerPart = function (intPart, grouping, thousandsSep) { + + // empty separator string? no grouping? + // -> return immediately with no formatting! + if (thousandsSep == "" || grouping == "-1") + return intPart; + + // turn the semicolon-separated string of integers into an array + var groupSizes = grouping.split(";"); + + // the formatted output string + var out = ""; + + // the intPart string position to process next, + // start at string end, e.g. "10000000 0) { + + // get next group size (if any, otherwise keep last) + if (groupSizes.length > 0) + size = parseInt(groupSizes.shift(), 10); + + // int parse error? + if (isNaN(size)) + throw "Error: Invalid grouping"; + + // size is -1? -> no more grouping, so just copy string remainder + if (size == -1) { + out = intPart.substring(0, pos) + out; + break; + } + + pos -= size; // move to next sep. char. position + + // position underrun? -> just copy string remainder + if (pos < 1) { + out = intPart.substring(0, pos + size) + out; + break; + } + + // extract group and apply sep. char. + out = thousandsSep + intPart.substring(pos, pos + size) + out; + } + + return out; +}; + + +/** + * @private + * + * @description Formats the fractional part to the specified decimal + * precision. + * + * @param {String} fracPart The fractional part of the amount + * @param {integer Number} precision The desired decimal precision + * + * @returns {String} The formatted fractional part. + */ +jsworld._formatFractionPart = function (fracPart, precision) { + + // append zeroes up to precision if necessary + for (var i=0; fracPart.length < precision; i++) + fracPart = fracPart + "0"; + + return fracPart; +}; + + +/** + * @private + * + * @desription Converts a number to string and pad it with leading zeroes if the + * string is shorter than length. + * + * @param {integer Number} number The number value subjected to selective padding. + * @param {integer Number} length If the number has fewer digits than this length + * apply padding. + * + * @returns {String} The formatted string. + */ +jsworld._zeroPad = function(number, length) { + + // ensure string + var s = number + ""; + + while (s.length < length) + s = "0" + s; + + return s; +}; + + +/** + * @private + * @description Converts a number to string and pads it with leading spaces if + * the string is shorter than length. + * + * @param {integer Number} number The number value subjected to selective padding. + * @param {integer Number} length If the number has fewer digits than this length + * apply padding. + * + * @returns {String} The formatted string. + */ +jsworld._spacePad = function(number, length) { + + // ensure string + var s = number + ""; + + while (s.length < length) + s = " " + s; + + return s; +}; + + + +/** + * @class + * Represents a POSIX-style locale with its numeric, monetary and date/time + * properties. Also provides a set of locale helper methods. + * + *

The locale properties follow the POSIX standards: + * + *

+ * + * @public + * @constructor + * @description Creates a new locale object (POSIX-style) with the specified + * properties. + * + * @param {object} properties An object containing the raw locale properties: + * + * @param {String} properties.decimal_point + * + * A string containing the symbol that shall be used as the decimal + * delimiter (radix character) in numeric, non-monetary formatted + * quantities. This property cannot be omitted and cannot be set to the + * empty string. + * + * + * @param {String} properties.thousands_sep + * + * A string containing the symbol that shall be used as a separator for + * groups of digits to the left of the decimal delimiter in numeric, + * non-monetary formatted monetary quantities. + * + * + * @param {String} properties.grouping + * + * Defines the size of each group of digits in formatted non-monetary + * quantities. The operand is a sequence of integers separated by + * semicolons. Each integer specifies the number of digits in each group, + * with the initial integer defining the size of the group immediately + * preceding the decimal delimiter, and the following integers defining + * the preceding groups. If the last integer is not -1, then the size of + * the previous group (if any) shall be repeatedly used for the + * remainder of the digits. If the last integer is -1, then no further + * grouping shall be performed. + * + * + * @param {String} properties.int_curr_symbol + * + * The first three letters signify the ISO-4217 currency code, + * the fourth letter is the international symbol separation character + * (normally a space). + * + * + * @param {String} properties.currency_symbol + * + * The local shorthand currency symbol, e.g. "$" for the en_US locale + * + * + * @param {String} properties.mon_decimal_point + * + * The symbol to be used as the decimal delimiter (radix character) + * + * + * @param {String} properties.mon_thousands_sep + * + * The symbol to be used as a separator for groups of digits to the + * left of the decimal delimiter. + * + * + * @param {String} properties.mon_grouping + * + * A string that defines the size of each group of digits. The + * operand is a sequence of integers separated by semicolons (";"). + * Each integer specifies the number of digits in each group, with the + * initial integer defining the size of the group preceding the + * decimal delimiter, and the following integers defining the + * preceding groups. If the last integer is not -1, then the size of + * the previous group (if any) must be repeatedly used for the + * remainder of the digits. If the last integer is -1, then no + * further grouping is to be performed. + * + * + * @param {String} properties.positive_sign + * + * The string to indicate a non-negative monetary amount. + * + * + * @param {String} properties.negative_sign + * + * The string to indicate a negative monetary amount. + * + * + * @param {integer Number} properties.frac_digits + * + * An integer representing the number of fractional digits (those to + * the right of the decimal delimiter) to be written in a formatted + * monetary quantity using currency_symbol. + * + * + * @param {integer Number} properties.int_frac_digits + * + * An integer representing the number of fractional digits (those to + * the right of the decimal delimiter) to be written in a formatted + * monetary quantity using int_curr_symbol. + * + * + * @param {integer Number} properties.p_cs_precedes + * + * An integer set to 1 if the currency_symbol precedes the value for a + * monetary quantity with a non-negative value, and set to 0 if the + * symbol succeeds the value. + * + * + * @param {integer Number} properties.n_cs_precedes + * + * An integer set to 1 if the currency_symbol precedes the value for a + * monetary quantity with a negative value, and set to 0 if the symbol + * succeeds the value. + * + * + * @param {integer Number} properties.p_sep_by_space + * + * Set to a value indicating the separation of the currency_symbol, + * the sign string, and the value for a non-negative formatted monetary + * quantity: + * + *

0 No space separates the currency symbol and value.

+ * + *

1 If the currency symbol and sign string are adjacent, a space + * separates them from the value; otherwise, a space separates + * the currency symbol from the value.

+ * + *

2 If the currency symbol and sign string are adjacent, a space + * separates them; otherwise, a space separates the sign string + * from the value.

+ * + * + * @param {integer Number} properties.n_sep_by_space + * + * Set to a value indicating the separation of the currency_symbol, + * the sign string, and the value for a negative formatted monetary + * quantity. Rules same as for p_sep_by_space. + * + * + * @param {integer Number} properties.p_sign_posn + * + * An integer set to a value indicating the positioning of the + * positive_sign for a monetary quantity with a non-negative value: + * + *

0 Parentheses enclose the quantity and the currency_symbol.

+ * + *

1 The sign string precedes the quantity and the currency_symbol.

+ * + *

2 The sign string succeeds the quantity and the currency_symbol.

+ * + *

3 The sign string precedes the currency_symbol.

+ * + *

4 The sign string succeeds the currency_symbol.

+ * + * + * @param {integer Number} properties.n_sign_posn + * + * An integer set to a value indicating the positioning of the + * negative_sign for a negative formatted monetary quantity. Rules same + * as for p_sign_posn. + * + * + * @param {integer Number} properties.int_p_cs_precedes + * + * An integer set to 1 if the int_curr_symbol precedes the value for a + * monetary quantity with a non-negative value, and set to 0 if the + * symbol succeeds the value. + * + * + * @param {integer Number} properties.int_n_cs_precedes + * + * An integer set to 1 if the int_curr_symbol precedes the value for a + * monetary quantity with a negative value, and set to 0 if the symbol + * succeeds the value. + * + * + * @param {integer Number} properties.int_p_sep_by_space + * + * Set to a value indicating the separation of the int_curr_symbol, + * the sign string, and the value for a non-negative internationally + * formatted monetary quantity. Rules same as for p_sep_by_space. + * + * + * @param {integer Number} properties.int_n_sep_by_space + * + * Set to a value indicating the separation of the int_curr_symbol, + * the sign string, and the value for a negative internationally + * formatted monetary quantity. Rules same as for p_sep_by_space. + * + * + * @param {integer Number} properties.int_p_sign_posn + * + * An integer set to a value indicating the positioning of the + * positive_sign for a positive monetary quantity formatted with the + * international format. Rules same as for p_sign_posn. + * + * + * @param {integer Number} properties.int_n_sign_posn + * + * An integer set to a value indicating the positioning of the + * negative_sign for a negative monetary quantity formatted with the + * international format. Rules same as for p_sign_posn. + * + * + * @param {String[] | String} properties.abday + * + * The abbreviated weekday names, corresponding to the %a conversion + * specification. The property must be either an array of 7 strings or + * a string consisting of 7 semicolon-separated substrings, each + * surrounded by double-quotes. The first must be the abbreviated name + * of the day corresponding to Sunday, the second the abbreviated name + * of the day corresponding to Monday, and so on. + * + * + * @param {String[] | String} properties.day + * + * The full weekday names, corresponding to the %A conversion + * specification. The property must be either an array of 7 strings or + * a string consisting of 7 semicolon-separated substrings, each + * surrounded by double-quotes. The first must be the full name of the + * day corresponding to Sunday, the second the full name of the day + * corresponding to Monday, and so on. + * + * + * @param {String[] | String} properties.abmon + * + * The abbreviated month names, corresponding to the %b conversion + * specification. The property must be either an array of 12 strings or + * a string consisting of 12 semicolon-separated substrings, each + * surrounded by double-quotes. The first must be the abbreviated name + * of the first month of the year (January), the second the abbreviated + * name of the second month, and so on. + * + * + * @param {String[] | String} properties.mon + * + * The full month names, corresponding to the %B conversion + * specification. The property must be either an array of 12 strings or + * a string consisting of 12 semicolon-separated substrings, each + * surrounded by double-quotes. The first must be the full name of the + * first month of the year (January), the second the full name of the second + * month, and so on. + * + * + * @param {String} properties.d_fmt + * + * The appropriate date representation. The string may contain any + * combination of characters and conversion specifications (%). + * + * + * @param {String} properties.t_fmt + * + * The appropriate time representation. The string may contain any + * combination of characters and conversion specifications (%). + * + * + * @param {String} properties.d_t_fmt + * + * The appropriate date and time representation. The string may contain + * any combination of characters and conversion specifications (%). + * + * + * @param {String[] | String} properties.am_pm + * + * The appropriate representation of the ante-meridiem and post-meridiem + * strings, corresponding to the %p conversion specification. The property + * must be either an array of 2 strings or a string consisting of 2 + * semicolon-separated substrings, each surrounded by double-quotes. + * The first string must represent the ante-meridiem designation, the + * last string the post-meridiem designation. + * + * + * @throws @throws Error on a undefined or invalid locale property. + */ +jsworld.Locale = function(properties) { + + + /** + * @private + * + * @description Identifies the class for internal library purposes. + */ + this._className = "jsworld.Locale"; + + + /** + * @private + * + * @description Parses a day or month name definition list, which + * could be a ready JS array, e.g. ["Mon", "Tue", "Wed"...] or + * it could be a string formatted according to the classic POSIX + * definition e.g. "Mon";"Tue";"Wed";... + * + * @param {String[] | String} namesAn array or string defining + * the week/month names. + * @param {integer Number} expectedItems The number of expected list + * items, e.g. 7 for weekdays, 12 for months. + * + * @returns {String[]} The parsed (and checked) items. + * + * @throws Error on missing definition, unexpected item count or + * missing double-quotes. + */ + this._parseList = function(names, expectedItems) { + + var array = []; + + if (names == null) { + throw "Names not defined"; + } + else if (typeof names == "object") { + // we got a ready array + array = names; + } + else if (typeof names == "string") { + // we got the names in the classic POSIX form, do parse + array = names.split(";", expectedItems); + + for (var i = 0; i < array.length; i++) { + // check for and strip double quotes + if (array[i][0] == "\"" && array[i][array[i].length - 1] == "\"") + array[i] = array[i].slice(1, -1); + else + throw "Missing double quotes"; + } + } + else { + throw "Names must be an array or a string"; + } + + if (array.length != expectedItems) + throw "Expected " + expectedItems + " items, got " + array.length; + + return array; + }; + + + /** + * @private + * + * @description Validates a date/time format string, such as "H:%M:%S". + * Checks that the argument is of type "string" and is not empty. + * + * @param {String} formatString The format string. + * + * @returns {String} The validated string. + * + * @throws Error on null or empty string. + */ + this._validateFormatString = function(formatString) { + + if (typeof formatString == "string" && formatString.length > 0) + return formatString; + else + throw "Empty or no string"; + }; + + + // LC_NUMERIC + + if (properties == null || typeof properties != "object") + throw "Error: Invalid/missing locale properties"; + + + if (typeof properties.decimal_point != "string") + throw "Error: Invalid/missing decimal_point property"; + + this.decimal_point = properties.decimal_point; + + + if (typeof properties.thousands_sep != "string") + throw "Error: Invalid/missing thousands_sep property"; + + this.thousands_sep = properties.thousands_sep; + + + if (typeof properties.grouping != "string") + throw "Error: Invalid/missing grouping property"; + + this.grouping = properties.grouping; + + + // LC_MONETARY + + if (typeof properties.int_curr_symbol != "string") + throw "Error: Invalid/missing int_curr_symbol property"; + + if (! /[A-Za-z]{3}.?/.test(properties.int_curr_symbol)) + throw "Error: Invalid int_curr_symbol property"; + + this.int_curr_symbol = properties.int_curr_symbol; + + + if (typeof properties.currency_symbol != "string") + throw "Error: Invalid/missing currency_symbol property"; + + this.currency_symbol = properties.currency_symbol; + + + if (typeof properties.frac_digits != "number" && properties.frac_digits < 0) + throw "Error: Invalid/missing frac_digits property"; + + this.frac_digits = properties.frac_digits; + + + // may be empty string/null for currencies with no fractional part + if (properties.mon_decimal_point === null || properties.mon_decimal_point == "") { + + if (this.frac_digits > 0) + throw "Error: Undefined mon_decimal_point property"; + else + properties.mon_decimal_point = ""; + } + + if (typeof properties.mon_decimal_point != "string") + throw "Error: Invalid/missing mon_decimal_point property"; + + this.mon_decimal_point = properties.mon_decimal_point; + + + if (typeof properties.mon_thousands_sep != "string") + throw "Error: Invalid/missing mon_thousands_sep property"; + + this.mon_thousands_sep = properties.mon_thousands_sep; + + + if (typeof properties.mon_grouping != "string") + throw "Error: Invalid/missing mon_grouping property"; + + this.mon_grouping = properties.mon_grouping; + + + if (typeof properties.positive_sign != "string") + throw "Error: Invalid/missing positive_sign property"; + + this.positive_sign = properties.positive_sign; + + + if (typeof properties.negative_sign != "string") + throw "Error: Invalid/missing negative_sign property"; + + this.negative_sign = properties.negative_sign; + + + + if (properties.p_cs_precedes !== 0 && properties.p_cs_precedes !== 1) + throw "Error: Invalid/missing p_cs_precedes property, must be 0 or 1"; + + this.p_cs_precedes = properties.p_cs_precedes; + + + if (properties.n_cs_precedes !== 0 && properties.n_cs_precedes !== 1) + throw "Error: Invalid/missing n_cs_precedes, must be 0 or 1"; + + this.n_cs_precedes = properties.n_cs_precedes; + + + if (properties.p_sep_by_space !== 0 && + properties.p_sep_by_space !== 1 && + properties.p_sep_by_space !== 2) + throw "Error: Invalid/missing p_sep_by_space property, must be 0, 1 or 2"; + + this.p_sep_by_space = properties.p_sep_by_space; + + + if (properties.n_sep_by_space !== 0 && + properties.n_sep_by_space !== 1 && + properties.n_sep_by_space !== 2) + throw "Error: Invalid/missing n_sep_by_space property, must be 0, 1, or 2"; + + this.n_sep_by_space = properties.n_sep_by_space; + + + if (properties.p_sign_posn !== 0 && + properties.p_sign_posn !== 1 && + properties.p_sign_posn !== 2 && + properties.p_sign_posn !== 3 && + properties.p_sign_posn !== 4) + throw "Error: Invalid/missing p_sign_posn property, must be 0, 1, 2, 3 or 4"; + + this.p_sign_posn = properties.p_sign_posn; + + + if (properties.n_sign_posn !== 0 && + properties.n_sign_posn !== 1 && + properties.n_sign_posn !== 2 && + properties.n_sign_posn !== 3 && + properties.n_sign_posn !== 4) + throw "Error: Invalid/missing n_sign_posn property, must be 0, 1, 2, 3 or 4"; + + this.n_sign_posn = properties.n_sign_posn; + + + if (typeof properties.int_frac_digits != "number" && properties.int_frac_digits < 0) + throw "Error: Invalid/missing int_frac_digits property"; + + this.int_frac_digits = properties.int_frac_digits; + + + if (properties.int_p_cs_precedes !== 0 && properties.int_p_cs_precedes !== 1) + throw "Error: Invalid/missing int_p_cs_precedes property, must be 0 or 1"; + + this.int_p_cs_precedes = properties.int_p_cs_precedes; + + + if (properties.int_n_cs_precedes !== 0 && properties.int_n_cs_precedes !== 1) + throw "Error: Invalid/missing int_n_cs_precedes property, must be 0 or 1"; + + this.int_n_cs_precedes = properties.int_n_cs_precedes; + + + if (properties.int_p_sep_by_space !== 0 && + properties.int_p_sep_by_space !== 1 && + properties.int_p_sep_by_space !== 2) + throw "Error: Invalid/missing int_p_sep_by_spacev, must be 0, 1 or 2"; + + this.int_p_sep_by_space = properties.int_p_sep_by_space; + + + if (properties.int_n_sep_by_space !== 0 && + properties.int_n_sep_by_space !== 1 && + properties.int_n_sep_by_space !== 2) + throw "Error: Invalid/missing int_n_sep_by_space property, must be 0, 1, or 2"; + + this.int_n_sep_by_space = properties.int_n_sep_by_space; + + + if (properties.int_p_sign_posn !== 0 && + properties.int_p_sign_posn !== 1 && + properties.int_p_sign_posn !== 2 && + properties.int_p_sign_posn !== 3 && + properties.int_p_sign_posn !== 4) + throw "Error: Invalid/missing int_p_sign_posn property, must be 0, 1, 2, 3 or 4"; + + this.int_p_sign_posn = properties.int_p_sign_posn; + + + if (properties.int_n_sign_posn !== 0 && + properties.int_n_sign_posn !== 1 && + properties.int_n_sign_posn !== 2 && + properties.int_n_sign_posn !== 3 && + properties.int_n_sign_posn !== 4) + throw "Error: Invalid/missing int_n_sign_posn property, must be 0, 1, 2, 3 or 4"; + + this.int_n_sign_posn = properties.int_n_sign_posn; + + + // LC_TIME + + if (properties == null || typeof properties != "object") + throw "Error: Invalid/missing time locale properties"; + + + // parse the supported POSIX LC_TIME properties + + // abday + try { + this.abday = this._parseList(properties.abday, 7); + } + catch (error) { + throw "Error: Invalid abday property: " + error; + } + + // day + try { + this.day = this._parseList(properties.day, 7); + } + catch (error) { + throw "Error: Invalid day property: " + error; + } + + // abmon + try { + this.abmon = this._parseList(properties.abmon, 12); + } catch (error) { + throw "Error: Invalid abmon property: " + error; + } + + // mon + try { + this.mon = this._parseList(properties.mon, 12); + } catch (error) { + throw "Error: Invalid mon property: " + error; + } + + // d_fmt + try { + this.d_fmt = this._validateFormatString(properties.d_fmt); + } catch (error) { + throw "Error: Invalid d_fmt property: " + error; + } + + // t_fmt + try { + this.t_fmt = this._validateFormatString(properties.t_fmt); + } catch (error) { + throw "Error: Invalid t_fmt property: " + error; + } + + // d_t_fmt + try { + this.d_t_fmt = this._validateFormatString(properties.d_t_fmt); + } catch (error) { + throw "Error: Invalid d_t_fmt property: " + error; + } + + // am_pm + try { + var am_pm_strings = this._parseList(properties.am_pm, 2); + this.am = am_pm_strings[0]; + this.pm = am_pm_strings[1]; + } catch (error) { + // ignore empty/null string errors + this.am = ""; + this.pm = ""; + } + + + /** + * @public + * + * @description Returns the abbreviated name of the specified weekday. + * + * @param {integer Number} [weekdayNum] An integer between 0 and 6. Zero + * corresponds to Sunday, one to Monday, etc. If omitted the + * method will return an array of all abbreviated weekday + * names. + * + * @returns {String | String[]} The abbreviated name of the specified weekday + * or an array of all abbreviated weekday names. + * + * @throws Error on invalid argument. + */ + this.getAbbreviatedWeekdayName = function(weekdayNum) { + + if (typeof weekdayNum == "undefined" || weekdayNum === null) + return this.abday; + + if (! jsworld._isInteger(weekdayNum) || weekdayNum < 0 || weekdayNum > 6) + throw "Error: Invalid weekday argument, must be an integer [0..6]"; + + return this.abday[weekdayNum]; + }; + + + /** + * @public + * + * @description Returns the name of the specified weekday. + * + * @param {integer Number} [weekdayNum] An integer between 0 and 6. Zero + * corresponds to Sunday, one to Monday, etc. If omitted the + * method will return an array of all weekday names. + * + * @returns {String | String[]} The name of the specified weekday or an + * array of all weekday names. + * + * @throws Error on invalid argument. + */ + this.getWeekdayName = function(weekdayNum) { + + if (typeof weekdayNum == "undefined" || weekdayNum === null) + return this.day; + + if (! jsworld._isInteger(weekdayNum) || weekdayNum < 0 || weekdayNum > 6) + throw "Error: Invalid weekday argument, must be an integer [0..6]"; + + return this.day[weekdayNum]; + }; + + + /** + * @public + * + * @description Returns the abbreviated name of the specified month. + * + * @param {integer Number} [monthNum] An integer between 0 and 11. Zero + * corresponds to January, one to February, etc. If omitted the + * method will return an array of all abbreviated month names. + * + * @returns {String | String[]} The abbreviated name of the specified month + * or an array of all abbreviated month names. + * + * @throws Error on invalid argument. + */ + this.getAbbreviatedMonthName = function(monthNum) { + + if (typeof monthNum == "undefined" || monthNum === null) + return this.abmon; + + if (! jsworld._isInteger(monthNum) || monthNum < 0 || monthNum > 11) + throw "Error: Invalid month argument, must be an integer [0..11]"; + + return this.abmon[monthNum]; + }; + + + /** + * @public + * + * @description Returns the name of the specified month. + * + * @param {integer Number} [monthNum] An integer between 0 and 11. Zero + * corresponds to January, one to February, etc. If omitted the + * method will return an array of all month names. + * + * @returns {String | String[]} The name of the specified month or an array + * of all month names. + * + * @throws Error on invalid argument. + */ + this.getMonthName = function(monthNum) { + + if (typeof monthNum == "undefined" || monthNum === null) + return this.mon; + + if (! jsworld._isInteger(monthNum) || monthNum < 0 || monthNum > 11) + throw "Error: Invalid month argument, must be an integer [0..11]"; + + return this.mon[monthNum]; + }; + + + + /** + * @public + * + * @description Gets the decimal delimiter (radix) character for + * numeric quantities. + * + * @returns {String} The radix character. + */ + this.getDecimalPoint = function() { + + return this.decimal_point; + }; + + + /** + * @public + * + * @description Gets the local shorthand currency symbol. + * + * @returns {String} The currency symbol. + */ + this.getCurrencySymbol = function() { + + return this.currency_symbol; + }; + + + /** + * @public + * + * @description Gets the internaltion currency symbol (ISO-4217 code). + * + * @returns {String} The international currency symbol. + */ + this.getIntCurrencySymbol = function() { + + return this.int_curr_symbol.substring(0,3); + }; + + + /** + * @public + * + * @description Gets the position of the local (shorthand) currency + * symbol relative to the amount. Assumes a non-negative amount. + * + * @returns {Boolean} True if the symbol precedes the amount, false if + * the symbol succeeds the amount. + */ + this.currencySymbolPrecedes = function() { + + if (this.p_cs_precedes == 1) + return true; + else + return false; + }; + + + /** + * @public + * + * @description Gets the position of the international (ISO-4217 code) + * currency symbol relative to the amount. Assumes a non-negative + * amount. + * + * @returns {Boolean} True if the symbol precedes the amount, false if + * the symbol succeeds the amount. + */ + this.intCurrencySymbolPrecedes = function() { + + if (this.int_p_cs_precedes == 1) + return true; + else + return false; + + }; + + + /** + * @public + * + * @description Gets the decimal delimiter (radix) for monetary + * quantities. + * + * @returns {String} The radix character. + */ + this.getMonetaryDecimalPoint = function() { + + return this.mon_decimal_point; + }; + + + /** + * @public + * + * @description Gets the number of fractional digits for local + * (shorthand) symbol formatting. + * + * @returns {integer Number} The number of fractional digits. + */ + this.getFractionalDigits = function() { + + return this.frac_digits; + }; + + + /** + * @public + * + * @description Gets the number of fractional digits for + * international (ISO-4217 code) formatting. + * + * @returns {integer Number} The number of fractional digits. + */ + this.getIntFractionalDigits = function() { + + return this.int_frac_digits; + }; +}; + + + +/** + * @class + * Class for localised formatting of numbers. + * + *

See: + * POSIX LC_NUMERIC. + * + * + * @public + * @constructor + * @description Creates a new numeric formatter for the specified locale. + * + * @param {jsworld.Locale} locale A locale object specifying the required + * POSIX LC_NUMERIC formatting properties. + * + * @throws Error on constructor failure. + */ +jsworld.NumericFormatter = function(locale) { + + if (typeof locale != "object" || locale._className != "jsworld.Locale") + throw "Constructor error: You must provide a valid jsworld.Locale instance"; + + this.lc = locale; + + + /** + * @public + * + * @description Formats a decimal numeric value according to the preset + * locale. + * + * @param {Number|String} number The number to format. + * @param {String} [options] Options to modify the formatted output: + *

    + *
  • "^" suppress grouping + *
  • "+" force positive sign for positive amounts + *
  • "~" suppress positive/negative sign + *
  • ".n" specify decimal precision 'n' + *
+ * + * @returns {String} The formatted number. + * + * @throws "Error: Invalid input" on bad input. + */ + this.format = function(number, options) { + + if (typeof number == "string") + number = jsworld._trim(number); + + if (! jsworld._isNumber(number)) + throw "Error: The input is not a number"; + + var floatAmount = parseFloat(number, 10); + + // get the required precision + var reqPrecision = jsworld._getPrecision(options); + + // round to required precision + if (reqPrecision != -1) + floatAmount = Math.round(floatAmount * Math.pow(10, reqPrecision)) / Math.pow(10, reqPrecision); + + + // convert the float number to string and parse into + // object with properties integer and fraction + var parsedAmount = jsworld._splitNumber(String(floatAmount)); + + // format integer part with grouping chars + var formattedIntegerPart; + + if (floatAmount === 0) + formattedIntegerPart = "0"; + else + formattedIntegerPart = jsworld._hasOption("^", options) ? + parsedAmount.integer : + jsworld._formatIntegerPart(parsedAmount.integer, + this.lc.grouping, + this.lc.thousands_sep); + + // format the fractional part + var formattedFractionPart = + reqPrecision != -1 ? + jsworld._formatFractionPart(parsedAmount.fraction, reqPrecision) : + parsedAmount.fraction; + + + // join the integer and fraction parts using the decimal_point property + var formattedAmount = + formattedFractionPart.length ? + formattedIntegerPart + this.lc.decimal_point + formattedFractionPart : + formattedIntegerPart; + + // prepend sign? + if (jsworld._hasOption("~", options) || floatAmount === 0) { + // suppress both '+' and '-' signs, i.e. return abs value + return formattedAmount; + } + else { + if (jsworld._hasOption("+", options) || floatAmount < 0) { + if (floatAmount > 0) + // force '+' sign for positive amounts + return "+" + formattedAmount; + else if (floatAmount < 0) + // prepend '-' sign + return "-" + formattedAmount; + else + // zero case + return formattedAmount; + } + else { + // positive amount with no '+' sign + return formattedAmount; + } + } + }; +}; + + +/** + * @class + * Class for localised formatting of dates and times. + * + *

See: + * POSIX LC_TIME. + * + * @public + * @constructor + * @description Creates a new date/time formatter for the specified locale. + * + * @param {jsworld.Locale} locale A locale object specifying the required + * POSIX LC_TIME formatting properties. + * + * @throws Error on constructor failure. + */ +jsworld.DateTimeFormatter = function(locale) { + + + if (typeof locale != "object" || locale._className != "jsworld.Locale") + throw "Constructor error: You must provide a valid jsworld.Locale instance."; + + this.lc = locale; + + + /** + * @public + * + * @description Formats a date according to the preset locale. + * + * @param {Date|String} date A valid Date object instance or a string + * containing a valid ISO-8601 formatted date, e.g. "2010-31-03" + * or "2010-03-31 23:59:59". + * + * @returns {String} The formatted date + * + * @throws Error on invalid date argument + */ + this.formatDate = function(date) { + + var d = null; + + if (typeof date == "string") { + // assume ISO-8601 date string + try { + d = jsworld.parseIsoDate(date); + } catch (error) { + // try full ISO-8601 date/time string + d = jsworld.parseIsoDateTime(date); + } + } + else if (date !== null && typeof date == "object") { + // assume ready Date object + d = date; + } + else { + throw "Error: Invalid date argument, must be a Date object or an ISO-8601 date/time string"; + } + + return this._applyFormatting(d, this.lc.d_fmt); + }; + + + /** + * @public + * + * @description Formats a time according to the preset locale. + * + * @param {Date|String} date A valid Date object instance or a string + * containing a valid ISO-8601 formatted time, e.g. "23:59:59" + * or "2010-03-31 23:59:59". + * + * @returns {String} The formatted time. + * + * @throws Error on invalid date argument. + */ + this.formatTime = function(date) { + + var d = null; + + if (typeof date == "string") { + // assume ISO-8601 time string + try { + d = jsworld.parseIsoTime(date); + } catch (error) { + // try full ISO-8601 date/time string + d = jsworld.parseIsoDateTime(date); + } + } + else if (date !== null && typeof date == "object") { + // assume ready Date object + d = date; + } + else { + throw "Error: Invalid date argument, must be a Date object or an ISO-8601 date/time string"; + } + + return this._applyFormatting(d, this.lc.t_fmt); + }; + + + /** + * @public + * + * @description Formats a date/time value according to the preset + * locale. + * + * @param {Date|String} date A valid Date object instance or a string + * containing a valid ISO-8601 formatted date/time, e.g. + * "2010-03-31 23:59:59". + * + * @returns {String} The formatted time. + * + * @throws Error on invalid argument. + */ + this.formatDateTime = function(date) { + + var d = null; + + if (typeof date == "string") { + // assume ISO-8601 format + d = jsworld.parseIsoDateTime(date); + } + else if (date !== null && typeof date == "object") { + // assume ready Date object + d = date; + } + else { + throw "Error: Invalid date argument, must be a Date object or an ISO-8601 date/time string"; + } + + return this._applyFormatting(d, this.lc.d_t_fmt); + }; + + + /** + * @private + * + * @description Apples formatting to the Date object according to the + * format string. + * + * @param {Date} d A valid Date instance. + * @param {String} s The formatting string with '%' placeholders. + * + * @returns {String} The formatted string. + */ + this._applyFormatting = function(d, s) { + + s = s.replace(/%%/g, '%'); + s = s.replace(/%a/g, this.lc.abday[d.getDay()]); + s = s.replace(/%A/g, this.lc.day[d.getDay()]); + s = s.replace(/%b/g, this.lc.abmon[d.getMonth()]); + s = s.replace(/%B/g, this.lc.mon[d.getMonth()]); + s = s.replace(/%d/g, jsworld._zeroPad(d.getDate(), 2)); + s = s.replace(/%e/g, jsworld._spacePad(d.getDate(), 2)); + s = s.replace(/%F/g, d.getFullYear() + + "-" + + jsworld._zeroPad(d.getMonth()+1, 2) + + "-" + + jsworld._zeroPad(d.getDate(), 2)); + s = s.replace(/%h/g, this.lc.abmon[d.getMonth()]); // same as %b + s = s.replace(/%H/g, jsworld._zeroPad(d.getHours(), 2)); + s = s.replace(/%I/g, jsworld._zeroPad(this._hours12(d.getHours()), 2)); + s = s.replace(/%k/g, d.getHours()); + s = s.replace(/%l/g, this._hours12(d.getHours())); + s = s.replace(/%m/g, jsworld._zeroPad(d.getMonth()+1, 2)); + s = s.replace(/%n/g, "\n"); + s = s.replace(/%M/g, jsworld._zeroPad(d.getMinutes(), 2)); + s = s.replace(/%p/g, this._getAmPm(d.getHours())); + s = s.replace(/%P/g, this._getAmPm(d.getHours()).toLocaleLowerCase()); // safe? + s = s.replace(/%R/g, jsworld._zeroPad(d.getHours(), 2) + + ":" + + jsworld._zeroPad(d.getMinutes(), 2)); + s = s.replace(/%S/g, jsworld._zeroPad(d.getSeconds(), 2)); + s = s.replace(/%T/g, jsworld._zeroPad(d.getHours(), 2) + + ":" + + jsworld._zeroPad(d.getMinutes(), 2) + + ":" + + jsworld._zeroPad(d.getSeconds(), 2)); + s = s.replace(/%w/g, this.lc.day[d.getDay()]); + s = s.replace(/%y/g, new String(d.getFullYear()).substring(2)); + s = s.replace(/%Y/g, d.getFullYear()); + + s = s.replace(/%Z/g, ""); // to do: ignored until a reliable TMZ method found + + s = s.replace(/%[a-zA-Z]/g, ""); // ignore all other % sequences + + return s; + }; + + + /** + * @private + * + * @description Does 24 to 12 hour conversion. + * + * @param {integer Number} hour24 Hour [0..23]. + * + * @returns {integer Number} Corresponding hour [1..12]. + */ + this._hours12 = function(hour24) { + + if (hour24 === 0) + return 12; // 00h is 12AM + + else if (hour24 > 12) + return hour24 - 12; // 1PM to 11PM + + else + return hour24; // 1AM to 12PM + }; + + + /** + * @private + * + * @description Gets the appropriate localised AM or PM string depending + * on the day hour. Special cases: midnight is 12AM, noon is 12PM. + * + * @param {integer Number} hour24 Hour [0..23]. + * + * @returns {String} The corresponding localised AM or PM string. + */ + this._getAmPm = function(hour24) { + + if (hour24 < 12) + return this.lc.am; + else + return this.lc.pm; + }; +}; + + + +/** + * @class Class for localised formatting of currency amounts. + * + *

See: + * POSIX LC_MONETARY. + * + * @public + * @constructor + * @description Creates a new monetary formatter for the specified locale. + * + * @param {jsworld.Locale} locale A locale object specifying the required + * POSIX LC_MONETARY formatting properties. + * @param {String} [currencyCode] Set the currency explicitly by + * passing its international ISO-4217 code, e.g. "USD", "EUR", "GBP". + * Use this optional parameter to override the default local currency + * @param {String} [altIntSymbol] Non-local currencies are formatted + * with their international ISO-4217 code to prevent ambiguity. + * Use this optional argument to force a different symbol, such as the + * currency's shorthand sign. This is mostly useful when the shorthand + * sign is both internationally recognised and identifies the currency + * uniquely (e.g. the Euro sign). + * + * @throws Error on constructor failure. + */ +jsworld.MonetaryFormatter = function(locale, currencyCode, altIntSymbol) { + + if (typeof locale != "object" || locale._className != "jsworld.Locale") + throw "Constructor error: You must provide a valid jsworld.Locale instance"; + + this.lc = locale; + + /** + * @private + * @description Lookup table to determine the fraction digits for a + * specific currency; most currencies subdivide at 1/100 (2 fractional + * digits), so we store only those that deviate from the default. + * + *

The data is from Unicode's CLDR version 1.7.0. The two currencies + * with non-decimal subunits (MGA and MRO) are marked as having no + * fractional digits as well as all currencies that have no subunits + * in circulation. + * + *

It is "hard-wired" for referential convenience and is only looked + * up when an overriding currencyCode parameter is supplied. + */ + this.currencyFractionDigits = { + "AFN" : 0, "ALL" : 0, "AMD" : 0, "BHD" : 3, "BIF" : 0, + "BYR" : 0, "CLF" : 0, "CLP" : 0, "COP" : 0, "CRC" : 0, + "DJF" : 0, "GNF" : 0, "GYD" : 0, "HUF" : 0, "IDR" : 0, + "IQD" : 0, "IRR" : 0, "ISK" : 0, "JOD" : 3, "JPY" : 0, + "KMF" : 0, "KRW" : 0, "KWD" : 3, "LAK" : 0, "LBP" : 0, + "LYD" : 3, "MGA" : 0, "MMK" : 0, "MNT" : 0, "MRO" : 0, + "MUR" : 0, "OMR" : 3, "PKR" : 0, "PYG" : 0, "RSD" : 0, + "RWF" : 0, "SLL" : 0, "SOS" : 0, "STD" : 0, "SYP" : 0, + "TND" : 3, "TWD" : 0, "TZS" : 0, "UGX" : 0, "UZS" : 0, + "VND" : 0, "VUV" : 0, "XAF" : 0, "XOF" : 0, "XPF" : 0, + "YER" : 0, "ZMK" : 0 + }; + + + // optional currencyCode argument? + if (typeof currencyCode == "string") { + // user wanted to override the local currency + this.currencyCode = currencyCode.toUpperCase(); + + // must override the frac digits too, for some + // currencies have 0, 2 or 3! + var numDigits = this.currencyFractionDigits[this.currencyCode]; + if (typeof numDigits != "number") + numDigits = 2; // default for most currencies + this.lc.frac_digits = numDigits; + this.lc.int_frac_digits = numDigits; + } + else { + // use local currency + this.currencyCode = this.lc.int_curr_symbol.substring(0,3).toUpperCase(); + } + + // extract intl. currency separator + this.intSep = this.lc.int_curr_symbol.charAt(3); + + // flag local or intl. sign formatting? + if (this.currencyCode == this.lc.int_curr_symbol.substring(0,3)) { + // currency matches the local one? -> + // formatting with local symbol and parameters + this.internationalFormatting = false; + this.curSym = this.lc.currency_symbol; + } + else { + // currency doesn't match the local -> + + // do we have an overriding currency symbol? + if (typeof altIntSymbol == "string") { + // -> force formatting with local parameters, using alt symbol + this.curSym = altIntSymbol; + this.internationalFormatting = false; + } + else { + // -> force formatting with intl. sign and parameters + this.internationalFormatting = true; + } + } + + + /** + * @public + * + * @description Gets the currency symbol used in formatting. + * + * @returns {String} The currency symbol. + */ + this.getCurrencySymbol = function() { + + return this.curSym; + }; + + + /** + * @public + * + * @description Gets the position of the currency symbol relative to + * the amount. Assumes a non-negative amount and local formatting. + * + * @param {String} intFlag Optional flag to force international + * formatting by passing the string "i". + * + * @returns {Boolean} True if the symbol precedes the amount, false if + * the symbol succeeds the amount. + */ + this.currencySymbolPrecedes = function(intFlag) { + + if (typeof intFlag == "string" && intFlag == "i") { + // international formatting was forced + if (this.lc.int_p_cs_precedes == 1) + return true; + else + return false; + + } + else { + // check whether local formatting is on or off + if (this.internationalFormatting) { + if (this.lc.int_p_cs_precedes == 1) + return true; + else + return false; + } + else { + if (this.lc.p_cs_precedes == 1) + return true; + else + return false; + } + } + }; + + + /** + * @public + * + * @description Gets the decimal delimiter (radix) used in formatting. + * + * @returns {String} The radix character. + */ + this.getDecimalPoint = function() { + + return this.lc.mon_decimal_point; + }; + + + /** + * @public + * + * @description Gets the number of fractional digits. Assumes local + * formatting. + * + * @param {String} intFlag Optional flag to force international + * formatting by passing the string "i". + * + * @returns {integer Number} The number of fractional digits. + */ + this.getFractionalDigits = function(intFlag) { + + if (typeof intFlag == "string" && intFlag == "i") { + // international formatting was forced + return this.lc.int_frac_digits; + } + else { + // check whether local formatting is on or off + if (this.internationalFormatting) + return this.lc.int_frac_digits; + else + return this.lc.frac_digits; + } + }; + + + /** + * @public + * + * @description Formats a monetary amount according to the preset + * locale. + * + *

+	 * For local currencies the native shorthand symbol will be used for
+	 * formatting.
+	 * Example:
+	 *        locale is en_US
+	 *        currency is USD
+	 *        -> the "$" symbol will be used, e.g. $123.45
+	 *        
+	 * For non-local currencies the international ISO-4217 code will be
+	 * used for formatting.
+	 * Example:
+	 *       locale is en_US (which has USD as currency)
+	 *       currency is EUR
+	 *       -> the ISO three-letter code will be used, e.g. EUR 123.45
+	 *
+	 * If the currency is non-local, but an alternative currency symbol was
+	 * provided, this will be used instead.
+	 * Example
+	 *       locale is en_US (which has USD as currency)
+	 *       currency is EUR
+	 *       an alternative symbol is provided - "€"
+	 *       -> the alternative symbol will be used, e.g. €123.45
+	 * 
+ * + * @param {Number|String} amount The amount to format as currency. + * @param {String} [options] Options to modify the formatted output: + *
'; +html += '
Post Game Log Message
'; +html += '
'; +html += ''; +html += '
Enter your log message here. Plain text only please.
'; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "hide_popup_dialog()") + ' ' + large_icon_button('check', 'Post Message', "glog_post('"+game_id+"')") + '
'; +html += '
'; +html += ''; +session.hooks.keys[ESC_KEY] = 'hide_popup_dialog'; +safe_focus( 'fe_glog_body' ); +show_popup_dialog(500, 175, html); +} +function glog_post(game_id) { +var msg = trim( $('fe_glog_body').value ); +if (msg) { +hide_popup_dialog(); +effect_api_send('game_post_log', { +GameID: game_id, +Message: msg +}, [this, 'glog_post_finish'], { _game_id: game_id }); +} +} +function glog_post_finish(response, tx) { +show_glog_widget( tx._game_id ); +} +function hide_glog_widget() { +$('glog_widget').hide(); +} +function get_icon_for_glog_type(type) { +var icon = 'page_white.png'; +switch (type) { +case 'asset': icon = 'folder_page_white.png'; break; +case 'game': icon = 'controller.png'; break; +case 'member': icon = 'user'; break; +case 'comment': icon = 'comment.png'; break; +case 'level': icon = 'world.png'; break; +case 'sprite': icon = 'cog.png'; break; +case 'tile': icon = 'brick.png'; break; +case 'tileset': icon = 'color_swatch.png'; break; +case 'rev': icon = 'cd.png'; break; +case 'revision': icon = 'cd.png'; break; +case 'font': icon = 'style.png'; break; +case 'key': icon = 'keyboard.png'; break; +case 'audio': icon = 'sound'; break; +case 'payment': icon = 'money.png'; break; +case 'env': icon = 'weather.png'; break; +case 'environment': icon = 'weather.png'; break; +} +return icon; +} +function effect_load_script(url) { +Debug.trace('api', 'Loading script: ' + url); +load_script(url); +} +function effect_api_get_ie(cmd, params, userData) { +if (!session.api_state_ie) session.api_state_ie = {}; +var unique_id = get_unique_id(); +session.api_state_ie[unique_id] = userData; +params.format = 'js'; +params.onafter = 'effect_api_response_ie(' + unique_id + ', response);'; +var url = '/effect/api/' + cmd + composeQueryString(params); +Debug.trace('api', "Sending MSIE HTTP GET: " + url); +load_script(url); +} +function effect_api_response_ie(unique_id, tree) { +Debug.trace('api', "Got response from MSIE HTTP GET"); +var tx = session.api_state_ie[unique_id]; +delete session.api_state_ie[unique_id]; +if (tree.Code == 'session') { +do_logout_2(); +return; +} +if (tree.Code == 'access') { +do_notice("Access Denied", tree.Description, 'do_not_pass_go'); +return; +} +if (tree.Code != 0) { +if (tx._on_error) return fire_callback( tx._on_error, tree, tx ); +return do_error( tree.Description ); +} +if (tree.SessionID) { +if (tree.SessionID == '_DELETE_') { +delete session.cookie.tree.effect_session_id; +} +else { +session.cookie.set( 'effect_session_id', tree.SessionID ); +} +session.cookie.save(); +} +if (tx._api_callback) { +fire_callback( tx._api_callback, tree, tx ); +} +} +function effect_api_get(cmd, params, callback, userData) { +if (!userData) userData = {}; +userData._api_callback = callback; +if (!session.api_mod_cache[cmd] && session.username) session.api_mod_cache[cmd] = hires_time_now(); +if (!params.mod && session.api_mod_cache[cmd]) params.mod = session.api_mod_cache[cmd]; +if (ie) return effect_api_get_ie(cmd, params, userData); +var url = '/effect/api/' + cmd + composeQueryString(params); +Debug.trace('api', "Sending HTTP GET: " + url); +ajax.get( url, 'effect_api_response', userData ); +} +function effect_api_send(cmd, xml, callback, userData) { +if (!userData) userData = {}; +userData._api_callback = callback; +var data = compose_xml('EffectRequest', xml); +Debug.trace('api', "Sending API Command: " + cmd + ": " + data); +ajax.send({ +method: 'POST', +url: '/effect/api/' + cmd, +data: data, +headers: { 'Content-Type': 'text/xml' } +}, 'effect_api_response', userData); +} +function effect_api_response(tx) { +Debug.trace('api', "HTTP " + tx.response.code + ": " + tx.response.data); +if (tx.response.code == 999) { +if (tx.request._auto_retry) { +session.net_error = false; +show_progress_dialog(1, "Trying to reestablish connection..."); +session.net_error = true; +setTimeout( function() { ajax.send(tx.request); }, 1000 ); +return; +} +else return do_error( "HTTP ERROR: " + tx.response.code + ": " + tx.response.data + ' (URL: ' + tx.request.url + ')' ); +} +if (session.net_error) { +hide_progress_dialog(); +session.net_error = false; +} +if (tx.response.code != 200) { +if (tx._silent) return; +else return do_error( "HTTP ERROR: " + tx.response.code + ": " + tx.response.data + ' (URL: ' + tx.request.url + ')' ); +} +var tree = null; +if (!tx._raw) { +var parser = new XML({ +preserveAttributes: true, +text: tx.response.data +}); +if (parser.getLastError()) return do_error("XML PARSE ERROR: " + parser.getLastError()); +tree = parser.getTree(); +if (tree.Code == 'session') { +do_logout_2(); +return; +} +if (tree.Code == 'access') { +do_notice("Access Denied", tree.Description, 'do_not_pass_go'); +return; +} +if (tree.Code != 0) { +if (tx._on_error) return fire_callback( tx._on_error, tree, tx ); +return do_error( tree.Description ); +} +if (tree.SessionID) { +if (tree.SessionID == '_DELETE_') { +delete session.cookie.tree.effect_session_id; +} +else { +session.cookie.set( 'effect_session_id', tree.SessionID ); +} +session.cookie.save(); +} +} +if (tx._api_callback) { +fire_callback( tx._api_callback, tree, tx ); +} +} +function effect_api_mod_touch() { +for (var idx = 0, len = arguments.length; idx < len; idx++) { +session.api_mod_cache[ arguments[idx] ] = hires_time_now(); +} +} +function do_not_pass_go() { +Nav.go('Main'); +} +var Nav = { +loc: '', +old_loc: '', +inited: false, +nodes: [], +init: function() { +if (!this.inited) { +this.inited = true; +this.loc = 'init'; +this.monitor(); +} +}, +monitor: function() { +var parts = window.location.href.split(/\#/); +var anchor = parts[1]; +if (!anchor) anchor = 'Main'; +var full_anchor = '' + anchor; +var sub_anchor = ''; +anchor = anchor.replace(/\%7C/, '|'); +if (anchor.match(/\|(\w+)$/)) { +sub_anchor = RegExp.$1.toLowerCase(); +anchor = anchor.replace(/\|(\w+)$/, ''); +} +if ((anchor != this.loc) && !anchor.match(/^_/)) { +Debug.trace('nav', "Caught navigation anchor: " + full_anchor); +var page_name = ''; +var page_args = null; +if (full_anchor.match(/^\w+\?.+/)) { +parts = full_anchor.split(/\?/); +page_name = parts[0]; +page_args = parseQueryString( parts[1] ); +} +else if (full_anchor.match(/^(\w+)\/(.*)$/)) { +page_name = RegExp.$1; +page_args = RegExp.$2; +} +else { +parts = full_anchor.split(/\//); +page_name = parts[0]; +page_args = parts.slice(1); +} +Debug.trace('nav', "Calling page: " + page_name + ": " + serialize(page_args)); +hide_popup_dialog(); +var result = page_manager.click( page_name, page_args ); +if (result) { +if (window.pageTracker && (this.loc != 'init')) { +setTimeout( function() { pageTracker._trackPageview('/effect/' + anchor); }, 1000 ); +} +this.old_loc = this.loc; +if (this.old_loc == 'init') this.old_loc = 'Main'; +this.loc = anchor; +} +else { +this.go( this.loc ); +} +} +else if (sub_anchor != this.sub_anchor) { +Debug.trace('nav', "Caught sub-anchor: " + sub_anchor); +$P().gosub( sub_anchor ); +} +this.sub_anchor = sub_anchor; +setTimeout( 'Nav.monitor()', 100 ); +}, +go: function(anchor, force) { +anchor = anchor.replace(/^\#/, ''); +if (force) this.loc = 'init'; +window.location.href = '#' + anchor; +}, +prev: function() { +this.go( this.old_loc || 'Main' ); +}, +refresh: function() { +this.loc = 'refresh'; +}, +bar: function() { +var nodes = arguments; +var html = ''; +for (var idx = 0, len = nodes.length; idx < len; idx++) { +var node = nodes[idx]; +if (node) this.nodes[idx] = node; +else node = this.nodes[idx]; +if (node != '_ignore_') { +html += ''; +} +} +html += '
'; +$('d_nav_bar').innerHTML = html; +}, +title: function(name) { +if (name) document.title = name + ' | EffectGames.com'; +else document.title = 'EffectGames.com'; +}, +currentAnchor: function() { +var parts = window.location.href.split(/\#/); +var anchor = parts[1] || ''; +var sub_anchor = ''; +anchor = anchor.replace(/\%7C/, '|'); +if (anchor.match(/\|(\w+)$/)) { +sub_anchor = RegExp.$1.toLowerCase(); +anchor = anchor.replace(/\|(\w+)$/, ''); +} +return anchor; +} +}; +var Blog = { +edit_caption: '
*Bold*  |Italic|  {monospace}  [http://link]  Formatting Guide...
', +search: function(args) { +if (!args.mode) args.mode = 'and'; +if (!args.offset) args.offset = 0; +if (!args.limit) args.limit = 10; +if (!args.format) args.format = 'xml'; +var query_args = copy_object( args ); +delete query_args.callback; +effect_api_get( 'article_search', query_args, [this, 'search_response'], { _search_args: args } ); +}, +get_article_preview: function(row, args) { +var html = ''; +Debug.trace('blog', 'Row: ' + dumper(row)); +html += '
'; +var ext_article_url = 'http://' + location.hostname + '/effect/article.psp.html' + row.Path + '/' + row.ArticleID; +var article_url = '#Article' + row.Path + '/' + row.ArticleID; +html += ''; +if (!args.title_only) { +html += '
'; +html += row.Preview; +html += '  ' + (args.link_title || 'Read Full Story...') + ''; +html += '
'; +html += ''; +html += '
'; +var elem_class = args.footer_element_class || 'blog_preview_footer_element'; +if ((session.username == row.Username) || is_admin()) { +html += '
' + +icon('page_white_edit.png', "Edit", '#ArticleEdit?path=' + row.Path + '&id=' + row.ArticleID) + '
'; +} +html += '
' + get_user_display(row.Username) + '
'; +html += '
' + icon('calendar', get_short_date_time(row.Published)) + '
'; +html += '
' + icon('talk', row.Comments) + '
'; +if (0 && row.Tags) html += '
' + icon('note.png', make_tag_links(row.Tags, 3)) + '
'; +html += '
' + icon('facebook.png', 'Facebook', "window.open('http://www.facebook.com/sharer.php?u="+encodeURIComponent(ext_article_url)+'&t='+encodeURIComponent(row.Title)+"','sharer','toolbar=0,status=0,width=626,height=436')", "Share on Facebook") + '
'; +html += '
' + icon('twitter.png', 'Twitter', "window.open('http://twitter.com/home?status=Reading%20" + encodeURIComponent(row.Title) + "%3A%20" + encodeURIComponent(ext_article_url)+"')", "Share on Twitter") + '
'; +html += '
'; +html += '
'; +html += '
'; +} +html += '
'; +return html; +}, +search_response: function(response, tx) { +var args = tx._search_args; +if (args.callback) return fire_callback(args.callback, response, args); +var div = $(args.target); +assert(div, "Could not find target DIV: " + args.target); +var html = ''; +if (response.Rows && response.Rows.Row) { +var rows = always_array( response.Rows.Row ); +for (var idx = 0, len = rows.length; idx < len; idx++) { +var row = rows[idx]; +html += this.get_article_preview( row, args ); +} +if (args.more && (rows.length == args.limit)) { +html += large_icon_button('page_white_put.png', 'More...', "Blog.more(this, "+encode_object(args)+")") + '
'; +html += spacer(1,15) + '
'; +} +if (args.after) html += args.after; +} +else if (response.Code != 0) { +html = 'Search Error: ' . response.Code + ': ' + response.Description; +} +else { +html = args.none_found_msg || 'No articles found.'; +} +div.innerHTML = html; +}, +more: function(div, args) { +args.offset += args.limit; +Debug.trace('blog', "More Args: " + dumper(args)); +div.innerHTML = ''; +effect_api_get( 'article_search', args, [this, 'more_response'], { _search_args: args, _div: div } ); +}, +more_response: function(response, tx) { +var args = tx._search_args; +var button = tx._div; +var html = ''; +if (response.Rows && response.Rows.Row) { +var rows = always_array( response.Rows.Row ); +for (var idx = 0, len = rows.length; idx < len; idx++) { +var row = rows[idx]; +html += this.get_article_preview( row, args ); +} +if (args.more && (rows.length == args.limit)) { +html += large_icon_button('page_white_put.png', 'More...', "Blog.more(this, "+encode_object(args)+")") + '
'; +html += spacer(1,15) + '
'; +} +} +else if (response.Code != 0) { +html = 'Search Error: ' . response.Code + ': ' + response.Description; +} +else { +html = args.none_found_msg || 'No more articles found.'; +} +var div = document.createElement('div'); +div.innerHTML = html; +button.parentNode.replaceChild( div, button ); +} +}; +function make_tag_links(csv, max, base_url) { +if (!base_url) base_url = ''; +var tags = csv.split(/\,\s*/); +var append = ''; +if (max && (tags.length > max)) { +tags.length = max; +append = '...'; +} +var html = ''; +for (var idx = 0, len = tags.length; idx < len; idx++) { +html += ''+tags[idx]+''; +if (idx < len - 1) html += ', '; +} +html += append; +return html; +} +function get_url_friendly_title(title) { +title = title.toString().replace(/\W+/g, '_'); +if (title.length > 40) title = title.substring(0, 40); +title = title.replace(/^_+/, ''); +title = title.replace(/_+$/, ''); +return title; +} +function get_full_url(url) { +if (url.match(/^\#/)) { +var parts = window.location.href.split(/\#/); +url = parts[0] + url; +} +return url; +} +var Comments = { +comments_per_page: 10, +get: function(page_id) { +var html = ''; +html += '
'; +html += '
Comments'; +html += '
'; +html += '
'; +html += '
'; +setTimeout( function() { Comments.search({ page_id: page_id }); }, 1 ); +return html; +}, +search: function(args) { +if (!args.limit) args.limit = this.comments_per_page; +if (!args.offset) args.offset = 0; +assert(args.page_id, "Comments.search: No page_id specified"); +args.format = 'xml'; +this.last_search = args; +effect_api_get( 'comments_get', args, [this, 'search_response'], { _search_args: args } ); +}, +research: function(offset) { +var args = this.last_search; +if (!args) return; +args.offset = offset; +effect_api_get( 'comments_get', args, [this, 'search_response'], { _search_args: args } ); +}, +search_response: function(response, tx) { +this.comments = []; +var args = tx._search_args; +if (args.callback) return fire_callback(args.callback, response, args); +var html = ''; +html += '
' + +large_icon_button( 'comment_edit.png', 'Post Comment...', "Comments.add('"+args.page_id+"')" ) + '
'; +if (args.page_id.match(/^Article\//)) { +html += '
' + icon('feed.png', 'RSS', '/effect/api/comment_feed/' + args.page_id + '.rss', 'Comments RSS Feed') + '
'; +} +if (response.Items && response.Items.Item && response.List && response.List.length) { +html += ''; +html += '
'; +var items = this.comments = always_array( response.Items.Item ); +for (var idx = 0, len = items.length; idx < len; idx++) { +var item = items[idx]; +var extra_classes = (args.highlight && (args.highlight == item.ID)) ? ' highlight' : ''; +html += '
'; +html += '
'; +if (item.Username) html += ''; +html += '' + item.Name.toString().toUpperCase() + ''; +if (item.Username) html += ''; +html += ', ' + get_short_date_time(item.Date) + '
'; +html += '
'; +html += this.get_comment_controls( args.page_id, item ); +html += '
'; +html += '
'; +html += '
' + item.Comment + '
'; +html += '
'; +html += ''; +if (item.LastReply && ((item.LastReply >= time_now() - (86400 * 7)) || (session.username && (session.username == item.Username)))) { +setTimeout( "Comments.show_replies('"+args.page_id+"','"+item.ID+"')", 1 ); +} +} +} +else { +} +$( 'd_comments_' + args.page_id ).innerHTML = html; +}, +get_control: function(icon, code, text, status_text) { +if (!icon.match(/\.\w+$/)) icon += '.gif'; +return '' + code_link(code, text, status_text) + ''; +}, +get_comment_controls: function(page_id, comment) { +var html = ''; +var spacer_txt = '  |  '; +if (session.user) { +html += this.get_control('comment', "Comments.reply('"+page_id+"','"+comment.ID+"')", 'Reply') + spacer_txt; +} +if (comment.Replies) { +if (comment._replies_visible) html += this.get_control('magnify_minus', "Comments.hide_replies('"+page_id+"','"+comment.ID+"')", 'Hide Replies'); +else html += this.get_control('magnify_plus', "Comments.show_replies('"+page_id+"','"+comment.ID+"')", 'Show Replies ('+comment.Replies+')'); +if (session.user) html += spacer_txt; +} +if (session.user) { +html += this.get_control( +'star', +"Comments.like('"+page_id+"','"+comment.ID+"')", +'Like' + (comment.Like ? (' ('+comment.Like+')') : ''), +comment.Like ? (comment.Like + ' ' + ((comment.Like == 1) ? 'person likes this' : 'people like this')) : 'I like this comment' +) + spacer_txt; +if (is_admin()) html += this.get_control('trash', "Comments._delete('"+page_id+"','"+comment.ID+"')", 'Delete') + spacer_txt; +html += this.get_control('warning', "Comments.report('"+page_id+"','"+comment.ID+"')", 'Report Abuse'); +} +return html; +}, +reply: function(page_id, comment_id) { +hide_popup_dialog(); +delete session.progress; +var comment = find_object( this.comments, { ID: comment_id } ); +var html = ''; +html += '
'; +html += '\n \n \n \n'); + }; + __out.push('\n\n'); + __out.push(require('templates/clients/modules/sub_header').call(this, { + heading: t("Ride Request") + })); + __out.push('\n\n\n
\n
\n
\n
\n \n \n \n \n
\n\n
'; +html += '
Reply to Comment by "'+comment.Name+'"
'; +html += '
'; +var name = this.get_name(); +html += '

Posted by: ' + name; +if (!session.user) html += ' → Create Account'; +html += '


'; +html += ''; +html += Blog.edit_caption; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "hide_popup_dialog()") + ' ' + large_icon_button('check', 'Post Reply', "Comments.post_reply('"+page_id+"','"+comment_id+"')") + '
'; +html += '
'; +html += ''; +session.hooks.keys[ESC_KEY] = 'hide_popup_dialog'; +safe_focus( 'fe_comment_body' ); +show_popup_dialog(600, 300, html); +}, +post_reply: function(page_id, comment_id) { +var value = $('fe_comment_body').value; +if (!value) return; +hide_popup_dialog(); +show_progress_dialog(1, "Posting reply..."); +var name = this.get_name(); +effect_api_mod_touch('comment_replies_get'); +effect_api_send('comment_post_reply', { +PageID: page_id, +CommentID: comment_id, +Username: session.username || '', +Name: name, +Comment: value, +PageURL: location.href +}, [this, 'post_reply_finish'], { _page_id: page_id, _comment_id: comment_id } ); +}, +post_reply_finish: function(response, tx) { +hide_popup_dialog(); +var page_id = tx._page_id; +var comment_id = tx._comment_id; +var comment = find_object( this.comments, { ID: comment_id } ); +do_message('success', "Comment reply posted successfully."); +this.show_replies(page_id, comment_id); +if (!comment.Replies) comment.Replies = 1; else comment.Replies++; +$('d_comment_controls_'+comment_id).innerHTML = this.get_comment_controls( page_id, comment ); +}, +show_replies: function(page_id, comment_id) { +var comment = find_object( this.comments, { ID: comment_id } ); +if (!comment._replies_visible) { +$('d_comment_replies_' + comment_id).show().innerHTML = ''; +} +var args = { page_id: page_id, comment_id: comment_id, offset: 0, limit: 100 }; +effect_api_get( 'comment_replies_get', args, [this, 'receive_replies_response'], { _search_args: args } ); +}, +receive_replies_response: function(response, tx) { +var page_id = tx._search_args.page_id; +var comment_id = tx._search_args.comment_id; +var comment = find_object( this.comments, { ID: comment_id } ); +var html = ''; +var replies = always_array( response.Items.Item ); +for (var idx = 0, len = replies.length; idx < len; idx++) { +var reply = replies[idx]; +html += get_chat_balloon( +(reply.Username == session.username) ? 'blue' : 'grey', +reply.Username, +reply.Comment.replace(/^]*?>(.+)<\/div>$/i, '$1') +); +} +$('d_comment_replies_' + comment_id).innerHTML = html; +if (!comment._replies_visible) { +$('d_comment_replies_' + comment_id).hide(); +animate_div_visibility( 'd_comment_replies_' + comment_id, true ); +} +comment._replies_visible = true; +$('d_comment_controls_'+comment_id).innerHTML = this.get_comment_controls( page_id, comment ); +}, +hide_replies: function(page_id, comment_id) { +var comment = find_object( this.comments, { ID: comment_id } ); +if (comment._replies_visible) { +animate_div_visibility( 'd_comment_replies_' + comment_id, false ); +comment._replies_visible = false; +$('d_comment_controls_'+comment_id).innerHTML = this.get_comment_controls( page_id, comment ); +} +}, +like: function(page_id, comment_id) { +effect_api_mod_touch('comments_get'); +effect_api_send('comment_like', { +PageID: page_id, +CommentID: comment_id +}, [this, 'like_finish'], { _page_id: page_id, _comment_id: comment_id, _on_error: [this, 'like_error'] } ); +}, +like_error: function(response, tx) { +if (response.Code == 'comment_already_like') do_message('error', "You already like this comment."); +else do_error( response.Description ); +}, +like_finish: function(resopnse, tx) { +var page_id = tx._page_id; +var comment_id = tx._comment_id; +var comment = find_object( this.comments, { ID: comment_id } ); +do_message('success', "You now like this comment."); +if (!comment.Like) comment.Like = 1; else comment.Like++; +$('d_comment_controls_'+comment_id).innerHTML = this.get_comment_controls( page_id, comment ); +}, +add: function(page_id) { +hide_popup_dialog(); +delete session.progress; +var html = ''; +html += '
'; +html += '\n \n \n \n \n \n \n \n \n \n '); + }, this); + __out.push('\n\n
\n
'; +html += '
Post New Comment
'; +html += '
'; +var name = this.get_name(); +html += '

Posted by: ' + name; +if (!session.user) html += ' → Create Account'; +html += '


'; +html += ''; +html += Blog.edit_caption; +html += '
'; +html += '

'; +html += ''; +html += ''; +html += ''; +html += '
' + large_icon_button('x', 'Cancel', "hide_popup_dialog()") + ' ' + large_icon_button('check', 'Post Comment', "Comments.post('"+page_id+"')") + '
'; +html += '
'; +html += ''; +session.hooks.keys[ESC_KEY] = 'hide_popup_dialog'; +safe_focus( 'fe_comment_body' ); +show_popup_dialog(600, 300, html); +}, +report: function(page_id, comment_id) { +if (confirm('Are you sure you want to report this comment to the site administrators as abusive and/or spam?')) { +effect_api_send('comment_report_abuse', { +PageID: page_id, +CommentID: comment_id +}, [this, 'report_finish'], { _page_id: page_id, _comment_id: comment_id } ); +} +}, +report_finish: function(response, tx) { +do_message('success', 'Your abuse report has been received, and will be evaluated by the site administrators.'); +}, +_delete: function(page_id, comment_id) { +if (confirm('Are you sure you want to permanently delete this comment?')) { +effect_api_mod_touch('comments_get'); +effect_api_send('comment_delete', { +PageID: page_id, +CommentID: comment_id +}, [this, 'delete_finish'], { _page_id: page_id, _comment_id: comment_id } ); +} +}, +delete_finish: function(response, tx) { +do_message('success', 'The comment was deleted successfully.'); +var page_id = tx._page_id; +this.search({ page_id: page_id }); +}, +get_name: function() { +var name = '(Anonymous)'; +if (session.user) { +if (get_bool_pref('public_profile')) name = session.user.FullName; +else name = session.username; +} +return name; +}, +post: function(page_id) { +var value = $('fe_comment_body').value; +if (!value) return; +hide_popup_dialog(); +show_progress_dialog(1, "Posting comment..."); +var name = this.get_name(); +effect_api_mod_touch('comments_get'); +effect_api_send('comment_post', { +PageID: page_id, +Username: session.username || '', +Name: name, +Comment: value +}, [this, 'post_finish'], { _page_id: page_id } ); +}, +post_finish: function(response, tx) { +hide_popup_dialog(); +var comment_id = response.CommentID; +var page_id = tx._page_id; +this.search({ page_id: page_id, highlight: comment_id }); +} +}; +Class.create( 'Menu', { +id: '', +menu: null, +__construct: function(id) { +this.id = id; +}, +load: function() { +if (!this.menu) { +this.menu = $(this.id); +assert( !!this.menu, "Could not locate DOM element: " + this.id ); +} +}, +get_value: function() { +this.load(); +return this.menu.options[this.menu.selectedIndex].value; +}, +set_value: function(value, auto_add) { +value = str_value(value); +this.load(); +for (var idx = 0, len = this.menu.options.length; idx < len; idx++) { +if (this.menu.options[idx].value == value) { +this.menu.selectedIndex = idx; +return true; +} +} +if (auto_add) { +this.menu.options[this.menu.options.length] = new Option(value, value); +this.menu.selectedIndex = this.menu.options.length - 1; +return true; +} +return false; +}, +disable: function() { +this.load(); +this.menu.disabled = true; +this.menu.setAttribute( 'disabled', 'disabled' ); +}, +enable: function() { +this.load(); +this.menu.setAttribute( 'disabled', '' ); +this.menu.disabled = false; +}, +populate: function(items, sel_value) { +this.load(); +this.menu.options.length = 0; +for (var idx = 0, len = items.length; idx < len; idx++) { +var item = items[idx]; +var item_name = ''; +var item_value = ''; +if (isa_hash(item)) { +item_name = item.label; +item_value = item.data; +} +else if (isa_array(item)) { +item_name = item[0]; +item_value = item[1]; +} +else { +item_name = item_value = item; +} +this.menu.options[ this.menu.options.length ] = new Option( item_name, item_value ); +if (item_value == sel_value) this.menu.selectedIndex = idx; +} +} +} ); +Class.subclass( Menu, 'MultiMenu', { +__static: { +toggle_type: function(id) { +var menu = $(id); +assert(menu, "Could not find menu in DOM: " + id); +if (menu.disabled) return; +var obj = MenuManager.find(id); +assert(obj, "Could not find menu in MenuManager: " + id); +var div = $( 'd_inner_' + id ); +var ic = $( 'ic_' + id ); +var is_multiple = (ic.src.indexOf('contract') > -1); +obj.multi = !is_multiple; +var multiple_tag = !is_multiple ? +' multiple="multiple" size=5' : ''; +var items = []; +for (var idx = 0; idx < menu.options.length; idx++) { +var option = menu.options[idx]; +array_push( items, { +value: option.value, +text: option.text, +selected: option.selected +}); +} +var html = ''; +html += ''; +div.innerHTML = html; +ic.src = images_uri + '/menu_' + (is_multiple ? 'expand' : 'contract') + '.gif'; +obj.menu = null; +} +}, +attribs: null, +multi: false, +toggle: true, +__construct: function(id, attribs) { +this.id = id; +if (attribs) this.attribs = attribs; +}, +get_html: function(items, selected_csv, attribs) { +if (!items) items = []; +if (!selected_csv) selected_csv = ''; +if (attribs) this.attribs = attribs; +var selected = csv_to_hash(selected_csv); +this.menu = null; +if (num_keys(selected) > 1) this.multi = true; +var html = '
'; +html += ''; +html += ''; +html += ''; +if (this.toggle) html += ''; +html += '
' + spacer(1,1) + '
'+spacer(1,2)+'
'; +html += '
'; +return html; +}, +get_value: function() { +this.load(); +var value = ''; +for (var idx = 0; idx < this.menu.options.length; idx++) { +var option = this.menu.options[idx]; +if (option.selected && option.value.length) { +if (value.length > 0) value += ','; +value += option.value; +} +} +return value; +}, +set_value: function(value, auto_add) { +value = '' + value; +this.load(); +if (!value) { +value = ''; +for (var idx = 0; idx < this.menu.options.length; idx++) { +var option = this.menu.options[idx]; +option.selected = (option.value == value); +} +return; +} +var selected = csv_to_hash(value); +if ((num_keys(selected) > 1) && !this.multi) { +MultiMenu.toggle_type(this.id); +var self = this; +setTimeout( function() { +self.set_value(value, auto_add); +}, 1 ); +return; +} +for (var idx = 0; idx < this.menu.options.length; idx++) { +var option = this.menu.options[idx]; +option.selected = selected[option.value] ? true : false; +} +}, +populate: function(items, value) { +this.load(); +this.menu.options.length = 0; +if (!value) value = ''; +var selected = csv_to_hash(value); +for (var idx = 0, len = items.length; idx < len; idx++) { +var item = items[idx]; +var item_name = ''; +var item_value = ''; +if (isa_hash(item)) { +item_name = item.label; +item_value = item.data; +} +else if (isa_array(item)) { +item_name = item[0]; +item_value = item[1]; +} +else { +item_name = item_value = item; +} +var opt = new Option( item_name, item_value ); +this.menu.options[ this.menu.options.length ] = opt; +opt.selected = selected[item_value] ? true : false; +} +}, +collapse: function() { +if (this.multi) MultiMenu.toggle_type(this.id); +}, +expand: function() { +if (!this.multi) MultiMenu.toggle_type(this.id); +} +} ); +Class.create( 'MenuManager', { +__static: { +menus: {}, +register: function(menu) { +this.menus[ menu.id ] = menu; +return menu; +}, +find: function(id) { +return this.menus[id]; +} +} +} ); +Class.create( 'GrowlManager', { +lifetime: 10, +marginRight: 0, +marginTop: 0, +__construct: function() { +this.growls = []; +}, +growl: function(type, msg) { +if (find_object(this.growls, { type: type, msg: msg })) return; +var div = $(document.createElement('div')); +div.className = 'growl_message ' + type; +div.setOpacity(0.0); +div.innerHTML = '
' + msg + '
' + spacer(1,5) + '
'; +$('d_growl_wrapper').insertBefore( div, $('d_growl_top').nextSibling ); +var growl = { id:get_unique_id(), type: type, msg: msg, opacity:0.0, start:hires_time_now(), div:div }; +this.growls.push(growl); +this.handle_resize(); +this.animate(growl); +var self = this; +div.onclick = function() { +delete_object(self.growls, { id: growl.id }); +$('d_growl_wrapper').removeChild( div ); +}; +}, +animate: function(growl) { +if (growl.deleted) return; +var now = hires_time_now(); +var div = growl.div; +if (now - growl.start <= 0.5) { +div.setOpacity( tweenFrame(0.0, 1.0, (now - growl.start) * 2, 'EaseOut', 'Quadratic') ); +} +else if (now - growl.start <= this.lifetime) { +if (!growl._fully_opaque) { +div.setOpacity( 1.0 ); +growl._fully_opaque = true; +} +} +else if (now - growl.start <= this.lifetime + 1.0) { +div.setOpacity( tweenFrame(1.0, 0.0, (now - growl.start) - this.lifetime, 'EaseOut', 'Quadratic') ); +} +else { +delete_object(this.growls, { id: growl.id }); +$('d_growl_wrapper').removeChild( div ); +return; +} +var self = this; +setTimeout( function() { self.animate(growl); }, 33 ); +}, +handle_resize: function() { +var div = $('d_growl_wrapper'); +if (this.growls.length) { +var size = getInnerWindowSize(); +div.style.top = '' + (10 + this.marginTop) + 'px'; +div.style.left = '' + Math.floor((size.width - 310) - this.marginRight) + 'px'; +} +else { +div.style.left = '-2000px'; +} +} +} ); +window.$GR = new GrowlManager(); +if (window.addEventListener) { +window.addEventListener( "resize", function() { +$GR.handle_resize(); +}, false ); +} +else if (window.attachEvent && !ie6) { +window.attachEvent("onresize", function() { +$GR.handle_resize(); +}); +} +Class.create( 'Effect.Page', { +ID: '', +data: null, +active: false, +__construct: function(config) { +if (!config) return; +this.data = {}; +if (!config) config = {}; +for (var key in config) this[key] = config[key]; +this.div = $('page_' + this.ID); +assert(this.div, "Cannot find page div: page_" + this.ID); +}, +onInit: function() { +}, +onActivate: function() { +return true; +}, +onDeactivate: function() { +return true; +}, +show: function() { +this.div.show(); +}, +hide: function() { +this.div.hide(); +}, +gosub: function(anchor) { +} +} ); +Class.require( 'Effect.Page' ); +Class.create( 'Effect.PageManager', { +pages: null, +current_page_id: '', +on_demand: {}, +__construct: function(page_list) { +this.pages = []; +this.page_list = page_list; +for (var idx = 0, len = page_list.length; idx < len; idx++) { +Debug.trace( 'page', "Initializing page: " + page_list[idx].ID ); +if (Effect.Page[ page_list[idx].ID ]) { +var page = new Effect.Page[ page_list[idx].ID ]( page_list[idx] ); +page.onInit(); +this.pages.push(page); +} +else { +Debug.trace( 'page', 'Page ' + page_list[idx].ID + ' will be loaded on-demand' ); +} +} +}, +find: function(id) { +var page = find_object( this.pages, { ID: id } ); +if (!page) Debug.trace('PageManager', "Could not find page: " + id); +return page; +}, +notify_load: function(file, id) { +for (var idx = 0, len = this.page_list.length; idx < len; idx++) { +var page_config = this.page_list[idx]; +if (page_config.File == file) { +Debug.trace( 'page', "Initializing page on-demand: " + page_config.ID ); +var page = new Effect.Page[ page_config.ID ]( page_config ); +page.onInit(); +this.pages.push(page); +} +} +var self = this; +setTimeout( function() { +var result = self.activate(id, self.temp_args); +delete self.temp_args; +$('d_page_loading').hide(); +if (!result) { +$('page_'+id).hide(); +self.current_page_id = ''; +} +}, 1 ); +}, +activate: function(id, args) { +if (!find_object( this.pages, { ID: id } )) { +var page_config = find_object( this.page_list, { ID: id } ); +assert(!!page_config, "Page config not found: " + id ); +Debug.trace('page', "Loading file on-demand: " + page_config.File + " for page: " + id); +var url = '/effect/api/load_page/' + page_config.File + '?onafter=' + escape('page_manager.notify_load(\''+page_config.File+'\',\''+id+'\')'); +if (page_config.Requires) { +var files = page_config.Requires.split(/\,\s*/); +for (var idx = 0, len = files.length; idx < len; idx++) { +var filename = files[idx]; +if (!this.on_demand[filename]) { +Debug.trace('page', "Also loading file: " + filename); +url += '&file=' + filename; +this.on_demand[filename] = 1; +} +} +} +$('d_page_loading').show(); +this.temp_args = args; +load_script( url ); +return true; +} +$('page_'+id).show(); +var page = this.find(id); +page.active = true; +if (!args) args = []; +if (!isa_array(args)) args = [ args ]; +var result = page.onActivate.apply(page, args); +if (typeof(result) == 'boolean') return result; +else return alert("Page " + id + " onActivate did not return a boolean!"); +}, +deactivate: function(id, new_id) { +var page = this.find(id); +var result = page.onDeactivate(new_id); +if (result) { +$('page_'+id).hide(); +page.active = false; +} +return result; +}, +click: function(id, args) { +Debug.trace('page', "Switching pages to: " + id); +var old_id = this.current_page_id; +if (this.current_page_id) { +var result = this.deactivate( this.current_page_id, id ); +if (!result) return false; +} +this.current_page_id = id; +this.old_page_id = old_id; +window.scrollTo( 0, 0 ); +var result = this.activate(id, args); +if (!result) { +$('page_'+id).hide(); +this.current_page_id = ''; +} +return true; +} +} ); +Class.subclass( Effect.Page, "Effect.Page.Main", { +inited: false, +onActivate: function() { +Nav.bar( ['Main', 'EffectGames.com'] ); +Nav.title(''); +$('d_blog_news').innerHTML = loading_image(); +$('d_blog_community').innerHTML = loading_image(); +$('d_blog_featured').innerHTML = loading_image(); +Blog.search({ +stag: 'featured_game', +limit: 4, +full: 1, +callback: [this, 'receive_featured_games'] +}); +effect_api_get( 'get_site_info', { cat: 'pop_pub_games' }, [this, 'receive_pop_pub_games'], { } ); +Blog.search({ +stag: 'front_page', +limit: 5, +target: 'd_blog_news', +more: 1 +}); +Blog.search({ +path: '/community', +limit: 5, +target: 'd_blog_community', +more: 1 +}); +if (!this.inited) { +this.inited = true; +config.Strings.MainSlideshow.Slide = always_array( config.Strings.MainSlideshow.Slide ); +this.slide_idx = 0; +this.num_slides = config.Strings.MainSlideshow.Slide.length; +this.slide_div_num = 0; +this.slide_dir = 1; +this.bk_pos = -340; +this.bk_pos_target = -340; +this.slide_images = []; +for (var idx = 0, len = this.num_slides; idx < len; idx++) { +var url = images_uri + '/' + config.Strings.MainSlideshow.Slide[idx].Photo; +this.slide_images[idx] = new Image(); +this.slide_images[idx].src = png(url, true); +} +} +this.height_target = 470; +this.height_start = $('d_header').offsetHeight; +this.time_start = hires_time_now(); +this.duration = 0.75; +if (!this.timer) this.timer = setTimeout( '$P("Main").animate_mhs()', 33 ); +if (session.user) $('d_blurb_main').hide(); +else { +$('d_blurb_main').innerHTML = get_string('/Main/Blurb'); +$('d_blurb_main').show(); +} +return true; +}, +receive_pop_pub_games: function(response, tx) { +var html = ''; +if (response.Data && response.Data.Games && response.Data.Games.Game) { +var games = always_array( response.Data.Games.Game ); +for (var idx = 0, len = Math.min(games.length, 16); idx < len; idx++) { +var game = games[idx]; +html += '
' + +(game.Logo ? +user_image_thumbnail(game.Logo, 80, 60) : +'' +) + '
' + ww_fit_box(game.Title, 80, 2, session.em_width, 1) + '
'; +} +html += '
'; +} +else { +html += 'No active public games found! Why not create a new one?'; +} +$('d_main_pop_pub_games').innerHTML = html; +}, +receive_featured_games: function(response, tx) { +var html = ''; +if (response.Rows && response.Rows.Row) { +html += ''; +var rows = always_array( response.Rows.Row ); +for (var idx = 0, len = rows.length; idx < len; idx++) { +var row = rows[idx]; +var image_url = row.Params.featured_image; +if (image_url && image_url.match(/^(\w+)\/(\w+\.\w+)$/)) { +image_url = '/effect/api/view/users/' + RegExp.$1 + '/images/' + RegExp.$2; +} +if (idx % 2 == 0) html += ''; +html += ''; +if (idx % 2 == 1) html += ''; +} +if (rows.length % 2 == 1) { +html += ''; +html += ''; +} +html += '
'; +html += ''; +html += ''; +html += ''; +html += ''; +html += ''; +html += '
'; +html += ''; +html += '' + spacer(10,1) + ''; +html += ''; +html += ''; +html += '' + spacer(15,1) + '
'; +html += spacer(1,20); +html += '
'; +} +$('d_blog_featured').innerHTML = html; +}, +animate_mhs: function() { +var now = hires_time_now(); +if (now - this.time_start >= this.duration) { +$('d_header').style.height = '' + this.height_target + 'px'; +$('d_shadow').style.height = '' + this.height_target + 'px'; +delete this.timer; +} +else { +var height = tweenFrame(this.height_start, this.height_target, (now - this.time_start) / this.duration, 'EaseOut', 'Circular'); +$('d_header').style.height = '' + height + 'px'; +$('d_shadow').style.height = '' + height + 'px'; +this.timer = setTimeout( '$P("Main").animate_mhs()', 33 ); +} +}, +onDeactivate: function() { +$('d_blog_news').innerHTML = ''; +$('d_blog_community').innerHTML = ''; +this.height_target = 75; +this.height_start = $('d_header').offsetHeight; +this.time_start = hires_time_now(); +if (!this.timer) this.timer = setTimeout( '$P("Main").animate_mhs()', 33 ); +return true; +}, +draw_slide: function() { +if (this.slide_timer) return; +var slide = config.Strings.MainSlideshow.Slide[ this.slide_idx ]; +this.old_photo = $('d_header_slideshow_photo_' + this.slide_div_num); +this.old_text = $('d_header_slideshow_text_' + this.slide_div_num); +this.slide_div_num = 1 - this.slide_div_num; +this.new_photo = $('d_header_slideshow_photo_' + this.slide_div_num); +this.new_text = $('d_header_slideshow_text_' + this.slide_div_num); +this.new_photo.style.backgroundImage = 'url('+png(images_uri+'/'+slide.Photo, true)+')'; +this.new_photo.setOpacity(0.0); +var html = ''; +html += slide.Text; +this.slide_width = this.new_text.offsetWidth; +this.new_text.innerHTML = html; +if (this.slide_dir == 1) this.new_text.style.left = '' + this.slide_width + 'px'; +else this.new_text.style.left = '-' + this.slide_width + 'px'; +this.slide_time_start = hires_time_now(); +this.slide_timer = setTimeout( '$P("Main").animate_mhs_slide()', 33 ); +}, +animate_mhs_slide: function() { +var now = hires_time_now(); +if (now - this.slide_time_start >= this.duration) { +this.new_text.style.left = '0px'; +this.old_text.style.left = '-' + this.slide_width + 'px'; +this.new_photo.setOpacity( 1.0 ); +this.old_photo.setOpacity( 0.0 ); +delete this.slide_timer; +this.bk_pos = this.bk_pos_target; +} +else { +var value = tweenFrame(0.0, 1.0, (now - this.slide_time_start) / this.duration, 'EaseOut', 'Circular'); +if (this.slide_dir == 1) { +this.new_text.style.left = '' + Math.floor( this.slide_width - (this.slide_width * value) ) + 'px'; +this.old_text.style.left = '-' + Math.floor( this.slide_width * value ) + 'px'; +} +else { +this.new_text.style.left = '-' + Math.floor( this.slide_width - (this.slide_width * value) ) + 'px'; +this.old_text.style.left = '' + Math.floor( this.slide_width * value ) + 'px'; +} +this.new_photo.setOpacity( value ); +this.old_photo.setOpacity( 1.0 - value ); +var bkp = Math.floor( this.bk_pos + ((this.bk_pos_target - this.bk_pos) * value) ); +$('d_header').style.backgroundPosition = '' + bkp + 'px 0px'; +this.slide_timer = setTimeout( '$P("Main").animate_mhs_slide()', 33 ); +} +}, +prev_slide: function() { +this.bk_pos_target += 200; +this.slide_idx--; +if (this.slide_idx < 0) this.slide_idx += this.num_slides; +this.slide_dir = -1; +this.draw_slide(); +}, +next_slide: function() { +this.bk_pos_target -= 200; +this.slide_idx++; +if (this.slide_idx >= this.num_slides) this.slide_idx -= this.num_slides; +this.slide_dir = 1; +this.draw_slide(); +} +} ); +Class.subclass( Effect.Page, "Effect.Page.PublicGameList", { +onActivate: function() { +Nav.bar( +['Main', 'EffectGames.com'], +['PublicGameList', "All Public Games"] +); +Nav.title( "List of All Public Game Projects" ); +effect_api_get( 'get_site_info', { cat: 'all_pub_games' }, [this, 'receive_all_pub_games'], { } ); +this.div.innerHTML = loading_image(); +return true; +}, +onDeactivate: function() { +this.div.innerHTML = ''; +return true; +}, +receive_all_pub_games: function(response, tx) { +var html = ''; +html += '

List of All Public Game Projects

'; +html += '
This is the complete list of public games currently being built by our users, presented in alphabetical order. Maybe they could use some help! Check out the game project pages and see (requires user account).
'; +if (response.Data && response.Data.Games && response.Data.Games.Game) { +var games = always_array( response.Data.Games.Game ); +for (var idx = 0, len = games.length; idx < len; idx++) { +var game = games[idx]; +html += '
' + +(game.Logo ? +user_image_thumbnail(game.Logo, 80, 60) : +'' +) + '
' + ww_fit_box(game.Title, 80, 2, session.em_width, 1) + '
'; +} +html += '
'; +} +else { +html += 'No public games found! Why not create a new one?'; +} +this.div.innerHTML = html; +} +} ); +Class.subclass( Effect.Page, "Effect.Page.Search", { +onActivate: function(args) { +if (!args) args = {}; +var search_text = args.q; +var start = args.s || 0; +if (!start) start = 0; +var title = 'Search results for "'+search_text+'"'; +Nav.bar( +['Main', 'EffectGames.com'], +['Search?q=' + escape(search_text), "Search Results"] +); +Nav.title( title ); +this.last_search_text = search_text; +$('d_article_search').innerHTML = loading_image(); +load_script( 'http://www.google.com/uds/GwebSearch?callback=receive_google_search_results&context=0&lstkp=0&rsz=large&hl=en&source=gsc&gss=.com&sig=&q='+escape(search_text)+'%20site%3Ahttp%3A%2F%2Fwww.effectgames.com%2F&key=notsupplied&v=1.0&start='+start+'&nocache=' + (new Date()).getTime() ); +$('h_article_search').innerHTML = title; +return true; +}, +onDeactivate: function(new_page) { +$('fe_search_bar').value = ''; +$('d_article_search').innerHTML = ''; +return true; +} +} ); +function do_search_bar() { +var search_text = $('fe_search_bar').value; +if (search_text.length) { +Nav.go('Search?q=' + escape(search_text)); +} +} +function receive_google_search_results(context, response) { +var html = ''; +html += '
Powered by
'; +if (response.results.length) { +for (var idx = 0, len = response.results.length; idx < len; idx++) { +var row = response.results[idx]; +var url = row.unescapedUrl.replace(/^.+article\.psp\.html/, '#Article'); +html += '
'; +html += ''; +html += '
' + row.content + '
'; +html += '
'; +} +} +else { +html += 'No results found.'; +} +if (response.cursor.pages) { +html += '
Page: '; +for (var idx = 0, len = response.cursor.pages.length; idx < len; idx++) { +html += ''; +var page = response.cursor.pages[idx]; +var url = '#Search?q=' + escape($P('Search').last_search_text) + '&s=' + page.start; +if (response.cursor.currentPageIndex != idx) html += ''; +else html += ''; +html += page.label; +if (response.cursor.currentPageIndex != idx) html += ''; +else html += ''; +html += ''; +} +html += '
'; +} +$('d_article_search').innerHTML = html; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/index.js b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/index.js new file mode 100644 index 0000000..8b164a4 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/index.js @@ -0,0 +1 @@ +exports.ZeParser = require('./ZeParser').ZeParser; diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/package.json b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/package.json new file mode 100644 index 0000000..63aa5b3 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/package.json @@ -0,0 +1,30 @@ +{ + "author": { + "name": "Peter van der Zee", + "url": "http://qfox.nl/" + }, + "name": "zeparser", + "description": "My JavaScript parser", + "version": "0.0.5", + "homepage": "https://github.com/qfox/ZeParser/", + "repository": { + "type": "git", + "url": "git://github.com/qfox/ZeParser.git" + }, + "main": "./index", + "engines": { + "node": "*" + }, + "dependencies": {}, + "devDependencies": {}, + "_id": "zeparser@0.0.5", + "optionalDependencies": {}, + "_engineSupported": true, + "_npmVersion": "1.1.4", + "_nodeVersion": "v0.6.12", + "_defaultsLoaded": true, + "dist": { + "shasum": "c530a6fa4cb4c5b2cabda19be70761499f72d453" + }, + "_from": "zeparser@0.0.5" +} diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-parser.html b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-parser.html new file mode 100755 index 0000000..1ff5ff4 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-parser.html @@ -0,0 +1,26 @@ + + + + Parser Test Suite Page + + + + (c) qfox.nl
+ Parser test suite
+
Running...
+ + + + + + + \ No newline at end of file diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-tokenizer.html b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-tokenizer.html new file mode 100755 index 0000000..0e0d1b1 --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/test-tokenizer.html @@ -0,0 +1,23 @@ + + + + Tokenizer Test Suite Page + + + + (c) qfox.nl
+ + + + + + \ No newline at end of file diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/tests.js b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/tests.js new file mode 100644 index 0000000..8a4138b --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/active-x-obfuscator/node_modules/zeparser/tests.js @@ -0,0 +1,478 @@ +// tests for both the tokenizer and parser. Parser test results could be checked tighter. +// api: [input, token-output-count, ?regex-hints, desc] +// regex-hints are for tokenizer, will tell for each token whether it might parse regex or not (parser's job) +var Tests = [ + +["var abc;", 4, "Variable Declaration"], +["var abc = 5;", 8, "Variable Declaration, Assignment"], +["/* */", 1, "Block Comment"], +["/** **/", 1, "JSDoc-style Comment"], +["var f = function(){;};", 13, "Assignment, Function Expression"], +["hi; // moo", 4, "Trailing Line Comment"], +["hi; // moo\n;", 6, "Trailing Line Comment, Linefeed, `;`"], +["var varwithfunction;", 4, "Variable Declaration, Identifier Containing Reserved Words, `;`"], +["a + b;", 6, "Addition/Concatenation"], + +["'a'", 1, "Single-Quoted String"], +["'a';", 2, "Single-Quoted String, `;`"], // Taken from the parser test suite. + +["'a\\n'", 1, "Single-Quoted String With Escaped Linefeed"], +["'a\\n';", 2, "Single-Quoted String With Escaped Linefeed, `;`"], // Taken from the parser test suite. + +["\"a\"", 1, "Double-Quoted String"], +["\"a\";", 2, "Double-Quoted String, `;`"], // Taken from the parser test suite. + +["\"a\\n\"", 1, "Double-Quoted String With Escaped Linefeed"], +["\"a\\n\";", 2, "Double-Quoted String With Escaped Linefeed, `;`"], // Taken from the parser test suite. + +["500", 1, "Integer"], +["500;", 2, "Integer, `;`"], // Taken from the parser test suite. + +["500.", 1, "Double With Trailing Decimal Point"], +["500.;", 2, "Double With Trailing Decimal Point"], // Taken from the parser test suite. + +["500.432", 1, "Double With Decimal Component"], +["500.432;", 2, "Double With Decimal Component, `;`"], // Taken from the parser test suite. + +[".432432", 1, "Number, 0 < Double < 1"], +[".432432;", 2, "Number, 0 < Double < 1, `;`"], // Taken from the parser test suite. + +["(a,b,c)", 7, "Parentheses, Comma-separated identifiers"], +["(a,b,c);", 8, "Parentheses, Comma-separated identifiers, `;`"], // Taken from the parser test suite. + +["[1,2,abc]", 7, "Array literal"], +["[1,2,abc];", 8, "Array literal, `;`"], // Taken from the parser test suite. + +["{a:1,\"b\":2,c:c}", 13, "Object literal"], +["var o = {a:1,\"b\":2,c:c};", 20, "Assignment, Object Literal, `;`"], // Taken from the parser test suite. + +["var x;\nvar y;", 9, "2 Variable Declarations, Multiple lines"], +["var x;\nfunction n(){ }", 13, "Variable, Linefeed, Function Declaration"], +["var x;\nfunction n(abc){ }", 14, "Variable, Linefeed, Function Declaration With One Argument"], +["var x;\nfunction n(abc, def){ }", 17, "Variable, Linefeed, Function Declaration With Multiple Arguments"], +["function n(){ \"hello\"; }", 11, "Function Declaration, Body"], + +["/a/;", 2, [true, false], "RegExp Literal, `;`"], +["/a/b;", 2, [true, true], "RegExp Literal, Flags, `;`"], +["++x;", 3, "Unary Increment, Prefix, `;`"], +[" / /;", 3, [true, true, false], "RegExp, Leading Whitespace, `;`"], +["/ / / / /", 5, [true, false, false, false, true], "RegExp Containing One Space, Space, Division, Space, RegExp Containing One Space"], + +// Taken from the parser test suite. + +["\"var\";", 2, "Keyword String, `;`"], +["\"variable\";", 2, "String Beginning With Keyword, `;`"], +["\"somevariable\";", 2, "String Containing Keyword, `;`"], +["\"somevar\";", 2, "String Ending With Keyword, `;`"], + +["var varwithfunction;", 4, "Keywords should not be matched in identifiers"], + +["var o = {a:1};", 12, "Object Literal With Unquoted Property"], +["var o = {\"b\":2};", 12, "Object Literal With Quoted Property"], +["var o = {c:c};", 12, "Object Literal With Equivalent Property Name and Identifier"], + +["/a/ / /b/;", 6, [true, true, false, false, true, false], "RegExp, Division, RegExp, `;`"], +["a/b/c;", 6, "Triple Division (Identifier / Identifier / Identifier)"], + +["+function(){/regex/;};", 9, [false, false, false, false, false, true, false, false, false], "Unary `+` Operator, Function Expression Containing RegExp and Semicolon, `;`"], + +// Line Terminators. +["\r\n", 1, "CRLF Line Ending = 1 Linefeed"], +["\r", 1, "CR Line Ending = 1 Linefeed"], +["\n", 1, "LF Line Ending = 1 Linefeed"], +["\r\n\n\u2028\u2029\r", 5, "Various Line Terminators"], + +// Whitespace. +["a \t\u000b\u000c\u00a0\uFFFFb", 8, "Whitespace"], + +// Comments. +["//foo!@#^&$1234\nbar;", 4, "Line Comment, Linefeed, Identifier, `;`"], +["/* abcd!@#@$* { } && null*/;", 2, "Single-Line Block Comment, `;`"], +["/*foo\nbar*/;", 2, "Multi-Line Block Comment, `;`"], +["/*x*x*/;", 2, "Block Comment With Asterisks, `;`"], +["/**/;", 2, "Empty Comment, `;`"], + +// Identifiers. +["x;", 2, "Single-Character Identifier, `;`"], +["_x;", 2, "Identifier With Leading `_`, `;`"], +["xyz;", 2, "Identifier With Letters Only, `;`"], +["$x;", 2, "Identifier With Leading `$`, `;`"], +["x5;", 2, "Identifier With Number As Second Character, `;`"], +["x_y;", 2, "Identifier Containing `_`, `;`"], +["x+5;", 4, "Identifier, Binary `+` Operator, Identifier, `;`"], +["xyz123;", 2, "Alphanumeric Identifier, `;`"], +["x1y1z1;", 2, "Alternating Alphanumeric Identifier, `;`"], +["foo\\u00d8bar;", 2, "Identifier With Unicode Escape Sequence (`\\uXXXX`), `;`"], +["f\u00d8\u00d8bar;", 2, "Identifier With Embedded Unicode Character"], + +// Numbers. +["5;", 2, "Integer, `;`"], +["5.5;", 2, "Double, `;`"], +["0;", 2, "Integer Zero, `;`"], +["0.0;", 2, "Double Zero, `;`"], +["0.001;", 2, "0 < Decimalized Double < 1, `;`"], +["1.e2;", 2, "Integer With Decimal and Exponential Component (`e`), `;`"], +["1.e-2;", 2, "Integer With Decimal and Negative Exponential Component, `;`"], +["1.E2;", 2, "Integer With Decimal and Uppercase Exponential Component (`E`), `;`"], +["1.E-2;", 2, "Integer With Decimal and Uppercase Negative Exponential Component, `;`"], +[".5;", 2, "0 < Double < 1, `;`"], +[".5e3;", 2, "(0 < Double < 1) With Exponential Component"], +[".5e-3;", 2, "(0 < Double < 1) With Negative Exponential Component"], +["0.5e3;", 2, "(0 < Decimalized Double < 1) With Exponential Component"], +["55;", 2, "Two-Digit Integer, `;`"], +["123;", 2, "Three-Digit Integer, `;`"], +["55.55;", 2, "Two-Digit Double, `;`"], +["55.55e10;", 2, "Two-Digit Double With Exponential Component, `;`"], +["123.456;", 2, "Three-Digit Double, `;`"], +["1+e;", 4, "Additive Expression, `;`"], +["0x01;", 2, "Hexadecimal `1` With 1 Leading Zero, `;`"], +["0xcafe;", 2, "Hexadecimal `51966`, `;`"], +["0x12345678;", 2, "Hexadecimal `305419896`, `;`"], +["0x1234ABCD;", 2, "Hexadecimal `305441741` With Uppercase Letters, `;`"], +["0x0001;", 2, "Hexadecimal `1` with 3 Leading Zeros, `;`"], + +// Strings. +["\"foo\";", 2, "Multi-Character Double-Quoted String, `;`"], +["\"a\\n\";", 2, "Double-Quoted String Containing Linefeed, `;`"], +["\'foo\';", 2, "Single-Quoted String, `;`"], +["'a\\n';", 2, "Single-Quoted String Containing Linefeed, `;`"], +["\"x\";", 2, "Single-Character Double-Quoted String, `;`"], +["'';", 2, "Empty Single-Quoted String, `;`"], +["\"foo\\tbar\";", 2, "Double-Quoted String With Tab Character, `;`"], +["\"!@#$%^&*()_+{}[]\";", 2, "Double-Quoted String Containing Punctuators, `;`"], +["\"/*test*/\";", 2, "Double-Quoted String Containing Block Comment, `;`"], +["\"//test\";", 2, "Double-Quoted String Containing Line Comment, `;`"], +["\"\\\\\";", 2, "Double-Quoted String Containing Reverse Solidus, `;`"], +["\"\\u0001\";", 2, "Double-Quoted String Containing Numeric Unicode Escape Sequence, `;`"], +["\"\\uFEFF\";", 2, "Double-Quoted String Containing Alphanumeric Unicode Escape Sequence, `;`"], +["\"\\u10002\";", 2, "Double-Quoted String Containing 5-Digit Unicode Escape Sequence, `;`"], +["\"\\x55\";", 2, "Double-Quoted String Containing Hex Escape Sequence, `;`"], +["\"\\x55a\";", 2, "Double-Quoted String Containing Hex Escape Sequence and Additional Character, `;`"], +["\"a\\\\nb\";", 2, "Double-Quoted String Containing Escaped Linefeed, `;`"], +["\";\"", 1, "Double-Quoted String Containing `;`"], +["\"a\\\nb\";", 2, "Double-Quoted String Containing Reverse Solidus and Linefeed, `;`"], +["'\\\\'+ ''", 4, "Single-Quoted String Containing Reverse Solidus, `+`, Empty Single-Quoted String"], + +// `null`, `true`, and `false`. +["null;", 2, "`null`, `;`"], +["true;", 2, "`true`, `;`"], +["false;", 2, "`false`, `;`"], + +// RegExps +["/a/;", 2, [true, true], "Single-Character RegExp, `;`"], +["/abc/;", 2, [true, true], "Multi-Character RegExp, `;`"], +["/abc[a-z]*def/g;", 2, [true, true], "RegExp Containing Character Range and Quantifier, `;`"], +["/\\b/;", 2, [true, true], "RegExp Containing Control Character, `;`"], +["/[a-zA-Z]/;", 2, [true, true], "RegExp Containing Extended Character Range, `;`"], +["/foo(.*)/g;", 2, [true, false], "RegExp Containing Capturing Group and Quantifier, `;`"], + +// Array Literals. +["[];", 3, "Empty Array, `;`"], +["[\b\n\f\r\t\x20];", 9, "Array Containing Whitespace, `;`"], +["[1];", 4, "Array Containing 1 Element, `;`"], +["[1,2];", 6, "Array Containing 2 Elements, `;`"], +["[1,2,,];", 8, "Array Containing 2 Elisions, `;`"], +["[1,2,3];", 8, "Array Containing 3 Elements, `;`"], +["[1,2,3,,,];", 11, "Array Containing 3 Elisions, `;`"], + +// Object Literals. +["({x:5});", 8, "Object Literal Containing 1 Member; `;`"], +["({x:5,y:6});", 12, "Object Literal Containing 2 Members, `;`"], +["({x:5,});", 9, "Object Literal Containing 1 Member and Trailing Comma, `;`"], +["({if:5});", 8, "Object Literal Containing Reserved Word Property Name, `;`"], +["({ get x() {42;} });", 17, "Object Literal Containing Getter, `;`"], +["({ set y(a) {1;} });", 18, "Object Literal Containing Setter, `;`"], + +// Member Expressions. +["o.m;", 4, "Dot Member Accessor, `;`"], +["o['m'];", 5, "Square Bracket Member Accessor, `;`"], +["o['n']['m'];", 8, "Nested Square Bracket Member Accessor, `;`"], +["o.n.m;", 6, "Nested Dot Member Accessor, `;`"], +["o.if;", 4, "Dot Reserved Property Name Accessor, `;`"], + +// Function Calls. +["f();", 4, "Function Call Operator, `;`"], +["f(x);", 5, "Function Call Operator With 1 Argument, `;`"], +["f(x,y);", 7, "Function Call Operator With Multiple Arguments, `;`"], +["o.m();", 6, "Dot Member Accessor, Function Call, `;`"], +["o['m']();", 7, "Square Bracket Member Accessor, Function Call, `;`"], +["o.m(x);", 7, "Dot Member Accessor, Function Call With 1 Argument, `;`"], +["o['m'](x);", 8, "Square Bracket Member Accessor, Function Call With 1 Argument, `;`"], +["o.m(x,y);", 9, "Dot Member Accessor, Function Call With 2 Arguments, `;`"], +["o['m'](x,y);", 10, "Square Bracket Member Accessor, Function Call With 2 Arguments, `;`"], +["f(x)(y);", 8, "Nested Function Call With 1 Argument Each, `;`"], +["f().x;", 6, "Function Call, Dot Member Accessor, `;`"], + +// `eval` Function. +["eval('x');", 5, "`eval` Invocation With 1 Argument, `;`"], +["(eval)('x');", 7, "Direct `eval` Call Example, `;`"], +["(1,eval)('x');", 9, "Indirect `eval` Call Example, `;`"], +["eval(x,y);", 7, "`eval` Invocation With 2 Arguments, `;`"], + +// `new` Operator. +["new f();", 6, "`new` Operator, Function Call, `;`"], +["new o;", 4, "`new` Operator, Identifier, `;`"], +["new o.m;", 6, "`new` Operator, Dot Member Accessor, `;`"], +["new o.m(x);", 9, "`new` Operator, Dot Member Accessor, Function Call With 1 Argument, `;`"], +["new o.m(x,y);", 11, "``new` Operator, Dot Member Accessor, Function Call With 2 Arguments , `;`"], + +// Prefix and Postfix Increment. +["++x;", 3, "Prefix Increment, Identifier, `;`"], +["x++;", 3, "Identifier, Postfix Increment, `;`"], +["--x;", 3, "Prefix Decrement, Identifier, `;`"], +["x--;", 3, "Postfix Decrement, Identifier, `;`"], +["x ++;", 4, "Identifier, Space, Postfix Increment, `;`"], +["x /* comment */ ++;", 6, "Identifier, Block Comment, Postfix Increment, `;`"], +["++ /* comment */ x;", 6, "Prefix Increment, Block Comment, Identifier, `;`"], + +// Unary Operators. +["delete x;", 4, "`delete` Operator, Space, Identifier, `;`"], +["void x;", 4, "`void` Operator, Space, Identifier, `;`"], +["typeof x;", 4, "`typeof` Operator, Space, Identifier, `;`"], +["+x;", 3, "Unary `+` Operator, Identifier, `;`"], +["-x;", 3, "Unary Negation Operator, Identifier, `;`"], +["~x;", 3, "Bitwise NOT Operator, Identifier, `;`"], +["!x;", 3, "Logical NOT Operator, Identifier, `;`"], + +// Comma Operator. +["x, y;", 5, "Comma Operator"], + +// Miscellaneous. +["new Date++;", 5, "`new` Operator, Identifier, Postfix Increment, `;`"], +["+x++;", 4, "Unary `+`, Identifier, Postfix Increment, `;`"], + +// Expressions. +["1 * 2;", 6, "Integer, Multiplication, Integer, `;`"], +["1 / 2;", 6, "Integer, Division, Integer, `;`"], +["1 % 2;", 6, "Integer, Modulus, Integer, `;`"], +["1 + 2;", 6, "Integer, Addition, Integer, `;`"], +["1 - 2;", 6, "Integer, Subtraction, Integer, `;`"], +["1 << 2;", 6, "Integer, Bitwise Left Shift, Integer, `;`"], +["1 >>> 2;", 6, "Integer, Bitwise Zero-fill Right Shift, Integer, `;`"], +["1 >> 2;", 6, "Integer, Bitwise Sign-Propagating Right Shift, Integer, `;`"], +["1 * 2 + 3;", 10, "Order-of-Operations Expression, `;`"], +["(1+2)*3;", 8, "Parenthesized Additive Expression, Multiplication, `;`"], +["1*(2+3);", 8, "Multiplication, Parenthesized Additive Expression, `;`"], +["xy;", 4, "Greater-Than Relational Operator, `;`"], +["x<=y;", 4, "Less-Than-or-Equal-To Relational Operator, `;`"], +["x>=y;", 4, "Greater-Than-or-Equal-To Relational Operator, `;`"], +["x instanceof y;", 6, "`instanceof` Operator, `;`"], +["x in y;", 6, "`in` Operator, `;`"], +["x&y;", 4, "Bitwise AND Operator, `;`"], +["x^y;", 4, "Bitwise XOR Operator, `;`"], +["x|y;", 4, "Bitwise OR Operator, `;`"], +["x+y>>= y;", 6, "Bitwise Zero-Fill Right Shift Assignment, `;`"], +["x <<= y;", 6, "Bitwise Left Shift Assignment, `;`"], +["x += y;", 6, "Additive Assignment, `;`"], +["x -= y;", 6, "Subtractive Assignment, `;`"], +["x *= y;", 6, "Multiplicative Assignment, `;`"], +["x /= y;", 6, "Divisive Assignment, `;`"], +["x %= y;", 6, "Modulus Assignment, `;`"], +["x >>= y;", 6, "Bitwise Sign-Propagating Right Shift Assignment, `;`"], +["x &= y;", 6, "Bitwise AND Assignment, `;`"], +["x ^= y;", 6, "Bitwise XOR Assignment, `;`"], +["x |= y;", 6, "Bitwise OR Assignment, `;`"], + +// Blocks. +["{};", 3, "Empty Block, `;`"], +["{x;};", 5, "Block Containing 1 Identifier, `;`"], +["{x;y;};", 7, "Block Containing 2 Identifiers, `;`"], + +// Variable Declarations. +["var abc;", 4, "Variable Declaration"], +["var x,y;", 6, "Comma-Separated Variable Declarations, `;`"], +["var x=1,y=2;", 10, "Comma-Separated Variable Initializations, `;`"], +["var x,y=2;", 8, "Variable Declaration, Variable Initialization, `;`"], + +// Empty Statements. +[";", 1, "Empty Statement"], +["\n;", 2, "Linefeed, `;`"], + +// Expression Statements. +["x;", 2, "Identifier, `;`"], +["5;", 2, "Integer, `;`"], +["1+2;", 4, "Additive Statement, `;`"], + +// `if...else` Statements. +["if (c) x; else y;", 13, "Space-Delimited `if...else` Statement"], +["if (c) x;", 8, "Space-Delimited `if` Statement, `;`"], +["if (c) {} else {};", 14, "Empty Block-Delimited `if...else` Statement"], +["if (c1) if (c2) s1; else s2;", 19, "Nested `if...else` Statement Without Dangling `else`"], + +// `while` and `do...while` Loops. +["do s; while (e);", 11, "Space-Delimited `do...while` Loop"], +["do { s; } while (e);", 15, "Block-Delimited `do...while` Loop"], +["while (e) s;", 8, "Space-Delimited `while` Loop"], +["while (e) { s; };", 13, "Block-Delimited `while` Loop"], + +// `for` and `for...in` Loops. +["for (;;) ;", 8, "Infinite Space-Delimited `for` Loop"], +["for (;c;x++) x;", 12, "`for` Loop: Empty Initialization Condition; Space-Delimited Body"], +["for (i;i + + + +UglifyJS – a JavaScript parser/compressor/beautifier + + + + + + + + + + + + + +
+ +
+ +
+

UglifyJS – a JavaScript parser/compressor/beautifier

+ + + + +
+

1 UglifyJS — a JavaScript parser/compressor/beautifier

+
+ + +

+This package implements a general-purpose JavaScript +parser/compressor/beautifier toolkit. It is developed on 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 parse-js.js and it's a +port to JavaScript of the excellent parse-js Common Lisp library from Marijn Haverbeke. +

+

+( See cl-uglify-js if you're looking for the Common Lisp version of +UglifyJS. ) +

+

+The second part of this package, implemented in 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). + +
    • +
    • act a limited version of a pre-processor (c.f. the pre-processor of + C/C++) to allow you to safely replace selected global symbols with + specified values. When combined with the optimisations above this can + make UglifyJS operate slightly more like a compilation process, in + that when certain symbols are replaced by constant values, entire code + blocks may be optimised away as unreachable. +
    • +
    + +
  • +
+ + + +
+ +
+

1.1 Unsafe transformations

+
+ + +

+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. +

+ +
+ +
+

1.1.1 Calls involving the global Array constructor

+
+ + +

+The following transformations occur: +

+ + + +
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)
+
+ + +

+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: +

+ + + +
// 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.
+
+ + +
+ +
+ +
+

1.1.2 obj.toString() ==> obj+“”

+
+ + +
+
+ +
+ +
+

1.2 Install (NPM)

+
+ + +

+UglifyJS is now available through NPM — npm install uglify-js should do +the job. +

+
+ +
+ +
+

1.3 Install latest code from GitHub

+
+ + + + + +
## 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)
+
+ + +
+ +
+ +
+

1.4 Usage

+
+ + +

+There is a command-line tool that exposes the functionality of this library +for your shell-scripting needs: +

+ + + +
uglifyjs [ options... ] [ filename ]
+
+ + +

+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 names. + +
  • +
  • -nmf or --no-mangle-functions – in case you want to mangle variable + names, but not touch function 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). + +
  • +
  • -d SYMBOL[=VALUE] or --define SYMBOL[=VALUE] — will replace + all instances of the specified symbol where used as an identifier + (except where symbol has properly declared by a var declaration or + use as function parameter or similar) with the specified value. This + argument may be specified multiple times to define multiple + symbols - if no value is specified the symbol will be replaced with + the value true, or you can specify a numeric value (such as + 1024), a quoted string value (such as ="object"= or + ='https://github.com'), or the name of another symbol or keyword (such as =null or document). + This allows you, for example, to assign meaningful names to key + constant values but discard the symbolic names in the uglified + version for brevity/efficiency, or when used wth care, allows + UglifyJS to operate as a form of conditional compilation + whereby defining appropriate values may, by dint of the constant + folding and dead code removal features above, remove entire + superfluous code blocks (e.g. completely remove instrumentation or + trace code for production use). + Where string values are being defined, the handling of quotes are + likely to be subject to the specifics of your command shell + environment, so you may need to experiment with quoting styles + depending on your platform, or you may find the option + --define-from-module more suitable for use. + +
  • +
  • -define-from-module SOMEMODULE — will load the named module (as + per the NodeJS require() function) and iterate all the exported + properties of the module defining them as symbol names to be defined + (as if by the --define option) per the name of each property + (i.e. without the module name prefix) and given the value of the + property. This is a much easier way to handle and document groups of + symbols to be defined rather than a large number of --define + options. + +
  • +
  • --unsafe — enable other additional optimizations that are known to be + unsafe in some contrived situations, but could still be generally useful. + For now only these: + +
      +
    • foo.toString() ==> foo+"" +
    • +
    • new Array(x,…) ==> [x,…] +
    • +
    • new Array(x) ==> Array(x) + +
    • +
    + +
  • +
  • --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. + +
  • +
  • --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. +
    • +
    + +
  • +
+ + + +
+ +
+

1.4.1 API

+
+ + +

+To use the library from JavaScript, you'd do the following (example for +NodeJS): +

+ + + +
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
+
+ + +

+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_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: +

  • +
+ + + + + +
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() { ... }
+}
+
+ + +
    +
  • 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. +
    • +
    • defines – an object with properties named after symbols to + replace (see the --define option for the script) and the values + representing the AST replacement value. + +
    • +
    + +
  • +
  • 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 +
    • +
    + +
  • +
+ + +
+ +
+ +
+

1.4.2 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. +

+
+ +
+ +
+

1.4.3 Use as a code pre-processor

+
+ + +

+The --define option can be used, particularly when combined with the +constant folding logic, as a form of pre-processor to enable or remove +particular constructions, such as might be used for instrumenting +development code, or to produce variations aimed at a specific +platform. +

+

+The code below illustrates the way this can be done, and how the +symbol replacement is performed. +

+ + + +
CLAUSE1: if (typeof DEVMODE === 'undefined') {
+    DEVMODE = true;
+}
+
+CLAUSE2: function init() {
+    if (DEVMODE) {
+        console.log("init() called");
+    }
+    ....
+    DEVMODE &amp;&amp; console.log("init() complete");
+}
+
+CLAUSE3: function reportDeviceStatus(device) {
+    var DEVMODE = device.mode, DEVNAME = device.name;
+    if (DEVMODE === 'open') {
+        ....
+    }
+}
+
+ + +

+When the above code is normally executed, the undeclared global +variable DEVMODE will be assigned the value true (see CLAUSE1) +and so the init() function (CLAUSE2) will write messages to the +console log when executed, but in CLAUSE3 a locally declared +variable will mask access to the DEVMODE global symbol. +

+

+If the above code is processed by UglifyJS with an argument of +--define DEVMODE=false then UglifyJS will replace DEVMODE with the +boolean constant value false within CLAUSE1 and CLAUSE2, but it +will leave CLAUSE3 as it stands because there DEVMODE resolves to +a validly declared variable. +

+

+And more so, the constant-folding features of UglifyJS will recognise +that the if condition of CLAUSE1 is thus always false, and so will +remove the test and body of CLAUSE1 altogether (including the +otherwise slightly problematical statement false = true; which it +will have formed by replacing DEVMODE in the body). Similarly, +within CLAUSE2 both calls to console.log() will be removed +altogether. +

+

+In this way you can mimic, to a limited degree, the functionality of +the C/C++ pre-processor to enable or completely remove blocks +depending on how certain symbols are defined - perhaps using UglifyJS +to generate different versions of source aimed at different +environments +

+

+It is recommmended (but not made mandatory) that symbols designed for +this purpose are given names consisting of UPPER_CASE_LETTERS to +distinguish them from other (normal) symbols and avoid the sort of +clash that CLAUSE3 above illustrates. +

+
+
+ +
+ +
+

1.5 Compression – how good is it?

+
+ + +

+Here are updated statistics. (I also updated my Google Closure and YUI +installations). +

+

+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. +

+ + ++ + + + + + + + + + +
FileUglifyJSUglifyJS+gzipClosureClosure+gzipYUIYUI+gzip
jquery-1.6.2.js91001 (0:01.59)3189690678 (0:07.40)31979101527 (0:01.82)34646
paper.js142023 (0:01.65)43334134301 (0:07.42)42495173383 (0:01.58)48785
prototype.js88544 (0:01.09)2668086955 (0:06.97)2632692130 (0:00.79)28624
thelib-full.js (DynarchLIB)251939 (0:02.55)72535249911 (0:09.05)72696258869 (0:01.94)76584
+ + +
+ +
+ +
+

1.6 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 hacks1 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 (use the Google Group or email me directly). +

+
+ +
+ +
+

1.7 Links

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

1.8 License

+
+ + +

+UglifyJS is released 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.
+
+ + +
+

Footnotes:

+
+

1 I even reported a few bugs and suggested some fixes in the original + parse-js library, and Marijn pushed fixes literally in minutes. +

+
+
+ +
+
+
+ +
+

Date: 2011-12-09 14:59:08 EET

+

Author: Mihai Bazon

+

Org version 7.7 with Emacs version 23

+Validate XHTML 1.0 + +
+ + diff --git a/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/README.org b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/README.org new file mode 100644 index 0000000..4d01fdf --- /dev/null +++ b/networking/node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/README.org @@ -0,0 +1,574 @@ +#+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: +#+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). + + - act a limited version of a pre-processor (c.f. the pre-processor of + C/C++) to allow you to safely replace selected global symbols with + specified values. When combined with the optimisations above this can + make UglifyJS operate slightly more like a compilation process, in + that when certain symbols are replaced by constant values, entire code + blocks may be optimised away as unreachable. + +** <> + +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 + +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 + +*** =obj.toString()= ==> =obj+“”= + +** 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 names. + +- =-nmf= or =--no-mangle-functions= -- in case you want to mangle variable + names, but not touch function 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). + +- =-d SYMBOL[=VALUE]= or =--define SYMBOL[=VALUE]= --- will replace + all instances of the specified symbol where used as an identifier + (except where symbol has properly declared by a var declaration or + use as function parameter or similar) with the specified value. This + argument may be specified multiple times to define multiple + symbols - if no value is specified the symbol will be replaced with + the value =true=, or you can specify a numeric value (such as + =1024=), a quoted string value (such as ="object"= or + ='https://github.com'=), or the name of another symbol or keyword + (such as =null= or =document=). + This allows you, for example, to assign meaningful names to key + constant values but discard the symbolic names in the uglified + version for brevity/efficiency, or when used wth care, allows + UglifyJS to operate as a form of *conditional compilation* + whereby defining appropriate values may, by dint of the constant + folding and dead code removal features above, remove entire + superfluous code blocks (e.g. completely remove instrumentation or + trace code for production use). + Where string values are being defined, the handling of quotes are + likely to be subject to the specifics of your command shell + environment, so you may need to experiment with quoting styles + depending on your platform, or you may find the option + =--define-from-module= more suitable for use. + +- =-define-from-module SOMEMODULE= --- will load the named module (as + per the NodeJS =require()= function) and iterate all the exported + properties of the module defining them as symbol names to be defined + (as if by the =--define= option) per the name of each property + (i.e. without the module name prefix) and given the value of the + property. This is a much easier way to handle and document groups of + symbols to be defined rather than a large number of =--define= + options. + +- =--unsafe= --- enable other additional optimizations that are known to be + unsafe in some contrived situations, but could still be generally useful. + For now only these: + + - foo.toString() ==> foo+"" + - new Array(x,...) ==> [x,...] + - new Array(x) ==> Array(x) + +- =--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 = + + + */ + +(function() { + this.loggly = function(opts) { + this.user_agent = get_agent(); + this.browser_size = get_size(); + log_methods = {'error': 5, 'warn': 4, 'info': 3, 'debug': 2, 'log': 1}; + if (!opts.url) throw new Error("Please include a Loggly HTTP URL."); + if (!opts.level) { + this.level = log_methods['info']; + } else { + this.level = log_methods[opts.level]; + } + this.log = function(data) { + if (log_methods['log'] == this.level) { + opts.data = data; + janky(opts); + } + }; + this.debug = function(data) { + if (log_methods['debug'] >= this.level) { + opts.data = data; + janky(opts); + } + }; + this.info = function(data) { + if (log_methods['info'] >= this.level) { + opts.data = data; + janky(opts); + } + }; + this.warn = function(data) { + if (log_methods['warn'] >= this.level) { + opts.data = data; + janky(opts); + } + }; + this.error = function(data) { + if (log_methods['error'] >= this.level) { + opts.data = data; + janky(opts); + } + }; + }; + this.janky = function(opts) { + janky._form(function(iframe, form) { + form.setAttribute("action", opts.url); + form.setAttribute("method", "post"); + janky._input(iframe, form, opts.data); + form.submit(); + setTimeout(function(){ + document.body.removeChild(iframe); + }, 2000); + }); + }; + this.janky._form = function(cb) { + var iframe = document.createElement("iframe"); + document.body.appendChild(iframe); + iframe.style.display = "none"; + setTimeout(function() { + var form = iframe.contentWindow.document.createElement("form"); + iframe.contentWindow.document.body.appendChild(form); + cb(iframe, form); + }, 0); + }; + this.janky._input = function(iframe, form, data) { + var inp = iframe.contentWindow.document.createElement("input"); + inp.setAttribute("type", "hidden"); + inp.setAttribute("name", "source"); + inp.value = "castor " + data; + form.appendChild(inp); + }; + this.get_agent = function () { + return navigator.appCodeName + navigator.appName + navigator.appVersion; + }; + this.get_size = function () { + var width = 0; var height = 0; + if( typeof( window.innerWidth ) == 'number' ) { + width = window.innerWidth; height = window.innerHeight; + } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) { + width = document.documentElement.clientWidth; height = document.documentElement.clientHeight; + } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) { + width = document.body.clientWidth; height = document.body.clientHeight; + } + return {'height': height, 'width': width}; + }; +})(); + + +jsworld={};jsworld.formatIsoDateTime=function(a,b){if(typeof a==="undefined")a=new Date;if(typeof b==="undefined")b=false;var c=jsworld.formatIsoDate(a)+" "+jsworld.formatIsoTime(a);if(b){var d=a.getHours()-a.getUTCHours();var e=Math.abs(d);var f=a.getUTCMinutes();var g=a.getMinutes();if(g!=f&&f<30&&d<0)e--;if(g!=f&&f>30&&d>0)e--;var h;if(g!=f)h=":30";else h=":00";var i;if(e<10)i="0"+e+h;else i=""+e+h;if(d<0)i="-"+i;else i="+"+i;c=c+i}return c};jsworld.formatIsoDate=function(a){if(typeof a==="undefined")a=new Date;var b=a.getFullYear();var c=a.getMonth()+1;var d=a.getDate();return b+"-"+jsworld._zeroPad(c,2)+"-"+jsworld._zeroPad(d,2)};jsworld.formatIsoTime=function(a){if(typeof a==="undefined")a=new Date;var b=a.getHours();var c=a.getMinutes();var d=a.getSeconds();return jsworld._zeroPad(b,2)+":"+jsworld._zeroPad(c,2)+":"+jsworld._zeroPad(d,2)};jsworld.parseIsoDateTime=function(a){if(typeof a!="string")throw"Error: The parameter must be a string";var b=a.match(/^(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d):(\d\d):(\d\d)/);if(b===null)b=a.match(/^(\d\d\d\d)(\d\d)(\d\d)[T ](\d\d)(\d\d)(\d\d)/);if(b===null)b=a.match(/^(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d)(\d\d)(\d\d)/);if(b===null)b=a.match(/^(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d):(\d\d):(\d\d)/);if(b===null)throw"Error: Invalid ISO-8601 date/time string";var c=parseInt(b[1],10);var d=parseInt(b[2],10);var e=parseInt(b[3],10);var f=parseInt(b[4],10);var g=parseInt(b[5],10);var h=parseInt(b[6],10);if(d<1||d>12||e<1||e>31||f<0||f>23||g<0||g>59||h<0||h>59)throw"Error: Invalid ISO-8601 date/time value";var i=new Date(c,d-1,e,f,g,h);if(i.getDate()!=e||i.getMonth()+1!=d)throw"Error: Invalid date";return i};jsworld.parseIsoDate=function(a){if(typeof a!="string")throw"Error: The parameter must be a string";var b=a.match(/^(\d\d\d\d)-(\d\d)-(\d\d)/);if(b===null)b=a.match(/^(\d\d\d\d)(\d\d)(\d\d)/);if(b===null)throw"Error: Invalid ISO-8601 date string";var c=parseInt(b[1],10);var d=parseInt(b[2],10);var e=parseInt(b[3],10);if(d<1||d>12||e<1||e>31)throw"Error: Invalid ISO-8601 date value";var f=new Date(c,d-1,e);if(f.getDate()!=e||f.getMonth()+1!=d)throw"Error: Invalid date";return f};jsworld.parseIsoTime=function(a){if(typeof a!="string")throw"Error: The parameter must be a string";var b=a.match(/^(\d\d):(\d\d):(\d\d)/);if(b===null)b=a.match(/^(\d\d)(\d\d)(\d\d)/);if(b===null)throw"Error: Invalid ISO-8601 date/time string";var c=parseInt(b[1],10);var d=parseInt(b[2],10);var e=parseInt(b[3],10);if(c<0||c>23||d<0||d>59||e<0||e>59)throw"Error: Invalid ISO-8601 time value";return new Date(0,0,0,c,d,e)};jsworld._trim=function(a){var b=" \n\r\t\f \u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000";for(var c=0;c=0;c--){if(b.indexOf(a.charAt(c))===-1){a=a.substring(0,c+1);break}}return b.indexOf(a.charAt(0))===-1?a:""};jsworld._isNumber=function(a){if(typeof a=="number")return true;if(typeof a!="string")return false;var b=a+"";return/^-?(\d+|\d*\.\d+)$/.test(b)};jsworld._isInteger=function(a){if(typeof a!="number"&&typeof a!="string")return false;var b=a+"";return/^-?\d+$/.test(b)};jsworld._isFloat=function(a){if(typeof a!="number"&&typeof a!="string")return false;var b=a+"";return/^-?\.\d+?$/.test(b)};jsworld._hasOption=function(a,b){if(typeof a!="string"||typeof b!="string")return false;if(b.indexOf(a)!=-1)return true;else return false};jsworld._stringReplaceAll=function(a,b,c){var d;if(b.length==1&&c.length==1){d="";for(var e=0;e0){if(d.length>0)g=parseInt(d.shift(),10);if(isNaN(g))throw"Error: Invalid grouping";if(g==-1){e=a.substring(0,f)+e;break}f-=g;if(f<1){e=a.substring(0,f+g)+e;break}e=c+a.substring(f,f+g)+e}return e};jsworld._formatFractionPart=function(a,b){for(var c=0;a.length0)return a;else throw"Empty or no string"};if(a==null||typeof a!="object")throw"Error: Invalid/missing locale properties";if(typeof a.decimal_point!="string")throw"Error: Invalid/missing decimal_point property";this.decimal_point=a.decimal_point;if(typeof a.thousands_sep!="string")throw"Error: Invalid/missing thousands_sep property";this.thousands_sep=a.thousands_sep;if(typeof a.grouping!="string")throw"Error: Invalid/missing grouping property";this.grouping=a.grouping;if(typeof a.int_curr_symbol!="string")throw"Error: Invalid/missing int_curr_symbol property";if(!/[A-Za-z]{3}.?/.test(a.int_curr_symbol))throw"Error: Invalid int_curr_symbol property";this.int_curr_symbol=a.int_curr_symbol;if(typeof a.currency_symbol!="string")throw"Error: Invalid/missing currency_symbol property";this.currency_symbol=a.currency_symbol;if(typeof a.frac_digits!="number"&&a.frac_digits<0)throw"Error: Invalid/missing frac_digits property";this.frac_digits=a.frac_digits;if(a.mon_decimal_point===null||a.mon_decimal_point==""){if(this.frac_digits>0)throw"Error: Undefined mon_decimal_point property";else a.mon_decimal_point=""}if(typeof a.mon_decimal_point!="string")throw"Error: Invalid/missing mon_decimal_point property";this.mon_decimal_point=a.mon_decimal_point;if(typeof a.mon_thousands_sep!="string")throw"Error: Invalid/missing mon_thousands_sep property";this.mon_thousands_sep=a.mon_thousands_sep;if(typeof a.mon_grouping!="string")throw"Error: Invalid/missing mon_grouping property";this.mon_grouping=a.mon_grouping;if(typeof a.positive_sign!="string")throw"Error: Invalid/missing positive_sign property";this.positive_sign=a.positive_sign;if(typeof a.negative_sign!="string")throw"Error: Invalid/missing negative_sign property";this.negative_sign=a.negative_sign;if(a.p_cs_precedes!==0&&a.p_cs_precedes!==1)throw"Error: Invalid/missing p_cs_precedes property, must be 0 or 1";this.p_cs_precedes=a.p_cs_precedes;if(a.n_cs_precedes!==0&&a.n_cs_precedes!==1)throw"Error: Invalid/missing n_cs_precedes, must be 0 or 1";this.n_cs_precedes=a.n_cs_precedes;if(a.p_sep_by_space!==0&&a.p_sep_by_space!==1&&a.p_sep_by_space!==2)throw"Error: Invalid/missing p_sep_by_space property, must be 0, 1 or 2";this.p_sep_by_space=a.p_sep_by_space;if(a.n_sep_by_space!==0&&a.n_sep_by_space!==1&&a.n_sep_by_space!==2)throw"Error: Invalid/missing n_sep_by_space property, must be 0, 1, or 2";this.n_sep_by_space=a.n_sep_by_space;if(a.p_sign_posn!==0&&a.p_sign_posn!==1&&a.p_sign_posn!==2&&a.p_sign_posn!==3&&a.p_sign_posn!==4)throw"Error: Invalid/missing p_sign_posn property, must be 0, 1, 2, 3 or 4";this.p_sign_posn=a.p_sign_posn;if(a.n_sign_posn!==0&&a.n_sign_posn!==1&&a.n_sign_posn!==2&&a.n_sign_posn!==3&&a.n_sign_posn!==4)throw"Error: Invalid/missing n_sign_posn property, must be 0, 1, 2, 3 or 4";this.n_sign_posn=a.n_sign_posn;if(typeof a.int_frac_digits!="number"&&a.int_frac_digits<0)throw"Error: Invalid/missing int_frac_digits property";this.int_frac_digits=a.int_frac_digits;if(a.int_p_cs_precedes!==0&&a.int_p_cs_precedes!==1)throw"Error: Invalid/missing int_p_cs_precedes property, must be 0 or 1";this.int_p_cs_precedes=a.int_p_cs_precedes;if(a.int_n_cs_precedes!==0&&a.int_n_cs_precedes!==1)throw"Error: Invalid/missing int_n_cs_precedes property, must be 0 or 1";this.int_n_cs_precedes=a.int_n_cs_precedes;if(a.int_p_sep_by_space!==0&&a.int_p_sep_by_space!==1&&a.int_p_sep_by_space!==2)throw"Error: Invalid/missing int_p_sep_by_spacev, must be 0, 1 or 2";this.int_p_sep_by_space=a.int_p_sep_by_space;if(a.int_n_sep_by_space!==0&&a.int_n_sep_by_space!==1&&a.int_n_sep_by_space!==2)throw"Error: Invalid/missing int_n_sep_by_space property, must be 0, 1, or 2";this.int_n_sep_by_space=a.int_n_sep_by_space;if(a.int_p_sign_posn!==0&&a.int_p_sign_posn!==1&&a.int_p_sign_posn!==2&&a.int_p_sign_posn!==3&&a.int_p_sign_posn!==4)throw"Error: Invalid/missing int_p_sign_posn property, must be 0, 1, 2, 3 or 4";this.int_p_sign_posn=a.int_p_sign_posn;if(a.int_n_sign_posn!==0&&a.int_n_sign_posn!==1&&a.int_n_sign_posn!==2&&a.int_n_sign_posn!==3&&a.int_n_sign_posn!==4)throw"Error: Invalid/missing int_n_sign_posn property, must be 0, 1, 2, 3 or 4";this.int_n_sign_posn=a.int_n_sign_posn;if(a==null||typeof a!="object")throw"Error: Invalid/missing time locale properties";try{this.abday=this._parseList(a.abday,7)}catch(b){throw"Error: Invalid abday property: "+b}try{this.day=this._parseList(a.day,7)}catch(b){throw"Error: Invalid day property: "+b}try{this.abmon=this._parseList(a.abmon,12)}catch(b){throw"Error: Invalid abmon property: "+b}try{this.mon=this._parseList(a.mon,12)}catch(b){throw"Error: Invalid mon property: "+b}try{this.d_fmt=this._validateFormatString(a.d_fmt)}catch(b){throw"Error: Invalid d_fmt property: "+b}try{this.t_fmt=this._validateFormatString(a.t_fmt)}catch(b){throw"Error: Invalid t_fmt property: "+b}try{this.d_t_fmt=this._validateFormatString(a.d_t_fmt)}catch(b){throw"Error: Invalid d_t_fmt property: "+b}try{var c=this._parseList(a.am_pm,2);this.am=c[0];this.pm=c[1]}catch(b){this.am="";this.pm=""}this.getAbbreviatedWeekdayName=function(a){if(typeof a=="undefined"||a===null)return this.abday;if(!jsworld._isInteger(a)||a<0||a>6)throw"Error: Invalid weekday argument, must be an integer [0..6]";return this.abday[a]};this.getWeekdayName=function(a){if(typeof a=="undefined"||a===null)return this.day;if(!jsworld._isInteger(a)||a<0||a>6)throw"Error: Invalid weekday argument, must be an integer [0..6]";return this.day[a]};this.getAbbreviatedMonthName=function(a){if(typeof a=="undefined"||a===null)return this.abmon;if(!jsworld._isInteger(a)||a<0||a>11)throw"Error: Invalid month argument, must be an integer [0..11]";return this.abmon[a]};this.getMonthName=function(a){if(typeof a=="undefined"||a===null)return this.mon;if(!jsworld._isInteger(a)||a<0||a>11)throw"Error: Invalid month argument, must be an integer [0..11]";return this.mon[a]};this.getDecimalPoint=function(){return this.decimal_point};this.getCurrencySymbol=function(){return this.currency_symbol};this.getIntCurrencySymbol=function(){return this.int_curr_symbol.substring(0,3)};this.currencySymbolPrecedes=function(){if(this.p_cs_precedes==1)return true;else return false};this.intCurrencySymbolPrecedes=function(){if(this.int_p_cs_precedes==1)return true;else return false};this.getMonetaryDecimalPoint=function(){return this.mon_decimal_point};this.getFractionalDigits=function(){return this.frac_digits};this.getIntFractionalDigits=function(){return this.int_frac_digits}};jsworld.NumericFormatter=function(a){if(typeof a!="object"||a._className!="jsworld.Locale")throw"Constructor error: You must provide a valid jsworld.Locale instance";this.lc=a;this.format=function(a,b){if(typeof a=="string")a=jsworld._trim(a);if(!jsworld._isNumber(a))throw"Error: The input is not a number";var c=parseFloat(a,10);var d=jsworld._getPrecision(b);if(d!=-1)c=Math.round(c*Math.pow(10,d))/Math.pow(10,d);var e=jsworld._splitNumber(String(c));var f;if(c===0)f="0";else f=jsworld._hasOption("^",b)?e.integer:jsworld._formatIntegerPart(e.integer,this.lc.grouping,this.lc.thousands_sep);var g=d!=-1?jsworld._formatFractionPart(e.fraction,d):e.fraction;var h=g.length?f+this.lc.decimal_point+g:f;if(jsworld._hasOption("~",b)||c===0){return h}else{if(jsworld._hasOption("+",b)||c<0){if(c>0)return"+"+h;else if(c<0)return"-"+h;else return h}else{return h}}}};jsworld.DateTimeFormatter=function(a){if(typeof a!="object"||a._className!="jsworld.Locale")throw"Constructor error: You must provide a valid jsworld.Locale instance.";this.lc=a;this.formatDate=function(a){var b=null;if(typeof a=="string"){try{b=jsworld.parseIsoDate(a)}catch(c){b=jsworld.parseIsoDateTime(a)}}else if(a!==null&&typeof a=="object"){b=a}else{throw"Error: Invalid date argument, must be a Date object or an ISO-8601 date/time string"}return this._applyFormatting(b,this.lc.d_fmt)};this.formatTime=function(a){var b=null;if(typeof a=="string"){try{b=jsworld.parseIsoTime(a)}catch(c){b=jsworld.parseIsoDateTime(a)}}else if(a!==null&&typeof a=="object"){b=a}else{throw"Error: Invalid date argument, must be a Date object or an ISO-8601 date/time string"}return this._applyFormatting(b,this.lc.t_fmt)};this.formatDateTime=function(a){var b=null;if(typeof a=="string"){b=jsworld.parseIsoDateTime(a)}else if(a!==null&&typeof a=="object"){b=a}else{throw"Error: Invalid date argument, must be a Date object or an ISO-8601 date/time string"}return this._applyFormatting(b,this.lc.d_t_fmt)};this._applyFormatting=function(a,b){b=b.replace(/%%/g,"%");b=b.replace(/%a/g,this.lc.abday[a.getDay()]);b=b.replace(/%A/g,this.lc.day[a.getDay()]);b=b.replace(/%b/g,this.lc.abmon[a.getMonth()]);b=b.replace(/%B/g,this.lc.mon[a.getMonth()]);b=b.replace(/%d/g,jsworld._zeroPad(a.getDate(),2));b=b.replace(/%e/g,jsworld._spacePad(a.getDate(),2));b=b.replace(/%F/g,a.getFullYear()+"-"+jsworld._zeroPad(a.getMonth()+1,2)+"-"+jsworld._zeroPad(a.getDate(),2));b=b.replace(/%h/g,this.lc.abmon[a.getMonth()]);b=b.replace(/%H/g,jsworld._zeroPad(a.getHours(),2));b=b.replace(/%I/g,jsworld._zeroPad(this._hours12(a.getHours()),2));b=b.replace(/%k/g,a.getHours());b=b.replace(/%l/g,this._hours12(a.getHours()));b=b.replace(/%m/g,jsworld._zeroPad(a.getMonth()+1,2));b=b.replace(/%n/g,"\n");b=b.replace(/%M/g,jsworld._zeroPad(a.getMinutes(),2));b=b.replace(/%p/g,this._getAmPm(a.getHours()));b=b.replace(/%P/g,this._getAmPm(a.getHours()).toLocaleLowerCase());b=b.replace(/%R/g,jsworld._zeroPad(a.getHours(),2)+":"+jsworld._zeroPad(a.getMinutes(),2));b=b.replace(/%S/g,jsworld._zeroPad(a.getSeconds(),2));b=b.replace(/%T/g,jsworld._zeroPad(a.getHours(),2)+":"+jsworld._zeroPad(a.getMinutes(),2)+":"+jsworld._zeroPad(a.getSeconds(),2));b=b.replace(/%w/g,this.lc.day[a.getDay()]);b=b.replace(/%y/g,(new String(a.getFullYear())).substring(2));b=b.replace(/%Y/g,a.getFullYear());b=b.replace(/%Z/g,"");b=b.replace(/%[a-zA-Z]/g,"");return b};this._hours12=function(a){if(a===0)return 12;else if(a>12)return a-12;else return a};this._getAmPm=function(a){if(a===0||a>12)return this.lc.pm;else return this.lc.am}};jsworld.MonetaryFormatter=function(a,b,c){if(typeof a!="object"||a._className!="jsworld.Locale")throw"Constructor error: You must provide a valid jsworld.Locale instance";this.lc=a;this.currencyFractionDigits={AFN:0,ALL:0,AMD:0,BHD:3,BIF:0,BYR:0,CLF:0,CLP:0,COP:0,CRC:0,DJF:0,GNF:0,GYD:0,HUF:0,IDR:0,IQD:0,IRR:0,ISK:0,JOD:3,JPY:0,KMF:0,KRW:0,KWD:3,LAK:0,LBP:0,LYD:3,MGA:0,MMK:0,MNT:0,MRO:0,MUR:0,OMR:3,PKR:0,PYG:0,RSD:0,RWF:0,SLL:0,SOS:0,STD:0,SYP:0,TND:3,TWD:0,TZS:0,UGX:0,UZS:0,VND:0,VUV:0,XAF:0,XOF:0,XPF:0,YER:0,ZMK:0};if(typeof b=="string"){this.currencyCode=b.toUpperCase();var d=this.currencyFractionDigits[this.currencyCode];if(typeof d!="number")d=2;this.lc.frac_digits=d;this.lc.int_frac_digits=d}else{this.currencyCode=this.lc.int_curr_symbol.substring(0,3).toUpperCase()}this.intSep=this.lc.int_curr_symbol.charAt(3);if(this.currencyCode==this.lc.int_curr_symbol.substring(0,3)){this.internationalFormatting=false;this.curSym=this.lc.currency_symbol}else{if(typeof c=="string"){this.curSym=c;this.internationalFormatting=false}else{this.internationalFormatting=true}}this.getCurrencySymbol=function(){return this.curSym};this.currencySymbolPrecedes=function(a){if(typeof a=="string"&&a=="i"){if(this.lc.int_p_cs_precedes==1)return true;else return false}else{if(this.internationalFormatting){if(this.lc.int_p_cs_precedes==1)return true;else return false}else{if(this.lc.p_cs_precedes==1)return true;else return false}}};this.getDecimalPoint=function(){return this.lc.mon_decimal_point};this.getFractionalDigits=function(a){if(typeof a=="string"&&a=="i"){return this.lc.int_frac_digits}else{if(this.internationalFormatting)return this.lc.int_frac_digits;else return this.lc.frac_digits}};this.format=function(a,b){var c;if(typeof a=="string"){a=jsworld._trim(a);c=parseFloat(a);if(typeof c!="number"||isNaN(c))throw"Error: Amount string not a number"}else if(typeof a=="number"){c=a}else{throw"Error: Amount not a number"}var d=jsworld._getPrecision(b);if(d==-1){if(this.internationalFormatting||jsworld._hasOption("i",b))d=this.lc.int_frac_digits;else d=this.lc.frac_digits}c=Math.round(c*Math.pow(10,d))/Math.pow(10,d);var e=jsworld._splitNumber(String(c));var f;if(c===0)f="0";else f=jsworld._hasOption("^",b)?e.integer:jsworld._formatIntegerPart(e.integer,this.lc.mon_grouping,this.lc.mon_thousands_sep);var g;if(d==-1){if(this.internationalFormatting||jsworld._hasOption("i",b))g=jsworld._formatFractionPart(e.fraction,this.lc.int_frac_digits);else g=jsworld._formatFractionPart(e.fraction,this.lc.frac_digits)}else{g=jsworld._formatFractionPart(e.fraction,d)}var h;if(this.lc.frac_digits>0||g.length)h=f+this.lc.mon_decimal_point+g;else h=f;if(jsworld._hasOption("~",b)){return h}else{var i=jsworld._hasOption("!",b)?true:false;var j=c<0?"-":"+";if(this.internationalFormatting||jsworld._hasOption("i",b)){if(i)return this._formatAsInternationalCurrencyWithNoSym(j,h);else return this._formatAsInternationalCurrency(j,h)}else{if(i)return this._formatAsLocalCurrencyWithNoSym(j,h);else return this._formatAsLocalCurrency(j,h)}}};this._formatAsLocalCurrency=function(a,b){if(a=="+"){if(this.lc.p_sign_posn===0&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return"("+b+this.curSym+")"}else if(this.lc.p_sign_posn===0&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return"("+this.curSym+b+")"}else if(this.lc.p_sign_posn===0&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return"("+b+" "+this.curSym+")"}else if(this.lc.p_sign_posn===0&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return"("+this.curSym+" "+b+")"}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return this.lc.positive_sign+b+this.curSym}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+this.curSym+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return this.lc.positive_sign+b+" "+this.curSym}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+this.curSym+" "+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return this.lc.positive_sign+" "+b+this.curSym}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+" "+this.curSym+b}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return b+this.curSym+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.curSym+b+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return b+" "+this.curSym+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.curSym+" "+b+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return b+this.curSym+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.curSym+b+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign+this.curSym}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+this.curSym+b}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return b+" "+this.lc.positive_sign+this.curSym}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+this.curSym+" "+b}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign+" "+this.curSym}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+" "+this.curSym+b}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return b+this.curSym+this.lc.positive_sign}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.curSym+this.lc.positive_sign+b}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return b+" "+this.curSym+this.lc.positive_sign}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.curSym+this.lc.positive_sign+" "+b}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return b+this.curSym+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.curSym+" "+this.lc.positive_sign+b}}else if(a=="-"){if(this.lc.n_sign_posn===0&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return"("+b+this.curSym+")"}else if(this.lc.n_sign_posn===0&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return"("+this.curSym+b+")"}else if(this.lc.n_sign_posn===0&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return"("+b+" "+this.curSym+")"}else if(this.lc.n_sign_posn===0&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return"("+this.curSym+" "+b+")"}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return this.lc.negative_sign+b+this.curSym}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+this.curSym+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return this.lc.negative_sign+b+" "+this.curSym}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+this.curSym+" "+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return this.lc.negative_sign+" "+b+this.curSym}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+this.curSym+b}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return b+this.curSym+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.curSym+b+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return b+" "+this.curSym+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.curSym+" "+b+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return b+this.curSym+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.curSym+b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return b+this.lc.negative_sign+this.curSym}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+this.curSym+b}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return b+" "+this.lc.negative_sign+this.curSym}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+this.curSym+" "+b}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return b+this.lc.negative_sign+" "+this.curSym}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+this.curSym+b}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return b+this.curSym+this.lc.negative_sign}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.curSym+this.lc.negative_sign+b}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return b+" "+this.curSym+this.lc.negative_sign}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.curSym+this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return b+this.curSym+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.curSym+" "+this.lc.negative_sign+b}}throw"Error: Invalid POSIX LC MONETARY definition"};this._formatAsInternationalCurrency=function(a,b){if(a=="+"){if(this.lc.int_p_sign_posn===0&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return"("+b+this.currencyCode+")"}else if(this.lc.int_p_sign_posn===0&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return"("+this.currencyCode+b+")"}else if(this.lc.int_p_sign_posn===0&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return"("+b+this.intSep+this.currencyCode+")"}else if(this.lc.int_p_sign_posn===0&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return"("+this.currencyCode+this.intSep+b+")"}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return this.lc.positive_sign+b+this.currencyCode}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.currencyCode+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return this.lc.positive_sign+b+this.intSep+this.currencyCode}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.currencyCode+this.intSep+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return this.lc.positive_sign+this.intSep+b+this.currencyCode}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+this.currencyCode+b}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return b+this.currencyCode+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.currencyCode+b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.currencyCode+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.currencyCode+this.intSep+b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return b+this.currencyCode+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.currencyCode+b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return b+this.lc.positive_sign+this.currencyCode}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.currencyCode+b}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.lc.positive_sign+this.currencyCode}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.currencyCode+this.intSep+b}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return b+this.lc.positive_sign+this.intSep+this.currencyCode}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+this.currencyCode+b}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return b+this.currencyCode+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.currencyCode+this.lc.positive_sign+b}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.currencyCode+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.currencyCode+this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return b+this.currencyCode+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.currencyCode+this.intSep+this.lc.positive_sign+b}}else if(a=="-"){if(this.lc.int_n_sign_posn===0&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return"("+b+this.currencyCode+")"}else if(this.lc.int_n_sign_posn===0&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return"("+this.currencyCode+b+")"}else if(this.lc.int_n_sign_posn===0&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return"("+b+this.intSep+this.currencyCode+")"}else if(this.lc.int_n_sign_posn===0&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return"("+this.currencyCode+this.intSep+b+")"}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return this.lc.negative_sign+b+this.currencyCode}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.currencyCode+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return this.lc.negative_sign+b+this.intSep+this.currencyCode}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.currencyCode+this.intSep+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return this.lc.negative_sign+this.intSep+b+this.currencyCode}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+this.currencyCode+b}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return b+this.currencyCode+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.currencyCode+b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.currencyCode+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.currencyCode+this.intSep+b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return b+this.currencyCode+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.currencyCode+b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return b+this.lc.negative_sign+this.currencyCode}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.currencyCode+b}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.lc.negative_sign+this.currencyCode}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.currencyCode+this.intSep+b}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return b+this.lc.negative_sign+this.intSep+this.currencyCode}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+this.currencyCode+b}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return b+this.currencyCode+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.currencyCode+this.lc.negative_sign+b}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.currencyCode+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.currencyCode+this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return b+this.currencyCode+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.currencyCode+this.intSep+this.lc.negative_sign+b}}throw"Error: Invalid POSIX LC MONETARY definition"};this._formatAsLocalCurrencyWithNoSym=function(a,b){if(a=="+"){if(this.lc.p_sign_posn===0){return"("+b+")"}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return this.lc.positive_sign+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return this.lc.positive_sign+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return this.lc.positive_sign+" "+b}else if(this.lc.p_sign_posn===1&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+" "+b}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return b+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===2&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return b+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return b+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+" "+b}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===3&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+" "+b}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===0&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===0){return b+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===1&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+" "+b}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===0){return b+" "+this.lc.positive_sign}else if(this.lc.p_sign_posn===4&&this.lc.p_sep_by_space===2&&this.lc.p_cs_precedes===1){return this.lc.positive_sign+b}}else if(a=="-"){if(this.lc.n_sign_posn===0){return"("+b+")"}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return this.lc.negative_sign+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return this.lc.negative_sign+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===1&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return b+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return b+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===2&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+b}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.n_sign_posn===3&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===0&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+b}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===0){return b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===1&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+" "+b}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===0){return b+" "+this.lc.negative_sign}else if(this.lc.n_sign_posn===4&&this.lc.n_sep_by_space===2&&this.lc.n_cs_precedes===1){return this.lc.negative_sign+b}}throw"Error: Invalid POSIX LC MONETARY definition"};this._formatAsInternationalCurrencyWithNoSym=function(a,b){if(a=="+"){if(this.lc.int_p_sign_posn===0){return"("+b+")"}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return this.lc.positive_sign+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return this.lc.positive_sign+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===1&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===2&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===3&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===0){return b+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===0&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+b}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===1&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+this.intSep+b}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===0){return b+this.intSep+this.lc.positive_sign}else if(this.lc.int_p_sign_posn===4&&this.lc.int_p_sep_by_space===2&&this.lc.int_p_cs_precedes===1){return this.lc.positive_sign+b}}else if(a=="-"){if(this.lc.int_n_sign_posn===0){return"("+b+")"}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return this.lc.negative_sign+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return this.lc.negative_sign+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===1&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===2&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+b}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===3&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===0){return b+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===0&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+b}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===1&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+this.intSep+b}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===0){return b+this.intSep+this.lc.negative_sign}else if(this.lc.int_n_sign_posn===4&&this.lc.int_n_sep_by_space===2&&this.lc.int_n_cs_precedes===1){return this.lc.negative_sign+b}}throw"Error: Invalid POSIX LC_MONETARY definition"}};jsworld.NumericParser=function(a){if(typeof a!="object"||a._className!="jsworld.Locale")throw"Constructor error: You must provide a valid jsworld.Locale instance";this.lc=a;this.parse=function(a){if(typeof a!="string")throw"Parse error: Argument must be a string";var b=jsworld._trim(a);b=jsworld._stringReplaceAll(a,this.lc.thousands_sep,"");b=jsworld._stringReplaceAll(b,this.lc.decimal_point,".");if(jsworld._isNumber(b))return parseFloat(b,10);else throw"Parse error: Invalid number string"}};jsworld.DateTimeParser=function(a){if(typeof a!="object"||a._className!="jsworld.Locale")throw"Constructor error: You must provide a valid jsworld.Locale instance.";this.lc=a;this.parseTime=function(a){if(typeof a!="string")throw"Parse error: Argument must be a string";var b=this._extractTokens(this.lc.t_fmt,a);var c=false;if(b.hour!==null&&b.minute!==null&&b.second!==null){c=true}else if(b.hourAmPm!==null&&b.am!==null&&b.minute!==null&&b.second!==null){if(b.am){b.hour=parseInt(b.hourAmPm,10)}else{if(b.hourAmPm==12)b.hour=0;else b.hour=parseInt(b.hourAmPm,10)+12}c=true}if(c)return jsworld._zeroPad(b.hour,2)+":"+jsworld._zeroPad(b.minute,2)+":"+jsworld._zeroPad(b.second,2);else throw"Parse error: Invalid/ambiguous time string"};this.parseDate=function(a){if(typeof a!="string")throw"Parse error: Argument must be a string";var b=this._extractTokens(this.lc.d_fmt,a);var c=false;if(b.year!==null&&b.month!==null&&b.day!==null){c=true}if(c)return jsworld._zeroPad(b.year,4)+"-"+jsworld._zeroPad(b.month,2)+"-"+jsworld._zeroPad(b.day,2);else throw"Parse error: Invalid date string"};this.parseDateTime=function(a){if(typeof a!="string")throw"Parse error: Argument must be a string";var b=this._extractTokens(this.lc.d_t_fmt,a);var c=false;var d=false;if(b.hour!==null&&b.minute!==null&&b.second!==null){c=true}else if(b.hourAmPm!==null&&b.am!==null&&b.minute!==null&&b.second!==null){if(b.am){b.hour=parseInt(b.hourAmPm,10)}else{if(b.hourAmPm==12)b.hour=0;else b.hour=parseInt(b.hourAmPm,10)+12}c=true}if(b.year!==null&&b.month!==null&&b.day!==null){d=true}if(d&&c)return jsworld._zeroPad(b.year,4)+"-"+jsworld._zeroPad(b.month,2)+"-"+jsworld._zeroPad(b.day,2)+" "+jsworld._zeroPad(b.hour,2)+":"+jsworld._zeroPad(b.minute,2)+":"+jsworld._zeroPad(b.second,2);else throw"Parse error: Invalid/ambiguous date/time string"};this._extractTokens=function(a,b){var c={year:null,month:null,day:null,hour:null,hourAmPm:null,am:null,minute:null,second:null,weekday:null};while(a.length>0){if(a.charAt(0)=="%"&&a.charAt(1)!=""){var d=a.substring(0,2);if(d=="%%"){b=b.substring(1)}else if(d=="%a"){for(var e=0;e31)throw"Parse error: Unrecognised day of the month (%e)";b=b.substring(f.length)}else if(d=="%F"){if(/^\d\d\d\d/.test(b)){c.year=parseInt(b.substring(0,4),10);b=b.substring(4)}else{throw"Parse error: Unrecognised date (%F)"}if(jsworld._stringStartsWith(b,"-"))b=b.substring(1);else throw"Parse error: Unrecognised date (%F)";if(/^0[1-9]|1[0-2]/.test(b)){c.month=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised date (%F)";if(jsworld._stringStartsWith(b,"-"))b=b.substring(1);else throw"Parse error: Unrecognised date (%F)";if(/^0[1-9]|[1-2][0-9]|3[0-1]/.test(b)){c.day=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised date (%F)"}else if(d=="%H"){if(/^[0-1][0-9]|2[0-3]/.test(b)){c.hour=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised hour (%H)"}else if(d=="%I"){if(/^0[1-9]|1[0-2]/.test(b)){c.hourAmPm=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised hour (%I)"}else if(d=="%k"){var g=b.match(/^(\d{1,2})/);c.hour=parseInt(g,10);if(isNaN(c.hour)||c.hour<0||c.hour>23)throw"Parse error: Unrecognised hour (%k)";b=b.substring(g.length)}else if(d=="%l"){var g=b.match(/^(\d{1,2})/);c.hourAmPm=parseInt(g,10);if(isNaN(c.hourAmPm)||c.hourAmPm<1||c.hourAmPm>12)throw"Parse error: Unrecognised hour (%l)";b=b.substring(g.length)}else if(d=="%m"){if(/^0[1-9]|1[0-2]/.test(b)){c.month=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised month (%m)"}else if(d=="%M"){if(/^[0-5][0-9]/.test(b)){c.minute=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised minute (%M)"}else if(d=="%n"){if(b.charAt(0)=="\n")b=b.substring(1);else throw"Parse error: Unrecognised new line (%n)"}else if(d=="%p"){if(jsworld._stringStartsWith(b,this.lc.am)){c.am=true;b=b.substring(this.lc.am.length)}else if(jsworld._stringStartsWith(b,this.lc.pm)){c.am=false;b=b.substring(this.lc.pm.length)}else throw"Parse error: Unrecognised AM/PM value (%p)"}else if(d=="%P"){if(jsworld._stringStartsWith(b,this.lc.am.toLowerCase())){c.am=true;b=b.substring(this.lc.am.length)}else if(jsworld._stringStartsWith(b,this.lc.pm.toLowerCase())){c.am=false;b=b.substring(this.lc.pm.length)}else throw"Parse error: Unrecognised AM/PM value (%P)"}else if(d=="%R"){if(/^[0-1][0-9]|2[0-3]/.test(b)){c.hour=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised time (%R)";if(jsworld._stringStartsWith(b,":"))b=b.substring(1);else throw"Parse error: Unrecognised time (%R)";if(/^[0-5][0-9]/.test(b)){c.minute=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised time (%R)"}else if(d=="%S"){if(/^[0-5][0-9]/.test(b)){c.second=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised second (%S)"}else if(d=="%T"){if(/^[0-1][0-9]|2[0-3]/.test(b)){c.hour=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised time (%T)";if(jsworld._stringStartsWith(b,":"))b=b.substring(1);else throw"Parse error: Unrecognised time (%T)";if(/^[0-5][0-9]/.test(b)){c.minute=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised time (%T)";if(jsworld._stringStartsWith(b,":"))b=b.substring(1);else throw"Parse error: Unrecognised time (%T)";if(/^[0-5][0-9]/.test(b)){c.second=parseInt(b.substring(0,2),10);b=b.substring(2)}else throw"Parse error: Unrecognised time (%T)"}else if(d=="%w"){if(/^\d/.test(b)){c.weekday=parseInt(b.substring(0,1),10);b=b.substring(1)}else throw"Parse error: Unrecognised weekday number (%w)"}else if(d=="%y"){if(/^\d\d/.test(b)){var h=parseInt(b.substring(0,2),10);if(h>50)c.year=1900+h;else c.year=2e3+h;b=b.substring(2)}else throw"Parse error: Unrecognised year (%y)"}else if(d=="%Y"){if(/^\d\d\d\d/.test(b)){c.year=parseInt(b.substring(0,4),10);b=b.substring(4)}else throw"Parse error: Unrecognised year (%Y)"}else if(d=="%Z"){if(a.length===0)break}a=a.substring(2)}else{if(a.charAt(0)!=b.charAt(0))throw'Parse error: Unexpected symbol "'+b.charAt(0)+'" in date/time string';a=a.substring(1);b=b.substring(1)}}return c}};jsworld.MonetaryParser=function(a){if(typeof a!="object"||a._className!="jsworld.Locale")throw"Constructor error: You must provide a valid jsworld.Locale instance";this.lc=a;this.parse=function(a){if(typeof a!="string")throw"Parse error: Argument must be a string";var b=this._detectCurrencySymbolType(a);var c,d;if(b=="local"){c="local";d=a.replace(this.lc.getCurrencySymbol(),"")}else if(b=="int"){c="int";d=a.replace(this.lc.getIntCurrencySymbol(),"")}else if(b=="none"){c="local";d=a}else throw"Parse error: Internal assert failure";d=jsworld._stringReplaceAll(d,this.lc.mon_thousands_sep,"");d=d.replace(this.lc.mon_decimal_point,".");d=d.replace(/\s*/g,"");d=this._removeLocalNonNegativeSign(d,c);d=this._normaliseNegativeSign(d,c);if(jsworld._isNumber(d))return parseFloat(d,10);else throw"Parse error: Invalid currency amount string"};this._detectCurrencySymbolType=function(a){if(this.lc.getCurrencySymbol().length>this.lc.getIntCurrencySymbol().length){if(a.indexOf(this.lc.getCurrencySymbol())!=-1)return"local";else if(a.indexOf(this.lc.getIntCurrencySymbol())!=-1)return"int";else return"none"}else{if(a.indexOf(this.lc.getIntCurrencySymbol())!=-1)return"int";else if(a.indexOf(this.lc.getCurrencySymbol())!=-1)return"local";else return"none"}};this._removeLocalNonNegativeSign=function(a,b){a=a.replace(this.lc.positive_sign,"");if((b=="local"&&this.lc.p_sign_posn===0||b=="int"&&this.lc.int_p_sign_posn===0)&&/\(\d+\.?\d*\)/.test(a)){a=a.replace("(","");a=a.replace(")","")}return a};this._normaliseNegativeSign=function(a,b){a=a.replace(this.lc.negative_sign,"-");if(b=="local"&&this.lc.n_sign_posn===0||b=="int"&&this.lc.int_n_sign_posn===0){if(/^\(\d+\.?\d*\)$/.test(a)){a=a.replace("(","");a=a.replace(")","");return"-"+a}}if(b=="local"&&this.lc.n_sign_posn==2||b=="int"&&this.lc.int_n_sign_posn==2){if(/^\d+\.?\d*-$/.test(a)){a=a.replace("-","");return"-"+a}}if(b=="local"&&this.lc.n_cs_precedes===0&&this.lc.n_sign_posn==3||b=="local"&&this.lc.n_cs_precedes===0&&this.lc.n_sign_posn==4||b=="int"&&this.lc.int_n_cs_precedes===0&&this.lc.int_n_sign_posn==3||b=="int"&&this.lc.int_n_cs_precedes===0&&this.lc.int_n_sign_posn==4){if(/^\d+\.?\d*-$/.test(a)){a=a.replace("-","");return"-"+a}}return a}} + + +if(typeof POSIX_LC == "undefined") var POSIX_LC = {}; + +POSIX_LC.en_US = { + "decimal_point" : ".", + "thousands_sep" : ",", + "grouping" : "3", + "abday" : ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"], + "day" : ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"], + "abmon" : ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"], + "mon" : ["January","February","March","April","May","June","July","August","September","October","November","December"], + "d_fmt" : "%m/%e/%y", + "t_fmt" : "%I:%M:%S %p", + "d_t_fmt" : "%B %e, %Y %I:%M:%S %p %Z", + "am_pm" : ["AM","PM"], + "int_curr_symbol" : "USD ", + "currency_symbol" : "\u0024", + "mon_decimal_point" : ".", + "mon_thousands_sep" : ",", + "mon_grouping" : "3", + "positive_sign" : "", + "negative_sign" : "-", + "int_frac_digits" : 2, + "frac_digits" : 2, + "p_cs_precedes" : 1, + "n_cs_precedes" : 1, + "p_sep_by_space" : 0, + "n_sep_by_space" : 0, + "p_sign_posn" : 1, + "n_sign_posn" : 1, + "int_p_cs_precedes" : 1, + "int_n_cs_precedes" : 1, + "int_p_sep_by_space" : 0, + "int_n_sep_by_space" : 0, + "int_p_sign_posn" : 1, + "int_n_sign_posn" : 1 +} + +if(typeof POSIX_LC == "undefined") var POSIX_LC = {}; + +POSIX_LC.fr_FR = { + "decimal_point" : ",", + "thousands_sep" : "\u00a0", + "grouping" : "3", + "abday" : ["dim.","lun.","mar.", + "mer.","jeu.","ven.", + "sam."], + "day" : ["dimanche","lundi","mardi", + "mercredi","jeudi","vendredi", + "samedi"], + "abmon" : ["janv.","f\u00e9vr.","mars", + "avr.","mai","juin", + "juil.","ao\u00fbt","sept.", + "oct.","nov.","d\u00e9c."], + "mon" : ["janvier","f\u00e9vrier","mars", + "avril","mai","juin", + "juillet","ao\u00fbt","septembre", + "octobre","novembre","d\u00e9cembre"], + "d_fmt" : "%d/%m/%y", + "t_fmt" : "%H:%M:%S", + "d_t_fmt" : "%e %B %Y %H:%M:%S %Z", + "am_pm" : ["AM","PM"], + "int_curr_symbol" : "EUR ", + "currency_symbol" : "\u20ac", + "mon_decimal_point" : ",", + "mon_thousands_sep" : "\u00a0", + "mon_grouping" : "3", + "positive_sign" : "", + "negative_sign" : "-", + "int_frac_digits" : 2, + "frac_digits" : 2, + "p_cs_precedes" : 0, + "n_cs_precedes" : 0, + "p_sep_by_space" : 1, + "n_sep_by_space" : 1, + "p_sign_posn" : 1, + "n_sign_posn" : 1, + "int_p_cs_precedes" : 0, + "int_n_cs_precedes" : 0, + "int_p_sep_by_space" : 1, + "int_n_sep_by_space" : 1, + "int_p_sign_posn" : 1, + "int_n_sign_posn" : 1 +}; + +/** https://github.com/csnover/js-iso8601 */(function(n,f){var u=n.parse,c=[1,4,5,6,7,10,11];n.parse=function(t){var i,o,a=0;if(o=/^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(t)){for(var v=0,r;r=c[v];++v)o[r]=+o[r]||0;o[2]=(+o[2]||1)-1,o[3]=+o[3]||1,o[8]!=="Z"&&o[9]!==f&&(a=o[10]*60+o[11],o[9]==="+"&&(a=0-a)),i=n.UTC(o[1],o[2],o[3],o[4],o[5]+a,o[6],o[7])}else i=u?u(t):NaN;return i}})(Date) + +/*! + * geo-location-javascript v0.4.3 + * http://code.google.com/p/geo-location-javascript/ + * + * Copyright (c) 2009 Stan Wiechers + * Licensed under the MIT licenses. + * + * Revision: $Rev: 68 $: + * Author: $Author: whoisstan $: + * Date: $Date: 2010-02-15 13:42:19 +0100 (Mon, 15 Feb 2010) $: + */ +var geo_position_js=function() { + + var pub = {}; + var provider=null; + + pub.getCurrentPosition = function(successCallback,errorCallback,options) + { + provider.getCurrentPosition(successCallback, errorCallback,options); + } + + pub.init = function() + { + try + { + if (typeof(geo_position_js_simulator)!="undefined") + { + provider=geo_position_js_simulator; + } + else if (typeof(bondi)!="undefined" && typeof(bondi.geolocation)!="undefined") + { + provider=bondi.geolocation; + } + else if (typeof(navigator.geolocation)!="undefined") + { + provider=navigator.geolocation; + pub.getCurrentPosition = function(successCallback, errorCallback, options) + { + function _successCallback(p) + { + //for mozilla geode,it returns the coordinates slightly differently + if(typeof(p.latitude)!="undefined") + { + successCallback({timestamp:p.timestamp, coords: {latitude:p.latitude,longitude:p.longitude}}); + } + else + { + successCallback(p); + } + } + provider.getCurrentPosition(_successCallback,errorCallback,options); + } + } + else if(typeof(window.google)!="undefined" && typeof(google.gears)!="undefined") + { + provider=google.gears.factory.create('beta.geolocation'); + } + else if ( typeof(Mojo) !="undefined" && typeof(Mojo.Service.Request)!="Mojo.Service.Request") + { + provider=true; + pub.getCurrentPosition = function(successCallback, errorCallback, options) + { + + parameters={}; + if(options) + { + //http://developer.palm.com/index.php?option=com_content&view=article&id=1673#GPS-getCurrentPosition + if (options.enableHighAccuracy && options.enableHighAccuracy==true) + { + parameters.accuracy=1; + } + if (options.maximumAge) + { + parameters.maximumAge=options.maximumAge; + } + if (options.responseTime) + { + if(options.responseTime<5) + { + parameters.responseTime=1; + } + else if (options.responseTime<20) + { + parameters.responseTime=2; + } + else + { + parameters.timeout=3; + } + } + } + + + r=new Mojo.Service.Request('palm://com.palm.location', { + method:"getCurrentPosition", + parameters:parameters, + onSuccess: function(p){successCallback({timestamp:p.timestamp, coords: {latitude:p.latitude, longitude:p.longitude,heading:p.heading}});}, + onFailure: function(e){ + if (e.errorCode==1) + { + errorCallback({code:3,message:"Timeout"}); + } + else if (e.errorCode==2) + { + errorCallback({code:2,message:"Position Unavailable"}); + } + else + { + errorCallback({code:0,message:"Unknown Error: webOS-code"+errorCode}); + } + } + }); + } + + } + else if (typeof(device)!="undefined" && typeof(device.getServiceObject)!="undefined") + { + provider=device.getServiceObject("Service.Location", "ILocation"); + + //override default method implementation + pub.getCurrentPosition = function(successCallback, errorCallback, options) + { + function callback(transId, eventCode, result) { + if (eventCode == 4) + { + errorCallback({message:"Position unavailable", code:2}); + } + else + { + //no timestamp of location given? + successCallback({timestamp:null, coords: {latitude:result.ReturnValue.Latitude, longitude:result.ReturnValue.Longitude, altitude:result.ReturnValue.Altitude,heading:result.ReturnValue.Heading}}); + } + } + //location criteria + var criteria = new Object(); + criteria.LocationInformationClass = "BasicLocationInformation"; + //make the call + provider.ILocation.GetLocation(criteria,callback); + } + } + } + catch (e){ + alert("error="+e); + if(typeof(console)!="undefined") + { + console.log(e); + } + return false; + } + return provider!=null; + } + + + return pub; +}(); +// Couldn't get unminified version to work , go here for docs => https://github.com/iamnoah/writeCapture +(function(E,a){var j=a.document;function A(Q){var Z=j.createElement("div");j.body.insertBefore(Z,null);E.replaceWith(Z,'\n \n
\n
\n \n\n
\n
\n \n
\n

'); + __out.push(__sanitize(t('Invite Link'))); + __out.push(' '); + __out.push(__sanitize(USER.referral_url)); + __out.push('

\n\n \n\n
\n\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "templates/clients/login": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + __out.push('
\n\t

'); + __out.push(__sanitize(t('Sign In'))); + __out.push('

\n\t
\n\t\t
\n\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\n\t\t\t
\n\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\n\t\t\t
\n\n
\n\n

'); + __out.push(__sanitize(t('Forgot Password?'))); + __out.push('

\n\n\t\t
\n\t
\n
\n\n
\n
\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "templates/clients/modules/credit_card": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + var printCard; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + if (this.cards === "new") { + __out.push('\n
\n
\n
\n
\n
\n
\n \n \n
\n
\n
\n
\n \n \n
\n
\n \n \n
\n
\n
\n
\n \n \n
\n
\n
\n \n \n
\n
\n
\n \n \n
\n
\n
\n \n
\n
\n
\n'); + } else { + __out.push('\n '); + printCard = __bind(function(card, index) { + var exp, style; + __out.push('\n
\n '); + style = "background-position:-173px"; + __out.push('\n '); + if (card.get("card_type") === "Visa") { + style = "background-position:0px"; + } + __out.push('\n '); + if (card.get("card_type") === "MasterCard") { + style = "background-position:-42px"; + } + __out.push('\n '); + if (card.get("card_type") === "American Express") { + style = "background-position:-130px"; + } + __out.push('\n '); + if (card.get("card_type") === "Discover Card") { + style = "background-position:-85px"; + } + __out.push('\n
\n
\n ****'); + __out.push(__sanitize(card.get("card_number"))); + __out.push('\n \n '); + if (card.get("card_expiration")) { + __out.push('\n '); + __out.push(__sanitize(t('Expiry'))); + __out.push('\n '); + exp = card.get('card_expiration').split('-'); + __out.push('\n '); + __out.push(__sanitize("" + exp[0] + "-" + exp[1])); + __out.push('\n '); + } + __out.push('\n \n \n \n '); + if (card.get("default")) { + __out.push('\n ('); + __out.push(__sanitize(t('default card'))); + __out.push(')\n '); + } + __out.push('\n '); + if (this.cards.length > 1 && !card.get("default")) { + __out.push('\n '); + __out.push(__sanitize(t('make default'))); + __out.push('\n '); + } + __out.push('\n \n '); + __out.push(__sanitize(t('Edit'))); + __out.push('\n \n '); + if (this.cards.length > 1) { + __out.push('\n '); + __out.push(__sanitize(t('Delete'))); + __out.push('\n '); + } + __out.push('\n
\n '); + _.each(this.cards.models, printCard); + __out.push('\n
\n
\n\n'); + } + __out.push('\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "templates/clients/modules/sub_header": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + __out.push('
\n
'); + __out.push(__sanitize(this.heading)); + __out.push('
\n
\n '); + if (window.USER.first_name) { + __out.push('\n '); + __out.push(__sanitize(t('Hello Greeting', { + name: USER.first_name + }))); + __out.push('\n '); + } + __out.push('\n
\n
\n
\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "templates/clients/promotions": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + var promo, _i, _len, _ref; + __out.push(require('templates/clients/modules/sub_header').call(this, { + heading: t("Promotions") + })); + __out.push('\n\n
\n
\n
\n \n \n
\n
\n \n \n\n \n
\n '); + if (this.promos.length > 0) { + __out.push('\n
\n

'); + __out.push(__sanitize(t('Your Available Promotions'))); + __out.push('

\n \n \n\n \n \n \n \n \n \n \n \n '); + _ref = this.promos; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + promo = _ref[_i]; + __out.push('\n \n \n \n \n \n \n '); + } + __out.push('\n \n
'); + __out.push(__sanitize(t('Code'))); + __out.push(''); + __out.push(__sanitize(t('Details'))); + __out.push(''); + __out.push(__sanitize(t('Starts'))); + __out.push(''); + __out.push(__sanitize(t('Expires'))); + __out.push('
'); + __out.push(__sanitize(promo.code)); + __out.push(''); + __out.push(__sanitize(promo.description)); + __out.push(''); + __out.push(__sanitize(app.helpers.formatDate(promo.starts_at, true, "America/Los_Angeles"))); + __out.push(''); + __out.push(__sanitize(app.helpers.formatDate(promo.ends_at, true, "America/Los_Angeles"))); + __out.push('
\n
\n '); + } else { + __out.push('\n\n

'); + __out.push(__sanitize(t('No Active Promotions'))); + __out.push('

\n '); + } + __out.push('\n\n
\n
\n
\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "templates/clients/request": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + var showFavoriteLocation; + showFavoriteLocation = function(location, index) { + var alphabet; + __out.push('\n '); + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + __out.push('\n
\n '); + __out.push(__sanitize(location.nickname)); + return __out.push('\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n

'); + __out.push(__sanitize(t('Driver Name:'))); + __out.push('

\n

\n
\n

'); + __out.push(__sanitize(t('Driver #:'))); + __out.push('

\n

\n
\n

'); + __out.push(__sanitize(t('Pickup Address:'))); + __out.push('

\n

\n
\n ');
+      __out.push(__sanitize(t('Add to Favorite Locations')));
+      __out.push('\n
\n
\n

\n '); + __out.push(__sanitize(t('Nickname:'))); + __out.push('\n \n \n \n \n
\n
\n
\n
\n

'); + __out.push(__sanitize(t('Your last trip'))); + __out.push('

\n
\n \n ');
+      __out.push(__sanitize(t('Star')));
+      __out.push('\n ');
+      __out.push(__sanitize(t('Star')));
+      __out.push('\n ');
+      __out.push(__sanitize(t('Star')));
+      __out.push('\n ');
+      __out.push(__sanitize(t('Star')));
+      __out.push('\n ');
+      __out.push(__sanitize(t('Star')));
+      __out.push('\n \n \n
\n \n
\n \n
\n \n
\n \n\n
\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "templates/shared/menu": function(exports, require, module) {module.exports = function(__obj) { + if (!__obj) __obj = {}; + var __out = [], __capture = function(callback) { + var out = __out, result; + __out = []; + callback.call(this); + result = __out.join(''); + __out = out; + return __safe(result); + }, __sanitize = function(value) { + if (value && value.ecoSafe) { + return value; + } else if (typeof value !== 'undefined' && value != null) { + return __escape(value); + } else { + return ''; + } + }, __safe, __objSafe = __obj.safe, __escape = __obj.escape; + __safe = __obj.safe = function(value) { + if (value && value.ecoSafe) { + return value; + } else { + if (!(typeof value !== 'undefined' && value != null)) value = ''; + var result = new String(value); + result.ecoSafe = true; + return result; + } + }; + if (!__escape) { + __escape = __obj.escape = function(value) { + return ('' + value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + }; + } + (function() { + (function() { + __out.push('\n'); + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}}, "translations/en": function(exports, require, module) {(function() { + exports.translations = { + "Uber": "Uber", + "Sign Up": "Sign Up", + "Ride Request": "Ride Request", + "Invite Friends": "Invite Friends", + "Promotions": "Promotions", + "Billing": "Billing", + "Settings": "Settings", + "Forgot Password?": "Forgot Password?", + "Password Recovery": "Password Recovery", + "Login": "Login", + "Trip Detail": "Trip Detail", + "Password Reset": "Password Reset", + "Confirm Email": "Confirm Email", + "Request Ride": "Request Ride", + "Credit Card Number": "Credit Card Number", + "month": "month", + "01-Jan": "01-Jan", + "02-Feb": "02-Feb", + "03-Mar": "03-Mar", + "04-Apr": "04-Apr", + "05-May": "05-May", + "06-Jun": "06-Jun", + "07-Jul": "07-Jul", + "08-Aug": "08-Aug", + "09-Sep": "09-Sep", + "10-Oct": "10-Oct", + "11-Nov": "11-Nov", + "12-Dec": "12-Dec", + "year": "year", + "CVV": "CVV", + "Category": "Category", + "personal": "personal", + "business": "business", + "Default Credit Card": "Default Credit Card", + "Add Credit Card": "Add Credit Card", + "Expiry": "Expiry", + "default card": "default card", + "make default": "make default", + "Edit": "Edit", + "Delete": "Delete", + "Expiry Month": "Expiry Month", + "Expiry Year": "Expiry Year", + "Unable to Verify Card": "Unable to verify card at this time. Please try again later.", + "Credit Card Update Succeeded": "Your card has been successfully updated!", + "Credit Card Update Failed": "We couldn't save your changes. Please try again in a few minutes.", + "Credit Card Delete Succeeded": "Your card has been deleted!", + "Credit Card Delete Failed": "We were unable to delete your card. Please try again later.", + "Credit Card Update Category Succeeded": "Successfully changed card category!", + "Credit Card Update Category Failed": "We couldn't change your card category. Please try again in a few minutes.", + "Credit Card Update Default Succeeded": "Successfully changed default card!", + "Credit Card Update Default Failed": "We couldn't change your default card. Please try again in a few minutes.", + "Hello Greeting": "Hello, <%= name %>", + "Card Ending in": "Card Ending in", + "Trip Map": "Trip Map", + "Amount": "Amount: <%= amount %>", + "Last Attempt to Bill": "Last Attempt to Bill: <%= date %>", + "Charge": "Charge", + "Uber Credit Balance Note": "Your account has an UberCredit balance of <%= amount %>. When billing for trips, we'll deplete your UberCredit balance before applying charges to your credit card.", + "Please Add Credit Card": "Please add a credit card to bill your outstanding charges.", + "Credit Cards": "Credit Cards", + "add a new credit card": "add a new credit card", + "Account Balance": "Account Balance", + "Arrears": "Arrears", + "Billing Succeeded": "Your card was successfully billed.", + "Confirm Email Succeeded": "Successfully confirmed email token, redirecting to log in page...", + "Confirm Email Failed": "Unable to confirm email. Please contact support@uber.com if this problem persists.", + "Email Already Confirmed": "Your email address has already been confirmed, redirecting to log in page...", + "Credit Card Added": "Credit Card Added", + "No Credit Card": "No Credit Card", + "Mobile Number Confirmed": "Mobile Number Confirmed", + "No Confirmed Mobile": "No Confirmed Mobile", + "E-mail Address Confirmed": "E-mail Address Confirmed", + "No Confirmed E-mail": "No Confirmed E-mail", + 'Reply to sign up text': 'Reply "GO" to the text message you received at sign up.', + "Resend text message": "Resend text message", + "Click sign up link": "Click the link in the email you received at sign up.", + "Resend email": "Resend email", + "Add a credit card to ride": "Add a credit card and you'll be ready to ride Uber.", + "Your Most Recent Trip": "Your Most Recent Trip", + "details": "details", + "Your Trip History ": "Your Trip History ", + "Status": "Status", + "Here's how it works:": "Here's how it works:", + "Show all trips": "Show all trips", + "Set your location:": "Set your location:", + "App search for address": "iPhone/Android app: fix the pin or search for an address", + "SMS text address": "SMS: text your address to UBRCAB (827222)", + "Confirm pickup request": "Confirm your pickup request", + "Uber sends ETA": "Uber will send you an ETA (usually within 5-10 minutes)", + "Car arrives": "When your car is arriving, Uber will inform you again.", + "Ride to destination": "Hop in the car and tell the driver your destination.", + "Thank your driver": "That’s it! Please thank your driver but remember that your tip is included and no cash is necessary.", + "Trip started here": "Trip started here", + "Trip ended here": "Trip ended here", + "Sending Email": "Sending email...", + "Resend Email Succeeded": "We just sent the email. Please click on the confirmation link you recieve.", + "Resend Email Failed": "There was an error sending the email. Please contact support if the problem persists.", + "Resend Text Succeeded": 'We just sent the text message. Please reply "GO" to the message you recieve. It may take a few minutes for the message to reach you phone.', + "Resend Text Failed": "There was an error sending the text message. Please contact support if the problem persists.", + "Password Reset Error": "There was an error processing your password reset request.", + "New Password": "New Password", + "Forgot Password": "Forgot Password", + "Forgot Password Error": "Your email address could not be found. Please make sure to use the same email address you used when you signed up.", + "Forgot Password Success": "Please check your email for a link to reset your password.", + "Forgot Password Enter Email": 'Enter your email address and Uber will send you a link to reset your password. If you remember your password, you can sign in here.', + "Invite friends": "Invite friends", + "Give $ Get $": "Give $10, Get $10", + "Give $ Get $ Description": "Every friend you invite to Uber gets $10 of Uber credit. After someone you’ve invited takes his/her first ride, you get $10 of Uber credits too!", + "What are you waiting for?": "So, what are you waiting for? Invite away!", + "Tweet": "Tweet", + "Invite Link": "Email or IM this link to your friends:", + "Email Address": "Email Address", + "Reset Password": "Reset Password", + "Enter Promotion Code": "If you have a promotion code, enter it here:", + "Your Active Promotions": "Your Active Promotions", + "Code": "Code", + "Details": "Details", + "Trips Remaining": "Trips Remaining", + "Expires": "Expires", + "No Active Promotions": "There are no active promotions on your account.", + "Your Available Promotions": "Your Available Promotions", + "Where do you want us to pick you up?": "Where do you want us to pick you up?", + "Address to search": "Address to search", + "Search": "Search", + "Driver Name:": "Driver Name:", + "Driver #:": "Driver #:", + "Pickup Address:": "Pickup Address:", + "Add to Favorite Locations": "Add to Favorite Locations", + "Star": "Star", + "Nickname:": "Nickname:", + "Add": "Add", + "Your last trip": "Your last trip", + "Please rate your driver:": "Please rate your driver:", + "Comments: (optional)": "Comments: (optional)", + "Rate Trip": "Rate Trip", + "Pickup time:": "Pickup time:", + "Miles:": "Miles:", + "Trip time:": "Trip time:", + "Fare:": "Fare:", + "Favorite Locations": "Favorite Locations", + "Search Results": "Search Results", + "You have no favorite locations saved.": "You have no favorite locations saved.", + "Loading...": "Loading...", + "Request Pickup": "Request Pickup", + "Cancel Pickup": "Cancel Pickup", + "Requesting Closest Driver": "Requesting the closest driver to pick you up...", + "En Route": "You are currently en route...", + "Rate Last Trip": "Please rate your trip to make another request", + "Rate Before Submitting": "Please rate your trip before submitting the form", + "Address too short": "Address too short", + "or did you mean": "or did you mean", + "Search Address Failed": "Unable to find the given address. Please enter another address close to your location.", + "Sending pickup request...": "Sending pickup request...", + "Cancel Request Prompt": "Are you sure you want to cancel your request?", + "Cancel Request Arrived Prompt": 'Are you sure you want to cancel your request? Your driver has arrived so there is a $10 cancellation fee. It may help to call your driver now', + "Favorite Location Nickname Length Error": "Nickname has to be atleast 3 characters", + "Favorite Location Save Succeeded": "Location Saved!", + "Favorite Location Save Failed": "Unable to save your location. Please try again later.", + "Favorite Location Title": "Favorite Location <%= id %>", + "Search Location Title": "Search Location <%= id %>", + "ETA Message": "ETA: Around <%= minutes %> Minutes", + "Nearest Cab Message": "The closest driver is approximately <%= minutes %> minute(s) away", + "Arrival ETA Message": "Your Uber will arrive in about <%= minutes %> minute(s)", + "Arriving Now Message": "Your Uber is arriving now...", + "Rating Driver Failed": "Unable to contact server. Please try again later or email support if this issue persists.", + "Account Information": "Account Information", + "Mobile Phone Information": "Mobile Phone Information", + "settings": "settings", + "Information": "Information", + "Picture": "Picture", + "Change password": "Change password", + "Your current Picture": "Your current Picture", + "Your Favorite Locations": "Your Favorite Locations", + "You have no favorite locations saved.": "You have no favorite locations saved.", + "Purpose of Mobile": "We send text messages to your mobile phone to tell you when your driver is arriving. You can also request trips using text messages.", + "Country": "Country", + "Mobile Number": "Mobile Number", + "Submit": "Submit", + "Favorite Location": "Favorite Location", + "No Approximate Address": "Could not find an approximate address", + "Address:": "Address:", + "Information Update Succeeded": "Your information has been updated!", + "Information Update Failed": "We couldn't update your information. Please try again in few minutes or contact support if the problem persists.", + "Location Delete Succeeded": "Location deleted!", + "Location Delete Failed": "We were unable to delete your favorite location. Please try again later or contact support of the issue persists.", + "Location Edit Succeeded": "Changes Saved!", + "Location Edit Failed": "We couldn't save your changes. Please try again in a few minutes.", + "Picture Update Succeeded": "Your picture has been updated!", + "Picture Update Failed": "We couldn't change your picture. Please try again in a few minutes.", + "Personal Information": "Personal Information", + "Mobile Phone Number": "Mobile Phone Number", + "Payment Information": "Payment Information", + "Purpose of Credit Card": "We keep your credit card on file so that your trip go as fast as possible. You will not be charged until you take a trip.", + "Your card will not be charged until you take a trip.": "Your card will not be charged until you take a trip.", + "Credit Card Number": "Credit Card Number", + "Expiration Date": "Expiration Date", + "Promotion Code": "Promotion Code", + "Enter Promo Here": "If you have a code for a promotion, invitation or group deal, you can enter it here.", + "Promotion Code Input Label": "Promotion, Invite or Groupon Code (optional)", + "Terms and Conditions": "Terms and Conditions", + "HELP": "HELP", + "STOP": "STOP", + "Legal Information": "Legal Information", + "Sign Up Agreement": "By signing up, I agree to the Uber <%= terms_link %> and <%= privacy_link %> and understand that Uber is a request tool, not a transportation carrier.", + "Sign Up Agreement Error": "You must agree to the Uber Terms and Conditions and Privacy Policy to continue.", + "Message and Data Rates Disclosure": "Message and Data Rates May Apply. Reply <%= help_string %> to 827-222 for help. Reply <%= stop_string %> to 827-222 to stop texts. For additional assistance, visit support.uber.com or call (866) 576-1039. Supported Carriers: AT&T, Sprint, Verizon, and T-Mobile.", + "I Agree": "I agree to the Terms & Conditions and Privacy Policy", + "Security Code": "Security Code", + "Type of Card": "Type of Card", + "Personal": "Personal", + "Business": "Business", + "Code": "Code", + "Zip or Postal Code": "Zip or Postal Code", + "Your Trip": "Your Trip", + "Trip Info": "Trip Info", + "Request a fare review": "Request a fare review", + "Fare Review Submitted": "Your fare review has been submitted. We'll get back to you soon about your request. Sorry for any inconvenience this may have caused!", + "Fair Price Consideration": "We're committed to delivering Uber service at a fair price. Before requesting a fare review, please consider:", + "Your Fare Calculation": "Your Fare Calculation", + "Charges": "Charges", + "Discounts": "Discounts", + "Total Charge": "Total Charge", + "Uber pricing information": "Uber pricing information", + "Uber Pricing Information Message": "<%= learn_link %> is published on our website.", + "GPS Point Capture Disclosure": "Due to a finite number of GPS point captures, corners on your trip map may appear cut off or rounded. These minor inaccuracies result in a shorter measured distance, which always results in a cheaper trip.", + "Fare Review Note": "Please elaborate on why this trip requires a fare review. Your comments below will help us better establish the correct price for your trip:", + "Fare Review Error": "There was an error submitting the review. Please ensure that you have a message.", + "Sign In": "Sign In" + }; +}).call(this); +}, "translations/fr": function(exports, require, module) {(function() { + exports.translations = { + "Uber": "Uber", + "Sign Up": "Inscription", + "Ride Request": "Passer une Commande", + "Invite Friends": "Inviter vos Amis", + "Promotions": "Promotions", + "Billing": "Paiement", + "Settings": "Paramètres", + "Forgot Password?": "Mot de passe oublié ?", + "Password Recovery": "Récupération du mot de passe", + "Login": "Connexion", + "Trip Detail": "Détail de la Course", + "Password Reset": "Réinitialisation du mot de passe", + "Confirm Email": "Confirmation de l’e-mail", + "Request Ride": "Passer une Commande", + "Credit Card Number": "Numéro de Carte de Crédit", + "month": "mois", + "01-Jan": "01-Jan", + "02-Feb": "02-Fév", + "03-Mar": "03-Mar", + "04-Apr": "04-Avr", + "05-May": "05-Mai", + "06-Jun": "06-Juin", + "07-Jul": "07-Jui", + "08-Aug": "08-Aoû", + "09-Sep": "09-Sep", + "10-Oct": "10-Oct", + "11-Nov": "11-Nov", + "12-Dec": "12-Déc", + "year": "année", + "CVV": "Code de Sécurité", + "Category": "Type", + "personal": "personnel", + "business": "entreprise", + "Default Credit Card": "Carte par Défaut", + "Add Credit Card": "Ajouter une Carte", + "Expiry": "Expire", + "default card": "carte par défaut", + "make default": "choisir par défaut", + "Edit": "Modifier", + "Delete": "Supprimer", + "Expiry Month": "Mois d’Expiration", + "Expiry Year": "Année d’Expiration", + "Unable to Verify Card": "Impossible de vérifier la carte pour le moment. Merci de réessayer un peu plus tard.", + "Credit Card Update Succeeded": "Votre carte a été mise à jour avec succès !", + "Credit Card Update Failed": "Nous ne pouvons enregistrer vos changements. Merci de réessayer dans quelques minutes.", + "Credit Card Delete Succeeded": "Votre carte a été supprimée !", + "Credit Card Delete Failed": "Nous n’avons pas été en mesure de supprimer votre carte. Merci de réessayer plus tard.", + "Credit Card Update Category Succeeded": "Changement de catégorie de carte réussi !", + "Credit Card Update Category Failed": "Nous ne pouvons pas changer la catégorie de votre carte. Merci de réessayer dans quelques minutes.", + "Credit Card Update Default Succeeded": "Carte par défaut changée avec succès !", + "Credit Card Update Default Failed": "Nous ne pouvons pas changer votre carte par défaut. Merci de réessayer dans quelques minutes.", + "Hello Greeting": "Bonjour, <%= name %>", + "Card Ending in": "La carte expire dans", + "Trip Map": "Carte des Courses", + "Amount": "Montant: <%= amount %>", + "Last Attempt to Bill": "Dernière tentative de prélèvement : <%= date %>", + "Charge": "Débit", + "Uber Credit Balance Note": "Votre compte a un solde de <%= amount %> UberCredits. Lorsque nous facturons des courses, nous réduirons votre solde d’UberCredits avant de prélever votre carte de crédit.", + "Please Add Credit Card": "Merci d’ajouter une carte de crédit pour que nous puissions vous facturer.", + "Credit Cards": "Cartes de crédit", + "add a new credit card": "Ajouter une nouvelle carte de crédit", + "Account Balance": "Solde du compte", + "Arrears": "Arriérés", + "Billing Succeeded": "Votre carte a été correctement débitée.", + "Confirm Email Succeeded": "L’adresse e-mail a bien été validée, vous êtes redirigé vers le tableau de bord...", + "Confirm Email Failed": "Impossible de confirmer l’adresse e-mail. Merci de contacter support@uber.com si le problème persiste.", + "Credit Card Added": "Carte de crédit ajoutée", + "No Credit Card": "Pas de carte de crédit", + "Mobile Number Confirmed": "Numéro de téléphone confirmé", + "No Confirmed Mobile": "Pas de numéro de téléphone confirmé", + "E-mail Address Confirmed": "Adresse e-mail confirmée", + "No Confirmed E-mail": "Pas d’adresse e-mail confirmée", + 'Reply to sign up text': 'Répondre "GO" au SMS que vous avez reçu à l’inscription.', + "Resend text message": "Renvoyer le SMS", + "Click sign up link": "Cliquez sur le lien contenu dans l’e-mail reçu à l’inscription.", + "Resend email": "Renvoyer l’e-mail", + "Add a credit card to ride": "Ajouter une carte de crédit et vous serez prêt à voyager avec Uber.", + "Your Most Recent Trip": "Votre course la plus récente", + "details": "détails", + "Your Trip History": "Historique de votre trajet", + "Status": "Statut", + "Here's how it works:": "Voici comment ça marche :", + "Show all trips": "Montrer toutes les courses", + "Set your location:": "Définir votre position :", + "App search for address": "Application iPhone/Android : positionner la punaise ou rechercher une adresse", + "SMS text address": "SMS : envoyez votre adresse à UBRCAB (827222)", + "Confirm pickup request": "Validez la commande", + "Uber sends ETA": "Uber envoie un temps d’attente estimé (habituellement entre 5 et 10 minutes)", + "Car arrives": "Lorsque votre voiture arrive, Uber vous en informera encore..", + "Ride to destination": "Montez dans la voiture et donnez votre destination au chauffeur.", + "Thank your driver": "C’est tout ! Remerciez le chauffeur mais souvenez-vous que les pourboires sont compris et qu’il n’est pas nécessaire d’avoir du liquide sur soi.", + "Trip started here": "La course a commencé ici.", + "Trip ended here": "La course s’est terminée ici.", + "Sending Email": "Envoi de l’e-mail...", + "Resend Email Succeeded": "Nous venons d’envoyer l’e-mail. Merci de cliquer sur le lien de confirmation que vous avez reçu.", + "Resend Email Failed": "Il y a eu un problème lors de l’envoi de l’email. Merci de contacter le support si le problème persiste.", + "Resend Text Succeeded": 'Nous venons d’envoyer le SMS. Merci de répondre "GO" au message que vous avez reçu. Il se peut que cela prenne quelques minutes pour que le message arrive sur votre téléphone.', + "Resend Text Failed": "Il y a eu un problème lors de l’envoi du SMS. Merci de contacter le support si le problème persiste.", + "Password Reset Error": "Il y a eu une error lors de la réinitialisation de votre mot de passe.", + "New Password:": "Nouveau mot de passe:", + "Forgot Password Error": "Votre nom d’utilisateur / adresse email ne peut être trouvé. Merci d’utiliser la même qu’à l’inscription.", + "Forgot Password Success": "Merci de consulter votre boîte mail pour suivre la demande de ‘réinitialisation de mot de passe.", + "Forgot Password Enter Email": "Merci de saisir votre adresse email et nous vous enverrons un lien vous permettant de réinitialiser votre mot de passe :", + "Invite friends": "Inviter vos amis", + "Give $ Get $": "Donnez $10, Recevez $10", + "Give $ Get $ Description": "Chaque ami que vous invitez à Uber recevra $10 de crédits Uber. Dès lors qu’une personne que vous aurez invité aura utilisé Uber pour la première, vous recevrez $10 de crédits Uber également !", + "What are you waiting for?": "N’attendez plus ! Lancez les invitations !", + "Tweet": "Tweeter", + "Invite Link": "Envoyez ce lien par email ou messagerie instantanée à vos amis :", + "Enter Promotion Code": "Si vous avez un code promo, saisissez-le ici:", + "Your Active Promotions": "Vos Codes Promos Actifs", + "Code": "Code", + "Details": "Détails", + "Trips Remaining": "Courses restantes", + "Expires": "Expire", + "No Active Promotions": "Vous n’avez pas de code promo actif.", + "Your Available Promotions": "Votres Promos Disponibles", + "Where do you want us to pick you up?": "Où souhaitez-vous que nous vous prenions en charge ?", + "Address to search": "Adresse à rechercher", + "Search": "Chercher", + "Driver Name:": "Nom du chauffeur:", + "Driver #:": "# Chauffeur:", + "Pickup Address:": "Lieu de prise en charge:", + "Add to Favorite Locations": "Ajoutez aux Lieux Favoris", + "Star": "Étoiles", + "Nickname:": "Pseudo", + "Add": "Ajouter", + "Your last trip": "Votre dernière course", + "Please rate your driver:": "Merci de noter votre chauffeur :", + "Comments: (optional)": "Commentaires: (optionnel)", + "Rate Trip": "Notez votre course", + "Pickup time:": "Heure de Prise en Charge :", + "Miles:": "Kilomètres :", + "Trip time:": "Temps de course :", + "Fare:": "Tarif :", + "Favorite Locations": "Lieux Favoris", + "Search Results": "Résultats", + "You have no favorite locations saved.": "Vous n’avez pas de lieux de prise en charge favoris.", + "Loading...": "Chargement...", + "Request Pickup": "Commander ici", + "Cancel Pickup": "Annuler", + "Requesting Closest Driver": "Nous demandons au chauffeur le plus proche de vous prendre en charge...", + "En Route": "Vous êtes actuellement en route...", + "Rate Last Trip": "Merci de noter votre précédent trajet pour faire une autre course.", + "Rate Before Submitting": "Merci de noter votre trajet avant de le valider.", + "Address too short": "L’adresse est trop courte", + "or did you mean": "ou vouliez-vous dire", + "Search Address Failed": "Impossible de trouver l’adresse spécifiée. Merci de saisir une autre adresse proche de l’endroit où vous vous trouvez.", + "Sending pickup request...": "Envoi de la demande de prise en charge...", + "Cancel Request Prompt": "Voulez-vous vraiment annuler votre demande ?", + "Cancel Request Arrived Prompt": 'Voulez-vous vraiment annuler votre demande ? Votre chauffeur est arrivé, vous serez donc facturé de $10 de frais d’annulation. Il pourrait être utile que vous appeliez votre chauffeur maintenant.', + "Favorite Location Nickname Length Error": "Le pseudo doit faire au moins 3 caractères de long", + "Favorite Location Save Succeeded": "Adresse enregistrée !", + "Favorite Location Save Failed": "Impossible d’enregistrer votre adresse. Merci de réessayer ultérieurement.", + "Favorite Location Title": "Adresse favorie <%= id %>", + "Search Location Title": "Recherche d’adresse <%= id %>", + "ETA Message": "Temps d’attente estimé: environ <%= minutes %> minutes", + "Nearest Cab Message": "Le chauffeur le plus proche sera là dans <%= minutes %> minute(s)", + "Arrival ETA Message": "Votre chauffeur arrivera dans <%= minutes %> minute(s)", + "Arriving Now Message": "Votre chauffeur est en approche...", + "Rating Driver Failed": "Impossible de contacter le serveur. Merci de réessayer ultérieurement ou de contacter le support si le problème persiste.", + "settings": "Paramètres", + "Information": "Information", + "Picture": "Photo", + "Change password": "Modifier votre mot de passe", + "Your current Picture": "Votre photo", + "Your Favorite Locations": "Vos lieux favoris", + "You have no favorite locations saved.": "Vous n’avez pas de lieu favori", + "Account Information": "Informations Personnelles", + "Mobile Phone Information": "Informations de Mobile", + "Change Your Password": "Changez votre mot de passe.", + "Country": "Pays", + "Language": "Langue", + "Favorite Location": "Lieu favori", + "No Approximate Address": "Impossible de trouver une adresse même approximative", + "Address:": "Adresse :", + "Information Update Succeeded": "Vos informations ont été mises à jour !", + "Information Update Failed": "Nous n’avons pas pu mettre à jour vos informations. Merci de réessayer dans quelques instants ou de contacter le support si le problème persiste.", + "Location Delete Succeeded": "Adresse supprimée !", + "Location Delete Failed": "Nous n’avons pas pu supprimée votre adresse favorie. Merci de réessayer plus tard ou de contacter le support si le problème persiste.", + "Location Edit Succeeded": "Modifications sauvegardées !", + "Location Edit Failed": "Nous n’avons pas pu sauvegarder vos modifications. Merci de réessayer dans quelques minutes.", + "Picture Update Succeeded": "Votre photo a été mise à jour !", + "Picture Update Failed": "Nous n’avons pas pu mettre à jour votre photo. Merci de réessayer dans quelques instants.", + "Personal Information": "Informations Personnelles", + "Mobile Phone Number": "Numéro de Téléphone Portable", + "Payment Information": "Informations de Facturation", + "Your card will not be charged until you take a trip.": "Votre carte ne sera pas débitée avant votre premier trajet.", + "Card Number": "Numéro de Carte", + "Promotion Code Input Label": "Code promo, code d’invitation ou “deal” acheté en ligne (optionnel)", + "Terms and Conditions": "Conditions Générales", + "HELP": "HELP", + "STOP": "STOP", + "Sign Up Agreement": "En souscrivant, j’accepte les <%= terms_link %> et <%= privacy_link %> et comprends qu’Uber est un outil de commande de chauffeur, et non un transporteur.", + "Sign Up Agreement Error": "Vous devez accepter les Conditions Générales d’utilisation d’Uber Terms and Conditions et la Politique de Confidentialité pour continuer.", + "Message and Data Rates Disclosure": "Les frais d’envoi de SMS et de consommation de données peuvent s’appliquer. Répondez <%= help_string %> au 827-222 pour obtenir de l’aide. Répondez <%= stop_string %> au 827-222 pour ne plus recevoir de SMS. Pour plus d’aide, visitez support.uber.com ou appelez le (866) 576-1039. Opérateurs supportés: AT&T, Sprint, Verizon, T-Mobile, Orange, SFR et Bouygues Telecom.", + "Zip/Postal Code": "Code Postal", + "Expiration Date": "Date D'expiration", + "Security Code": "Code de Sécurité", + "Type of Card": "Type", + "Personal": "Personnel", + "Business": "Entreprise", + "Promotion Code": "Code Promo", + "Legal Information": "Mentions Légales", + "I Agree": "J'accepte.", + "Your Trip": "Votre Course", + "Trip Info": "Informations de la Course", + "Request a fare review": "Demander un contrôle du tarif", + "Fare Review Submitted": "Votre demande de contrôle du tarif a été soumis. Nous reviendrons vers vous rapidement concernant cette demande. Nous nous excusons pour les dérangements éventuellement occasionnés !", + "Fair Price Consideration": "Nous nous engageons à proposer Uber à un tarif juste. Avant de demander un contrôle du tarif, merci de prendre en compte :", + "Your Fare Calculation": "Calcul du Prix", + "Charges": "Coûts", + "Discounts": "Réductions", + "Total Charge": "Coût total", + "Uber pricing information": "Information sur les prix d’Uber", + "Uber Pricing Information Message": "<%= learn_link %> est disponible sur notre site web.", + "GPS Point Capture Disclosure": "A cause d’un nombre limité de coordonnées GPS sauvegardées, les angles de votre trajet sur la carte peuvent apparaître coupés ou arrondis. Ces légères incohérences débouchent sur des distances mesurées plus courtes, ce qui implique toujours un prix du trajet moins élevé.", + "Fare Review Note": "Merci de nous expliquer pourquoi le tarif de cette course nécessite d’être contrôlé. Vos commentaires ci-dessous nous aideront à établir un prix plus juste si nécessaire :", + "Fare Review Error": "Il y a eu une erreur lors de l’envoi de la demande. Assurez-vous d’avoir bien ajouté une description à votre demande." + }; +}).call(this); +}, "views/clients/billing": function(exports, require, module) {(function() { + var clientsBillingTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + clientsBillingTemplate = require('templates/clients/billing'); + exports.ClientsBillingView = (function() { + __extends(ClientsBillingView, UberView); + function ClientsBillingView() { + ClientsBillingView.__super__.constructor.apply(this, arguments); + } + ClientsBillingView.prototype.id = 'billing_view'; + ClientsBillingView.prototype.className = 'view_container'; + ClientsBillingView.prototype.events = { + 'click a#add_card': 'addCard', + 'click .charge_arrear': 'chargeArrear' + }; + ClientsBillingView.prototype.render = function() { + this.RefreshUserInfo(__bind(function() { + var cards, newForm; + this.HideSpinner(); + $(this.el).html(clientsBillingTemplate()); + if (USER.payment_gateway.payment_profiles.length === 0) { + newForm = new app.views.clients.modules.creditcard; + $(this.el).find("#add_card_wrapper").html(newForm.render(0).el); + } else { + cards = new app.views.clients.modules.creditcard; + $("#cards").html(cards.render("all").el); + } + return this.delegateEvents(); + }, this)); + return this; + }; + ClientsBillingView.prototype.addCard = function(e) { + var newCard; + e.preventDefault(); + newCard = new app.views.clients.modules.creditcard; + $('#cards').append(newCard.render("new").el); + return $("a#add_card").hide(); + }; + ClientsBillingView.prototype.chargeArrear = function(e) { + var $el, arrearId, attrs, cardId, options, tryCharge; + e.preventDefault(); + $(".error_message").text(""); + $el = $(e.currentTarget); + arrearId = $el.attr('id'); + cardId = $el.parent().find('#card_to_charge').val(); + this.ShowSpinner('submit'); + tryCharge = new app.models.clientbills({ + id: arrearId + }); + attrs = { + payment_profile_id: cardId, + dataType: 'json' + }; + options = { + success: __bind(function(data, textStatus, jqXHR) { + $el.parent().find(".success_message").text(t("Billing Succeeded")); + $el.hide(); + return $el.parent().find('#card_to_charge').hide(); + }, this), + error: __bind(function(jqXHR, status, errorThrown) { + return $el.parent().find(".error_message").text(JSON.parse(status.responseText).error); + }, this), + complete: __bind(function() { + return this.HideSpinner(); + }, this) + }; + return tryCharge.save(attrs, options); + }; + return ClientsBillingView; + })(); +}).call(this); +}, "views/clients/confirm_email": function(exports, require, module) {(function() { + var clientsConfirmEmailTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + clientsConfirmEmailTemplate = require('templates/clients/confirm_email'); + exports.ClientsConfirmEmailView = (function() { + __extends(ClientsConfirmEmailView, UberView); + function ClientsConfirmEmailView() { + ClientsConfirmEmailView.__super__.constructor.apply(this, arguments); + } + ClientsConfirmEmailView.prototype.id = 'confirm_email_view'; + ClientsConfirmEmailView.prototype.className = 'view_container'; + ClientsConfirmEmailView.prototype.render = function(token) { + var attrs; + $(this.el).html(clientsConfirmEmailTemplate()); + attrs = { + data: { + email_token: token + }, + success: __bind(function(data, textStatus, jqXHR) { + var show_dashboard; + this.HideSpinner(); + show_dashboard = function() { + return app.routers.clients.navigate('!/dashboard', true); + }; + if (data.status === 'OK') { + $('.success_message').show(); + return _.delay(show_dashboard, 3000); + } else if (data.status === 'ALREADY_COMFIRMED') { + $('.already_confirmed_message').show(); + return _.delay(show_dashboard, 3000); + } else { + return $('.error_message').show(); + } + }, this), + error: __bind(function(e) { + this.HideSpinner(); + return $('.error_message').show(); + }, this), + complete: function(status) { + return $('#attempt_text').hide(); + }, + dataType: 'json', + type: 'PUT', + url: "" + API + "/users/self" + }; + $.ajax(attrs); + this.ShowSpinner('submit'); + return this; + }; + return ClientsConfirmEmailView; + })(); +}).call(this); +}, "views/clients/dashboard": function(exports, require, module) {(function() { + var clientsDashboardTemplate; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsDashboardTemplate = require('templates/clients/dashboard'); + exports.ClientsDashboardView = (function() { + var displayFirstTrip; + __extends(ClientsDashboardView, UberView); + function ClientsDashboardView() { + this.showAllTrips = __bind(this.showAllTrips, this); + this.render = __bind(this.render, this); + ClientsDashboardView.__super__.constructor.apply(this, arguments); + } + ClientsDashboardView.prototype.id = 'dashboard_view'; + ClientsDashboardView.prototype.className = 'view_container'; + ClientsDashboardView.prototype.events = { + 'click a.confirmation': 'confirmationClick', + 'click #resend_email': 'resendEmail', + 'click #resend_mobile': 'resendMobile', + 'click #show_all_trips': 'showAllTrips' + }; + ClientsDashboardView.prototype.render = function() { + var displayPage, downloadTrips; + this.HideSpinner(); + displayPage = __bind(function() { + $(this.el).html(clientsDashboardTemplate()); + this.confirmationsSetup(); + return this.RequireMaps(__bind(function() { + if (USER.trips.models[0]) { + if (!USER.trips.models[0].get("points")) { + return USER.trips.models[0].fetch({ + data: { + relationships: 'points' + }, + success: __bind(function() { + this.CacheData("USERtrips", USER.trips); + return displayFirstTrip(); + }, this) + }); + } else { + return displayFirstTrip(); + } + } + }, this)); + }, this); + downloadTrips = __bind(function() { + return this.DownloadUserTrips(displayPage, false, 10); + }, this); + this.RefreshUserInfo(downloadTrips); + return this; + }; + displayFirstTrip = __bind(function() { + var bounds, endPos, map, myOptions, path, polyline, startPos; + myOptions = { + zoom: 12, + mapTypeId: google.maps.MapTypeId.ROADMAP, + zoomControl: false, + rotateControl: false, + panControl: false, + mapTypeControl: false, + scrollwheel: false + }; + if (USER.trips.length === 10) { + $("#show_all_trips").show(); + } + if (USER.trips.length > 0) { + map = new google.maps.Map(document.getElementById("trip_details_map"), myOptions); + bounds = new google.maps.LatLngBounds(); + path = []; + _.each(USER.trips.models[0].get('points'), __bind(function(point) { + path.push(new google.maps.LatLng(point.lat, point.lng)); + return bounds.extend(_.last(path)); + }, this)); + map.fitBounds(bounds); + startPos = new google.maps.Marker({ + position: _.first(path), + map: map, + title: t('Trip started here'), + icon: 'https://uber-static.s3.amazonaws.com/marker_start.png' + }); + endPos = new google.maps.Marker({ + position: _.last(path), + map: map, + title: t('Trip ended here'), + icon: 'https://uber-static.s3.amazonaws.com/marker_end.png' + }); + polyline = new google.maps.Polyline({ + path: path, + strokeColor: '#003F87', + strokeOpacity: 1, + strokeWeight: 5 + }); + return polyline.setMap(map); + } + }, ClientsDashboardView); + ClientsDashboardView.prototype.confirmationsSetup = function() { + var blink, cardForm, element, _ref, _ref2, _ref3, _ref4, _ref5; + blink = function(element) { + var opacity; + opacity = 0.5; + if (element.css('opacity') === "0.5") { + opacity = 1.0; + } + return element.fadeTo(2000, opacity, function() { + return blink(element); + }); + }; + if (((_ref = window.USER) != null ? (_ref2 = _ref.payment_gateway) != null ? (_ref3 = _ref2.payment_profiles) != null ? _ref3.length : void 0 : void 0 : void 0) === 0) { + element = $('#confirmed_credit_card'); + cardForm = new app.views.clients.modules.creditcard; + $('#card.info').append(cardForm.render().el); + blink(element); + } + if (((_ref4 = window.USER) != null ? _ref4.confirm_email : void 0) === false) { + element = $('#confirmed_email'); + blink(element); + } + if ((((_ref5 = window.USER) != null ? _ref5.confirm_mobile : void 0) != null) === false) { + element = $('#confirmed_mobile'); + return blink(element); + } + }; + ClientsDashboardView.prototype.confirmationClick = function(e) { + e.preventDefault(); + $('.info').hide(); + $('#more_info').show(); + switch (e.currentTarget.id) { + case "card": + return $('#card.info').slideToggle(); + case "mobile": + return $('#mobile.info').slideToggle(); + case "email": + return $('#email.info').slideToggle(); + } + }; + ClientsDashboardView.prototype.resendEmail = function(e) { + var $el; + e.preventDefault(); + $el = $(e.currentTarget); + $el.removeAttr('href').prop({ + disabled: true + }); + $el.html(t("Sending Email")); + return $.ajax({ + type: 'GET', + url: API + '/users/request_confirm_email', + data: { + token: USER.token + }, + dataType: 'json', + success: __bind(function(data, textStatus, jqXHR) { + return $el.html(t("Resend Email Succeeded")); + }, this), + error: __bind(function(jqXHR, textStatus, errorThrown) { + return $el.html(t("Resend Email Failed")); + }, this) + }); + }; + ClientsDashboardView.prototype.resendMobile = function(e) { + var $el; + e.preventDefault(); + $el = $(e.currentTarget); + $el.removeAttr('href').prop({ + disabled: true + }); + $el.html("Sending message..."); + return $.ajax({ + type: 'GET', + url: API + '/users/request_confirm_mobile', + data: { + token: USER.token + }, + dataType: 'json', + success: __bind(function(data, textStatus, jqXHR) { + return $el.html(t("Resend Text Succeeded")); + }, this), + error: __bind(function(jqXHR, textStatus, errorThrown) { + return $el.html(t("Resend Text Failed")); + }, this) + }); + }; + ClientsDashboardView.prototype.showAllTrips = function(e) { + e.preventDefault(); + $(e.currentTarget).hide(); + return this.DownloadUserTrips(this.render, true, 1000); + }; + return ClientsDashboardView; + }).call(this); +}).call(this); +}, "views/clients/forgot_password": function(exports, require, module) {(function() { + var clientsForgotPasswordTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + clientsForgotPasswordTemplate = require('templates/clients/forgot_password'); + exports.ClientsForgotPasswordView = (function() { + __extends(ClientsForgotPasswordView, UberView); + function ClientsForgotPasswordView() { + ClientsForgotPasswordView.__super__.constructor.apply(this, arguments); + } + ClientsForgotPasswordView.prototype.id = 'forgotpassword_view'; + ClientsForgotPasswordView.prototype.className = 'view_container modal_view_container'; + ClientsForgotPasswordView.prototype.events = { + "submit #password_reset": "passwordReset", + "click #password_reset_submit": "passwordReset", + "submit #forgot_password": "forgotPassword", + "click #forgot_password_submit": "forgotPassword" + }; + ClientsForgotPasswordView.prototype.render = function(token) { + this.HideSpinner(); + $(this.el).html(clientsForgotPasswordTemplate({ + token: token + })); + this.delegateEvents(); + return this; + }; + ClientsForgotPasswordView.prototype.forgotPassword = function(e) { + var attrs; + e.preventDefault(); + $('.success_message').hide(); + $(".error_message").hide(); + attrs = { + data: { + login: $("#login").val() + }, + success: __bind(function(data, textStatus, jqXHR) { + this.HideSpinner(); + $('.success_message').show(); + return $("#forgot_password").hide(); + }, this), + error: __bind(function(e) { + this.HideSpinner(); + return $('.error_message').show(); + }, this), + dataType: 'json', + type: 'PUT', + url: "" + API + "/users/forgot_password" + }; + $.ajax(attrs); + return this.ShowSpinner('submit'); + }; + ClientsForgotPasswordView.prototype.passwordReset = function(e) { + var attrs; + e.preventDefault(); + attrs = { + data: { + email_token: $("#token").val(), + password: $("#password").val() + }, + success: __bind(function(data, textStatus, jqXHR) { + this.HideSpinner(); + $.cookie('token', data.token); + amplify.store('USERjson', data); + app.refreshMenu(); + return location.hash = '!/dashboard'; + }, this), + error: __bind(function(e) { + this.HideSpinner(); + return $('#error_reset').show(); + }, this), + dataType: 'json', + type: 'PUT', + url: "" + API + "/users/self" + }; + $.ajax(attrs); + return this.ShowSpinner('submit'); + }; + return ClientsForgotPasswordView; + })(); +}).call(this); +}, "views/clients/invite": function(exports, require, module) {(function() { + var clientsInviteTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsInviteTemplate = require('templates/clients/invite'); + exports.ClientsInviteView = (function() { + __extends(ClientsInviteView, UberView); + function ClientsInviteView() { + ClientsInviteView.__super__.constructor.apply(this, arguments); + } + ClientsInviteView.prototype.id = 'invite_view'; + ClientsInviteView.prototype.className = 'view_container'; + ClientsInviteView.prototype.render = function() { + this.ReadUserInfo(); + this.HideSpinner(); + $(this.el).html(clientsInviteTemplate()); + console.log(screen); + return this; + }; + return ClientsInviteView; + })(); +}).call(this); +}, "views/clients/login": function(exports, require, module) {(function() { + var clientsLoginTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsLoginTemplate = require('templates/clients/login'); + exports.ClientsLoginView = (function() { + __extends(ClientsLoginView, UberView); + function ClientsLoginView() { + ClientsLoginView.__super__.constructor.apply(this, arguments); + } + ClientsLoginView.prototype.id = 'login_view'; + ClientsLoginView.prototype.className = 'view_container modal_view_container'; + ClientsLoginView.prototype.events = { + 'submit form': 'authenticate', + 'click button': 'authenticate' + }; + ClientsLoginView.prototype.initialize = function() { + _.bindAll(this, 'render'); + return this.render(); + }; + ClientsLoginView.prototype.render = function() { + this.HideSpinner(); + $(this.el).html(clientsLoginTemplate()); + this.delegateEvents(); + return this.place(); + }; + ClientsLoginView.prototype.authenticate = function(e) { + e.preventDefault(); + return $.ajax({ + type: 'POST', + url: API + '/auth/web_login/client', + data: { + login: $("#login").val(), + password: $("#password").val() + }, + dataType: 'json', + success: function(data, textStatus, jqXHR) { + $.cookie('user', JSON.stringify(data)); + $.cookie('token', data.token); + amplify.store('USERjson', data); + $('header').html(app.views.shared.menu.render().el); + return app.routers.clients.navigate('!/dashboard', true); + }, + error: function(jqXHR, textStatus, errorThrown) { + $.cookie('user', null); + $.cookie('token', null); + if (jqXHR.status === 403) { + $.cookie('redirected_user', JSON.stringify(JSON.parse(jqXHR.responseText).error_obj), { + domain: '.uber.com' + }); + window.location = 'http://partners.uber.com/'; + } + return $('.error_message').html(JSON.parse(jqXHR.responseText).error).hide().fadeIn(); + } + }); + }; + return ClientsLoginView; + })(); +}).call(this); +}, "views/clients/modules/credit_card": function(exports, require, module) {(function() { + var creditCardTemplate; + var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + creditCardTemplate = require('templates/clients/modules/credit_card'); + exports.CreditCardView = (function() { + __extends(CreditCardView, UberView); + function CreditCardView() { + CreditCardView.__super__.constructor.apply(this, arguments); + } + CreditCardView.prototype.id = 'creditcard_view'; + CreditCardView.prototype.className = 'module_container'; + CreditCardView.prototype.events = { + 'submit #credit_card_form': 'processNewCard', + 'click #new_card': 'processNewCard', + 'change #card_number': 'showCardType', + 'click .edit_card_show': 'showEditCard', + 'click .edit_card': 'editCard', + 'click .delete_card': 'deleteCard', + 'click .make_default': 'makeDefault', + 'change .use_case': 'saveUseCase' + }; + CreditCardView.prototype.initialize = function() { + return app.collections.paymentprofiles.bind("refresh", __bind(function() { + return this.RefreshUserInfo(__bind(function() { + this.render("all"); + return this.HideSpinner(); + }, this)); + }, this)); + }; + CreditCardView.prototype.render = function(cards) { + if (cards == null) { + cards = "new"; + } + if (cards === "all") { + app.collections.paymentprofiles.reset(USER.payment_gateway.payment_profiles); + cards = app.collections.paymentprofiles; + } + $(this.el).html(creditCardTemplate({ + cards: cards + })); + return this; + }; + CreditCardView.prototype.processNewCard = function(e) { + var $el, attrs, model, options; + e.preventDefault(); + this.ClearGlobalStatus(); + $el = $("#credit_card_form"); + $el.find('.error_message').html(""); + attrs = { + card_number: $el.find('#card_number').val(), + card_code: $el.find('#card_code').val(), + card_expiration_month: $el.find('#card_expiration_month').val(), + card_expiration_year: $el.find('#card_expiration_year').val(), + use_case: $el.find('#use_case').val(), + "default": $el.find('#default_check').prop("checked") + }; + options = { + statusCode: { + 200: __bind(function(e) { + this.HideSpinner(); + $('#cc_form_wrapper').hide(); + app.collections.paymentprofiles.trigger("refresh"); + $(this.el).remove(); + $("a#add_card").show(); + return $('section').html(app.views.clients.billing.render().el); + }, this), + 406: __bind(function(e) { + var error, errors, _i, _len, _ref, _results; + this.HideSpinner(); + errors = JSON.parse(e.responseText); + _ref = _.keys(errors); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + error = _ref[_i]; + _results.push(error === "top_of_form" ? $("#top_of_form").html(errors[error]) : $("#credit_card_form").find("#" + error).parent().find(".error_message").html(errors[error])); + } + return _results; + }, this), + 420: __bind(function(e) { + this.HideSpinner(); + return $("#top_of_form").html(t("Unable to Verify Card")); + }, this) + } + }; + this.ShowSpinner("submit"); + model = new app.models.paymentprofile; + model.save(attrs, options); + return app.collections.paymentprofiles.add(model); + }; + CreditCardView.prototype.showCardType = function(e) { + var $el, reAmerica, reDiscover, reMaster, reVisa, validCard; + reVisa = /^4\d{3}-?\d{4}-?\d{4}-?\d{4}$/; + reMaster = /^5[1-5]\d{2}-?\d{4}-?\d{4}-?\d{4}$/; + reAmerica = /^6011-?\d{4}-?\d{4}-?\d{4}$/; + reDiscover = /^3[4,7]\d{13}$/; + $el = $("#card_logos"); + validCard = false; + if (e.currentTarget.value.match(reVisa)) { + validCard = true; + } else if (e.currentTarget.value.match(reMaster)) { + $el.css('background-position', "-60px"); + validCard = true; + } else if (e.currentTarget.value.match(reAmerica)) { + $el.css('background-position', "-120px"); + validCard = true; + } else if (e.currentTarget.value.match(reDiscover)) { + $el.css('background-position', "-180px"); + validCard = true; + } + if (validCard) { + $el.css('width', "60px"); + return $el.css('margin-left', "180px"); + } else { + $el.css('width', "250px"); + return $el.css('margin-left', "80px"); + } + }; + CreditCardView.prototype.showEditCard = function(e) { + var $el, id; + e.preventDefault(); + $el = $(e.currentTarget); + if ($el.html() === t("Edit")) { + id = $el.html(t("Cancel")).parents("tr").attr("id").substring(1); + return $("#e" + id).show(); + } else { + id = $el.html(t("Edit")).parents("tr").attr("id").substring(1); + return $("#e" + id).hide(); + } + }; + CreditCardView.prototype.editCard = function(e) { + var $el, attrs, id, options; + e.preventDefault(); + this.ClearGlobalStatus(); + $el = $(e.currentTarget).parents("td"); + id = $el.parents("tr").attr("id").substring(1); + $el.attr('disabled', 'disabled'); + this.ShowSpinner('submit'); + attrs = { + card_expiration_month: $el.find('#card_expiration_month').val(), + card_expiration_year: $el.find('#card_expiration_year').val(), + card_code: $el.find('#card_code').val() + }; + options = { + success: __bind(function(response) { + this.HideSpinner(); + this.ShowSuccess(t("Credit Card Update Succeeded")); + $("#e" + id).hide(); + $("#d" + id).find(".edit_card_show").html(t("Edit")); + return app.collections.paymentprofiles.trigger("refresh"); + }, this), + error: __bind(function(e) { + this.HideSpinner(); + this.ShowError(t("Credit Card Update Failed")); + return $el.removeAttr('disabled'); + }, this) + }; + app.collections.paymentprofiles.models[id].set(attrs); + return app.collections.paymentprofiles.models[id].save({}, options); + }; + CreditCardView.prototype.deleteCard = function(e) { + var $el, id, options; + e.preventDefault(); + $el = $(e.currentTarget).parents("td"); + id = $el.parents("tr").attr("id").substring(1); + this.ClearGlobalStatus(); + this.ShowSpinner('submit'); + options = { + success: __bind(function(response) { + this.ShowSuccess(t("Credit Card Delete Succeeded")); + $("form").hide(); + app.collections.paymentprofiles.trigger("refresh"); + return $('section').html(app.views.clients.billing.render().el); + }, this), + error: __bind(function(xhr, e) { + this.HideSpinner(); + return this.ShowError(t("Credit Card Delete Failed")); + }, this) + }; + return app.collections.paymentprofiles.models[id].destroy(options); + }; + CreditCardView.prototype.saveUseCase = function(e) { + var $el, attrs, id, options, use_case; + this.ClearGlobalStatus(); + $el = $(e.currentTarget); + use_case = $el.val(); + id = $el.parents("tr").attr("id").substring(1); + attrs = { + use_case: use_case + }; + options = { + success: __bind(function(response) { + return this.ShowSuccess(t("Credit Card Update Category Succeeded")); + }, this), + error: __bind(function(e) { + return this.ShowError(t("Credit Card Update Category Failed")); + }, this) + }; + app.collections.paymentprofiles.models[id].set(attrs); + return app.collections.paymentprofiles.models[id].save({}, options); + }; + CreditCardView.prototype.makeDefault = function(e) { + var $el, attrs, id, options; + e.preventDefault(); + this.ClearGlobalStatus(); + $el = $(e.currentTarget).parents("td"); + id = $el.parents("tr").attr("id").substring(1); + attrs = { + "default": true + }; + options = { + success: __bind(function(response) { + this.ShowSuccess(t("Credit Card Update Default Succeeded")); + return app.collections.paymentprofiles.trigger("refresh"); + }, this), + error: __bind(function(e) { + return this.ShowError(t("Credit Card Update Default Failed")); + }, this) + }; + app.collections.paymentprofiles.models[id].set(attrs); + return app.collections.paymentprofiles.models[id].save({}, options); + }; + return CreditCardView; + })(); +}).call(this); +}, "views/clients/promotions": function(exports, require, module) {(function() { + var clientsPromotionsTemplate; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsPromotionsTemplate = require('templates/clients/promotions'); + exports.ClientsPromotionsView = (function() { + __extends(ClientsPromotionsView, UberView); + function ClientsPromotionsView() { + this.render = __bind(this.render, this); + ClientsPromotionsView.__super__.constructor.apply(this, arguments); + } + ClientsPromotionsView.prototype.id = 'promotions_view'; + ClientsPromotionsView.prototype.className = 'view_container'; + ClientsPromotionsView.prototype.events = { + 'submit form': 'submitPromo', + 'click button': 'submitPromo' + }; + ClientsPromotionsView.prototype.initialize = function() { + if (this.model) { + return this.RefreshUserInfo(this.render); + } + }; + ClientsPromotionsView.prototype.render = function() { + var renderTemplate; + this.ReadUserInfo(); + renderTemplate = __bind(function() { + $(this.el).html(clientsPromotionsTemplate({ + promos: window.USER.unexpired_client_promotions || [] + })); + return this.HideSpinner(); + }, this); + this.DownloadUserPromotions(renderTemplate); + return this; + }; + ClientsPromotionsView.prototype.submitPromo = function(e) { + var attrs, model, options, refreshTable; + e.preventDefault(); + this.ClearGlobalStatus(); + refreshTable = __bind(function() { + $('section').html(this.render().el); + return this.HideSpinner(); + }, this); + attrs = { + code: $('#code').val() + }; + options = { + success: __bind(function(response) { + this.HideSpinner(); + if (response.get('first_name')) { + return this.ShowSuccess("Your promotion has been applied in the form of an account credit. Click here to check your balance."); + } else { + this.ShowSuccess("Your promotion has successfully been applied"); + return this.RefreshUserInfo(this.render, true); + } + }, this), + statusCode: { + 400: __bind(function(e) { + this.ShowError(JSON.parse(e.responseText).error); + return this.HideSpinner(); + }, this) + } + }; + this.ShowSpinner("submit"); + model = new app.models.promotions; + return model.save(attrs, options); + }; + return ClientsPromotionsView; + })(); +}).call(this); +}, "views/clients/request": function(exports, require, module) {(function() { + var clientsRequestTemplate; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { + for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + child.__super__ = parent.prototype; + return child; + }; + clientsRequestTemplate = require('templates/clients/request'); + exports.ClientsRequestView = (function() { + __extends(ClientsRequestView, UberView); + function ClientsRequestView() { + this.AjaxCall = __bind(this.AjaxCall, this); + this.AskDispatch = __bind(this.AskDispatch, this); + this.removeMarkers = __bind(this.removeMarkers, this); + this.displaySearchLoc = __bind(this.displaySearchLoc, this); + this.displayFavLoc = __bind(this.displayFavLoc, this); + this.showFavLoc = __bind(this.showFavLoc, this); + this.addToFavLoc = __bind(this.addToFavLoc, this); + this.removeCabs = __bind(this.removeCabs, this); + this.requestRide = __bind(this.requestRide, this); + this.rateTrip = __bind(this.rateTrip, this); + this.locationChange = __bind(this.locationChange, this); + this.panToLocation = __bind(this.panToLocation, this); + this.clickLocation = __bind(this.clickLocation, this); + this.searchLocation = __bind(this.searchLocation, this); + this.mouseoutLocation = __bind(this.mouseoutLocation, this); + this.mouseoverLocation = __bind(this.mouseoverLocation, this); + this.fetchTripDetails = __bind(this.fetchTripDetails, this); + this.submitRating = __bind(this.submitRating, this); + this.setStatus = __bind(this.setStatus, this); + this.initialize = __bind(this.initialize, this); + ClientsRequestView.__super__.constructor.apply(this, arguments); + } + ClientsRequestView.prototype.id = 'request_view'; + ClientsRequestView.prototype.className = 'view_container'; + ClientsRequestView.prototype.pollInterval = 2 * 1000; + ClientsRequestView.prototype.events = { + "submit #search_form": "searchAddress", + "click .locations_link": "locationLinkHandle", + "mouseover .location_row": "mouseoverLocation", + "mouseout .location_row": "mouseoutLocation", + "click .location_row": "clickLocation", + "click #search_location": "searchLocation", + "click #pickupHandle": "pickupHandle", + "click .stars": "rateTrip", + "submit #rating_form": "submitRating", + "click #addToFavButton": "showFavLoc", + "click #favLocNickname": "selectInputText", + "submit #favLoc_form": "addToFavLoc" + }; + ClientsRequestView.prototype.status = ""; + ClientsRequestView.prototype.pickupMarker = "https://uber-static.s3.amazonaws.com/pickup_marker.png"; + ClientsRequestView.prototype.cabMarker = "https://uber-static.s3.amazonaws.com/cab_marker.png"; + ClientsRequestView.prototype.initialize = function() { + var displayCabs; + displayCabs = __bind(function() { + return this.AskDispatch("NearestCab"); + }, this); + this.showCabs = _.throttle(displayCabs, this.pollInterval); + return this.numSearchToDisplay = 1; + }; + ClientsRequestView.prototype.setStatus = function(status) { + var autocomplete; + if (this.status === status) { + return; + } + try { + google.maps.event.trigger(this.map, 'resize'); + } catch (_e) {} + switch (status) { + case "init": + this.AskDispatch("StatusClient"); + this.status = "init"; + return this.ShowSpinner("load"); + case "ready": + this.HideSpinner(); + $(".panel").hide(); + $("#top_bar").fadeIn(); + $("#location_panel").fadeIn(); + $("#location_panel_control").fadeIn(); + $("#pickupHandle").attr("class", "button_green").fadeIn().find("span").html(t("Request Pickup")); + this.pickup_icon.setDraggable(true); + this.map.panTo(this.pickup_icon.getPosition()); + this.showCabs(); + try { + this.pickup_icon.setMap(this.map); + this.displayFavLoc(); + autocomplete = new google.maps.places.Autocomplete(document.getElementById('address'), { + types: ['geocode'] + }); + autocomplete.bindTo('bounds', this.map); + } catch (_e) {} + return this.status = "ready"; + case "searching": + this.HideSpinner(); + this.removeMarkers(); + $(".panel").hide(); + $("#top_bar").fadeOut(); + $("#status_message").html(t("Requesting Closest Driver")); + $("#pickupHandle").attr("class", "button_red").fadeIn().find("span").html(t("Cancel Pickup")); + this.pickup_icon.setDraggable(false); + this.pickup_icon.setMap(this.map); + return this.status = "searching"; + case "waiting": + this.HideSpinner(); + this.removeMarkers(); + $(".panel").hide(); + $("#top_bar").fadeOut(); + $("#pickupHandle").attr("class", "button_red").fadeIn().find("span").html(t("Cancel Pickup")); + $("#waiting_riding").fadeIn(); + this.pickup_icon.setDraggable(false); + this.pickup_icon.setMap(this.map); + return this.status = "waiting"; + case "arriving": + this.HideSpinner(); + this.removeMarkers(); + $(".panel").hide(); + $("#top_bar").fadeOut(); + $("#pickupHandle").attr("class", "button_red").fadeIn().find("span").html(t("Cancel Pickup")); + $("#waiting_riding").fadeIn(); + this.pickup_icon.setDraggable(false); + this.pickup_icon.setMap(this.map); + return this.status = "arriving"; + case "riding": + this.HideSpinner(); + this.removeMarkers(); + $(".panel").hide(); + $("#top_bar").fadeOut(); + $("#pickupHandle").fadeIn().attr("class", "button_red").find("span").html(t("Cancel Pickup")); + $("#waiting_riding").fadeIn(); + this.pickup_icon.setDraggable(false); + this.status = "riding"; + return $("#status_message").html(t("En Route")); + case "rate": + this.HideSpinner(); + $(".panel").hide(); + $("#pickupHandle").fadeOut(); + $("#trip_completed_panel").fadeIn(); + $('#status_message').html(t("Rate Last Trip")); + return this.status = "rate"; + } + }; + ClientsRequestView.prototype.render = function() { + this.ReadUserInfo(); + this.HideSpinner(); + this.ShowSpinner("load"); + $(this.el).html(clientsRequestTemplate()); + this.cabs = []; + this.RequireMaps(__bind(function() { + var center, myOptions, streetViewPano; + center = new google.maps.LatLng(37.7749295, -122.4194155); + this.markers = []; + this.pickup_icon = new google.maps.Marker({ + position: center, + draggable: true, + clickable: true, + icon: this.pickupMarker + }); + this.geocoder = new google.maps.Geocoder(); + myOptions = { + zoom: 12, + center: center, + mapTypeId: google.maps.MapTypeId.ROADMAP, + rotateControl: false, + rotateControl: false, + panControl: false + }; + this.map = new google.maps.Map($(this.el).find("#map_wrapper_right")[0], myOptions); + if (this.status === "ready") { + this.pickup_icon.setMap(this.map); + } + if (geo_position_js.init()) { + geo_position_js.getCurrentPosition(__bind(function(data) { + var location; + location = new google.maps.LatLng(data.coords.latitude, data.coords.longitude); + this.pickup_icon.setPosition(location); + this.map.panTo(location); + return this.map.setZoom(16); + }, this)); + } + this.setStatus("init"); + streetViewPano = this.map.getStreetView(); + google.maps.event.addListener(streetViewPano, 'visible_changed', __bind(function() { + if (streetViewPano.getVisible()) { + this.pickupMarker = "https://uber-static.s3.amazonaws.com/pickup_marker_large.png"; + this.cabMarker = "https://uber-static.s3.amazonaws.com/cab_marker_large.png"; + } else { + this.pickupMarker = "https://uber-static.s3.amazonaws.com/pickup_marker.png"; + this.cabMarker = "https://uber-static.s3.amazonaws.com/cab_marker.png"; + } + this.pickup_icon.setIcon(this.pickupMarker); + return _.each(this.cabs, __bind(function(cab) { + return cab.setIcon(this.cabMarker); + }, this)); + }, this)); + if (this.status === "ready") { + return this.displayFavLoc(); + } + }, this)); + return this; + }; + ClientsRequestView.prototype.submitRating = function(e) { + var $el, message, rating; + e.preventDefault(); + $el = $(e.currentTarget); + rating = 0; + _(5).times(function(num) { + if ($el.find(".stars#" + (num + 1)).attr("src") === "/web/img/star_active.png") { + return rating = num + 1; + } + }); + if (rating === 0) { + $("#status_message").html("").html(t("Rate Before Submitting")); + } else { + this.ShowSpinner("submit"); + this.AskDispatch("RatingDriver", { + rating: rating + }); + } + message = $el.find("#comments").val().toString(); + if (message.length > 5) { + return this.AskDispatch("Feedback", { + message: message + }); + } + }; + ClientsRequestView.prototype.fetchTripDetails = function(id) { + var trip; + trip = new app.models.trip({ + id: id + }); + return trip.fetch({ + data: { + relationships: 'points,driver,city' + }, + dataType: 'json', + success: __bind(function() { + var bounds, endPos, path, polyline, startPos; + bounds = new google.maps.LatLngBounds(); + path = []; + _.each(trip.get('points'), __bind(function(point) { + path.push(new google.maps.LatLng(point.lat, point.lng)); + return bounds.extend(_.last(path)); + }, this)); + startPos = new google.maps.Marker({ + position: _.first(path), + map: this.map, + title: t("Trip started here"), + icon: 'https://uber-static.s3.amazonaws.com/carstart.png' + }); + endPos = new google.maps.Marker({ + position: _.last(path), + map: this.map, + title: t("Trip ended here"), + icon: 'https://uber-static.s3.amazonaws.com/carstop.png' + }); + polyline = new google.maps.Polyline({ + path: path, + strokeColor: '#003F87', + strokeOpacity: 1, + strokeWeight: 5 + }); + polyline.setMap(this.map); + this.map.fitBounds(bounds); + $("#tripTime").html(app.helpers.parseDateTime(trip.get('pickup_local_time'), trip.get('city.timezone'))); + $("#tripDist").html(app.helpers.RoundNumber(trip.get('distance'), 2)); + $("#tripDur").html(app.helpers.FormatSeconds(trip.get('duration'))); + return $("#tripFare").html(app.helpers.FormatCurrency(trip.get('fare'))); + }, this) + }); + }; + ClientsRequestView.prototype.searchAddress = function(e) { + var $locationsDiv, address, alphabet, bounds, showResults; + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + try { + e.preventDefault(); + } catch (_e) {} + $('.error_message').html(""); + $locationsDiv = $("
"); + address = $('#address').val(); + bounds = new google.maps.LatLngBounds(); + if (address.length < 5) { + $('#status_message').html(t("Address too short")).fadeIn(); + return false; + } + showResults = __bind(function(address, index) { + var first_cell, row, second_cell; + if (index < this.numSearchToDisplay) { + first_cell = "
" + address.formatted_address + "
" + (t('or did you mean')) + "
" + address.formatted_address + "