From 7df9450f202f2a0f610edeec79829d7a5f6764d2 Mon Sep 17 00:00:00 2001 From: Ian Golden Date: Thu, 3 Dec 2015 15:03:41 -0500 Subject: [PATCH] Added ws node module --- node_modules/bindings/README.md | 97 + node_modules/bindings/bindings.js | 166 ++ node_modules/bindings/package.json | 84 + node_modules/bufferutil/.npmignore | 3 + node_modules/bufferutil/.travis.yml | 16 + node_modules/bufferutil/README.md | 62 + node_modules/bufferutil/binding.gyp | 11 + node_modules/bufferutil/build/Makefile | 342 +++ .../Release/.deps/Release/bufferutil.node.d | 1 + .../obj.target/bufferutil/src/bufferutil.o.d | 48 + .../bufferutil/build/Release/bufferutil.node | Bin 0 -> 19828 bytes .../obj.target/bufferutil/src/bufferutil.o | Bin 0 -> 197060 bytes .../bufferutil/build/binding.Makefile | 6 + .../bufferutil/build/bufferutil.target.mk | 165 ++ node_modules/bufferutil/build/config.gypi | 141 ++ node_modules/bufferutil/build/gyp-mac-tool | 612 +++++ node_modules/bufferutil/fallback.js | 57 + node_modules/bufferutil/index.js | 7 + node_modules/bufferutil/package.json | 85 + node_modules/bufferutil/src/bufferutil.cc | 120 + node_modules/nan/.dntrc | 30 + node_modules/nan/CHANGELOG.md | 384 +++ node_modules/nan/LICENSE.md | 13 + node_modules/nan/README.md | 371 +++ node_modules/nan/appveyor.yml | 37 + node_modules/nan/doc/.build.sh | 38 + node_modules/nan/doc/asyncworker.md | 97 + node_modules/nan/doc/buffers.md | 54 + node_modules/nan/doc/callback.md | 52 + node_modules/nan/doc/converters.md | 41 + node_modules/nan/doc/errors.md | 226 ++ node_modules/nan/doc/maybe_types.md | 500 ++++ node_modules/nan/doc/methods.md | 655 +++++ node_modules/nan/doc/new.md | 147 ++ node_modules/nan/doc/node_misc.md | 114 + node_modules/nan/doc/persistent.md | 295 +++ node_modules/nan/doc/scopes.md | 73 + node_modules/nan/doc/script.md | 38 + node_modules/nan/doc/string_bytes.md | 62 + node_modules/nan/doc/v8_internals.md | 199 ++ node_modules/nan/doc/v8_misc.md | 85 + node_modules/nan/include_dirs.js | 1 + node_modules/nan/nan.h | 2237 +++++++++++++++++ node_modules/nan/nan_callbacks.h | 88 + node_modules/nan/nan_callbacks_12_inl.h | 512 ++++ node_modules/nan/nan_callbacks_pre_12_inl.h | 506 ++++ node_modules/nan/nan_converters.h | 64 + node_modules/nan/nan_converters_43_inl.h | 42 + node_modules/nan/nan_converters_pre_43_inl.h | 42 + node_modules/nan/nan_implementation_12_inl.h | 404 +++ .../nan/nan_implementation_pre_12_inl.h | 264 ++ node_modules/nan/nan_maybe_43_inl.h | 224 ++ node_modules/nan/nan_maybe_pre_43_inl.h | 295 +++ node_modules/nan/nan_new.h | 340 +++ node_modules/nan/nan_object_wrap.h | 155 ++ node_modules/nan/nan_persistent_12_inl.h | 129 + node_modules/nan/nan_persistent_pre_12_inl.h | 242 ++ node_modules/nan/nan_string_bytes.h | 305 +++ node_modules/nan/nan_typedarray_contents.h | 87 + node_modules/nan/nan_weak.h | 422 ++++ node_modules/nan/package.json | 118 + node_modules/nan/tools/1to2.js | 412 +++ node_modules/nan/tools/README.md | 14 + node_modules/nan/tools/package.json | 19 + node_modules/options/.npmignore | 7 + node_modules/options/Makefile | 12 + node_modules/options/README.md | 69 + node_modules/options/lib/options.js | 86 + node_modules/options/package.json | 76 + node_modules/ultron/.npmignore | 3 + node_modules/ultron/.travis.yml | 21 + node_modules/ultron/LICENSE | 22 + node_modules/ultron/README.md | 97 + node_modules/ultron/index.js | 129 + node_modules/ultron/package.json | 100 + node_modules/ultron/test.js | 327 +++ node_modules/utf-8-validate/.npmignore | 3 + node_modules/utf-8-validate/.travis.yml | 16 + node_modules/utf-8-validate/README.md | 44 + node_modules/utf-8-validate/binding.gyp | 11 + node_modules/utf-8-validate/build/Makefile | 342 +++ .../obj.target/validation/src/validation.o.d | 48 + .../Release/.deps/Release/validation.node.d | 1 + .../obj.target/validation/src/validation.o | Bin 0 -> 184892 bytes .../build/Release/validation.node | Bin 0 -> 19748 bytes .../utf-8-validate/build/binding.Makefile | 6 + node_modules/utf-8-validate/build/config.gypi | 141 ++ .../utf-8-validate/build/gyp-mac-tool | 612 +++++ .../utf-8-validate/build/validation.target.mk | 165 ++ node_modules/utf-8-validate/fallback.js | 13 + node_modules/utf-8-validate/index.js | 7 + node_modules/utf-8-validate/package.json | 89 + node_modules/utf-8-validate/src/validation.cc | 148 ++ node_modules/ws/.npmignore | 11 + node_modules/ws/.travis.yml | 29 + node_modules/ws/Makefile | 40 + node_modules/ws/README.md | 225 ++ node_modules/ws/index.js | 49 + node_modules/ws/lib/BufferPool.js | 63 + node_modules/ws/lib/BufferUtil.fallback.js | 47 + node_modules/ws/lib/BufferUtil.js | 13 + node_modules/ws/lib/ErrorCodes.js | 24 + node_modules/ws/lib/Extensions.js | 70 + node_modules/ws/lib/PerMessageDeflate.js | 313 +++ node_modules/ws/lib/Receiver.hixie.js | 184 ++ node_modules/ws/lib/Receiver.js | 702 ++++++ node_modules/ws/lib/Sender.hixie.js | 124 + node_modules/ws/lib/Sender.js | 316 +++ node_modules/ws/lib/Validation.fallback.js | 12 + node_modules/ws/lib/Validation.js | 13 + node_modules/ws/lib/WebSocket.js | 964 +++++++ node_modules/ws/lib/WebSocketServer.js | 513 ++++ node_modules/ws/lib/browser.js | 43 + node_modules/ws/package.json | 111 + 114 files changed, 18917 insertions(+) create mode 100644 node_modules/bindings/README.md create mode 100644 node_modules/bindings/bindings.js create mode 100644 node_modules/bindings/package.json create mode 100644 node_modules/bufferutil/.npmignore create mode 100644 node_modules/bufferutil/.travis.yml create mode 100644 node_modules/bufferutil/README.md create mode 100644 node_modules/bufferutil/binding.gyp create mode 100644 node_modules/bufferutil/build/Makefile create mode 100644 node_modules/bufferutil/build/Release/.deps/Release/bufferutil.node.d create mode 100644 node_modules/bufferutil/build/Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d create mode 100755 node_modules/bufferutil/build/Release/bufferutil.node create mode 100644 node_modules/bufferutil/build/Release/obj.target/bufferutil/src/bufferutil.o create mode 100644 node_modules/bufferutil/build/binding.Makefile create mode 100644 node_modules/bufferutil/build/bufferutil.target.mk create mode 100644 node_modules/bufferutil/build/config.gypi create mode 100755 node_modules/bufferutil/build/gyp-mac-tool create mode 100644 node_modules/bufferutil/fallback.js create mode 100644 node_modules/bufferutil/index.js create mode 100644 node_modules/bufferutil/package.json create mode 100644 node_modules/bufferutil/src/bufferutil.cc create mode 100644 node_modules/nan/.dntrc create mode 100644 node_modules/nan/CHANGELOG.md create mode 100644 node_modules/nan/LICENSE.md create mode 100644 node_modules/nan/README.md create mode 100644 node_modules/nan/appveyor.yml create mode 100755 node_modules/nan/doc/.build.sh create mode 100644 node_modules/nan/doc/asyncworker.md create mode 100644 node_modules/nan/doc/buffers.md create mode 100644 node_modules/nan/doc/callback.md create mode 100644 node_modules/nan/doc/converters.md create mode 100644 node_modules/nan/doc/errors.md create mode 100644 node_modules/nan/doc/maybe_types.md create mode 100644 node_modules/nan/doc/methods.md create mode 100644 node_modules/nan/doc/new.md create mode 100644 node_modules/nan/doc/node_misc.md create mode 100644 node_modules/nan/doc/persistent.md create mode 100644 node_modules/nan/doc/scopes.md create mode 100644 node_modules/nan/doc/script.md create mode 100644 node_modules/nan/doc/string_bytes.md create mode 100644 node_modules/nan/doc/v8_internals.md create mode 100644 node_modules/nan/doc/v8_misc.md create mode 100644 node_modules/nan/include_dirs.js create mode 100644 node_modules/nan/nan.h create mode 100644 node_modules/nan/nan_callbacks.h create mode 100644 node_modules/nan/nan_callbacks_12_inl.h create mode 100644 node_modules/nan/nan_callbacks_pre_12_inl.h create mode 100644 node_modules/nan/nan_converters.h create mode 100644 node_modules/nan/nan_converters_43_inl.h create mode 100644 node_modules/nan/nan_converters_pre_43_inl.h create mode 100644 node_modules/nan/nan_implementation_12_inl.h create mode 100644 node_modules/nan/nan_implementation_pre_12_inl.h create mode 100644 node_modules/nan/nan_maybe_43_inl.h create mode 100644 node_modules/nan/nan_maybe_pre_43_inl.h create mode 100644 node_modules/nan/nan_new.h create mode 100644 node_modules/nan/nan_object_wrap.h create mode 100644 node_modules/nan/nan_persistent_12_inl.h create mode 100644 node_modules/nan/nan_persistent_pre_12_inl.h create mode 100644 node_modules/nan/nan_string_bytes.h create mode 100644 node_modules/nan/nan_typedarray_contents.h create mode 100644 node_modules/nan/nan_weak.h create mode 100644 node_modules/nan/package.json create mode 100755 node_modules/nan/tools/1to2.js create mode 100644 node_modules/nan/tools/README.md create mode 100644 node_modules/nan/tools/package.json create mode 100644 node_modules/options/.npmignore create mode 100644 node_modules/options/Makefile create mode 100644 node_modules/options/README.md create mode 100644 node_modules/options/lib/options.js create mode 100644 node_modules/options/package.json create mode 100644 node_modules/ultron/.npmignore create mode 100644 node_modules/ultron/.travis.yml create mode 100644 node_modules/ultron/LICENSE create mode 100644 node_modules/ultron/README.md create mode 100644 node_modules/ultron/index.js create mode 100644 node_modules/ultron/package.json create mode 100644 node_modules/ultron/test.js create mode 100644 node_modules/utf-8-validate/.npmignore create mode 100644 node_modules/utf-8-validate/.travis.yml create mode 100644 node_modules/utf-8-validate/README.md create mode 100644 node_modules/utf-8-validate/binding.gyp create mode 100644 node_modules/utf-8-validate/build/Makefile create mode 100644 node_modules/utf-8-validate/build/Release/.deps/Release/obj.target/validation/src/validation.o.d create mode 100644 node_modules/utf-8-validate/build/Release/.deps/Release/validation.node.d create mode 100644 node_modules/utf-8-validate/build/Release/obj.target/validation/src/validation.o create mode 100755 node_modules/utf-8-validate/build/Release/validation.node create mode 100644 node_modules/utf-8-validate/build/binding.Makefile create mode 100644 node_modules/utf-8-validate/build/config.gypi create mode 100755 node_modules/utf-8-validate/build/gyp-mac-tool create mode 100644 node_modules/utf-8-validate/build/validation.target.mk create mode 100644 node_modules/utf-8-validate/fallback.js create mode 100644 node_modules/utf-8-validate/index.js create mode 100644 node_modules/utf-8-validate/package.json create mode 100644 node_modules/utf-8-validate/src/validation.cc create mode 100644 node_modules/ws/.npmignore create mode 100644 node_modules/ws/.travis.yml create mode 100644 node_modules/ws/Makefile create mode 100644 node_modules/ws/README.md create mode 100644 node_modules/ws/index.js create mode 100644 node_modules/ws/lib/BufferPool.js create mode 100644 node_modules/ws/lib/BufferUtil.fallback.js create mode 100644 node_modules/ws/lib/BufferUtil.js create mode 100644 node_modules/ws/lib/ErrorCodes.js create mode 100644 node_modules/ws/lib/Extensions.js create mode 100644 node_modules/ws/lib/PerMessageDeflate.js create mode 100644 node_modules/ws/lib/Receiver.hixie.js create mode 100644 node_modules/ws/lib/Receiver.js create mode 100644 node_modules/ws/lib/Sender.hixie.js create mode 100644 node_modules/ws/lib/Sender.js create mode 100644 node_modules/ws/lib/Validation.fallback.js create mode 100644 node_modules/ws/lib/Validation.js create mode 100644 node_modules/ws/lib/WebSocket.js create mode 100644 node_modules/ws/lib/WebSocketServer.js create mode 100644 node_modules/ws/lib/browser.js create mode 100644 node_modules/ws/package.json diff --git a/node_modules/bindings/README.md b/node_modules/bindings/README.md new file mode 100644 index 0000000..585cf51 --- /dev/null +++ b/node_modules/bindings/README.md @@ -0,0 +1,97 @@ +node-bindings +============= +### Helper module for loading your native module's .node file + +This is a helper module for authors of Node.js native addon modules. +It is basically the "swiss army knife" of `require()`ing your native module's +`.node` file. + +Throughout the course of Node's native addon history, addons have ended up being +compiled in a variety of different places, depending on which build tool and which +version of node was used. To make matters worse, now the _gyp_ build tool can +produce either a _Release_ or _Debug_ build, each being built into different +locations. + +This module checks _all_ the possible locations that a native addon would be built +at, and returns the first one that loads successfully. + + +Installation +------------ + +Install with `npm`: + +``` bash +$ npm install bindings +``` + +Or add it to the `"dependencies"` section of your _package.json_ file. + + +Example +------- + +`require()`ing the proper bindings file for the current node version, platform +and architecture is as simple as: + +``` js +var bindings = require('bindings')('binding.node') + +// Use your bindings defined in your C files +bindings.your_c_function() +``` + + +Nice Error Output +----------------- + +When the `.node` file could not be loaded, `node-bindings` throws an Error with +a nice error message telling you exactly what was tried. You can also check the +`err.tries` Array property. + +``` +Error: Could not load the bindings file. Tried: + → /Users/nrajlich/ref/build/binding.node + → /Users/nrajlich/ref/build/Debug/binding.node + → /Users/nrajlich/ref/build/Release/binding.node + → /Users/nrajlich/ref/out/Debug/binding.node + → /Users/nrajlich/ref/Debug/binding.node + → /Users/nrajlich/ref/out/Release/binding.node + → /Users/nrajlich/ref/Release/binding.node + → /Users/nrajlich/ref/build/default/binding.node + → /Users/nrajlich/ref/compiled/0.8.2/darwin/x64/binding.node + at bindings (/Users/nrajlich/ref/node_modules/bindings/bindings.js:84:13) + at Object. (/Users/nrajlich/ref/lib/ref.js:5:47) + at Module._compile (module.js:449:26) + at Object.Module._extensions..js (module.js:467:10) + at Module.load (module.js:356:32) + at Function.Module._load (module.js:312:12) + ... +``` + + +License +------- + +(The MIT License) + +Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/bindings/bindings.js b/node_modules/bindings/bindings.js new file mode 100644 index 0000000..93dcf85 --- /dev/null +++ b/node_modules/bindings/bindings.js @@ -0,0 +1,166 @@ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , path = require('path') + , join = path.join + , dirname = path.dirname + , exists = fs.existsSync || path.existsSync + , defaults = { + arrow: process.env.NODE_BINDINGS_ARROW || ' → ' + , compiled: process.env.NODE_BINDINGS_COMPILED_DIR || 'compiled' + , platform: process.platform + , arch: process.arch + , version: process.versions.node + , bindings: 'bindings.node' + , try: [ + // node-gyp's linked version in the "build" dir + [ 'module_root', 'build', 'bindings' ] + // node-waf and gyp_addon (a.k.a node-gyp) + , [ 'module_root', 'build', 'Debug', 'bindings' ] + , [ 'module_root', 'build', 'Release', 'bindings' ] + // Debug files, for development (legacy behavior, remove for node v0.9) + , [ 'module_root', 'out', 'Debug', 'bindings' ] + , [ 'module_root', 'Debug', 'bindings' ] + // Release files, but manually compiled (legacy behavior, remove for node v0.9) + , [ 'module_root', 'out', 'Release', 'bindings' ] + , [ 'module_root', 'Release', 'bindings' ] + // Legacy from node-waf, node <= 0.4.x + , [ 'module_root', 'build', 'default', 'bindings' ] + // Production "Release" buildtype binary (meh...) + , [ 'module_root', 'compiled', 'version', 'platform', 'arch', 'bindings' ] + ] + } + +/** + * The main `bindings()` function loads the compiled bindings for a given module. + * It uses V8's Error API to determine the parent filename that this function is + * being invoked from, which is then used to find the root directory. + */ + +function bindings (opts) { + + // Argument surgery + if (typeof opts == 'string') { + opts = { bindings: opts } + } else if (!opts) { + opts = {} + } + opts.__proto__ = defaults + + // Get the module root + if (!opts.module_root) { + opts.module_root = exports.getRoot(exports.getFileName()) + } + + // Ensure the given bindings name ends with .node + if (path.extname(opts.bindings) != '.node') { + opts.bindings += '.node' + } + + var tries = [] + , i = 0 + , l = opts.try.length + , n + , b + , err + + for (; i=1.2.0 <1.3.0", + "_id": "bindings@1.2.1", + "_inCache": true, + "_installable": true, + "_location": "/bindings", + "_npmUser": { + "email": "nathan@tootallnate.net", + "name": "tootallnate" + }, + "_npmVersion": "1.4.14", + "_phantomChildren": {}, + "_requested": { + "name": "bindings", + "raw": "bindings@1.2.x", + "rawSpec": "1.2.x", + "scope": null, + "spec": ">=1.2.0 <1.3.0", + "type": "range" + }, + "_requiredBy": [ + "/bufferutil", + "/utf-8-validate" + ], + "_resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", + "_shasum": "14ad6113812d2d37d72e67b4cacb4bb726505f11", + "_shrinkwrap": null, + "_spec": "bindings@1.2.x", + "_where": "/Applications/MAMP/htdocs/stream2/WebRTC-Example/node_modules/bufferutil", + "author": { + "email": "nathan@tootallnate.net", + "name": "Nathan Rajlich", + "url": "http://tootallnate.net" + }, + "bugs": { + "url": "https://github.com/TooTallNate/node-bindings/issues" + }, + "dependencies": {}, + "description": "Helper module for loading your native module's .node file", + "devDependencies": {}, + "directories": {}, + "dist": { + "shasum": "14ad6113812d2d37d72e67b4cacb4bb726505f11", + "tarball": "http://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz" + }, + "gitHead": "e404152ee27f8478ccbc7122ee051246e8e5ec02", + "homepage": "https://github.com/TooTallNate/node-bindings", + "keywords": [ + "addon", + "bindings", + "c", + "c++", + "gyp", + "native", + "waf" + ], + "license": "MIT", + "main": "./bindings.js", + "maintainers": [ + { + "name": "TooTallNate", + "email": "nathan@tootallnate.net" + }, + { + "name": "tootallnate", + "email": "nathan@tootallnate.net" + } + ], + "name": "bindings", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git://github.com/TooTallNate/node-bindings.git" + }, + "scripts": {}, + "version": "1.2.1" +} diff --git a/node_modules/bufferutil/.npmignore b/node_modules/bufferutil/.npmignore new file mode 100644 index 0000000..0c90f67 --- /dev/null +++ b/node_modules/bufferutil/.npmignore @@ -0,0 +1,3 @@ +npm-debug.log +node_modules +build diff --git a/node_modules/bufferutil/.travis.yml b/node_modules/bufferutil/.travis.yml new file mode 100644 index 0000000..cd09de2 --- /dev/null +++ b/node_modules/bufferutil/.travis.yml @@ -0,0 +1,16 @@ +language: node_js +node_js: + - "iojs-v3" + - "iojs-v2" + - "iojs-v1" + - "0.12" + - "0.10" +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-4.9 + - g++-4.9 +before_install: + - export CC="gcc-4.9" CXX="g++-4.9" diff --git a/node_modules/bufferutil/README.md b/node_modules/bufferutil/README.md new file mode 100644 index 0000000..777e996 --- /dev/null +++ b/node_modules/bufferutil/README.md @@ -0,0 +1,62 @@ +# bufferutil + +[![Build Status](https://travis-ci.org/websockets/bufferutil.svg?branch=master)](https://travis-ci.org/websockets/bufferutil) + +Buffer utils is one of the modules that makes `ws` fast. It's optimized for +certain buffer based operations such as merging buffers, generating WebSocket +masks and unmasking. + +As the module consists of binary components, it should be used an +`optionalDependency` so when installation fails, it doesn't halt the +installation of your module. There are fallback files available in this +repository. See `fallback.js` for the suggest fallback implementation if +installation fails. + +## Installation + +``` +npm install bufferutil +``` + +## API + +In all examples we assume that you've already required the BufferUtil as +followed: + +```js +'use strict'; + +var bu = require('bufferutil').BufferUtil; +``` + +The module exposes 3 different functions: + +#### merge + +Merge multiple buffers in the first supplied buffer argument: + +```js +bu.merge(buffer, [buffer1, buffer2]); +``` + +This merges buffer1 and buffer2 which are in an array into buffer. + +#### mask + +Apply a WebSocket mask on the given data. + +```js +bu.mask(buffer, mask); +``` + +#### unmask + +Remove a WebSocket mask on the given data.;w + +```js +bu.unmask(buffer, mask); +``` + +## License + +MIT diff --git a/node_modules/bufferutil/binding.gyp b/node_modules/bufferutil/binding.gyp new file mode 100644 index 0000000..636f324 --- /dev/null +++ b/node_modules/bufferutil/binding.gyp @@ -0,0 +1,11 @@ +{ + 'targets': [ + { + 'target_name': 'bufferutil', + 'include_dirs': ["> $(depfile) +# Add extra rules as in (2). +# We remove slashes and replace spaces with new lines; +# remove blank lines; +# delete the first line and append a colon to the remaining lines. +sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ + grep -v '^$$' |\ + sed -e 1d -e 's|$$|:|' \ + >> $(depfile) +rm $(depfile).raw +endef + +# Command definitions: +# - cmd_foo is the actual command to run; +# - quiet_cmd_foo is the brief-output summary of the command. + +quiet_cmd_cc = CC($(TOOLSET)) $@ +cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_cxx = CXX($(TOOLSET)) $@ +cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_objc = CXX($(TOOLSET)) $@ +cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< + +quiet_cmd_objcxx = CXX($(TOOLSET)) $@ +cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# Commands for precompiled header files. +quiet_cmd_pch_c = CXX($(TOOLSET)) $@ +cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_cc = CXX($(TOOLSET)) $@ +cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_m = CXX($(TOOLSET)) $@ +cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< +quiet_cmd_pch_mm = CXX($(TOOLSET)) $@ +cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# gyp-mac-tool is written next to the root Makefile by gyp. +# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd +# already. +quiet_cmd_mac_tool = MACTOOL $(4) $< +cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@" + +quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@ +cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4) + +quiet_cmd_infoplist = INFOPLIST $@ +cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@" + +quiet_cmd_touch = TOUCH $@ +cmd_touch = touch $@ + +quiet_cmd_copy = COPY $@ +# send stderr to /dev/null to ignore messages when linking directories. +cmd_copy = rm -rf "$@" && cp -af "$<" "$@" + +quiet_cmd_alink = LIBTOOL-STATIC $@ +cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^) + +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) + + +# Define an escape_quotes function to escape single quotes. +# This allows us to handle quotes properly as long as we always use +# use single quotes and escape_quotes. +escape_quotes = $(subst ','\'',$(1)) +# This comment is here just to include a ' to unconfuse syntax highlighting. +# Define an escape_vars function to escape '$' variable syntax. +# This allows us to read/write command lines with shell variables (e.g. +# $LD_LIBRARY_PATH), without triggering make substitution. +escape_vars = $(subst $$,$$$$,$(1)) +# Helper that expands to a shell command to echo a string exactly as it is in +# make. This uses printf instead of echo because printf's behaviour with respect +# to escape sequences is more portable than echo's across different shells +# (e.g., dash, bash). +exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' + +# Helper to compare the command we're about to run against the command +# we logged the last time we ran the command. Produces an empty +# string (false) when the commands match. +# Tricky point: Make has no string-equality test function. +# The kernel uses the following, but it seems like it would have false +# positives, where one string reordered its arguments. +# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ +# $(filter-out $(cmd_$@), $(cmd_$(1)))) +# We instead substitute each for the empty string into the other, and +# say they're equal if both substitutions produce the empty string. +# .d files contain ? instead of spaces, take that into account. +command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\ + $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) + +# Helper that is non-empty when a prerequisite changes. +# Normally make does this implicitly, but we force rules to always run +# so we can check their command lines. +# $? -- new prerequisites +# $| -- order-only dependencies +prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) + +# Helper that executes all postbuilds until one fails. +define do_postbuilds + @E=0;\ + for p in $(POSTBUILDS); do\ + eval $$p;\ + E=$$?;\ + if [ $$E -ne 0 ]; then\ + break;\ + fi;\ + done;\ + if [ $$E -ne 0 ]; then\ + rm -rf "$@";\ + exit $$E;\ + fi +endef + +# do_cmd: run a command via the above cmd_foo names, if necessary. +# Should always run for a given target to handle command-line changes. +# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. +# Third argument, if non-zero, makes it do POSTBUILDS processing. +# Note: We intentionally do NOT call dirx for depfile, since it contains ? for +# spaces already and dirx strips the ? characters. +define do_cmd +$(if $(or $(command_changed),$(prereq_changed)), + @$(call exact_echo, $($(quiet)cmd_$(1))) + @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" + $(if $(findstring flock,$(word 2,$(cmd_$1))), + @$(cmd_$(1)) + @echo " $(quiet_cmd_$(1)): Finished", + @$(cmd_$(1)) + ) + @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) + @$(if $(2),$(fixup_dep)) + $(if $(and $(3), $(POSTBUILDS)), + $(call do_postbuilds) + ) +) +endef + +# Declare the "all" target first so it is the default, +# even though we don't have the deps yet. +.PHONY: all +all: + +# make looks for ways to re-generate included makefiles, but in our case, we +# don't have a direct way. Explicitly telling make that it has nothing to do +# for them makes it go faster. +%.d: ; + +# Use FORCE_DO_CMD to force a target to run. Should be coupled with +# do_cmd. +.PHONY: FORCE_DO_CMD +FORCE_DO_CMD: + +TOOLSET := target +# Suffix rules, putting all outputs into $(obj). +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + + +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,bufferutil.target.mk)))),) + include bufferutil.target.mk +endif + +quiet_cmd_regen_makefile = ACTION Regenerating $@ +cmd_regen_makefile = cd $(srcdir); /usr/local/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "--toplevel-dir=." -I/Applications/MAMP/htdocs/stream2/WebRTC-Example/node_modules/bufferutil/build/config.gypi -I/usr/local/lib/node_modules/npm/node_modules/node-gyp/addon.gypi -I/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/vincenthofmeister/.node-gyp/5.1.0" "-Dnode_gyp_dir=/usr/local/lib/node_modules/npm/node_modules/node-gyp" "-Dnode_lib_file=node.lib" "-Dmodule_root_dir=/Applications/MAMP/htdocs/stream2/WebRTC-Example/node_modules/bufferutil" binding.gyp +Makefile: $(srcdir)/../../../../../../../Users/vincenthofmeister/.node-gyp/5.1.0/include/node/common.gypi $(srcdir)/../../../../../../../usr/local/lib/node_modules/npm/node_modules/node-gyp/addon.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp + $(call do_cmd,regen_makefile) + +# "all" is a concatenation of the "all" targets from all the included +# sub-makefiles. This is just here to clarify. +all: + +# Add in dependency-tracking rules. $(all_deps) is the list of every single +# target in our tree. Only consider the ones with .d (dependency) info: +d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) +ifneq ($(d_files),) + include $(d_files) +endif diff --git a/node_modules/bufferutil/build/Release/.deps/Release/bufferutil.node.d b/node_modules/bufferutil/build/Release/.deps/Release/bufferutil.node.d new file mode 100644 index 0000000..0dc664f --- /dev/null +++ b/node_modules/bufferutil/build/Release/.deps/Release/bufferutil.node.d @@ -0,0 +1 @@ +cmd_Release/bufferutil.node := c++ -bundle -undefined dynamic_lookup -Wl,-search_paths_first -mmacosx-version-min=10.5 -arch x86_64 -L./Release -o Release/bufferutil.node Release/obj.target/bufferutil/src/bufferutil.o diff --git a/node_modules/bufferutil/build/Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d b/node_modules/bufferutil/build/Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d new file mode 100644 index 0000000..49800cd --- /dev/null +++ b/node_modules/bufferutil/build/Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d @@ -0,0 +1,48 @@ +cmd_Release/obj.target/bufferutil/src/bufferutil.o := c++ '-DNODE_GYP_MODULE_NAME=bufferutil' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DBUILDING_NODE_EXTENSION' -I/Users/vincenthofmeister/.node-gyp/5.1.0/include/node -I/Users/vincenthofmeister/.node-gyp/5.1.0/src -I/Users/vincenthofmeister/.node-gyp/5.1.0/deps/uv/include -I/Users/vincenthofmeister/.node-gyp/5.1.0/deps/v8/include -I../../nan -Os -gdwarf-2 -mmacosx-version-min=10.5 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -std=gnu++0x -fno-rtti -fno-exceptions -fno-threadsafe-statics -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d.raw -c -o Release/obj.target/bufferutil/src/bufferutil.o ../src/bufferutil.cc +Release/obj.target/bufferutil/src/bufferutil.o: ../src/bufferutil.cc \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/v8.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/v8-version.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/v8config.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node_version.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node_buffer.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node_object_wrap.h \ + ../../nan/nan.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-errno.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-version.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-unix.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-threadpool.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-darwin.h \ + ../../nan/nan_callbacks.h ../../nan/nan_callbacks_12_inl.h \ + ../../nan/nan_maybe_43_inl.h ../../nan/nan_converters.h \ + ../../nan/nan_converters_43_inl.h ../../nan/nan_new.h \ + ../../nan/nan_implementation_12_inl.h \ + ../../nan/nan_persistent_12_inl.h ../../nan/nan_weak.h \ + ../../nan/nan_object_wrap.h ../../nan/nan_typedarray_contents.h +../src/bufferutil.cc: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/v8.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/v8-version.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/v8config.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node_version.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node_buffer.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node_object_wrap.h: +../../nan/nan.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-errno.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-version.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-unix.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-threadpool.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-darwin.h: +../../nan/nan_callbacks.h: +../../nan/nan_callbacks_12_inl.h: +../../nan/nan_maybe_43_inl.h: +../../nan/nan_converters.h: +../../nan/nan_converters_43_inl.h: +../../nan/nan_new.h: +../../nan/nan_implementation_12_inl.h: +../../nan/nan_persistent_12_inl.h: +../../nan/nan_weak.h: +../../nan/nan_object_wrap.h: +../../nan/nan_typedarray_contents.h: diff --git a/node_modules/bufferutil/build/Release/bufferutil.node b/node_modules/bufferutil/build/Release/bufferutil.node new file mode 100755 index 0000000000000000000000000000000000000000..6d2de4ab36e76978b81b4ba214b41574bf9355eb GIT binary patch literal 19828 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 literal 0 HcmV?d00001 diff --git a/node_modules/bufferutil/build/Release/obj.target/bufferutil/src/bufferutil.o b/node_modules/bufferutil/build/Release/obj.target/bufferutil/src/bufferutil.o new file mode 100644 index 0000000000000000000000000000000000000000..79fe6d74f53b1a99640c5c1a770df4cb0fc8a8d0 GIT binary patch literal 197060 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 z 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

E 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 literal 0 HcmV?d00001 diff --git a/node_modules/bufferutil/build/binding.Makefile b/node_modules/bufferutil/build/binding.Makefile new file mode 100644 index 0000000..b532496 --- /dev/null +++ b/node_modules/bufferutil/build/binding.Makefile @@ -0,0 +1,6 @@ +# This file is generated by gyp; do not edit. + +export builddir_name ?= ./build/. +.PHONY: all +all: + $(MAKE) bufferutil diff --git a/node_modules/bufferutil/build/bufferutil.target.mk b/node_modules/bufferutil/build/bufferutil.target.mk new file mode 100644 index 0000000..0e34bd0 --- /dev/null +++ b/node_modules/bufferutil/build/bufferutil.target.mk @@ -0,0 +1,165 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := bufferutil +DEFS_Debug := \ + '-DNODE_GYP_MODULE_NAME=bufferutil' \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-DBUILDING_NODE_EXTENSION' \ + '-DDEBUG' \ + '-D_DEBUG' + +# Flags passed to all source files. +CFLAGS_Debug := \ + -O0 \ + -gdwarf-2 \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Debug := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Debug := \ + -std=gnu++0x \ + -fno-rtti \ + -fno-exceptions \ + -fno-threadsafe-statics \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Debug := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Debug := + +INCS_Debug := \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/include/node \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/src \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/deps/uv/include \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/deps/v8/include \ + -I$(srcdir)/../nan + +DEFS_Release := \ + '-DNODE_GYP_MODULE_NAME=bufferutil' \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-DBUILDING_NODE_EXTENSION' + +# Flags passed to all source files. +CFLAGS_Release := \ + -Os \ + -gdwarf-2 \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Release := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Release := \ + -std=gnu++0x \ + -fno-rtti \ + -fno-exceptions \ + -fno-threadsafe-statics \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Release := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Release := + +INCS_Release := \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/include/node \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/src \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/deps/uv/include \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/deps/v8/include \ + -I$(srcdir)/../nan + +OBJS := \ + $(obj).target/$(TARGET)/src/bufferutil.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_Debug := \ + -undefined dynamic_lookup \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -L$(builddir) + +LIBTOOLFLAGS_Debug := \ + -undefined dynamic_lookup \ + -Wl,-search_paths_first + +LDFLAGS_Release := \ + -undefined dynamic_lookup \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -L$(builddir) + +LIBTOOLFLAGS_Release := \ + -undefined dynamic_lookup \ + -Wl,-search_paths_first + +LIBS := + +$(builddir)/bufferutil.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(builddir)/bufferutil.node: LIBS := $(LIBS) +$(builddir)/bufferutil.node: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE)) +$(builddir)/bufferutil.node: TOOLSET := $(TOOLSET) +$(builddir)/bufferutil.node: $(OBJS) FORCE_DO_CMD + $(call do_cmd,solink_module) + +all_deps += $(builddir)/bufferutil.node +# Add target alias +.PHONY: bufferutil +bufferutil: $(builddir)/bufferutil.node + +# Short alias for building this executable. +.PHONY: bufferutil.node +bufferutil.node: $(builddir)/bufferutil.node + +# Add executable to "all" target. +.PHONY: all +all: $(builddir)/bufferutil.node + diff --git a/node_modules/bufferutil/build/config.gypi b/node_modules/bufferutil/build/config.gypi new file mode 100644 index 0000000..66c2faa --- /dev/null +++ b/node_modules/bufferutil/build/config.gypi @@ -0,0 +1,141 @@ +# Do not edit. File was generated by node-gyp's "configure" step +{ + "target_defaults": { + "cflags": [], + "default_configuration": "Release", + "defines": [], + "include_dirs": [], + "libraries": [] + }, + "variables": { + "asan": 0, + "host_arch": "x64", + "icu_data_file": "icudt56l.dat", + "icu_data_in": "../../deps/icu/source/data/in/icudt56l.dat", + "icu_endianness": "l", + "icu_gyp_path": "tools/icu/icu-generic.gyp", + "icu_locales": "en,root", + "icu_path": "./deps/icu", + "icu_small": "true", + "icu_ver_major": "56", + "llvm_version": 0, + "node_byteorder": "little", + "node_install_npm": "true", + "node_prefix": "/usr/local", + "node_release_urlbase": "https://nodejs.org/download/release/", + "node_shared_http_parser": "false", + "node_shared_libuv": "false", + "node_shared_openssl": "false", + "node_shared_zlib": "false", + "node_tag": "", + "node_use_dtrace": "true", + "node_use_etw": "false", + "node_use_lttng": "false", + "node_use_openssl": "true", + "node_use_perfctr": "false", + "openssl_fips": "", + "openssl_no_asm": 0, + "python": "/usr/bin/python", + "target_arch": "x64", + "uv_parent_path": "/deps/uv/", + "uv_use_dtrace": "true", + "v8_enable_gdbjit": 0, + "v8_enable_i18n_support": 1, + "v8_no_strict_aliasing": 1, + "v8_optimized_debug": 0, + "v8_random_seed": 0, + "v8_use_snapshot": 1, + "want_separate_host_toolset": 0, + "nodedir": "/Users/vincenthofmeister/.node-gyp/5.1.0", + "copy_dev_lib": "true", + "standalone_static_library": 1, + "dry_run": "", + "save_dev": "", + "browser": "", + "only": "", + "viewer": "man", + "also": "", + "rollback": "true", + "usage": "", + "globalignorefile": "/usr/local/etc/npmignore", + "init_author_url": "", + "shell": "/bin/bash", + "parseable": "", + "shrinkwrap": "true", + "init_license": "ISC", + "if_present": "", + "cache_max": "Infinity", + "init_author_email": "", + "sign_git_tag": "", + "cert": "", + "git_tag_version": "true", + "local_address": "", + "long": "", + "fetch_retries": "2", + "npat": "", + "registry": "https://registry.npmjs.org/", + "key": "", + "message": "%s", + "versions": "", + "globalconfig": "/usr/local/etc/npmrc", + "always_auth": "", + "cache_lock_retries": "10", + "cafile": "", + "heading": "npm", + "fetch_retry_mintimeout": "10000", + "proprietary_attribs": "true", + "access": "", + "json": "", + "description": "true", + "engine_strict": "", + "https_proxy": "", + "init_module": "/Users/vincenthofmeister/.npm-init.js", + "userconfig": "/Users/vincenthofmeister/.npmrc", + "node_version": "5.1.0", + "user": "501", + "editor": "vi", + "save": "", + "tag": "latest", + "global": "", + "progress": "true", + "optional": "true", + "bin_links": "true", + "force": "", + "searchopts": "", + "depth": "Infinity", + "rebuild_bundle": "true", + "searchsort": "name", + "unicode": "true", + "fetch_retry_maxtimeout": "60000", + "ca": "", + "save_prefix": "^", + "strict_ssl": "true", + "tag_version_prefix": "v", + "dev": "", + "fetch_retry_factor": "10", + "group": "20", + "save_exact": "", + "cache_lock_stale": "60000", + "version": "", + "cache_min": "10", + "cache": "/Users/vincenthofmeister/.npm", + "searchexclude": "", + "color": "true", + "save_optional": "", + "user_agent": "npm/3.3.12 node/v5.1.0 darwin x64", + "ignore_scripts": "", + "cache_lock_wait": "10000", + "production": "", + "save_bundle": "", + "init_version": "1.0.0", + "umask": "0022", + "git": "git", + "init_author_name": "", + "scope": "", + "onload_script": "", + "tmp": "/var/folders/nc/pbcngndd7hb32pqtmr6ncc100000gn/T", + "unsafe_perm": "true", + "link": "", + "prefix": "/usr/local" + } +} diff --git a/node_modules/bufferutil/build/gyp-mac-tool b/node_modules/bufferutil/build/gyp-mac-tool new file mode 100755 index 0000000..976c598 --- /dev/null +++ b/node_modules/bufferutil/build/gyp-mac-tool @@ -0,0 +1,612 @@ +#!/usr/bin/env python +# Generated by gyp. Do not edit. +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Utility functions to perform Xcode-style build steps. + +These functions are executed via gyp-mac-tool when using the Makefile generator. +""" + +import fcntl +import fnmatch +import glob +import json +import os +import plistlib +import re +import shutil +import string +import subprocess +import sys +import tempfile + + +def main(args): + executor = MacTool() + exit_code = executor.Dispatch(args) + if exit_code is not None: + sys.exit(exit_code) + + +class MacTool(object): + """This class performs all the Mac tooling steps. The methods can either be + executed directly, or dispatched from an argument list.""" + + def Dispatch(self, args): + """Dispatches a string command to a method.""" + if len(args) < 1: + raise Exception("Not enough arguments") + + method = "Exec%s" % self._CommandifyName(args[0]) + return getattr(self, method)(*args[1:]) + + def _CommandifyName(self, name_string): + """Transforms a tool name like copy-info-plist to CopyInfoPlist""" + return name_string.title().replace('-', '') + + def ExecCopyBundleResource(self, source, dest, convert_to_binary): + """Copies a resource file to the bundle/Resources directory, performing any + necessary compilation on each resource.""" + extension = os.path.splitext(source)[1].lower() + if os.path.isdir(source): + # Copy tree. + # TODO(thakis): This copies file attributes like mtime, while the + # single-file branch below doesn't. This should probably be changed to + # be consistent with the single-file branch. + if os.path.exists(dest): + shutil.rmtree(dest) + shutil.copytree(source, dest) + elif extension == '.xib': + return self._CopyXIBFile(source, dest) + elif extension == '.storyboard': + return self._CopyXIBFile(source, dest) + elif extension == '.strings': + self._CopyStringsFile(source, dest, convert_to_binary) + else: + shutil.copy(source, dest) + + def _CopyXIBFile(self, source, dest): + """Compiles a XIB file with ibtool into a binary plist in the bundle.""" + + # ibtool sometimes crashes with relative paths. See crbug.com/314728. + base = os.path.dirname(os.path.realpath(__file__)) + if os.path.relpath(source): + source = os.path.join(base, source) + if os.path.relpath(dest): + dest = os.path.join(base, dest) + + args = ['xcrun', 'ibtool', '--errors', '--warnings', '--notices', + '--output-format', 'human-readable-text', '--compile', dest, source] + ibtool_section_re = re.compile(r'/\*.*\*/') + ibtool_re = re.compile(r'.*note:.*is clipping its content') + ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE) + current_section_header = None + for line in ibtoolout.stdout: + if ibtool_section_re.match(line): + current_section_header = line + elif not ibtool_re.match(line): + if current_section_header: + sys.stdout.write(current_section_header) + current_section_header = None + sys.stdout.write(line) + return ibtoolout.returncode + + def _ConvertToBinary(self, dest): + subprocess.check_call([ + 'xcrun', 'plutil', '-convert', 'binary1', '-o', dest, dest]) + + def _CopyStringsFile(self, source, dest, convert_to_binary): + """Copies a .strings file using iconv to reconvert the input into UTF-16.""" + input_code = self._DetectInputEncoding(source) or "UTF-8" + + # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call + # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints + # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing + # semicolon in dictionary. + # on invalid files. Do the same kind of validation. + import CoreFoundation + s = open(source, 'rb').read() + d = CoreFoundation.CFDataCreate(None, s, len(s)) + _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None) + if error: + return + + fp = open(dest, 'wb') + fp.write(s.decode(input_code).encode('UTF-16')) + fp.close() + + if convert_to_binary == 'True': + self._ConvertToBinary(dest) + + def _DetectInputEncoding(self, file_name): + """Reads the first few bytes from file_name and tries to guess the text + encoding. Returns None as a guess if it can't detect it.""" + fp = open(file_name, 'rb') + try: + header = fp.read(3) + except e: + fp.close() + return None + fp.close() + if header.startswith("\xFE\xFF"): + return "UTF-16" + elif header.startswith("\xFF\xFE"): + return "UTF-16" + elif header.startswith("\xEF\xBB\xBF"): + return "UTF-8" + else: + return None + + def ExecCopyInfoPlist(self, source, dest, convert_to_binary, *keys): + """Copies the |source| Info.plist to the destination directory |dest|.""" + # Read the source Info.plist into memory. + fd = open(source, 'r') + lines = fd.read() + fd.close() + + # Insert synthesized key/value pairs (e.g. BuildMachineOSBuild). + plist = plistlib.readPlistFromString(lines) + if keys: + plist = dict(plist.items() + json.loads(keys[0]).items()) + lines = plistlib.writePlistToString(plist) + + # Go through all the environment variables and replace them as variables in + # the file. + IDENT_RE = re.compile(r'[/\s]') + for key in os.environ: + if key.startswith('_'): + continue + evar = '${%s}' % key + evalue = os.environ[key] + lines = string.replace(lines, evar, evalue) + + # Xcode supports various suffices on environment variables, which are + # all undocumented. :rfc1034identifier is used in the standard project + # template these days, and :identifier was used earlier. They are used to + # convert non-url characters into things that look like valid urls -- + # except that the replacement character for :identifier, '_' isn't valid + # in a URL either -- oops, hence :rfc1034identifier was born. + evar = '${%s:identifier}' % key + evalue = IDENT_RE.sub('_', os.environ[key]) + lines = string.replace(lines, evar, evalue) + + evar = '${%s:rfc1034identifier}' % key + evalue = IDENT_RE.sub('-', os.environ[key]) + lines = string.replace(lines, evar, evalue) + + # Remove any keys with values that haven't been replaced. + lines = lines.split('\n') + for i in range(len(lines)): + if lines[i].strip().startswith("${"): + lines[i] = None + lines[i - 1] = None + lines = '\n'.join(filter(lambda x: x is not None, lines)) + + # Write out the file with variables replaced. + fd = open(dest, 'w') + fd.write(lines) + fd.close() + + # Now write out PkgInfo file now that the Info.plist file has been + # "compiled". + self._WritePkgInfo(dest) + + if convert_to_binary == 'True': + self._ConvertToBinary(dest) + + def _WritePkgInfo(self, info_plist): + """This writes the PkgInfo file from the data stored in Info.plist.""" + plist = plistlib.readPlist(info_plist) + if not plist: + return + + # Only create PkgInfo for executable types. + package_type = plist['CFBundlePackageType'] + if package_type != 'APPL': + return + + # The format of PkgInfo is eight characters, representing the bundle type + # and bundle signature, each four characters. If that is missing, four + # '?' characters are used instead. + signature_code = plist.get('CFBundleSignature', '????') + if len(signature_code) != 4: # Wrong length resets everything, too. + signature_code = '?' * 4 + + dest = os.path.join(os.path.dirname(info_plist), 'PkgInfo') + fp = open(dest, 'w') + fp.write('%s%s' % (package_type, signature_code)) + fp.close() + + def ExecFlock(self, lockfile, *cmd_list): + """Emulates the most basic behavior of Linux's flock(1).""" + # Rely on exception handling to report errors. + fd = os.open(lockfile, os.O_RDONLY|os.O_NOCTTY|os.O_CREAT, 0o666) + fcntl.flock(fd, fcntl.LOCK_EX) + return subprocess.call(cmd_list) + + def ExecFilterLibtool(self, *cmd_list): + """Calls libtool and filters out '/path/to/libtool: file: foo.o has no + symbols'.""" + libtool_re = re.compile(r'^.*libtool: file: .* has no symbols$') + libtool_re5 = re.compile( + r'^.*libtool: warning for library: ' + + r'.* the table of contents is empty ' + + r'\(no object file members in the library define global symbols\)$') + env = os.environ.copy() + # Ref: + # http://www.opensource.apple.com/source/cctools/cctools-809/misc/libtool.c + # The problem with this flag is that it resets the file mtime on the file to + # epoch=0, e.g. 1970-1-1 or 1969-12-31 depending on timezone. + env['ZERO_AR_DATE'] = '1' + libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env) + _, err = libtoolout.communicate() + for line in err.splitlines(): + if not libtool_re.match(line) and not libtool_re5.match(line): + print >>sys.stderr, line + # Unconditionally touch the output .a file on the command line if present + # and the command succeeded. A bit hacky. + if not libtoolout.returncode: + for i in range(len(cmd_list) - 1): + if cmd_list[i] == "-o" and cmd_list[i+1].endswith('.a'): + os.utime(cmd_list[i+1], None) + break + return libtoolout.returncode + + def ExecPackageFramework(self, framework, version): + """Takes a path to Something.framework and the Current version of that and + sets up all the symlinks.""" + # Find the name of the binary based on the part before the ".framework". + binary = os.path.basename(framework).split('.')[0] + + CURRENT = 'Current' + RESOURCES = 'Resources' + VERSIONS = 'Versions' + + if not os.path.exists(os.path.join(framework, VERSIONS, version, binary)): + # Binary-less frameworks don't seem to contain symlinks (see e.g. + # chromium's out/Debug/org.chromium.Chromium.manifest/ bundle). + return + + # Move into the framework directory to set the symlinks correctly. + pwd = os.getcwd() + os.chdir(framework) + + # Set up the Current version. + self._Relink(version, os.path.join(VERSIONS, CURRENT)) + + # Set up the root symlinks. + self._Relink(os.path.join(VERSIONS, CURRENT, binary), binary) + self._Relink(os.path.join(VERSIONS, CURRENT, RESOURCES), RESOURCES) + + # Back to where we were before! + os.chdir(pwd) + + def _Relink(self, dest, link): + """Creates a symlink to |dest| named |link|. If |link| already exists, + it is overwritten.""" + if os.path.lexists(link): + os.remove(link) + os.symlink(dest, link) + + def ExecCompileXcassets(self, keys, *inputs): + """Compiles multiple .xcassets files into a single .car file. + + This invokes 'actool' to compile all the inputs .xcassets files. The + |keys| arguments is a json-encoded dictionary of extra arguments to + pass to 'actool' when the asset catalogs contains an application icon + or a launch image. + + Note that 'actool' does not create the Assets.car file if the asset + catalogs does not contains imageset. + """ + command_line = [ + 'xcrun', 'actool', '--output-format', 'human-readable-text', + '--compress-pngs', '--notices', '--warnings', '--errors', + ] + is_iphone_target = 'IPHONEOS_DEPLOYMENT_TARGET' in os.environ + if is_iphone_target: + platform = os.environ['CONFIGURATION'].split('-')[-1] + if platform not in ('iphoneos', 'iphonesimulator'): + platform = 'iphonesimulator' + command_line.extend([ + '--platform', platform, '--target-device', 'iphone', + '--target-device', 'ipad', '--minimum-deployment-target', + os.environ['IPHONEOS_DEPLOYMENT_TARGET'], '--compile', + os.path.abspath(os.environ['CONTENTS_FOLDER_PATH']), + ]) + else: + command_line.extend([ + '--platform', 'macosx', '--target-device', 'mac', + '--minimum-deployment-target', os.environ['MACOSX_DEPLOYMENT_TARGET'], + '--compile', + os.path.abspath(os.environ['UNLOCALIZED_RESOURCES_FOLDER_PATH']), + ]) + if keys: + keys = json.loads(keys) + for key, value in keys.iteritems(): + arg_name = '--' + key + if isinstance(value, bool): + if value: + command_line.append(arg_name) + elif isinstance(value, list): + for v in value: + command_line.append(arg_name) + command_line.append(str(v)) + else: + command_line.append(arg_name) + command_line.append(str(value)) + # Note: actool crashes if inputs path are relative, so use os.path.abspath + # to get absolute path name for inputs. + command_line.extend(map(os.path.abspath, inputs)) + subprocess.check_call(command_line) + + def ExecMergeInfoPlist(self, output, *inputs): + """Merge multiple .plist files into a single .plist file.""" + merged_plist = {} + for path in inputs: + plist = self._LoadPlistMaybeBinary(path) + self._MergePlist(merged_plist, plist) + plistlib.writePlist(merged_plist, output) + + def ExecCodeSignBundle(self, key, resource_rules, entitlements, provisioning): + """Code sign a bundle. + + This function tries to code sign an iOS bundle, following the same + algorithm as Xcode: + 1. copy ResourceRules.plist from the user or the SDK into the bundle, + 2. pick the provisioning profile that best match the bundle identifier, + and copy it into the bundle as embedded.mobileprovision, + 3. copy Entitlements.plist from user or SDK next to the bundle, + 4. code sign the bundle. + """ + resource_rules_path = self._InstallResourceRules(resource_rules) + substitutions, overrides = self._InstallProvisioningProfile( + provisioning, self._GetCFBundleIdentifier()) + entitlements_path = self._InstallEntitlements( + entitlements, substitutions, overrides) + subprocess.check_call([ + 'codesign', '--force', '--sign', key, '--resource-rules', + resource_rules_path, '--entitlements', entitlements_path, + os.path.join( + os.environ['TARGET_BUILD_DIR'], + os.environ['FULL_PRODUCT_NAME'])]) + + def _InstallResourceRules(self, resource_rules): + """Installs ResourceRules.plist from user or SDK into the bundle. + + Args: + resource_rules: string, optional, path to the ResourceRules.plist file + to use, default to "${SDKROOT}/ResourceRules.plist" + + Returns: + Path to the copy of ResourceRules.plist into the bundle. + """ + source_path = resource_rules + target_path = os.path.join( + os.environ['BUILT_PRODUCTS_DIR'], + os.environ['CONTENTS_FOLDER_PATH'], + 'ResourceRules.plist') + if not source_path: + source_path = os.path.join( + os.environ['SDKROOT'], 'ResourceRules.plist') + shutil.copy2(source_path, target_path) + return target_path + + def _InstallProvisioningProfile(self, profile, bundle_identifier): + """Installs embedded.mobileprovision into the bundle. + + Args: + profile: string, optional, short name of the .mobileprovision file + to use, if empty or the file is missing, the best file installed + will be used + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + + Returns: + A tuple containing two dictionary: variables substitutions and values + to overrides when generating the entitlements file. + """ + source_path, provisioning_data, team_id = self._FindProvisioningProfile( + profile, bundle_identifier) + target_path = os.path.join( + os.environ['BUILT_PRODUCTS_DIR'], + os.environ['CONTENTS_FOLDER_PATH'], + 'embedded.mobileprovision') + shutil.copy2(source_path, target_path) + substitutions = self._GetSubstitutions(bundle_identifier, team_id + '.') + return substitutions, provisioning_data['Entitlements'] + + def _FindProvisioningProfile(self, profile, bundle_identifier): + """Finds the .mobileprovision file to use for signing the bundle. + + Checks all the installed provisioning profiles (or if the user specified + the PROVISIONING_PROFILE variable, only consult it) and select the most + specific that correspond to the bundle identifier. + + Args: + profile: string, optional, short name of the .mobileprovision file + to use, if empty or the file is missing, the best file installed + will be used + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + + Returns: + A tuple of the path to the selected provisioning profile, the data of + the embedded plist in the provisioning profile and the team identifier + to use for code signing. + + Raises: + SystemExit: if no .mobileprovision can be used to sign the bundle. + """ + profiles_dir = os.path.join( + os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles') + if not os.path.isdir(profiles_dir): + print >>sys.stderr, ( + 'cannot find mobile provisioning for %s' % bundle_identifier) + sys.exit(1) + provisioning_profiles = None + if profile: + profile_path = os.path.join(profiles_dir, profile + '.mobileprovision') + if os.path.exists(profile_path): + provisioning_profiles = [profile_path] + if not provisioning_profiles: + provisioning_profiles = glob.glob( + os.path.join(profiles_dir, '*.mobileprovision')) + valid_provisioning_profiles = {} + for profile_path in provisioning_profiles: + profile_data = self._LoadProvisioningProfile(profile_path) + app_id_pattern = profile_data.get( + 'Entitlements', {}).get('application-identifier', '') + for team_identifier in profile_data.get('TeamIdentifier', []): + app_id = '%s.%s' % (team_identifier, bundle_identifier) + if fnmatch.fnmatch(app_id, app_id_pattern): + valid_provisioning_profiles[app_id_pattern] = ( + profile_path, profile_data, team_identifier) + if not valid_provisioning_profiles: + print >>sys.stderr, ( + 'cannot find mobile provisioning for %s' % bundle_identifier) + sys.exit(1) + # If the user has multiple provisioning profiles installed that can be + # used for ${bundle_identifier}, pick the most specific one (ie. the + # provisioning profile whose pattern is the longest). + selected_key = max(valid_provisioning_profiles, key=lambda v: len(v)) + return valid_provisioning_profiles[selected_key] + + def _LoadProvisioningProfile(self, profile_path): + """Extracts the plist embedded in a provisioning profile. + + Args: + profile_path: string, path to the .mobileprovision file + + Returns: + Content of the plist embedded in the provisioning profile as a dictionary. + """ + with tempfile.NamedTemporaryFile() as temp: + subprocess.check_call([ + 'security', 'cms', '-D', '-i', profile_path, '-o', temp.name]) + return self._LoadPlistMaybeBinary(temp.name) + + def _MergePlist(self, merged_plist, plist): + """Merge |plist| into |merged_plist|.""" + for key, value in plist.iteritems(): + if isinstance(value, dict): + merged_value = merged_plist.get(key, {}) + if isinstance(merged_value, dict): + self._MergePlist(merged_value, value) + merged_plist[key] = merged_value + else: + merged_plist[key] = value + else: + merged_plist[key] = value + + def _LoadPlistMaybeBinary(self, plist_path): + """Loads into a memory a plist possibly encoded in binary format. + + This is a wrapper around plistlib.readPlist that tries to convert the + plist to the XML format if it can't be parsed (assuming that it is in + the binary format). + + Args: + plist_path: string, path to a plist file, in XML or binary format + + Returns: + Content of the plist as a dictionary. + """ + try: + # First, try to read the file using plistlib that only supports XML, + # and if an exception is raised, convert a temporary copy to XML and + # load that copy. + return plistlib.readPlist(plist_path) + except: + pass + with tempfile.NamedTemporaryFile() as temp: + shutil.copy2(plist_path, temp.name) + subprocess.check_call(['plutil', '-convert', 'xml1', temp.name]) + return plistlib.readPlist(temp.name) + + def _GetSubstitutions(self, bundle_identifier, app_identifier_prefix): + """Constructs a dictionary of variable substitutions for Entitlements.plist. + + Args: + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + app_identifier_prefix: string, value for AppIdentifierPrefix + + Returns: + Dictionary of substitutions to apply when generating Entitlements.plist. + """ + return { + 'CFBundleIdentifier': bundle_identifier, + 'AppIdentifierPrefix': app_identifier_prefix, + } + + def _GetCFBundleIdentifier(self): + """Extracts CFBundleIdentifier value from Info.plist in the bundle. + + Returns: + Value of CFBundleIdentifier in the Info.plist located in the bundle. + """ + info_plist_path = os.path.join( + os.environ['TARGET_BUILD_DIR'], + os.environ['INFOPLIST_PATH']) + info_plist_data = self._LoadPlistMaybeBinary(info_plist_path) + return info_plist_data['CFBundleIdentifier'] + + def _InstallEntitlements(self, entitlements, substitutions, overrides): + """Generates and install the ${BundleName}.xcent entitlements file. + + Expands variables "$(variable)" pattern in the source entitlements file, + add extra entitlements defined in the .mobileprovision file and the copy + the generated plist to "${BundlePath}.xcent". + + Args: + entitlements: string, optional, path to the Entitlements.plist template + to use, defaults to "${SDKROOT}/Entitlements.plist" + substitutions: dictionary, variable substitutions + overrides: dictionary, values to add to the entitlements + + Returns: + Path to the generated entitlements file. + """ + source_path = entitlements + target_path = os.path.join( + os.environ['BUILT_PRODUCTS_DIR'], + os.environ['PRODUCT_NAME'] + '.xcent') + if not source_path: + source_path = os.path.join( + os.environ['SDKROOT'], + 'Entitlements.plist') + shutil.copy2(source_path, target_path) + data = self._LoadPlistMaybeBinary(target_path) + data = self._ExpandVariables(data, substitutions) + if overrides: + for key in overrides: + if key not in data: + data[key] = overrides[key] + plistlib.writePlist(data, target_path) + return target_path + + def _ExpandVariables(self, data, substitutions): + """Expands variables "$(variable)" in data. + + Args: + data: object, can be either string, list or dictionary + substitutions: dictionary, variable substitutions to perform + + Returns: + Copy of data where each references to "$(variable)" has been replaced + by the corresponding value found in substitutions, or left intact if + the key was not found. + """ + if isinstance(data, str): + for key, value in substitutions.iteritems(): + data = data.replace('$(%s)' % key, value) + return data + if isinstance(data, list): + return [self._ExpandVariables(v, substitutions) for v in data] + if isinstance(data, dict): + return dict((k, self._ExpandVariables(data[k], + substitutions)) for k in data) + return data + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/node_modules/bufferutil/fallback.js b/node_modules/bufferutil/fallback.js new file mode 100644 index 0000000..52d6379 --- /dev/null +++ b/node_modules/bufferutil/fallback.js @@ -0,0 +1,57 @@ +'use strict'; + +/*! + * bufferutil: WebSocket buffer utils + * Copyright(c) 2015 Einar Otto Stangvik + * MIT Licensed + */ + +module.exports.BufferUtil = { + merge: function(mergedBuffer, buffers) { + for (var i = 0, offset = 0, l = buffers.length; i < l; ++i) { + var buf = buffers[i]; + + buf.copy(mergedBuffer, offset); + offset += buf.length; + } + }, + + mask: function(source, mask, output, offset, length) { + var maskNum = mask.readUInt32LE(0, true) + , i = 0 + , num; + + for (; i < length - 3; i += 4) { + num = maskNum ^ source.readUInt32LE(i, true); + + if (num < 0) num = 4294967296 + num; + output.writeUInt32LE(num, offset + i, true); + } + + switch (length % 4) { + case 3: output[offset + i + 2] = source[i + 2] ^ mask[2]; + case 2: output[offset + i + 1] = source[i + 1] ^ mask[1]; + case 1: output[offset + i] = source[i] ^ mask[0]; + } + }, + + unmask: function(data, mask) { + var maskNum = mask.readUInt32LE(0, true) + , length = data.length + , i = 0 + , num; + + for (; i < length - 3; i += 4) { + num = maskNum ^ data.readUInt32LE(i, true); + + if (num < 0) num = 4294967296 + num; + data.writeUInt32LE(num, i, true); + } + + switch (length % 4) { + case 3: data[i + 2] = data[i + 2] ^ mask[2]; + case 2: data[i + 1] = data[i + 1] ^ mask[1]; + case 1: data[i] = data[i] ^ mask[0]; + } + } +}; diff --git a/node_modules/bufferutil/index.js b/node_modules/bufferutil/index.js new file mode 100644 index 0000000..00c607c --- /dev/null +++ b/node_modules/bufferutil/index.js @@ -0,0 +1,7 @@ +'use strict'; + +try { + module.exports = require('bindings')('bufferutil'); +} catch (e) { + module.exports = require('./fallback'); +} diff --git a/node_modules/bufferutil/package.json b/node_modules/bufferutil/package.json new file mode 100644 index 0000000..e2689fb --- /dev/null +++ b/node_modules/bufferutil/package.json @@ -0,0 +1,85 @@ +{ + "_args": [ + [ + "bufferutil@1.2.x", + "/Applications/MAMP/htdocs/stream2/WebRTC-Example/node_modules/ws" + ] + ], + "_from": "bufferutil@>=1.2.0 <1.3.0", + "_id": "bufferutil@1.2.1", + "_inCache": true, + "_installable": true, + "_location": "/bufferutil", + "_nodeVersion": "0.12.3", + "_npmUser": { + "email": "npm@3rd-Eden.com", + "name": "3rdeden" + }, + "_npmVersion": "2.9.1", + "_phantomChildren": {}, + "_requested": { + "name": "bufferutil", + "raw": "bufferutil@1.2.x", + "rawSpec": "1.2.x", + "scope": null, + "spec": ">=1.2.0 <1.3.0", + "type": "range" + }, + "_requiredBy": [ + "/ws" + ], + "_resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.2.1.tgz", + "_shasum": "37be5d36e1e06492221e68d474b1ac58e510cbd7", + "_shrinkwrap": null, + "_spec": "bufferutil@1.2.x", + "_where": "/Applications/MAMP/htdocs/stream2/WebRTC-Example/node_modules/ws", + "author": { + "email": "einaros@gmail.com", + "name": "Einar Otto Stangvik", + "url": "http://2x.io" + }, + "bugs": { + "url": "https://github.com/websockets/bufferutil/issues" + }, + "dependencies": { + "bindings": "1.2.x", + "nan": "^2.0.5" + }, + "description": "WebSocket buffer utils", + "devDependencies": {}, + "directories": {}, + "dist": { + "shasum": "37be5d36e1e06492221e68d474b1ac58e510cbd7", + "tarball": "http://registry.npmjs.org/bufferutil/-/bufferutil-1.2.1.tgz" + }, + "gitHead": "cb7163377b8032fb79ddd835a549c83488585859", + "gypfile": true, + "homepage": "https://github.com/websockets/bufferutil", + "keywords": [ + "bufferutil" + ], + "license": "MIT", + "main": "index.js", + "maintainers": [ + { + "name": "3rdeden", + "email": "npm@3rd-Eden.com" + }, + { + "name": "einaros", + "email": "einaros@gmail.com" + } + ], + "name": "bufferutil", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+https://github.com/websockets/bufferutil.git" + }, + "scripts": { + "install": "node-gyp rebuild", + "test": "echo \"Only testing builds, test have to be extraced from `ws`\" && exit 0" + }, + "version": "1.2.1" +} diff --git a/node_modules/bufferutil/src/bufferutil.cc b/node_modules/bufferutil/src/bufferutil.cc new file mode 100644 index 0000000..1e826b3 --- /dev/null +++ b/node_modules/bufferutil/src/bufferutil.cc @@ -0,0 +1,120 @@ +/*! + * bufferutil: WebSocket buffer utils + * Copyright(c) 2015 Einar Otto Stangvik + * MIT Licensed + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nan.h" + +using namespace v8; +using namespace node; + +class BufferUtil : public ObjectWrap +{ +public: + + static void Initialize(v8::Handle target) + { + Nan::HandleScope scope; + Local t = Nan::New(New); + t->InstanceTemplate()->SetInternalFieldCount(1); + Nan::SetMethod(t, "unmask", BufferUtil::Unmask); + Nan::SetMethod(t, "mask", BufferUtil::Mask); + Nan::SetMethod(t, "merge", BufferUtil::Merge); + Nan::Set(target, Nan::New("BufferUtil").ToLocalChecked(), t->GetFunction()); + } + +protected: + + static NAN_METHOD(New) + { + Nan::HandleScope scope; + BufferUtil* bufferUtil = new BufferUtil(); + bufferUtil->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); + } + + static NAN_METHOD(Merge) + { + Nan::HandleScope scope; + Local bufferObj = info[0]->ToObject(); + char* buffer = Buffer::Data(bufferObj); + Local array = Local::Cast(info[1]); + unsigned int arrayLength = array->Length(); + size_t offset = 0; + unsigned int i; + for (i = 0; i < arrayLength; ++i) { + Local src = array->Get(i)->ToObject(); + size_t length = Buffer::Length(src); + memcpy(buffer + offset, Buffer::Data(src), length); + offset += length; + } + info.GetReturnValue().Set(Nan::True()); + } + + static NAN_METHOD(Unmask) + { + Nan::HandleScope scope; + Local buffer_obj = info[0]->ToObject(); + size_t length = Buffer::Length(buffer_obj); + Local mask_obj = info[1]->ToObject(); + unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj); + unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj); + size_t len32 = length / 4; + unsigned int i; + for (i = 0; i < len32; ++i) *(from + i) ^= *mask; + from += i; + switch (length % 4) { + case 3: *((unsigned char*)from+2) = *((unsigned char*)from+2) ^ ((unsigned char*)mask)[2]; + case 2: *((unsigned char*)from+1) = *((unsigned char*)from+1) ^ ((unsigned char*)mask)[1]; + case 1: *((unsigned char*)from ) = *((unsigned char*)from ) ^ ((unsigned char*)mask)[0]; + case 0:; + } + info.GetReturnValue().Set(Nan::True()); + } + + static NAN_METHOD(Mask) + { + Nan::HandleScope scope; + Local buffer_obj = info[0]->ToObject(); + Local mask_obj = info[1]->ToObject(); + unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj); + Local output_obj = info[2]->ToObject(); + unsigned int dataOffset = info[3]->Int32Value(); + unsigned int length = info[4]->Int32Value(); + unsigned int* to = (unsigned int*)(Buffer::Data(output_obj) + dataOffset); + unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj); + unsigned int len32 = length / 4; + unsigned int i; + for (i = 0; i < len32; ++i) *(to + i) = *(from + i) ^ *mask; + to += i; + from += i; + switch (length % 4) { + case 3: *((unsigned char*)to+2) = *((unsigned char*)from+2) ^ *((unsigned char*)mask+2); + case 2: *((unsigned char*)to+1) = *((unsigned char*)from+1) ^ *((unsigned char*)mask+1); + case 1: *((unsigned char*)to ) = *((unsigned char*)from ) ^ *((unsigned char*)mask); + case 0:; + } + info.GetReturnValue().Set(Nan::True()); + } +}; + +#if !NODE_VERSION_AT_LEAST(0,10,0) +extern "C" +#endif +void init (Handle target) +{ + Nan::HandleScope scope; + BufferUtil::Initialize(target); +} + +NODE_MODULE(bufferutil, init) diff --git a/node_modules/nan/.dntrc b/node_modules/nan/.dntrc new file mode 100644 index 0000000..47971da --- /dev/null +++ b/node_modules/nan/.dntrc @@ -0,0 +1,30 @@ +## DNT config file +## see https://github.com/rvagg/dnt + +NODE_VERSIONS="\ + master \ + v0.11.13 \ + v0.10.30 \ + v0.10.29 \ + v0.10.28 \ + v0.10.26 \ + v0.10.25 \ + v0.10.24 \ + v0.10.23 \ + v0.10.22 \ + v0.10.21 \ + v0.10.20 \ + v0.10.19 \ + v0.8.28 \ + v0.8.27 \ + v0.8.26 \ + v0.8.24 \ +" +OUTPUT_PREFIX="nan-" +TEST_CMD=" \ + cd /dnt/ && \ + npm install && \ + node_modules/.bin/node-gyp --nodedir /usr/src/node/ rebuild --directory test && \ + node_modules/.bin/tap --gc test/js/*-test.js \ +" + diff --git a/node_modules/nan/CHANGELOG.md b/node_modules/nan/CHANGELOG.md new file mode 100644 index 0000000..8d3c618 --- /dev/null +++ b/node_modules/nan/CHANGELOG.md @@ -0,0 +1,384 @@ +# NAN ChangeLog + +**Version 2.1.0: current Node 4.1.2, Node 12: 0.12.7, Node 10: 0.10.40, iojs: 3.3.1** + +### 2.1.0 Oct 8 2015 + + - Deprecation: Deprecate NanErrnoException in favor of ErrnoException 0af1ca4cf8b3f0f65ed31bc63a663ab3319da55c + - Feature: added helper class for accessing contents of typedarrays 17b51294c801e534479d5463697a73462d0ca555 + - Feature: [Maybe types] Add MakeMaybe(...) 48d7b53d9702b0c7a060e69ea10fea8fb48d814d + - Feature: new: allow utf16 string with length 66ac6e65c8ab9394ef588adfc59131b3b9d8347b + - Feature: Introduce SetCallHandler and SetCallAsFunctionHandler 7764a9a115d60ba10dc24d86feb0fbc9b4f75537 + - Bugfix: Enable creating Locals from Globals under Node 0.10. 9bf9b8b190821af889790fdc18ace57257e4f9ff + - Bugfix: Fix issue #462 where PropertyCallbackInfo data is not stored safely. 55f50adedd543098526c7b9f4fffd607d3f9861f + +### 2.0.9 Sep 8 2015 + + - Bugfix: EscapableHandleScope in Nan::NewBuffer for Node 0.8 and 0.10 b1654d7 + +### 2.0.8 Aug 28 2015 + + - Work around duplicate linking bug in clang 11902da + +### 2.0.7 Aug 26 2015 + + - Build: Repackage + +### 2.0.6 Aug 26 2015 + + - Bugfix: Properly handle null callback in FunctionTemplate factory 6e99cb1 + - Bugfix: Remove unused static std::map instances 525bddc + - Bugfix: Make better use of maybe versions of APIs bfba85b + - Bugfix: Fix shadowing issues with handle in ObjectWrap 0a9072d + +### 2.0.5 Aug 10 2015 + + - Bugfix: Reimplement weak callback in ObjectWrap 98d38c1 + - Bugfix: Make sure callback classes are not assignable, copyable or movable 81f9b1d + +### 2.0.4 Aug 6 2015 + + - Build: Repackage + +### 2.0.3 Aug 6 2015 + + - Bugfix: Don't use clang++ / g++ syntax extension. 231450e + +### 2.0.2 Aug 6 2015 + + - Build: Repackage + +### 2.0.1 Aug 6 2015 + + - Bugfix: Add workaround for missing REPLACE_INVALID_UTF8 60d6687 + - Bugfix: Reimplement ObjectWrap from scratch to prevent memory leaks 6484601 + - Bugfix: Fix Persistent leak in FunctionCallbackInfo and PropertyCallbackInfo 641ef5f + - Bugfix: Add missing overload for Nan::NewInstance that takes argc/argv 29450ed + +### 2.0.0 Jul 31 2015 + + - Change: Renamed identifiers with leading underscores b5932b4 + - Change: Replaced NanObjectWrapHandle with class NanObjectWrap 464f1e1 + - Change: Replace NanScope and NanEscpableScope macros with classes 47751c4 + - Change: Rename NanNewBufferHandle to NanNewBuffer 6745f99 + - Change: Rename NanBufferUse to NanNewBuffer 3e8b0a5 + - Change: Rename NanNewBuffer to NanCopyBuffer d6af78d + - Change: Remove Nan prefix from all names 72d1f67 + - Change: Update Buffer API for new upstream changes d5d3291 + - Change: Rename Scope and EscapableScope to HandleScope and EscapableHandleScope 21a7a6a + - Change: Get rid of Handles e6c0daf + - Feature: Support io.js 3 with V8 4.4 + - Feature: Introduce NanPersistent 7fed696 + - Feature: Introduce NanGlobal 4408da1 + - Feature: Added NanTryCatch 10f1ca4 + - Feature: Update for V8 v4.3 4b6404a + - Feature: Introduce NanNewOneByteString c543d32 + - Feature: Introduce namespace Nan 67ed1b1 + - Removal: Remove NanLocker and NanUnlocker dd6e401 + - Removal: Remove string converters, except NanUtf8String, which now follows the node implementation b5d00a9 + - Removal: Remove NanReturn* macros d90a25c + - Removal: Remove HasInstance e8f84fe + + +### 1.9.0 Jul 31 2015 + + - Feature: Added `NanFatalException` 81d4a2c + - Feature: Added more error types 4265f06 + - Feature: Added dereference and function call operators to NanCallback c4b2ed0 + - Feature: Added indexed GetFromPersistent and SaveToPersistent edd510c + - Feature: Added more overloads of SaveToPersistent and GetFromPersistent 8b1cef6 + - Feature: Added NanErrnoException dd87d9e + - Correctness: Prevent assign, copy, and move for classes that do not support it 1f55c59, 4b808cb, c96d9b2, fba4a29, 3357130 + - Deprecation: Deprecate `NanGetPointerSafe` and `NanSetPointerSafe` 81d4a2c + - Deprecation: Deprecate `NanBooleanOptionValue` and `NanUInt32OptionValue` 0ad254b + +### 1.8.4 Apr 26 2015 + + - Build: Repackage + +### 1.8.3 Apr 26 2015 + + - Bugfix: Include missing header 1af8648 + +### 1.8.2 Apr 23 2015 + + - Build: Repackage + +### 1.8.1 Apr 23 2015 + + - Bugfix: NanObjectWrapHandle should take a pointer 155f1d3 + +### 1.8.0 Apr 23 2015 + + - Feature: Allow primitives with NanReturnValue 2e4475e + - Feature: Added comparison operators to NanCallback 55b075e + - Feature: Backport thread local storage 15bb7fa + - Removal: Remove support for signatures with arguments 8a2069d + - Correcteness: Replaced NanObjectWrapHandle macro with function 0bc6d59 + +### 1.7.0 Feb 28 2015 + + - Feature: Made NanCallback::Call accept optional target 8d54da7 + - Feature: Support atom-shell 0.21 0b7f1bb + +### 1.6.2 Feb 6 2015 + + - Bugfix: NanEncode: fix argument type for node::Encode on io.js 2be8639 + +### 1.6.1 Jan 23 2015 + + - Build: version bump + +### 1.5.3 Jan 23 2015 + + - Build: repackage + +### 1.6.0 Jan 23 2015 + + - Deprecated `NanNewContextHandle` in favor of `NanNew` 49259af + - Support utility functions moved in newer v8 versions (Node 0.11.15, io.js 1.0) a0aa179 + - Added `NanEncode`, `NanDecodeBytes` and `NanDecodeWrite` 75e6fb9 + +### 1.5.2 Jan 23 2015 + + - Bugfix: Fix non-inline definition build error with clang++ 21d96a1, 60fadd4 + - Bugfix: Readded missing String constructors 18d828f + - Bugfix: Add overload handling NanNew(..) 5ef813b + - Bugfix: Fix uv_work_cb versioning 997e4ae + - Bugfix: Add function factory and test 4eca89c + - Bugfix: Add object template factory and test cdcb951 + - Correctness: Lifted an io.js related typedef c9490be + - Correctness: Make explicit downcasts of String lengths 00074e6 + - Windows: Limit the scope of disabled warning C4530 83d7deb + +### 1.5.1 Jan 15 2015 + + - Build: version bump + +### 1.4.3 Jan 15 2015 + + - Build: version bump + +### 1.4.2 Jan 15 2015 + + - Feature: Support io.js 0dbc5e8 + +### 1.5.0 Jan 14 2015 + + - Feature: Support io.js b003843 + - Correctness: Improved NanNew internals 9cd4f6a + - Feature: Implement progress to NanAsyncWorker 8d6a160 + +### 1.4.1 Nov 8 2014 + + - Bugfix: Handle DEBUG definition correctly + - Bugfix: Accept int as Boolean + +### 1.4.0 Nov 1 2014 + + - Feature: Added NAN_GC_CALLBACK 6a5c245 + - Performance: Removed unnecessary local handle creation 18a7243, 41fe2f8 + - Correctness: Added constness to references in NanHasInstance 02c61cd + - Warnings: Fixed spurious warnings from -Wundef and -Wshadow, 541b122, 99d8cb6 + - Windoze: Shut Visual Studio up when compiling 8d558c1 + - License: Switch to plain MIT from custom hacked MIT license 11de983 + - Build: Added test target to Makefile e232e46 + - Performance: Removed superfluous scope in NanAsyncWorker f4b7821 + - Sugar/Feature: Added NanReturnThis() and NanReturnHolder() shorthands 237a5ff, d697208 + - Feature: Added suitable overload of NanNew for v8::Integer::NewFromUnsigned b27b450 + +### 1.3.0 Aug 2 2014 + + - Added NanNew(std::string) + - Added NanNew(std::string&) + - Added NanAsciiString helper class + - Added NanUtf8String helper class + - Added NanUcs2String helper class + - Deprecated NanRawString() + - Deprecated NanCString() + - Added NanGetIsolateData(v8::Isolate *isolate) + - Added NanMakeCallback(v8::Handle target, v8::Handle func, int argc, v8::Handle* argv) + - Added NanMakeCallback(v8::Handle target, v8::Handle symbol, int argc, v8::Handle* argv) + - Added NanMakeCallback(v8::Handle target, const char* method, int argc, v8::Handle* argv) + - Added NanSetTemplate(v8::Handle templ, v8::Handle name , v8::Handle value, v8::PropertyAttribute attributes) + - Added NanSetPrototypeTemplate(v8::Local templ, v8::Handle name, v8::Handle value, v8::PropertyAttribute attributes) + - Added NanSetInstanceTemplate(v8::Local templ, const char *name, v8::Handle value) + - Added NanSetInstanceTemplate(v8::Local templ, v8::Handle name, v8::Handle value, v8::PropertyAttribute attributes) + +### 1.2.0 Jun 5 2014 + + - Add NanSetPrototypeTemplate + - Changed NAN_WEAK_CALLBACK internals, switched _NanWeakCallbackData to class, + introduced _NanWeakCallbackDispatcher + - Removed -Wno-unused-local-typedefs from test builds + - Made test builds Windows compatible ('Sleep()') + +### 1.1.2 May 28 2014 + + - Release to fix more stuff-ups in 1.1.1 + +### 1.1.1 May 28 2014 + + - Release to fix version mismatch in nan.h and lack of changelog entry for 1.1.0 + +### 1.1.0 May 25 2014 + + - Remove nan_isolate, use v8::Isolate::GetCurrent() internally instead + - Additional explicit overloads for NanNew(): (char*,int), (uint8_t*[,int]), + (uint16_t*[,int), double, int, unsigned int, bool, v8::String::ExternalStringResource*, + v8::String::ExternalAsciiStringResource* + - Deprecate NanSymbol() + - Added SetErrorMessage() and ErrorMessage() to NanAsyncWorker + +### 1.0.0 May 4 2014 + + - Heavy API changes for V8 3.25 / Node 0.11.13 + - Use cpplint.py + - Removed NanInitPersistent + - Removed NanPersistentToLocal + - Removed NanFromV8String + - Removed NanMakeWeak + - Removed NanNewLocal + - Removed NAN_WEAK_CALLBACK_OBJECT + - Removed NAN_WEAK_CALLBACK_DATA + - Introduce NanNew, replaces NanNewLocal, NanPersistentToLocal, adds many overloaded typed versions + - Introduce NanUndefined, NanNull, NanTrue and NanFalse + - Introduce NanEscapableScope and NanEscapeScope + - Introduce NanMakeWeakPersistent (requires a special callback to work on both old and new node) + - Introduce NanMakeCallback for node::MakeCallback + - Introduce NanSetTemplate + - Introduce NanGetCurrentContext + - Introduce NanCompileScript and NanRunScript + - Introduce NanAdjustExternalMemory + - Introduce NanAddGCEpilogueCallback, NanAddGCPrologueCallback, NanRemoveGCEpilogueCallback, NanRemoveGCPrologueCallback + - Introduce NanGetHeapStatistics + - Rename NanAsyncWorker#SavePersistent() to SaveToPersistent() + +### 0.8.0 Jan 9 2014 + + - NanDispose -> NanDisposePersistent, deprecate NanDispose + - Extract _NAN_*_RETURN_TYPE, pull up NAN_*() + +### 0.7.1 Jan 9 2014 + + - Fixes to work against debug builds of Node + - Safer NanPersistentToLocal (avoid reinterpret_cast) + - Speed up common NanRawString case by only extracting flattened string when necessary + +### 0.7.0 Dec 17 2013 + + - New no-arg form of NanCallback() constructor. + - NanCallback#Call takes Handle rather than Local + - Removed deprecated NanCallback#Run method, use NanCallback#Call instead + - Split off _NAN_*_ARGS_TYPE from _NAN_*_ARGS + - Restore (unofficial) Node 0.6 compatibility at NanCallback#Call() + - Introduce NanRawString() for char* (or appropriate void*) from v8::String + (replacement for NanFromV8String) + - Introduce NanCString() for null-terminated char* from v8::String + +### 0.6.0 Nov 21 2013 + + - Introduce NanNewLocal(v8::Handle value) for use in place of + v8::Local::New(...) since v8 started requiring isolate in Node 0.11.9 + +### 0.5.2 Nov 16 2013 + + - Convert SavePersistent and GetFromPersistent in NanAsyncWorker from protected and public + +### 0.5.1 Nov 12 2013 + + - Use node::MakeCallback() instead of direct v8::Function::Call() + +### 0.5.0 Nov 11 2013 + + - Added @TooTallNate as collaborator + - New, much simpler, "include_dirs" for binding.gyp + - Added full range of NAN_INDEX_* macros to match NAN_PROPERTY_* macros + +### 0.4.4 Nov 2 2013 + + - Isolate argument from v8::Persistent::MakeWeak removed for 0.11.8+ + +### 0.4.3 Nov 2 2013 + + - Include node_object_wrap.h, removed from node.h for Node 0.11.8. + +### 0.4.2 Nov 2 2013 + + - Handle deprecation of v8::Persistent::Dispose(v8::Isolate* isolate)) for + Node 0.11.8 release. + +### 0.4.1 Sep 16 2013 + + - Added explicit `#include ` as it was removed from node.h for v0.11.8 + +### 0.4.0 Sep 2 2013 + + - Added NAN_INLINE and NAN_DEPRECATED and made use of them + - Added NanError, NanTypeError and NanRangeError + - Cleaned up code + +### 0.3.2 Aug 30 2013 + + - Fix missing scope declaration in GetFromPersistent() and SaveToPersistent + in NanAsyncWorker + +### 0.3.1 Aug 20 2013 + + - fix "not all control paths return a value" compile warning on some platforms + +### 0.3.0 Aug 19 2013 + + - Made NAN work with NPM + - Lots of fixes to NanFromV8String, pulling in features from new Node core + - Changed node::encoding to Nan::Encoding in NanFromV8String to unify the API + - Added optional error number argument for NanThrowError() + - Added NanInitPersistent() + - Added NanReturnNull() and NanReturnEmptyString() + - Added NanLocker and NanUnlocker + - Added missing scopes + - Made sure to clear disposed Persistent handles + - Changed NanAsyncWorker to allocate error messages on the heap + - Changed NanThrowError(Local) to NanThrowError(Handle) + - Fixed leak in NanAsyncWorker when errmsg is used + +### 0.2.2 Aug 5 2013 + + - Fixed usage of undefined variable with node::BASE64 in NanFromV8String() + +### 0.2.1 Aug 5 2013 + + - Fixed 0.8 breakage, node::BUFFER encoding type not available in 0.8 for + NanFromV8String() + +### 0.2.0 Aug 5 2013 + + - Added NAN_PROPERTY_GETTER, NAN_PROPERTY_SETTER, NAN_PROPERTY_ENUMERATOR, + NAN_PROPERTY_DELETER, NAN_PROPERTY_QUERY + - Extracted _NAN_METHOD_ARGS, _NAN_GETTER_ARGS, _NAN_SETTER_ARGS, + _NAN_PROPERTY_GETTER_ARGS, _NAN_PROPERTY_SETTER_ARGS, + _NAN_PROPERTY_ENUMERATOR_ARGS, _NAN_PROPERTY_DELETER_ARGS, + _NAN_PROPERTY_QUERY_ARGS + - Added NanGetInternalFieldPointer, NanSetInternalFieldPointer + - Added NAN_WEAK_CALLBACK, NAN_WEAK_CALLBACK_OBJECT, + NAN_WEAK_CALLBACK_DATA, NanMakeWeak + - Renamed THROW_ERROR to _NAN_THROW_ERROR + - Added NanNewBufferHandle(char*, size_t, node::smalloc::FreeCallback, void*) + - Added NanBufferUse(char*, uint32_t) + - Added NanNewContextHandle(v8::ExtensionConfiguration*, + v8::Handle, v8::Handle) + - Fixed broken NanCallback#GetFunction() + - Added optional encoding and size arguments to NanFromV8String() + - Added NanGetPointerSafe() and NanSetPointerSafe() + - Added initial test suite (to be expanded) + - Allow NanUInt32OptionValue to convert any Number object + +### 0.1.0 Jul 21 2013 + + - Added `NAN_GETTER`, `NAN_SETTER` + - Added `NanThrowError` with single Local argument + - Added `NanNewBufferHandle` with single uint32_t argument + - Added `NanHasInstance(Persistent&, Handle)` + - Added `Local NanCallback#GetFunction()` + - Added `NanCallback#Call(int, Local[])` + - Deprecated `NanCallback#Run(int, Local[])` in favour of Call diff --git a/node_modules/nan/LICENSE.md b/node_modules/nan/LICENSE.md new file mode 100644 index 0000000..77666cd --- /dev/null +++ b/node_modules/nan/LICENSE.md @@ -0,0 +1,13 @@ +The MIT License (MIT) +===================== + +Copyright (c) 2015 NAN contributors +----------------------------------- + +*NAN contributors listed at * + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/nan/README.md b/node_modules/nan/README.md new file mode 100644 index 0000000..7167ae3 --- /dev/null +++ b/node_modules/nan/README.md @@ -0,0 +1,371 @@ +Native Abstractions for Node.js +=============================== + +**A header file filled with macro and utility goodness for making add-on development for Node.js easier across versions 0.8, 0.10, 0.12 and 4.** + +***Current version: 2.1.0*** + +*(See [CHANGELOG.md](https://github.com/nodejs/nan/blob/master/CHANGELOG.md) for complete ChangeLog)* + +[![NPM](https://nodei.co/npm/nan.png?downloads=true&downloadRank=true)](https://nodei.co/npm/nan/) [![NPM](https://nodei.co/npm-dl/nan.png?months=6&height=3)](https://nodei.co/npm/nan/) + +[![Build Status](https://api.travis-ci.org/nodejs/nan.svg?branch=master)](http://travis-ci.org/nodejs/nan) +[![Build status](https://ci.appveyor.com/api/projects/status/kh73pbm9dsju7fgh)](https://ci.appveyor.com/project/RodVagg/nan) + +Thanks to the crazy changes in V8 (and some in Node core), keeping native addons compiling happily across versions, particularly 0.10 to 0.12 to 4.0, is a minor nightmare. The goal of this project is to store all logic necessary to develop native Node.js addons without having to inspect `NODE_MODULE_VERSION` and get yourself into a macro-tangle. + +This project also contains some helper utilities that make addon development a bit more pleasant. + + * **[News & Updates](#news)** + * **[Usage](#usage)** + * **[Example](#example)** + * **[API](#api)** + * **[Tests](#tests)** + * **[Governance & Contributing](#governance)** + + +## News & Updates + + +## Usage + +Simply add **NAN** as a dependency in the *package.json* of your Node addon: + +``` bash +$ npm install --save nan +``` + +Pull in the path to **NAN** in your *binding.gyp* so that you can use `#include ` in your *.cpp* files: + +``` python +"include_dirs" : [ + "` when compiling your addon. + + +## Example + +Just getting started with Nan? Refer to a [quick-start **Nan** Boilerplate](https://github.com/fcanas/node-native-boilerplate) for a ready-to-go project that utilizes basic Nan functionality. + +For a simpler example, see the **[async pi estimation example](https://github.com/nodejs/nan/tree/master/examples/async_pi_estimate)** in the examples directory for full code and an explanation of what this Monte Carlo Pi estimation example does. Below are just some parts of the full example that illustrate the use of **NAN**. + +For another example, see **[nan-example-eol](https://github.com/CodeCharmLtd/nan-example-eol)**. It shows newline detection implemented as a native addon. + + +## API + +Additional to the NAN documentation below, please consult: + +* [The V8 Getting Started Guide](https://developers.google.com/v8/get_started) +* [The V8 Embedders Guide](https://developers.google.com/v8/embed) +* [V8 API Documentation](http://v8docs.nodesource.com/) + + + +### JavaScript-accessible methods + +A _template_ is a blueprint for JavaScript functions and objects in a context. You can use a template to wrap C++ functions and data structures within JavaScript objects so that they can be manipulated from JavaScript. See the V8 Embedders Guide section on [Templates](https://developers.google.com/v8/embed#templates) for further information. + +In order to expose functionality to JavaScript via a template, you must provide it to V8 in a form that it understands. Across the versions of V8 supported by NAN, JavaScript-accessible method signatures vary widely, NAN fully abstracts method declaration and provides you with an interface that is similar to the most recent V8 API but is backward-compatible with older versions that still use the now-deceased `v8::Argument` type. + +* **Method argument types** + - Nan::FunctionCallbackInfo + - Nan::PropertyCallbackInfo + - Nan::ReturnValue +* **Method declarations** + - Method declaration + - Getter declaration + - Setter declaration + - Property getter declaration + - Property setter declaration + - Property enumerator declaration + - Property deleter declaration + - Property query declaration + - Index getter declaration + - Index setter declaration + - Index enumerator declaration + - Index deleter declaration + - Index query declaration +* Method and template helpers + - Nan::SetMethod() + - Nan::SetNamedPropertyHandler() + - Nan::SetIndexedPropertyHandler() + - Nan::SetPrototypeMethod() + - Nan::SetTemplate() + - Nan::SetPrototypeTemplate() + - Nan::SetInstanceTemplate() + - Nan::SetCallHandler() + - Nan::SetCallAsFunctionHandler() + +### Scopes + +A _local handle_ is a pointer to an object. All V8 objects are accessed using handles, they are necessary because of the way the V8 garbage collector works. + +A handle scope can be thought of as a container for any number of handles. When you've finished with your handles, instead of deleting each one individually you can simply delete their scope. + +The creation of `HandleScope` objects is different across the supported versions of V8. Therefore, NAN provides its own implementations that can be used safely across these. + + - Nan::HandleScope + - Nan::EscapableHandleScope + +Also see the V8 Embedders Guide section on [Handles and Garbage Collection](https://developers.google.com/v8/embed#handles). + +### Persistent references + +An object reference that is independent of any `HandleScope` is a _persistent_ reference. Where a `Local` handle only lives as long as the `HandleScope` in which it was allocated, a `Persistent` handle remains valid until it is explicitly disposed. + +Due to the evolution of the V8 API, it is necessary for NAN to provide a wrapper implementation of the `Persistent` classes to supply compatibility across the V8 versions supported. + + - Nan::PersistentBase & v8::PersistentBase + - Nan::NonCopyablePersistentTraits & v8::NonCopyablePersistentTraits + - Nan::CopyablePersistentTraits & v8::CopyablePersistentTraits + - Nan::Persistent + - Nan::Global + - Nan::WeakCallbackInfo + - Nan::WeakCallbackType + +Also see the V8 Embedders Guide section on [Handles and Garbage Collection](https://developers.google.com/v8/embed#handles). + +### New + +NAN provides a `Nan::New()` helper for the creation of new JavaScript objects in a way that's compatible across the supported versions of V8. + + - Nan::New() + - Nan::Undefined() + - Nan::Null() + - Nan::True() + - Nan::False() + - Nan::EmptyString() + + +### Converters + +NAN contains functions that convert `v8::Value`s to other `v8::Value` types and native types. Since type conversion is not guaranteed to succeed, they return `Nan::Maybe` types. These converters can be used in place of `value->ToX()` and `value->XValue()` (where `X` is one of the types, e.g. `Boolean`) in a way that provides a consistent interface across V8 versions. Newer versions of V8 use the new `v8::Maybe` and `v8::MaybeLocal` types for these conversions, older versions don't have this functionality so it is provided by NAN. + + - Nan::To() + +### Maybe Types + +The `Nan::MaybeLocal` and `Nan::Maybe` types are monads that encapsulate `v8::Local` handles that _may be empty_. + +* **Maybe Types** + - Nan::MaybeLocal + - Nan::Maybe + - Nan::Nothing + - Nan::Just +* **Maybe Helpers** + - Nan::ToDetailString() + - Nan::ToArrayIndex() + - Nan::Equals() + - Nan::NewInstance() + - Nan::GetFunction() + - Nan::Set() + - Nan::ForceSet() + - Nan::Get() + - Nan::GetPropertyAttributes() + - Nan::Has() + - Nan::Delete() + - Nan::GetPropertyNames() + - Nan::GetOwnPropertyNames() + - Nan::SetPrototype() + - Nan::ObjectProtoToString() + - Nan::HasOwnProperty() + - Nan::HasRealNamedProperty() + - Nan::HasRealIndexedProperty() + - Nan::HasRealNamedCallbackProperty() + - Nan::GetRealNamedPropertyInPrototypeChain() + - Nan::GetRealNamedProperty() + - Nan::CallAsFunction() + - Nan::CallAsConstructor() + - Nan::GetSourceLine() + - Nan::GetLineNumber() + - Nan::GetStartColumn() + - Nan::GetEndColumn() + - Nan::CloneElementAt() + - Nan::MakeMaybe() + +### Script + +NAN provides a `v8::Script` helpers as the API has changed over the supported versions of V8. + + - Nan::CompileScript() + - Nan::RunScript() + + +### Errors + +NAN includes helpers for creating, throwing and catching Errors as much of this functionality varies across the supported versions of V8 and must be abstracted. + +Note that an Error object is simply a specialized form of `v8::Value`. + +Also consult the V8 Embedders Guide section on [Exceptions](https://developers.google.com/v8/embed#exceptions) for more information. + + - Nan::Error() + - Nan::RangeError() + - Nan::ReferenceError() + - Nan::SyntaxError() + - Nan::TypeError() + - Nan::ThrowError() + - Nan::ThrowRangeError() + - Nan::ThrowReferenceError() + - Nan::ThrowSyntaxError() + - Nan::ThrowTypeError() + - Nan::FatalException() + - Nan::ErrnoException() + - Nan::TryCatch + + +### Buffers + +NAN's `node::Buffer` helpers exist as the API has changed across supported Node versions. Use these methods to ensure compatibility. + + - Nan::NewBuffer() + - Nan::CopyBuffer() + - Nan::FreeCallback() + +### Nan::Callback + +`Nan::Callback` makes it easier to use `v8::Function` handles as callbacks. A class that wraps a `v8::Function` handle, protecting it from garbage collection and making it particularly useful for storage and use across asynchronous execution. + + - Nan::Callback + +### Asynchronous work helpers + +`Nan::AsyncWorker` and `Nan::AsyncProgressWorker` are helper classes that make working with asynchronous code easier. + + - Nan::AsyncWorker + - Nan::AsyncProgressWorker + - Nan::AsyncQueueWorker + +### Strings & Bytes + +Miscellaneous string & byte encoding and decoding functionality provided for compatibility across supported versions of V8 and Node. Implemented by NAN to ensure that all encoding types are supported, even for older versions of Node where they are missing. + + - Nan::Encoding + - Nan::Encode() + - Nan::DecodeBytes() + - Nan::DecodeWrite() + + +### V8 internals + +The hooks to access V8 internals—including GC and statistics—are different across the supported versions of V8, therefore NAN provides its own hooks that call the appropriate V8 methods. + + - NAN_GC_CALLBACK() + - Nan::AddGCEpilogueCallback() + - Nan::RemoveGCEpilogueCallback() + - Nan::AddGCPrologueCallback() + - Nan::RemoveGCPrologueCallback() + - Nan::GetHeapStatistics() + - Nan::SetCounterFunction() + - Nan::SetCreateHistogramFunction() + - Nan::SetAddHistogramSampleFunction() + - Nan::IdleNotification() + - Nan::LowMemoryNotification() + - Nan::ContextDisposedNotification() + - Nan::GetInternalFieldPointer() + - Nan::SetInternalFieldPointer() + - Nan::AdjustExternalMemory() + + +### Miscellaneous V8 Helpers + + - Nan::Utf8String + - Nan::GetCurrentContext() + - Nan::SetIsolateData() + - Nan::GetIsolateData() + - Nan::TypedArrayContents + + +### Miscellaneous Node Helpers + + - Nan::MakeCallback() + - Nan::ObjectWrap + - NAN_MODULE_INIT() + - Nan::Export() + + + + + +### Tests + +To run the NAN tests do: + +``` sh +npm install +npm run-script rebuild-tests +npm test +``` + +Or just: + +``` sh +npm install +make test +``` + + +## Governance & Contributing + +NAN is governed by the [io.js](https://iojs.org/) Addon API Working Group + +### Addon API Working Group (WG) + +The NAN project is jointly governed by a Working Group which is responsible for high-level guidance of the project. + +Members of the WG are also known as Collaborators, there is no distinction between the two, unlike other io.js projects. + +The WG has final authority over this project including: + +* Technical direction +* Project governance and process (including this policy) +* Contribution policy +* GitHub repository hosting +* Maintaining the list of additional Collaborators + +For the current list of WG members, see the project [README.md](./README.md#collaborators). + +Individuals making significant and valuable contributions are made members of the WG and given commit-access to the project. These individuals are identified by the WG and their addition to the WG is discussed via GitHub and requires unanimous consensus amongst those WG members participating in the discussion with a quorum of 50% of WG members required for acceptance of the vote. + +_Note:_ If you make a significant contribution and are not considered for commit-access log an issue or contact a WG member directly. + +For the current list of WG members / Collaborators, see the project [README.md](./README.md#collaborators). + +### Consensus Seeking Process + +The WG follows a [Consensus Seeking](http://en.wikipedia.org/wiki/Consensus-seeking_decision-making) decision making model. + +Modifications of the contents of the NAN repository are made on a collaborative basis. Anybody with a GitHub account may propose a modification via pull request and it will be considered by the WG. All pull requests must be reviewed and accepted by a WG member with sufficient expertise who is able to take full responsibility for the change. In the case of pull requests proposed by an existing WG member, an additional WG member is required for sign-off. Consensus should be sought if additional WG members participate and there is disagreement around a particular modification. + +If a change proposal cannot reach a consensus, a WG member can call for a vote amongst the members of the WG. Simple majority wins. + +### Developer's Certificate of Origin 1.0 + +By making a contribution to this project, I certify that: + +* (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or +* (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or +* (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. + + +### WG Members / Collaborators + + + + + + + + + +
Rod VaggGitHub/rvaggTwitter/@rvagg
Benjamin ByholmGitHub/kkoopa-
Trevor NorrisGitHub/trevnorrisTwitter/@trevnorris
Nathan RajlichGitHub/TooTallNateTwitter/@TooTallNate
Brett LawsonGitHub/brett19Twitter/@brett19x
Ben NoordhuisGitHub/bnoordhuisTwitter/@bnoordhuis
David SiegelGitHub/agnat-
+ +## Licence & copyright + +Copyright (c) 2015 NAN WG Members / Collaborators (listed above). + +Native Abstractions for Node.js is licensed under an MIT license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details. diff --git a/node_modules/nan/appveyor.yml b/node_modules/nan/appveyor.yml new file mode 100644 index 0000000..694f84e --- /dev/null +++ b/node_modules/nan/appveyor.yml @@ -0,0 +1,37 @@ +# http://www.appveyor.com/docs/appveyor-yml + +# Test against these versions of Io.js and Node.js. +environment: + matrix: + # node.js + - nodejs_version: "0.8" + - nodejs_version: "0.10" + - nodejs_version: "0.12" + - nodejs_version: "3" + - nodejs_version: "4" + +# Install scripts. (runs after repo cloning) +install: + # Get the latest stable version of Node 0.STABLE.latest + - ps: Install-Product node $env:nodejs_version + - IF %nodejs_version% EQU 0.8 npm -g install npm@2 + - IF %nodejs_version% EQU 0.8 set PATH=%APPDATA%\npm;%PATH% + - npm -g install npm + - IF %nodejs_version% NEQ 0.8 set PATH=%APPDATA%\npm;%PATH% + # Typical npm stuff. + - npm install + - npm run rebuild-tests + +# Post-install test scripts. +test_script: + # Output useful info for debugging. + - node --version + - npm --version + # run tests + - IF %nodejs_version% LSS 1 (npm test) ELSE (IF %nodejs_version% LSS 4 (iojs node_modules\tap\bin\tap.js --gc test/js/*-test.js) ELSE (node node_modules\tap\bin\tap.js --gc test/js/*-test.js)) + +# Don't actually build. +build: off + +# Set build version format here instead of in the admin panel. +version: "{build}" diff --git a/node_modules/nan/doc/.build.sh b/node_modules/nan/doc/.build.sh new file mode 100755 index 0000000..75a975a --- /dev/null +++ b/node_modules/nan/doc/.build.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +files=" \ + methods.md \ + scopes.md \ + persistent.md \ + new.md \ + converters.md \ + maybe_types.md \ + script.md \ + errors.md \ + buffers.md \ + callback.md \ + asyncworker.md \ + string_bytes.md \ + v8_internals.md \ + v8_misc.md \ + node_misc.md \ +" + +__dirname=$(dirname "${BASH_SOURCE[0]}") +head=$(perl -e 'while (<>) { if (!$en){print;} if ($_=~/ NanNew("foo").ToLocalChecked() */ + if (arguments[groups[3][0]] === 'NanNew') { + return [arguments[0], '.ToLocalChecked()'].join(''); + } + + /* insert warning for removed functions as comment on new line above */ + switch (arguments[groups[4][0]]) { + case 'GetIndexedPropertiesExternalArrayData': + case 'GetIndexedPropertiesExternalArrayDataLength': + case 'GetIndexedPropertiesExternalArrayDataType': + case 'GetIndexedPropertiesPixelData': + case 'GetIndexedPropertiesPixelDataLength': + case 'HasIndexedPropertiesInExternalArrayData': + case 'HasIndexedPropertiesInPixelData': + case 'SetIndexedPropertiesToExternalArrayData': + case 'SetIndexedPropertiesToPixelData': + return arguments[groups[4][0] - 1] ? arguments[0] : [warning1, arguments[0]].join(''); + default: + } + + /* remove unnecessary NanScope() */ + switch (arguments[groups[5][0]]) { + case 'NAN_GETTER': + case 'NAN_METHOD': + case 'NAN_SETTER': + case 'NAN_INDEX_DELETER': + case 'NAN_INDEX_ENUMERATOR': + case 'NAN_INDEX_GETTER': + case 'NAN_INDEX_QUERY': + case 'NAN_INDEX_SETTER': + case 'NAN_PROPERTY_DELETER': + case 'NAN_PROPERTY_ENUMERATOR': + case 'NAN_PROPERTY_GETTER': + case 'NAN_PROPERTY_QUERY': + case 'NAN_PROPERTY_SETTER': + return arguments[groups[5][0] - 1]; + default: + } + + /* Value converstion */ + switch (arguments[groups[6][0]]) { + case 'Boolean': + case 'Int32': + case 'Integer': + case 'Number': + case 'Object': + case 'String': + case 'Uint32': + return [arguments[groups[6][0] - 2], 'NanTo(', arguments[groups[6][0] - 1]].join(''); + default: + } + + /* other value conversion */ + switch (arguments[groups[7][0]]) { + case 'BooleanValue': + return [arguments[groups[7][0] - 2], 'NanTo(', arguments[groups[7][0] - 1]].join(''); + case 'Int32Value': + return [arguments[groups[7][0] - 2], 'NanTo(', arguments[groups[7][0] - 1]].join(''); + case 'IntegerValue': + return [arguments[groups[7][0] - 2], 'NanTo(', arguments[groups[7][0] - 1]].join(''); + case 'Uint32Value': + return [arguments[groups[7][0] - 2], 'NanTo(', arguments[groups[7][0] - 1]].join(''); + default: + } + + /* NAN_WEAK_CALLBACK */ + if (arguments[groups[8][0]] === 'NAN_WEAK_CALLBACK') { + return ['template\nvoid ', + arguments[groups[8][0] + 1], '(const NanWeakCallbackInfo &data)'].join(''); + } + + /* use methods on NAN classes instead */ + switch (arguments[groups[9][0]]) { + case 'NanDisposePersistent': + return [arguments[groups[9][0] + 1], '.Reset('].join(''); + case 'NanObjectWrapHandle': + return [arguments[groups[9][0] + 1], '->handle('].join(''); + default: + } + + /* use method on NanPersistent instead */ + if (arguments[groups[10][0]] === 'NanMakeWeakPersistent') { + return arguments[groups[10][0] + 1] + '.SetWeak('; + } + + /* These return Maybes, the upper ones take no arguments */ + switch (arguments[groups[11][0]]) { + case 'GetEndColumn': + case 'GetFunction': + case 'GetLineNumber': + case 'GetOwnPropertyNames': + case 'GetPropertyNames': + case 'GetSourceLine': + case 'GetStartColumn': + case 'NewInstance': + case 'ObjectProtoToString': + case 'ToArrayIndex': + case 'ToDetailString': + return [arguments[groups[11][0] - 2], 'Nan', arguments[groups[11][0]], '(', arguments[groups[11][0] - 1]].join(''); + case 'CallAsConstructor': + case 'CallAsFunction': + case 'CloneElementAt': + case 'Delete': + case 'ForceSet': + case 'Get': + case 'GetPropertyAttributes': + case 'GetRealNamedProperty': + case 'GetRealNamedPropertyInPrototypeChain': + case 'Has': + case 'HasOwnProperty': + case 'HasRealIndexedProperty': + case 'HasRealNamedCallbackProperty': + case 'HasRealNamedProperty': + case 'Set': + case 'SetAccessor': + case 'SetIndexedPropertyHandler': + case 'SetNamedPropertyHandler': + case 'SetPrototype': + return [arguments[groups[11][0] - 2], 'Nan', arguments[groups[11][0]], '(', arguments[groups[11][0] - 1], ', '].join(''); + default: + } + + /* Automatic ToLocalChecked(), take it or leave it */ + switch (arguments[groups[12][0]]) { + case 'Date': + case 'String': + case 'RegExp': + return ['NanNew', arguments[groups[12][0] - 1], arguments[groups[12][0] + 1], '.ToLocalChecked()'].join(''); + default: + } + + /* NanEquals is now required for uniformity */ + if (arguments[groups[13][0]] === 'Equals') { + return [arguments[groups[13][0] - 1], 'NanEquals(', arguments[groups[13][0] - 1], ', ', arguments[groups[13][0] + 1]].join(''); + } + + /* use method on replacement class instead */ + if (arguments[groups[14][0]] === 'NanAssignPersistent') { + return [arguments[groups[14][0] + 1], '.Reset('].join(''); + } + + /* args --> info */ + if (arguments[groups[15][0]] === 'args') { + return [arguments[groups[15][0] - 1], 'info', arguments[groups[15][0] + 1]].join(''); + } + + /* ObjectWrap --> NanObjectWrap */ + if (arguments[groups[16][0]] === 'ObjectWrap') { + return [arguments[groups[16][0] - 1], 'NanObjectWrap', arguments[groups[16][0] + 1]].join(''); + } + + /* Persistent --> NanPersistent */ + if (arguments[groups[17][0]] === 'Persistent') { + return [arguments[groups[17][0] - 1], 'NanPersistent', arguments[groups[17][0] + 1]].join(''); + } + + /* This should not happen. A switch is probably missing a case if it does. */ + throw 'Unhandled match: ' + arguments[0]; +} + +/* reads a file, runs replacement and writes it back */ +function processFile(file) { + fs.readFile(file, {encoding: 'utf8'}, function (err, data) { + if (err) { + throw err; + } + + /* run replacement twice, might need more runs */ + fs.writeFile(file, data.replace(master, replace).replace(master, replace), function (err) { + if (err) { + throw err; + } + }); + }); +} + +/* process file names from command line and process the identified files */ +for (i = 2, length = process.argv.length; i < length; i++) { + glob(process.argv[i], function (err, matches) { + if (err) { + throw err; + } + matches.forEach(processFile); + }); +} diff --git a/node_modules/nan/tools/README.md b/node_modules/nan/tools/README.md new file mode 100644 index 0000000..7f07e4b --- /dev/null +++ b/node_modules/nan/tools/README.md @@ -0,0 +1,14 @@ +1to2 naively converts source code files from NAN 1 to NAN 2. There will be erroneous conversions, +false positives and missed opportunities. The input files are rewritten in place. Make sure that +you have backups. You will have to manually review the changes afterwards and do some touchups. + +```sh +$ tools/1to2.js + + Usage: 1to2 [options] + + Options: + + -h, --help output usage information + -V, --version output the version number +``` diff --git a/node_modules/nan/tools/package.json b/node_modules/nan/tools/package.json new file mode 100644 index 0000000..2dcdd78 --- /dev/null +++ b/node_modules/nan/tools/package.json @@ -0,0 +1,19 @@ +{ + "name": "1to2", + "version": "1.0.0", + "description": "NAN 1 -> 2 Migration Script", + "main": "1to2.js", + "repository": { + "type": "git", + "url": "git://github.com/nodejs/nan.git" + }, + "contributors": [ + "Benjamin Byholm (https://github.com/kkoopa/)", + "Mathias Küsel (https://github.com/mathiask88/)" + ], + "dependencies": { + "glob": "~5.0.10", + "commander": "~2.8.1" + }, + "license": "MIT" +} diff --git a/node_modules/options/.npmignore b/node_modules/options/.npmignore new file mode 100644 index 0000000..1b18fb3 --- /dev/null +++ b/node_modules/options/.npmignore @@ -0,0 +1,7 @@ +npm-debug.log +node_modules +.*.swp +.lock-* +build/ + +test diff --git a/node_modules/options/Makefile b/node_modules/options/Makefile new file mode 100644 index 0000000..7496b6f --- /dev/null +++ b/node_modules/options/Makefile @@ -0,0 +1,12 @@ +ALL_TESTS = $(shell find test/ -name '*.test.js') + +run-tests: + @./node_modules/.bin/mocha \ + -t 2000 \ + $(TESTFLAGS) \ + $(TESTS) + +test: + @$(MAKE) NODE_PATH=lib TESTS="$(ALL_TESTS)" run-tests + +.PHONY: test diff --git a/node_modules/options/README.md b/node_modules/options/README.md new file mode 100644 index 0000000..0dabc75 --- /dev/null +++ b/node_modules/options/README.md @@ -0,0 +1,69 @@ +# options.js # + +A very light-weight in-code option parsers for node.js. + +## Usage ## + +``` js +var Options = require("options"); + +// Create an Options object +function foo(options) { + var default_options = { + foo : "bar" + }; + + // Create an option object with default value + var opts = new Options(default_options); + + // Merge options + opts = opts.merge(options); + + // Reset to default value + opts.reset(); + + // Copy selected attributes out + var seled_att = opts.copy("foo"); + + // Read json options from a file. + opts.read("options.file"); // Sync + opts.read("options.file", function(err){ // Async + if(err){ // If error occurs + console.log("File error."); + }else{ + // No error + } + }); + + // Attributes defined or not + opts.isDefinedAndNonNull("foobar"); + opts.isDefined("foobar"); +} + +``` + + +## License ## + +(The MIT License) + +Copyright (c) 2012 Einar Otto Stangvik <einaros@gmail.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/node_modules/options/lib/options.js b/node_modules/options/lib/options.js new file mode 100644 index 0000000..4fc45e9 --- /dev/null +++ b/node_modules/options/lib/options.js @@ -0,0 +1,86 @@ +/*! + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var fs = require('fs'); + +function Options(defaults) { + var internalValues = {}; + var values = this.value = {}; + Object.keys(defaults).forEach(function(key) { + internalValues[key] = defaults[key]; + Object.defineProperty(values, key, { + get: function() { return internalValues[key]; }, + configurable: false, + enumerable: true + }); + }); + this.reset = function() { + Object.keys(defaults).forEach(function(key) { + internalValues[key] = defaults[key]; + }); + return this; + }; + this.merge = function(options, required) { + options = options || {}; + if (Object.prototype.toString.call(required) === '[object Array]') { + var missing = []; + for (var i = 0, l = required.length; i < l; ++i) { + var key = required[i]; + if (!(key in options)) { + missing.push(key); + } + } + if (missing.length > 0) { + if (missing.length > 1) { + throw new Error('options ' + + missing.slice(0, missing.length - 1).join(', ') + ' and ' + + missing[missing.length - 1] + ' must be defined'); + } + else throw new Error('option ' + missing[0] + ' must be defined'); + } + } + Object.keys(options).forEach(function(key) { + if (key in internalValues) { + internalValues[key] = options[key]; + } + }); + return this; + }; + this.copy = function(keys) { + var obj = {}; + Object.keys(defaults).forEach(function(key) { + if (keys.indexOf(key) !== -1) { + obj[key] = values[key]; + } + }); + return obj; + }; + this.read = function(filename, cb) { + if (typeof cb == 'function') { + var self = this; + fs.readFile(filename, function(error, data) { + if (error) return cb(error); + var conf = JSON.parse(data); + self.merge(conf); + cb(); + }); + } + else { + var conf = JSON.parse(fs.readFileSync(filename)); + this.merge(conf); + } + return this; + }; + this.isDefined = function(key) { + return typeof values[key] != 'undefined'; + }; + this.isDefinedAndNonNull = function(key) { + return typeof values[key] != 'undefined' && values[key] !== null; + }; + Object.freeze(values); + Object.freeze(this); +} + +module.exports = Options; diff --git a/node_modules/options/package.json b/node_modules/options/package.json new file mode 100644 index 0000000..dd28db2 --- /dev/null +++ b/node_modules/options/package.json @@ -0,0 +1,76 @@ +{ + "_args": [ + [ + "options@>=0.0.5", + "/Applications/MAMP/htdocs/stream2/WebRTC-Example/node_modules/ws" + ] + ], + "_from": "options@>=0.0.5", + "_id": "options@0.0.6", + "_inCache": true, + "_installable": true, + "_location": "/options", + "_npmUser": { + "email": "einaros@gmail.com", + "name": "einaros" + }, + "_npmVersion": "1.4.21", + "_phantomChildren": {}, + "_requested": { + "name": "options", + "raw": "options@>=0.0.5", + "rawSpec": ">=0.0.5", + "scope": null, + "spec": ">=0.0.5", + "type": "range" + }, + "_requiredBy": [ + "/ws" + ], + "_resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "_shasum": "ec22d312806bb53e731773e7cdaefcf1c643128f", + "_shrinkwrap": null, + "_spec": "options@>=0.0.5", + "_where": "/Applications/MAMP/htdocs/stream2/WebRTC-Example/node_modules/ws", + "author": { + "email": "einaros@gmail.com", + "name": "Einar Otto Stangvik", + "url": "http://2x.io" + }, + "bugs": { + "url": "https://github.com/einaros/options.js/issues" + }, + "dependencies": {}, + "description": "A very light-weight in-code option parsers for node.js.", + "devDependencies": { + "mocha": "latest" + }, + "directories": {}, + "dist": { + "shasum": "ec22d312806bb53e731773e7cdaefcf1c643128f", + "tarball": "http://registry.npmjs.org/options/-/options-0.0.6.tgz" + }, + "engines": { + "node": ">=0.4.0" + }, + "gitHead": "ff53d0a092c897cb95964232a96fe17da65c11af", + "homepage": "https://github.com/einaros/options.js", + "main": "lib/options", + "maintainers": [ + { + "name": "einaros", + "email": "einaros@gmail.com" + } + ], + "name": "options", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git://github.com/einaros/options.js.git" + }, + "scripts": { + "test": "make test" + }, + "version": "0.0.6" +} diff --git a/node_modules/ultron/.npmignore b/node_modules/ultron/.npmignore new file mode 100644 index 0000000..66210a2 --- /dev/null +++ b/node_modules/ultron/.npmignore @@ -0,0 +1,3 @@ +node_modules +coverage +.tern-port diff --git a/node_modules/ultron/.travis.yml b/node_modules/ultron/.travis.yml new file mode 100644 index 0000000..a505004 --- /dev/null +++ b/node_modules/ultron/.travis.yml @@ -0,0 +1,21 @@ +sudo: false +language: node_js +node_js: + - "0.12" + - "0.10" + - "0.8" + - "iojs" +before_install: + - 'if [ "${TRAVIS_NODE_VERSION}" == "0.8" ]; then npm install -g npm@2.11.1; fi' +script: + - "npm run test-travis" +after_script: + - "npm install coveralls@2.11.x && cat coverage/lcov.info | coveralls" +matrix: + fast_finish: true +notifications: + irc: + channels: + - "irc.freenode.org#unshift" + on_success: change + on_failure: change diff --git a/node_modules/ultron/LICENSE b/node_modules/ultron/LICENSE new file mode 100644 index 0000000..6dc9316 --- /dev/null +++ b/node_modules/ultron/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Unshift.io, Arnout Kazemier, the Contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/node_modules/ultron/README.md b/node_modules/ultron/README.md new file mode 100644 index 0000000..84fa3f2 --- /dev/null +++ b/node_modules/ultron/README.md @@ -0,0 +1,97 @@ +# Ultron + +[![Made by unshift](https://img.shields.io/badge/made%20by-unshift-00ffcc.svg?style=flat-square)](http://unshift.io)[![Version npm](http://img.shields.io/npm/v/ultron.svg?style=flat-square)](http://browsenpm.org/package/ultron)[![Build Status](http://img.shields.io/travis/unshiftio/ultron/master.svg?style=flat-square)](https://travis-ci.org/unshiftio/ultron)[![Dependencies](https://img.shields.io/david/unshiftio/ultron.svg?style=flat-square)](https://david-dm.org/unshiftio/ultron)[![Coverage Status](http://img.shields.io/coveralls/unshiftio/ultron/master.svg?style=flat-square)](https://coveralls.io/r/unshiftio/ultron?branch=master)[![IRC channel](http://img.shields.io/badge/IRC-irc.freenode.net%23unshift-00a8ff.svg?style=flat-square)](http://webchat.freenode.net/?channels=unshift) + +Ultron is a high-intelligence robot. It gathers intelligence so it can start +improving upon his rudimentary design. It will learn your event emitting +patterns and find ways to exterminate them. Allowing you to remove only the +event emitters that **you** assigned and not the ones that your users or +developers assigned. This can prevent race conditions, memory leaks and even file +descriptor leaks from ever happening as you won't remove clean up processes. + +## Installation + +The module is designed to be used in browsers using browserify and in Node.js. +You can install the module through the public npm registry by running the +following command in CLI: + +``` +npm install --save ultron +``` + +## Usage + +In all examples we assume that you've required the library as following: + +```js +'use strict'; + +var Ultron = require('ultron'); +``` + +Now that we've required the library we can construct our first `Ultron` instance. +The constructor requires one argument which should be the `EventEmitter` +instance that we need to operate upon. This can be the `EventEmitter` module +that ships with Node.js or `EventEmitter3` or anything else as long as it +follow the same API and internal structure as these 2. So with that in mind we +can create the instance: + +```js +// +// For the sake of this example we're going to construct an empty EventEmitter +// +var EventEmitter = require('events').EventEmitter; // or require('eventmitter3'); +var events = new EventEmitter(); + +var ultron = new Ultron(events); +``` + +You can now use the following API's from the Ultron instance: + +### Ultron.on + +Register a new event listener for the given event. It follows the exact same API +as `EventEmitter.on` but it will return itself instead of returning the +EventEmitter instance. If you are using EventEmitter3 it also supports the +context param: + +```js +ultron.on('event-name', handler, { custom: 'function context' }); +``` + +### Ultron.once + +Exactly the same as the [Ultron.on](#ultronon) but it only allows the execution +once. + +### Ultron.remove + +This is where all the magic happens and the safe removal starts. This function +accepts different argument styles: + +- No arguments, assume that all events need to be removed so it will work as + `removeAllListeners()` API. +- 1 argument, when it's a string it will be split on ` ` and `,` to create a + list of events that need to be cleared. +- Multiple arguments, we assume that they are all names of events that need to + be cleared. + +```js +ultron.remove('foo, bar baz'); // Removes foo, bar and baz. +ultron.remove('foo', 'bar', 'baz'); // Removes foo, bar and baz. +ultron.remove(); // Removes everything. +``` + +If you just want to remove a single event listener using a function reference +you can still use the EventEmitter's `removeListener(event, fn)` API: + +```js +function foo() {} + +ulton.on('foo', foo); +events.removeListener('foo', foo); +``` + +## License + +MIT diff --git a/node_modules/ultron/index.js b/node_modules/ultron/index.js new file mode 100644 index 0000000..af17ab7 --- /dev/null +++ b/node_modules/ultron/index.js @@ -0,0 +1,129 @@ +'use strict'; + +var has = Object.prototype.hasOwnProperty; + +/** + * An auto incrementing id which we can use to create "unique" Ultron instances + * so we can track the event emitters that are added through the Ultron + * interface. + * + * @type {Number} + * @private + */ +var id = 0; + +/** + * Ultron is high-intelligence robot. It gathers intelligence so it can start improving + * upon his rudimentary design. It will learn from your EventEmitting patterns + * and exterminate them. + * + * @constructor + * @param {EventEmitter} ee EventEmitter instance we need to wrap. + * @api public + */ +function Ultron(ee) { + if (!(this instanceof Ultron)) return new Ultron(ee); + + this.id = id++; + this.ee = ee; +} + +/** + * Register a new EventListener for the given event. + * + * @param {String} event Name of the event. + * @param {Functon} fn Callback function. + * @param {Mixed} context The context of the function. + * @returns {Ultron} + * @api public + */ +Ultron.prototype.on = function on(event, fn, context) { + fn.__ultron = this.id; + this.ee.on(event, fn, context); + + return this; +}; +/** + * Add an EventListener that's only called once. + * + * @param {String} event Name of the event. + * @param {Function} fn Callback function. + * @param {Mixed} context The context of the function. + * @returns {Ultron} + * @api public + */ +Ultron.prototype.once = function once(event, fn, context) { + fn.__ultron = this.id; + this.ee.once(event, fn, context); + + return this; +}; + +/** + * Remove the listeners we assigned for the given event. + * + * @returns {Ultron} + * @api public + */ +Ultron.prototype.remove = function remove() { + var args = arguments + , event; + + // + // When no event names are provided we assume that we need to clear all the + // events that were assigned through us. + // + if (args.length === 1 && 'string' === typeof args[0]) { + args = args[0].split(/[, ]+/); + } else if (!args.length) { + args = []; + + for (event in this.ee._events) { + if (has.call(this.ee._events, event)) args.push(event); + } + } + + for (var i = 0; i < args.length; i++) { + var listeners = this.ee.listeners(args[i]); + + for (var j = 0; j < listeners.length; j++) { + event = listeners[j]; + + // + // Once listeners have a `listener` property that stores the real listener + // in the EventEmitter that ships with Node.js. + // + if (event.listener) { + if (event.listener.__ultron !== this.id) continue; + delete event.listener.__ultron; + } else { + if (event.__ultron !== this.id) continue; + delete event.__ultron; + } + + this.ee.removeListener(args[i], event); + } + } + + return this; +}; + +/** + * Destroy the Ultron instance, remove all listeners and release all references. + * + * @returns {Boolean} + * @api public + */ +Ultron.prototype.destroy = function destroy() { + if (!this.ee) return false; + + this.remove(); + this.ee = null; + + return true; +}; + +// +// Expose the module. +// +module.exports = Ultron; diff --git a/node_modules/ultron/package.json b/node_modules/ultron/package.json new file mode 100644 index 0000000..a4d5cb3 --- /dev/null +++ b/node_modules/ultron/package.json @@ -0,0 +1,100 @@ +{ + "_args": [ + [ + "ultron@1.0.x", + "/Applications/MAMP/htdocs/stream2/WebRTC-Example/node_modules/ws" + ] + ], + "_from": "ultron@>=1.0.0 <1.1.0", + "_id": "ultron@1.0.2", + "_inCache": true, + "_installable": true, + "_location": "/ultron", + "_nodeVersion": "0.12.3", + "_npmUser": { + "email": "npm@3rd-Eden.com", + "name": "3rdeden" + }, + "_npmVersion": "2.9.1", + "_phantomChildren": {}, + "_requested": { + "name": "ultron", + "raw": "ultron@1.0.x", + "rawSpec": "1.0.x", + "scope": null, + "spec": ">=1.0.0 <1.1.0", + "type": "range" + }, + "_requiredBy": [ + "/ws" + ], + "_resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "_shasum": "ace116ab557cd197386a4e88f4685378c8b2e4fa", + "_shrinkwrap": null, + "_spec": "ultron@1.0.x", + "_where": "/Applications/MAMP/htdocs/stream2/WebRTC-Example/node_modules/ws", + "author": { + "name": "Arnout Kazemier" + }, + "bugs": { + "url": "https://github.com/unshiftio/ultron/issues" + }, + "dependencies": {}, + "description": "Ultron is high-intelligence robot. It gathers intel so it can start improving upon his rudimentary design", + "devDependencies": { + "assume": "1.2.x", + "eventemitter3": "1.1.x", + "istanbul": "0.3.x", + "mocha": "2.2.x", + "pre-commit": "1.0.x" + }, + "directories": {}, + "dist": { + "shasum": "ace116ab557cd197386a4e88f4685378c8b2e4fa", + "tarball": "http://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz" + }, + "gitHead": "a10482ae98a09120821545456c90c6d60d540f7c", + "homepage": "https://github.com/unshiftio/ultron", + "keywords": [ + "Ultron", + "cleanup", + "emitter", + "event", + "eventemitter", + "events", + "gather", + "intelligence", + "robot" + ], + "license": "MIT", + "main": "index.js", + "maintainers": [ + { + "name": "unshift", + "email": "npm@unshift.io" + }, + { + "name": "v1", + "email": "info@3rd-Eden.com" + }, + { + "name": "3rdeden", + "email": "npm@3rd-Eden.com" + } + ], + "name": "ultron", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+https://github.com/unshiftio/ultron.git" + }, + "scripts": { + "100%": "istanbul check-coverage --statements 100 --functions 100 --lines 100 --branches 100", + "coverage": "istanbul cover ./node_modules/.bin/_mocha -- test.js", + "test": "mocha test.js", + "test-travis": "istanbul cover node_modules/.bin/_mocha --report lcovonly -- test.js", + "watch": "mocha --watch test.js" + }, + "version": "1.0.2" +} diff --git a/node_modules/ultron/test.js b/node_modules/ultron/test.js new file mode 100644 index 0000000..1fd4f1b --- /dev/null +++ b/node_modules/ultron/test.js @@ -0,0 +1,327 @@ +/* istanbul ignore next */ +describe('Ultron', function () { + 'use strict'; + + var EventEmitter = require('eventemitter3') + , EE = require('events').EventEmitter + , assume = require('assume') + , Ultron = require('./') + , ultron + , ee; + + beforeEach(function () { + ee = new EventEmitter(); + ultron = new Ultron(ee); + }); + + afterEach(function () { + ultron.destroy(); + ee.removeAllListeners(); + }); + + it('is exposed as a function', function () { + assume(Ultron).is.a('function'); + }); + + it('can be initialized without the new keyword', function () { + assume(Ultron(ee)).is.instanceOf(Ultron); + }); + + it('assigns a unique id to every instance', function () { + for (var i = 0; i < 100; i++) { + assume(ultron.id).does.not.equal((new Ultron()).id); + } + }); + + it('allows removal through the event emitter', function () { + function foo() {} + function bar() {} + + ultron.on('foo', foo); + ultron.once('foo', bar); + + assume(foo.__ultron).equals(ultron.id); + assume(bar.__ultron).equals(ultron.id); + assume(ee.listeners('foo').length).equals(2); + + ee.removeListener('foo', foo); + assume(ee.listeners('foo').length).equals(1); + + ee.removeListener('foo', bar); + assume(ee.listeners('foo').length).equals(0); + }); + + describe('#on', function () { + it('assigns a listener', function () { + assume(ee.listeners('foo').length).equals(0); + + function foo() {} + + ultron.on('foo', foo); + assume(ee.listeners('foo').length).equals(1); + assume(ee.listeners('foo')[0]).equals(foo); + }); + + it('tags the assigned function', function () { + assume(ee.listeners('foo').length).equals(0); + + ultron.on('foo', function () {}); + assume(ee.listeners('foo')[0].__ultron).equals(ultron.id); + }); + + it('also passes in the context', function (next) { + var context = 1313; + + ultron.on('foo', function (a, b, c) { + assume(a).equals('a'); + assume(b).equals('b'); + assume(c).equals('c'); + + assume(this).equals(context); + + next(); + }, context); + + ee.emit('foo', 'a', 'b', 'c'); + }); + + it('works with regular eventemitters as well', function (next) { + var ee = new EE() + , ultron = new Ultron(ee); + + ultron.on('foo', function (a, b, c) { + assume(a).equals('a'); + assume(b).equals('b'); + assume(c).equals('c'); + + next(); + }); + + ee.emit('foo', 'a', 'b', 'c'); + }); + }); + + describe('#once', function () { + it('assigns a listener', function () { + assume(ee.listeners('foo').length).equals(0); + + function foo() {} + ultron.once('foo', foo); + assume(ee.listeners('foo').length).equals(1); + assume(ee.listeners('foo')[0]).equals(foo); + }); + + it('tags the assigned function', function () { + assume(ee.listeners('foo').length).equals(0); + + ultron.once('foo', function () {}); + assume(ee.listeners('foo')[0].__ultron).equals(ultron.id); + }); + + it('also passes in the context', function (next) { + var context = 1313; + + ultron.once('foo', function (a, b, c) { + assume(a).equals('a'); + assume(b).equals('b'); + assume(c).equals('c'); + + assume(this).equals(context); + + next(); + }, context); + + ee.emit('foo', 'a', 'b', 'c'); + ee.emit('foo', 'a', 'b', 'c'); // Ensure that we don't double execute + }); + + it('works with regular eventemitters as well', function (next) { + var ee = new EE() + , ultron = new Ultron(ee); + + ultron.once('foo', function (a, b, c) { + assume(a).equals('a'); + assume(b).equals('b'); + assume(c).equals('c'); + + next(); + }); + + ee.emit('foo', 'a', 'b', 'c'); + ee.emit('foo', 'a', 'b', 'c'); // Ensure that we don't double execute + }); + }); + + describe('#remove', function () { + it('removes only our assigned `on` listeners', function () { + function foo() {} + function bar() {} + + ee.on('foo', foo); + ultron.on('foo', bar); + assume(ee.listeners('foo').length).equals(2); + + ultron.remove('foo'); + assume(ee.listeners('foo').length).equals(1); + assume(ee.listeners('foo')[0]).equals(foo); + }); + + it('removes our private __ultron references', function () { + function once() {} + function on() {} + + assume('__ultron' in once).is.false(); + assume('__ultron' in on).is.false(); + + ultron.on('foo', on); + ultron.once('bar', once); + + assume('__ultron' in once).is.true(); + assume('__ultron' in on).is.true(); + + ultron.remove('foo, bar'); + + assume('__ultron' in once).is.false(); + assume('__ultron' in on).is.false(); + + ultron.destroy(); + + ee = new EE(); + ultron = new Ultron(ee); + + assume('__ultron' in once).is.false(); + assume('__ultron' in on).is.false(); + + ultron.on('foo', on); + ultron.once('bar', once); + + assume('__ultron' in once).is.true(); + assume('__ultron' in on).is.true(); + + ultron.remove('foo, bar'); + + assume('__ultron' in once).is.false(); + assume('__ultron' in on).is.false(); + }); + + it('removes only our assigned `once` listeners', function () { + function foo() {} + function bar() {} + + ee.once('foo', foo); + ultron.once('foo', bar); + assume(ee.listeners('foo').length).equals(2); + + ultron.remove('foo'); + assume(ee.listeners('foo').length).equals(1); + assume(ee.listeners('foo')[0]).equals(foo); + }); + + it('removes only our assigned `once` listeners from regular EE', function () { + var ee = new EE() + , ultron = new Ultron(ee); + + function foo() {} + function bar() {} + + ee.once('foo', foo); + ultron.once('foo', bar); + assume(ee.listeners('foo').length).equals(2); + + ultron.remove('foo'); + assume(ee.listeners('foo').length).equals(1); + assume(ee.listeners('foo')[0].listener).equals(foo); + }); + + it('removes all assigned events if called without args', function () { + function foo() {} + function bar() {} + + ultron.on('foo', foo); + ultron.on('bar', bar); + + assume(ee.listeners('foo').length).equals(1); + assume(ee.listeners('bar').length).equals(1); + + ultron.remove(); + + assume(ee.listeners('foo').length).equals(0); + assume(ee.listeners('bar').length).equals(0); + }); + + it('removes multiple listeners based on args', function () { + function foo() {} + function bar() {} + function baz() {} + + ultron.on('foo', foo); + ultron.on('bar', bar); + ultron.on('baz', baz); + + assume(ee.listeners('foo').length).equals(1); + assume(ee.listeners('bar').length).equals(1); + assume(ee.listeners('baz').length).equals(1); + + ultron.remove('foo', 'bar'); + + assume(ee.listeners('foo').length).equals(0); + assume(ee.listeners('bar').length).equals(0); + assume(ee.listeners('baz').length).equals(1); + }); + + it('removes multiple listeners if first arg is seperated string', function () { + function foo() {} + function bar() {} + function baz() {} + + ultron.on('foo', foo); + ultron.on('bar', bar); + ultron.on('baz', baz); + + assume(ee.listeners('foo').length).equals(1); + assume(ee.listeners('bar').length).equals(1); + assume(ee.listeners('baz').length).equals(1); + + ultron.remove('foo, bar'); + + assume(ee.listeners('foo').length).equals(0); + assume(ee.listeners('bar').length).equals(0); + assume(ee.listeners('baz').length).equals(1); + }); + }); + + describe('#destroy', function () { + it('removes all listeners', function () { + function foo() {} + function bar() {} + function baz() {} + + ultron.on('foo', foo); + ultron.on('bar', bar); + ultron.on('baz', baz); + + assume(ee.listeners('foo').length).equals(1); + assume(ee.listeners('bar').length).equals(1); + assume(ee.listeners('baz').length).equals(1); + + ultron.destroy(); + + assume(ee.listeners('foo').length).equals(0); + assume(ee.listeners('bar').length).equals(0); + assume(ee.listeners('baz').length).equals(0); + }); + + it('removes the .ee reference', function () { + assume(ultron.ee).equals(ee); + ultron.destroy(); + assume(ultron.ee).equals(null); + }); + + it('returns booleans for state indication', function () { + assume(ultron.destroy()).is.true(); + assume(ultron.destroy()).is.false(); + assume(ultron.destroy()).is.false(); + assume(ultron.destroy()).is.false(); + }); + }); +}); diff --git a/node_modules/utf-8-validate/.npmignore b/node_modules/utf-8-validate/.npmignore new file mode 100644 index 0000000..0c90f67 --- /dev/null +++ b/node_modules/utf-8-validate/.npmignore @@ -0,0 +1,3 @@ +npm-debug.log +node_modules +build diff --git a/node_modules/utf-8-validate/.travis.yml b/node_modules/utf-8-validate/.travis.yml new file mode 100644 index 0000000..cd09de2 --- /dev/null +++ b/node_modules/utf-8-validate/.travis.yml @@ -0,0 +1,16 @@ +language: node_js +node_js: + - "iojs-v3" + - "iojs-v2" + - "iojs-v1" + - "0.12" + - "0.10" +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-4.9 + - g++-4.9 +before_install: + - export CC="gcc-4.9" CXX="g++-4.9" diff --git a/node_modules/utf-8-validate/README.md b/node_modules/utf-8-validate/README.md new file mode 100644 index 0000000..7e6d7e6 --- /dev/null +++ b/node_modules/utf-8-validate/README.md @@ -0,0 +1,44 @@ +# utf-8-validate + +[![Build Status](https://travis-ci.org/websockets/utf-8-validate.svg?branch=master)](https://travis-ci.org/websockets/utf-8-validate) + +WebSocket connections require extensive UTF-8 validation in order to confirm to +the specification. This was unfortunately not possible in JavaScript, hence the +need for a binary addon. + +As the module consists of binary components, it should be used an +`optionalDependency` so when installation fails, it doesn't halt the +installation of your module. There are fallback files available in this +repository. See `fallback.js` for the suggest fallback implementation if +installation fails. + +## Installation + +``` +npm install utf-8-validate +``` + +## API + +In all examples we assume that you've already required the mdoule as +followed: + +```js +'use strict'; + +var isValid = require('utf-8-validate').isValidUTF8; +``` + +The module exposes 1 function: + +#### isValidUTF8 + +Validate if the passed in buffer contains valid UTF-8 chars. + +```js +bu.isValidUTF8(buffer); +``` + +## License + +MIT diff --git a/node_modules/utf-8-validate/binding.gyp b/node_modules/utf-8-validate/binding.gyp new file mode 100644 index 0000000..34222db --- /dev/null +++ b/node_modules/utf-8-validate/binding.gyp @@ -0,0 +1,11 @@ +{ + 'targets': [ + { + 'target_name': 'validation', + 'include_dirs': ["> $(depfile) +# Add extra rules as in (2). +# We remove slashes and replace spaces with new lines; +# remove blank lines; +# delete the first line and append a colon to the remaining lines. +sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ + grep -v '^$$' |\ + sed -e 1d -e 's|$$|:|' \ + >> $(depfile) +rm $(depfile).raw +endef + +# Command definitions: +# - cmd_foo is the actual command to run; +# - quiet_cmd_foo is the brief-output summary of the command. + +quiet_cmd_cc = CC($(TOOLSET)) $@ +cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_cxx = CXX($(TOOLSET)) $@ +cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_objc = CXX($(TOOLSET)) $@ +cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< + +quiet_cmd_objcxx = CXX($(TOOLSET)) $@ +cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# Commands for precompiled header files. +quiet_cmd_pch_c = CXX($(TOOLSET)) $@ +cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_cc = CXX($(TOOLSET)) $@ +cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_m = CXX($(TOOLSET)) $@ +cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< +quiet_cmd_pch_mm = CXX($(TOOLSET)) $@ +cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# gyp-mac-tool is written next to the root Makefile by gyp. +# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd +# already. +quiet_cmd_mac_tool = MACTOOL $(4) $< +cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@" + +quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@ +cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4) + +quiet_cmd_infoplist = INFOPLIST $@ +cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@" + +quiet_cmd_touch = TOUCH $@ +cmd_touch = touch $@ + +quiet_cmd_copy = COPY $@ +# send stderr to /dev/null to ignore messages when linking directories. +cmd_copy = rm -rf "$@" && cp -af "$<" "$@" + +quiet_cmd_alink = LIBTOOL-STATIC $@ +cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^) + +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) + + +# Define an escape_quotes function to escape single quotes. +# This allows us to handle quotes properly as long as we always use +# use single quotes and escape_quotes. +escape_quotes = $(subst ','\'',$(1)) +# This comment is here just to include a ' to unconfuse syntax highlighting. +# Define an escape_vars function to escape '$' variable syntax. +# This allows us to read/write command lines with shell variables (e.g. +# $LD_LIBRARY_PATH), without triggering make substitution. +escape_vars = $(subst $$,$$$$,$(1)) +# Helper that expands to a shell command to echo a string exactly as it is in +# make. This uses printf instead of echo because printf's behaviour with respect +# to escape sequences is more portable than echo's across different shells +# (e.g., dash, bash). +exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' + +# Helper to compare the command we're about to run against the command +# we logged the last time we ran the command. Produces an empty +# string (false) when the commands match. +# Tricky point: Make has no string-equality test function. +# The kernel uses the following, but it seems like it would have false +# positives, where one string reordered its arguments. +# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ +# $(filter-out $(cmd_$@), $(cmd_$(1)))) +# We instead substitute each for the empty string into the other, and +# say they're equal if both substitutions produce the empty string. +# .d files contain ? instead of spaces, take that into account. +command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\ + $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) + +# Helper that is non-empty when a prerequisite changes. +# Normally make does this implicitly, but we force rules to always run +# so we can check their command lines. +# $? -- new prerequisites +# $| -- order-only dependencies +prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) + +# Helper that executes all postbuilds until one fails. +define do_postbuilds + @E=0;\ + for p in $(POSTBUILDS); do\ + eval $$p;\ + E=$$?;\ + if [ $$E -ne 0 ]; then\ + break;\ + fi;\ + done;\ + if [ $$E -ne 0 ]; then\ + rm -rf "$@";\ + exit $$E;\ + fi +endef + +# do_cmd: run a command via the above cmd_foo names, if necessary. +# Should always run for a given target to handle command-line changes. +# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. +# Third argument, if non-zero, makes it do POSTBUILDS processing. +# Note: We intentionally do NOT call dirx for depfile, since it contains ? for +# spaces already and dirx strips the ? characters. +define do_cmd +$(if $(or $(command_changed),$(prereq_changed)), + @$(call exact_echo, $($(quiet)cmd_$(1))) + @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" + $(if $(findstring flock,$(word 2,$(cmd_$1))), + @$(cmd_$(1)) + @echo " $(quiet_cmd_$(1)): Finished", + @$(cmd_$(1)) + ) + @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) + @$(if $(2),$(fixup_dep)) + $(if $(and $(3), $(POSTBUILDS)), + $(call do_postbuilds) + ) +) +endef + +# Declare the "all" target first so it is the default, +# even though we don't have the deps yet. +.PHONY: all +all: + +# make looks for ways to re-generate included makefiles, but in our case, we +# don't have a direct way. Explicitly telling make that it has nothing to do +# for them makes it go faster. +%.d: ; + +# Use FORCE_DO_CMD to force a target to run. Should be coupled with +# do_cmd. +.PHONY: FORCE_DO_CMD +FORCE_DO_CMD: + +TOOLSET := target +# Suffix rules, putting all outputs into $(obj). +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + + +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,validation.target.mk)))),) + include validation.target.mk +endif + +quiet_cmd_regen_makefile = ACTION Regenerating $@ +cmd_regen_makefile = cd $(srcdir); /usr/local/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "--toplevel-dir=." -I/Applications/MAMP/htdocs/stream2/WebRTC-Example/node_modules/utf-8-validate/build/config.gypi -I/usr/local/lib/node_modules/npm/node_modules/node-gyp/addon.gypi -I/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/vincenthofmeister/.node-gyp/5.1.0" "-Dnode_gyp_dir=/usr/local/lib/node_modules/npm/node_modules/node-gyp" "-Dnode_lib_file=node.lib" "-Dmodule_root_dir=/Applications/MAMP/htdocs/stream2/WebRTC-Example/node_modules/utf-8-validate" binding.gyp +Makefile: $(srcdir)/../../../../../../../Users/vincenthofmeister/.node-gyp/5.1.0/include/node/common.gypi $(srcdir)/../../../../../../../usr/local/lib/node_modules/npm/node_modules/node-gyp/addon.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp + $(call do_cmd,regen_makefile) + +# "all" is a concatenation of the "all" targets from all the included +# sub-makefiles. This is just here to clarify. +all: + +# Add in dependency-tracking rules. $(all_deps) is the list of every single +# target in our tree. Only consider the ones with .d (dependency) info: +d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) +ifneq ($(d_files),) + include $(d_files) +endif diff --git a/node_modules/utf-8-validate/build/Release/.deps/Release/obj.target/validation/src/validation.o.d b/node_modules/utf-8-validate/build/Release/.deps/Release/obj.target/validation/src/validation.o.d new file mode 100644 index 0000000..ca337d6 --- /dev/null +++ b/node_modules/utf-8-validate/build/Release/.deps/Release/obj.target/validation/src/validation.o.d @@ -0,0 +1,48 @@ +cmd_Release/obj.target/validation/src/validation.o := c++ '-DNODE_GYP_MODULE_NAME=validation' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DBUILDING_NODE_EXTENSION' -I/Users/vincenthofmeister/.node-gyp/5.1.0/include/node -I/Users/vincenthofmeister/.node-gyp/5.1.0/src -I/Users/vincenthofmeister/.node-gyp/5.1.0/deps/uv/include -I/Users/vincenthofmeister/.node-gyp/5.1.0/deps/v8/include -I../../nan -Os -gdwarf-2 -mmacosx-version-min=10.5 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -std=gnu++0x -fno-rtti -fno-exceptions -fno-threadsafe-statics -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/validation/src/validation.o.d.raw -c -o Release/obj.target/validation/src/validation.o ../src/validation.cc +Release/obj.target/validation/src/validation.o: ../src/validation.cc \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/v8.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/v8-version.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/v8config.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node_version.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node_buffer.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node_object_wrap.h \ + ../../nan/nan.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-errno.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-version.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-unix.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-threadpool.h \ + /Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-darwin.h \ + ../../nan/nan_callbacks.h ../../nan/nan_callbacks_12_inl.h \ + ../../nan/nan_maybe_43_inl.h ../../nan/nan_converters.h \ + ../../nan/nan_converters_43_inl.h ../../nan/nan_new.h \ + ../../nan/nan_implementation_12_inl.h \ + ../../nan/nan_persistent_12_inl.h ../../nan/nan_weak.h \ + ../../nan/nan_object_wrap.h ../../nan/nan_typedarray_contents.h +../src/validation.cc: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/v8.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/v8-version.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/v8config.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node_version.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node_buffer.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/node_object_wrap.h: +../../nan/nan.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-errno.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-version.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-unix.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-threadpool.h: +/Users/vincenthofmeister/.node-gyp/5.1.0/include/node/uv-darwin.h: +../../nan/nan_callbacks.h: +../../nan/nan_callbacks_12_inl.h: +../../nan/nan_maybe_43_inl.h: +../../nan/nan_converters.h: +../../nan/nan_converters_43_inl.h: +../../nan/nan_new.h: +../../nan/nan_implementation_12_inl.h: +../../nan/nan_persistent_12_inl.h: +../../nan/nan_weak.h: +../../nan/nan_object_wrap.h: +../../nan/nan_typedarray_contents.h: diff --git a/node_modules/utf-8-validate/build/Release/.deps/Release/validation.node.d b/node_modules/utf-8-validate/build/Release/.deps/Release/validation.node.d new file mode 100644 index 0000000..77e9ea2 --- /dev/null +++ b/node_modules/utf-8-validate/build/Release/.deps/Release/validation.node.d @@ -0,0 +1 @@ +cmd_Release/validation.node := c++ -bundle -undefined dynamic_lookup -Wl,-search_paths_first -mmacosx-version-min=10.5 -arch x86_64 -L./Release -o Release/validation.node Release/obj.target/validation/src/validation.o diff --git a/node_modules/utf-8-validate/build/Release/obj.target/validation/src/validation.o b/node_modules/utf-8-validate/build/Release/obj.target/validation/src/validation.o new file mode 100644 index 0000000000000000000000000000000000000000..bfc8a0cd55bded98a8b72e6a5f8ad4a9b4400434 GIT binary patch literal 184892 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 No|s^)C`4+p{2yIY#|{7h literal 0 HcmV?d00001 diff --git a/node_modules/utf-8-validate/build/Release/validation.node b/node_modules/utf-8-validate/build/Release/validation.node new file mode 100755 index 0000000000000000000000000000000000000000..681272104867cc515d12cc73f17251a0ff0940ac GIT binary patch literal 19748 zcmeHP4|G)3nST>Ph(I#YqEd@>u)&RgNM-^FLBY+K49qM;8c9G}!N+9sl8j7d(wUbK z6f~HCjKg5Ir`uYkEnBsvRy`h%W|6vW5G&B?S?k)Cs$0S0_T^9&T8jdf+242nOy0aC zXzSVC({pl9?)|>sz2EoUd%t)8ym{}w{Kx5c&Q4Mk+XO{X@)4&Z9-pWvn|o~F6y>vs z-8qV)s*RqNjVvoWab!b9VAxb(Mj=W;Rduaf=RC*R_6Dc$vWbEcMzzBsSLqoBWG}9F zHpMep*7m({5iiQ;-B1V%mKEd+dwIeFx2Lvg;SMc^JgdEzFXn6$HbfC4s;afAEwMnm#&fOhtG<-y4+#S3$GE^m9W_!_1DEkSgNY+QM#xhU2W-%1V`ArZzdO} zxlVzw+1`0PJCnkH0X>j`Bkb)I_I3&p!e)EJnw+ES>P1vlzprkIr`9Le6sM4M2r6)~ z7&p{UnGU1j2AR63chn^k}$%Z9j(YMi8$b;e_5 z;ZPIBxZWJR`s&ikQVhvZ6N(XNy*2CEYzMIn*s}B**2i_Nz4V52=_$&O;P!02)?iSL zm%7Yq$`z=O+T8=cIY7xLgvpQNVcY}b9vJt)xCj1zJm7Bdr!JlMemd=LNY5&prYQEy zl=Q4pF#Y|@y@|KoH@R21m%AGqTnD|I)Aqi9!zSuaUHEnZkxTb5H1XGkgbJPo^0-dg z2WAv5vJWiyOigOqJlCLi{%L#fW)!)5(-Z7>-wtkRDr#F2oc1HX?X~n#UA?dW#&kOU5(<8ZxCQYs;BO;tN4yh}UH=sg-rheryoobLJMQiL zsm??G#0TEQ3&yLs&G9DQG#;Yt#0SRD2=_kkxY>Qn>V2f@O)b3RGq@`n+5ibTmdM(4 zU*fDU`FU^hc89ljpTnD6oVE{CPgyvC_H|D2Cf8kNtc9^-1wW=1Qys6dy7n8_z>+Vq z-d_wKUaBIs zv7fqj3U`a%LVXx4sX2y(^>uDFX72PwnDq@RbeL4V@E zjdzjfI_XdRo|SqN`+iLKchts5Ncv(@PwY27$LO16WgGG#=iU6ey>BL5;7wLMjC(9H zaRx=wE8fI&#?vI4s`xgpo(m%h75?6vc+H3)+n>@ne8JGTK{9X^SmQy4_Z#15l+{W3 zzQprOHy_0uNBfLBsVr474L8KDSDwLWNK-3=OoKP=eu%O9erw!{Y}Y~f$D8=AKk=5a zhAD5{Wju}FE5=-I>X*3FHJO^8F{Q62&pr-OIN8W!`TLE@pnRyINB+bq;|K)k3K?sN z>3zPQ#xlE{Mn7_fehDWSTZsEdwAR=_+$!Q?;EwIczUB_P<`19%77viqCxZV8-F+L! zC>QSEUqd&x3MeiOQTDsUo1Eyh1N9CTc@qj>nT8Vy{EIPPgmqLeFn)($n6e6Z(U0c*in0Vxr5B**5T@CxSNPPiNwF@|a5O%;3tXb=5ZFbdHc=?|I# zRpgBn8Axs1P2TtbKO#_1Z+DS$2WsoiKZbdUW_0I!d-ty~wn4OSP`68wW^Zz3{;?2m zLu%v8Wa259Fy=$h2jF71D=M>xz=f0xPt!pECb<}s;%elH6()x%ZG72?!ql-=)_|30 zz`ixc5#-Q#e49}=f+q`Ou<?FmMx7*um^z@#w zdF{1(Vc(ZnM9$o8`~}w<&a4vag;56aq16~n(rau_gy%|piC_5=ANUd<8B1BMKV?(s z=hPb*@+aOk-hnMz0NyixLRL)+zz=|pi>M{&$|a1lt|Yk}^UHT(3A(hBoJF>I^6v&- ziotZLFFB9QFCaCHk^;5_((>?i%1Kq+c{-hDi^F?tDxEOukdLJt&0|Zshr|;5XceE# z*hA=hiD|2Fo#g8N#A!cvl&r!bdiG}&A{lCggVY@9A$yW{av~_G_R^NnT{>`h0 z`pji=M%aztVO>nu;QEr#K8)VW_`2~F1}jGIg+P0JG0m1ZtqW2A?!Vm-|L z3-4q6a^p$1H^>F$tAym5mGR+PHis%Y7%6xXWDoA`6l1EWkKNy~UC`l6q?ab=(OTk9 zoHYInsin!*e0T4L;(W!vnO1vWvbLD5LtnYaJEiByq@KNK%)#DMIq@~Vq>6RRNkiyq zNMh*fb{dP5y~!!w>+ldMNpW|EygmKuFt0i7#qok zWie~uU3r-1Nva@7U1@`u;iitK7S83xTX^vtDsH9X%Xu+dYf=@hyx2{}w^H#06!)iR zg|S4YXGK`r!BSc@)3bDzcCoaZrMIz^?rGAq?qF#TOYdT7A4|8ebSq2mVd*xOZf9vf zOTWs}ud(#&EWMAV_p@{dOTW$1ohOX+SaJ?ncc-Nn*JSo$bSA7|+kEPaxtPqB1> zrMp?Who#T5^v5h6Wa)EAX;rv1fbDMR=%3PQ@T-YG#Q84~|03s?6Fo`Gv%HbACSYVa`_&zlQTJ;u|?Xn|LqhuOxl}=VuY`mU1{zBpv&Yw^G`+sEpEg;_D{CUK`!TE{Azsz|X@y~PqFIbd@c5|NY z8iyX`{GW;6$@vq+e~t6+5Wki4boV&4f%9(@-@*AK#5Z&PzldMS`QH%l=lm~;ujc$O zh@Z>(mxwRn{6XSpaQ>&n7jb?s@wuG;cj7-h!TSCT@qgev-B%7B22W$+?>X2$CgfPc z1QBu(CL&PZdz^@lLc{|TdK~$u5$_7cR|LYL=H-oxsuacr^iVXS-0{VxTeYBmQ!LP- zlr4{Iv3OZmC=%2ndRw%mT?^qsY^>j@J1<4ni0L^%2HpvP7B0pwSeAMa;36NYf)xe%02BJ`g)WtkHkhPy-5qKMInmf zs^fZxQ=yESKsekK2(DGA#@W~N!i5V_$}`#mk>;?bS}La}`=yID9sTdrO0IN3p{wfJ zYyHt+AiRJ$?u_fNy|zwUR}zXx!vS5p#*t<6O64Z<6|Z3S^}Yxk6bXbEg|u*UO|+A` z%v!l96pQPQK&-X19e!{`G_5)A(4&qf%@J@kb+)wNty^hnSv(dj>!J(8E=OrFs0<@K z-BuL5hGOq_a7kGpimi}>&4#~#ZG!FmDY>>^tej}0cZgmTP?YZjiO1~+p1T())m$?V zHgjj>C=+jjp|%_)=VXpD;q*i$$2m#KU53SCRlZ_t!Rm^A#rDy8%7mFp4mE`Z+KegK zZd<0=i+d`BH>HNVuxLw8O+lWocha`J)Wq$%_fm6|Vnjd1 z<6Qna%A_FW7x(6Fha}n65zh*__pNr9^yY2LSmkyff_#~f$4_D&q+J2Y?u&@`V_l(8 z^a<>K1o_*r22-fC%KLg*E68p!%C_PW6$Sb|%z~_c=}12`LZ<&cF27xfXZ#@SlD{@U zZrPu?9B#LGkah(mxrZP(SIE&dVL{5>(3|o9i;yc3a@9gCQ?E&md|oZ&9y^B|#+35H zCumg5d-9rBChuA zg`6Iq$!XE$oXYp%Z;1EehM?~Y%3g#)bSnKMN0=^Xv7k;t7YOPVv{BGCf`$d{7PL>$ zenEE#x=YZf1RWIgML`b&}RibAn2=tUW^9_6v{Zsq}#**eghA1&Ea1&1KXTC&X0Rw+ymnt827-q z2gW@x?tyU+jC)|*1LGbT_rSOZxCg30@Bk#QT2S$PEU#YRm4dDjv`tWY{y=)&g7yfy zRnUGx?-O*Vpt}TpLeSlU4hnie(3b^0BsGyEvQ$}dO=qTx<=48K|2KP7PLput%CLodLJnM@(v)u!|1%-0zV<};KkGO zdvdQkf4lAd3H><(Ip58hJfr$?+vFJ?=okVX{EZ_b6UbwpBYnq@_E}%QJ=*0^4eUVv{yt70ui!j#$-=E$GZxH zpV}`m$y0me^IF2BZ^op5`~nmp=t5s&sZVcZDG(ujGba5D#DnqELSJH%r~2jdTB&cw zq(4LG+jDvQC6@Z~ahKFLW74k@`o%(DVyRz^Hc*iI)eLb=`rSgmTIfqG^&dCM*CEr4 zN&gD*-1HWqFR|1&_m}j|nDm`Ozgy@_EcMO(C4Dm{eZSEEs?e8M>Wk$i(|hTm|glEKBJWlo`XcLUUXO zIyUfmV0yPhVS~W03VbhcA0!#nX%XHG05G zE`P~_@##!f`2q{xYQYCA_=E*thH+r7Z-)gRvfw;iYqR`J3tncyU$@{tSnza=3$wi& zEx5~qzh%L%Snvhdhs^dGEch!Hyvu@Lvfw{j@E33v(rmxef`4Gahb_3MC|myq3yxcG zis2qq$-}=`@D47IU5^KvH|F+z2!MN_!sDQ~fYNT#Fb+Y)6bBMiDy@zk*2LfYR5cI$|ec7veg^Zp8J7w;|q+xB-z4JKceZ*Jw%) z;wHqq5PK2(5H}-kLA)DrD`Eoi9>gT#HpG6!FC(gm8e$4@JL0{FHzTe>T!Ywx*oye~ z)(3}D=I-bShl1>-e!Og{due@Ho8BA^#>?RkOuG0IjU4GZbzv6Nd#%=L6`p!2d!;%e1f-h-+my(^0D90E4ERPAFIp zEJX2PT>4V8uDq+Nf}OhX)itP<{M3cV;~_2lMFJ6u zI7kA8a;F;8TG=@iUIp`M7ZugbsS8BrgxWj&<#QI{+fO>sQX>wA&>;;RGx022LY0*} zt>r#^1&qpFYQ+jV3^Jl}H7E?lRaZGaFAbwLf7|((t}5PS2f8z9_B3y1odcay^lQWs+8BhQG>H^qQ~Q59j;&0 zg+4c^WA(V9e0Xqp>Im^6+fb=`fNNBYpK^76L#Q+6DjH#P?AmI}$Fk-sHy^SRlgL$R&aA~*DmH=S^lfm$ zEi^6t{>;#w6F2P9oiuNLSKTRlo#nSGAt=U-)N zo{yi*qzXR9OpS}RBBL>CT^XlX`y+kAS~r)sU2Y;S7dA~F{^Lmir)9An$lU?lyqYLF z-L2D2h3uO}yWG{F=_AjMdO~9<@Ewbc%g$$2Ioc*ST=|F{(B;A@Sh+2JeB(bxpYL#^ zZndsT=_2VjvE_^^J+hM@yGLhj(efHJ%w;>Yn|A2z4LalBa;GOA40HsV!eX?t0bI#4 zHBWuk(3Lx!yf&ljjy2TES5&#m8>8&rft_?7_5c;lsSU+DqH%3;INB5le_YK_sN#~i zam3An7Sm|>Wi>Z5LZ}xb=LagSS{hiZ(PlnIb@g4+@1ySd(&t^K0S>G4Yw)`vb`G=B zf5M-xO6wf(gt7+p@cpKkMN+Y9l$nzmghHs?*$|Gd!!Xa19iCu9Y)&~E;SS>-PHV1@ zvc<|5v8dErZO?(un6rj_PU9}q`i2TM)AI)QFOAsR!R~u8U>@mu+0% zp$)fMUR#$FJ*(-A;qvRl<0(@*x3Mi2UFYczY8~{WD7&qhhRIfC)aDHvl}lKr>s6j^ ze$suENjfYf*OYniP#yj^Qg+Riyi2BGQze&$kuIIf^yyBU`*SYcaYB{cGp{~|?IxzL zck6IyQz!1}WoPDRdOe@HE*6W%&e;mK6IR~9PUO>W7MCkl_U|(DFGU)TW;Nb4+9fi- zYKP~Y*aXb-m3}SKs<&Ay5JOVBX9?M3Ke?(JqhjOCnjhAEh7>ZFNnB-iX_~`)2uIen b!%b=+j_*8lHKs=tmHj5;x8IrH*~${"): + lines[i] = None + lines[i - 1] = None + lines = '\n'.join(filter(lambda x: x is not None, lines)) + + # Write out the file with variables replaced. + fd = open(dest, 'w') + fd.write(lines) + fd.close() + + # Now write out PkgInfo file now that the Info.plist file has been + # "compiled". + self._WritePkgInfo(dest) + + if convert_to_binary == 'True': + self._ConvertToBinary(dest) + + def _WritePkgInfo(self, info_plist): + """This writes the PkgInfo file from the data stored in Info.plist.""" + plist = plistlib.readPlist(info_plist) + if not plist: + return + + # Only create PkgInfo for executable types. + package_type = plist['CFBundlePackageType'] + if package_type != 'APPL': + return + + # The format of PkgInfo is eight characters, representing the bundle type + # and bundle signature, each four characters. If that is missing, four + # '?' characters are used instead. + signature_code = plist.get('CFBundleSignature', '????') + if len(signature_code) != 4: # Wrong length resets everything, too. + signature_code = '?' * 4 + + dest = os.path.join(os.path.dirname(info_plist), 'PkgInfo') + fp = open(dest, 'w') + fp.write('%s%s' % (package_type, signature_code)) + fp.close() + + def ExecFlock(self, lockfile, *cmd_list): + """Emulates the most basic behavior of Linux's flock(1).""" + # Rely on exception handling to report errors. + fd = os.open(lockfile, os.O_RDONLY|os.O_NOCTTY|os.O_CREAT, 0o666) + fcntl.flock(fd, fcntl.LOCK_EX) + return subprocess.call(cmd_list) + + def ExecFilterLibtool(self, *cmd_list): + """Calls libtool and filters out '/path/to/libtool: file: foo.o has no + symbols'.""" + libtool_re = re.compile(r'^.*libtool: file: .* has no symbols$') + libtool_re5 = re.compile( + r'^.*libtool: warning for library: ' + + r'.* the table of contents is empty ' + + r'\(no object file members in the library define global symbols\)$') + env = os.environ.copy() + # Ref: + # http://www.opensource.apple.com/source/cctools/cctools-809/misc/libtool.c + # The problem with this flag is that it resets the file mtime on the file to + # epoch=0, e.g. 1970-1-1 or 1969-12-31 depending on timezone. + env['ZERO_AR_DATE'] = '1' + libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env) + _, err = libtoolout.communicate() + for line in err.splitlines(): + if not libtool_re.match(line) and not libtool_re5.match(line): + print >>sys.stderr, line + # Unconditionally touch the output .a file on the command line if present + # and the command succeeded. A bit hacky. + if not libtoolout.returncode: + for i in range(len(cmd_list) - 1): + if cmd_list[i] == "-o" and cmd_list[i+1].endswith('.a'): + os.utime(cmd_list[i+1], None) + break + return libtoolout.returncode + + def ExecPackageFramework(self, framework, version): + """Takes a path to Something.framework and the Current version of that and + sets up all the symlinks.""" + # Find the name of the binary based on the part before the ".framework". + binary = os.path.basename(framework).split('.')[0] + + CURRENT = 'Current' + RESOURCES = 'Resources' + VERSIONS = 'Versions' + + if not os.path.exists(os.path.join(framework, VERSIONS, version, binary)): + # Binary-less frameworks don't seem to contain symlinks (see e.g. + # chromium's out/Debug/org.chromium.Chromium.manifest/ bundle). + return + + # Move into the framework directory to set the symlinks correctly. + pwd = os.getcwd() + os.chdir(framework) + + # Set up the Current version. + self._Relink(version, os.path.join(VERSIONS, CURRENT)) + + # Set up the root symlinks. + self._Relink(os.path.join(VERSIONS, CURRENT, binary), binary) + self._Relink(os.path.join(VERSIONS, CURRENT, RESOURCES), RESOURCES) + + # Back to where we were before! + os.chdir(pwd) + + def _Relink(self, dest, link): + """Creates a symlink to |dest| named |link|. If |link| already exists, + it is overwritten.""" + if os.path.lexists(link): + os.remove(link) + os.symlink(dest, link) + + def ExecCompileXcassets(self, keys, *inputs): + """Compiles multiple .xcassets files into a single .car file. + + This invokes 'actool' to compile all the inputs .xcassets files. The + |keys| arguments is a json-encoded dictionary of extra arguments to + pass to 'actool' when the asset catalogs contains an application icon + or a launch image. + + Note that 'actool' does not create the Assets.car file if the asset + catalogs does not contains imageset. + """ + command_line = [ + 'xcrun', 'actool', '--output-format', 'human-readable-text', + '--compress-pngs', '--notices', '--warnings', '--errors', + ] + is_iphone_target = 'IPHONEOS_DEPLOYMENT_TARGET' in os.environ + if is_iphone_target: + platform = os.environ['CONFIGURATION'].split('-')[-1] + if platform not in ('iphoneos', 'iphonesimulator'): + platform = 'iphonesimulator' + command_line.extend([ + '--platform', platform, '--target-device', 'iphone', + '--target-device', 'ipad', '--minimum-deployment-target', + os.environ['IPHONEOS_DEPLOYMENT_TARGET'], '--compile', + os.path.abspath(os.environ['CONTENTS_FOLDER_PATH']), + ]) + else: + command_line.extend([ + '--platform', 'macosx', '--target-device', 'mac', + '--minimum-deployment-target', os.environ['MACOSX_DEPLOYMENT_TARGET'], + '--compile', + os.path.abspath(os.environ['UNLOCALIZED_RESOURCES_FOLDER_PATH']), + ]) + if keys: + keys = json.loads(keys) + for key, value in keys.iteritems(): + arg_name = '--' + key + if isinstance(value, bool): + if value: + command_line.append(arg_name) + elif isinstance(value, list): + for v in value: + command_line.append(arg_name) + command_line.append(str(v)) + else: + command_line.append(arg_name) + command_line.append(str(value)) + # Note: actool crashes if inputs path are relative, so use os.path.abspath + # to get absolute path name for inputs. + command_line.extend(map(os.path.abspath, inputs)) + subprocess.check_call(command_line) + + def ExecMergeInfoPlist(self, output, *inputs): + """Merge multiple .plist files into a single .plist file.""" + merged_plist = {} + for path in inputs: + plist = self._LoadPlistMaybeBinary(path) + self._MergePlist(merged_plist, plist) + plistlib.writePlist(merged_plist, output) + + def ExecCodeSignBundle(self, key, resource_rules, entitlements, provisioning): + """Code sign a bundle. + + This function tries to code sign an iOS bundle, following the same + algorithm as Xcode: + 1. copy ResourceRules.plist from the user or the SDK into the bundle, + 2. pick the provisioning profile that best match the bundle identifier, + and copy it into the bundle as embedded.mobileprovision, + 3. copy Entitlements.plist from user or SDK next to the bundle, + 4. code sign the bundle. + """ + resource_rules_path = self._InstallResourceRules(resource_rules) + substitutions, overrides = self._InstallProvisioningProfile( + provisioning, self._GetCFBundleIdentifier()) + entitlements_path = self._InstallEntitlements( + entitlements, substitutions, overrides) + subprocess.check_call([ + 'codesign', '--force', '--sign', key, '--resource-rules', + resource_rules_path, '--entitlements', entitlements_path, + os.path.join( + os.environ['TARGET_BUILD_DIR'], + os.environ['FULL_PRODUCT_NAME'])]) + + def _InstallResourceRules(self, resource_rules): + """Installs ResourceRules.plist from user or SDK into the bundle. + + Args: + resource_rules: string, optional, path to the ResourceRules.plist file + to use, default to "${SDKROOT}/ResourceRules.plist" + + Returns: + Path to the copy of ResourceRules.plist into the bundle. + """ + source_path = resource_rules + target_path = os.path.join( + os.environ['BUILT_PRODUCTS_DIR'], + os.environ['CONTENTS_FOLDER_PATH'], + 'ResourceRules.plist') + if not source_path: + source_path = os.path.join( + os.environ['SDKROOT'], 'ResourceRules.plist') + shutil.copy2(source_path, target_path) + return target_path + + def _InstallProvisioningProfile(self, profile, bundle_identifier): + """Installs embedded.mobileprovision into the bundle. + + Args: + profile: string, optional, short name of the .mobileprovision file + to use, if empty or the file is missing, the best file installed + will be used + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + + Returns: + A tuple containing two dictionary: variables substitutions and values + to overrides when generating the entitlements file. + """ + source_path, provisioning_data, team_id = self._FindProvisioningProfile( + profile, bundle_identifier) + target_path = os.path.join( + os.environ['BUILT_PRODUCTS_DIR'], + os.environ['CONTENTS_FOLDER_PATH'], + 'embedded.mobileprovision') + shutil.copy2(source_path, target_path) + substitutions = self._GetSubstitutions(bundle_identifier, team_id + '.') + return substitutions, provisioning_data['Entitlements'] + + def _FindProvisioningProfile(self, profile, bundle_identifier): + """Finds the .mobileprovision file to use for signing the bundle. + + Checks all the installed provisioning profiles (or if the user specified + the PROVISIONING_PROFILE variable, only consult it) and select the most + specific that correspond to the bundle identifier. + + Args: + profile: string, optional, short name of the .mobileprovision file + to use, if empty or the file is missing, the best file installed + will be used + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + + Returns: + A tuple of the path to the selected provisioning profile, the data of + the embedded plist in the provisioning profile and the team identifier + to use for code signing. + + Raises: + SystemExit: if no .mobileprovision can be used to sign the bundle. + """ + profiles_dir = os.path.join( + os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles') + if not os.path.isdir(profiles_dir): + print >>sys.stderr, ( + 'cannot find mobile provisioning for %s' % bundle_identifier) + sys.exit(1) + provisioning_profiles = None + if profile: + profile_path = os.path.join(profiles_dir, profile + '.mobileprovision') + if os.path.exists(profile_path): + provisioning_profiles = [profile_path] + if not provisioning_profiles: + provisioning_profiles = glob.glob( + os.path.join(profiles_dir, '*.mobileprovision')) + valid_provisioning_profiles = {} + for profile_path in provisioning_profiles: + profile_data = self._LoadProvisioningProfile(profile_path) + app_id_pattern = profile_data.get( + 'Entitlements', {}).get('application-identifier', '') + for team_identifier in profile_data.get('TeamIdentifier', []): + app_id = '%s.%s' % (team_identifier, bundle_identifier) + if fnmatch.fnmatch(app_id, app_id_pattern): + valid_provisioning_profiles[app_id_pattern] = ( + profile_path, profile_data, team_identifier) + if not valid_provisioning_profiles: + print >>sys.stderr, ( + 'cannot find mobile provisioning for %s' % bundle_identifier) + sys.exit(1) + # If the user has multiple provisioning profiles installed that can be + # used for ${bundle_identifier}, pick the most specific one (ie. the + # provisioning profile whose pattern is the longest). + selected_key = max(valid_provisioning_profiles, key=lambda v: len(v)) + return valid_provisioning_profiles[selected_key] + + def _LoadProvisioningProfile(self, profile_path): + """Extracts the plist embedded in a provisioning profile. + + Args: + profile_path: string, path to the .mobileprovision file + + Returns: + Content of the plist embedded in the provisioning profile as a dictionary. + """ + with tempfile.NamedTemporaryFile() as temp: + subprocess.check_call([ + 'security', 'cms', '-D', '-i', profile_path, '-o', temp.name]) + return self._LoadPlistMaybeBinary(temp.name) + + def _MergePlist(self, merged_plist, plist): + """Merge |plist| into |merged_plist|.""" + for key, value in plist.iteritems(): + if isinstance(value, dict): + merged_value = merged_plist.get(key, {}) + if isinstance(merged_value, dict): + self._MergePlist(merged_value, value) + merged_plist[key] = merged_value + else: + merged_plist[key] = value + else: + merged_plist[key] = value + + def _LoadPlistMaybeBinary(self, plist_path): + """Loads into a memory a plist possibly encoded in binary format. + + This is a wrapper around plistlib.readPlist that tries to convert the + plist to the XML format if it can't be parsed (assuming that it is in + the binary format). + + Args: + plist_path: string, path to a plist file, in XML or binary format + + Returns: + Content of the plist as a dictionary. + """ + try: + # First, try to read the file using plistlib that only supports XML, + # and if an exception is raised, convert a temporary copy to XML and + # load that copy. + return plistlib.readPlist(plist_path) + except: + pass + with tempfile.NamedTemporaryFile() as temp: + shutil.copy2(plist_path, temp.name) + subprocess.check_call(['plutil', '-convert', 'xml1', temp.name]) + return plistlib.readPlist(temp.name) + + def _GetSubstitutions(self, bundle_identifier, app_identifier_prefix): + """Constructs a dictionary of variable substitutions for Entitlements.plist. + + Args: + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + app_identifier_prefix: string, value for AppIdentifierPrefix + + Returns: + Dictionary of substitutions to apply when generating Entitlements.plist. + """ + return { + 'CFBundleIdentifier': bundle_identifier, + 'AppIdentifierPrefix': app_identifier_prefix, + } + + def _GetCFBundleIdentifier(self): + """Extracts CFBundleIdentifier value from Info.plist in the bundle. + + Returns: + Value of CFBundleIdentifier in the Info.plist located in the bundle. + """ + info_plist_path = os.path.join( + os.environ['TARGET_BUILD_DIR'], + os.environ['INFOPLIST_PATH']) + info_plist_data = self._LoadPlistMaybeBinary(info_plist_path) + return info_plist_data['CFBundleIdentifier'] + + def _InstallEntitlements(self, entitlements, substitutions, overrides): + """Generates and install the ${BundleName}.xcent entitlements file. + + Expands variables "$(variable)" pattern in the source entitlements file, + add extra entitlements defined in the .mobileprovision file and the copy + the generated plist to "${BundlePath}.xcent". + + Args: + entitlements: string, optional, path to the Entitlements.plist template + to use, defaults to "${SDKROOT}/Entitlements.plist" + substitutions: dictionary, variable substitutions + overrides: dictionary, values to add to the entitlements + + Returns: + Path to the generated entitlements file. + """ + source_path = entitlements + target_path = os.path.join( + os.environ['BUILT_PRODUCTS_DIR'], + os.environ['PRODUCT_NAME'] + '.xcent') + if not source_path: + source_path = os.path.join( + os.environ['SDKROOT'], + 'Entitlements.plist') + shutil.copy2(source_path, target_path) + data = self._LoadPlistMaybeBinary(target_path) + data = self._ExpandVariables(data, substitutions) + if overrides: + for key in overrides: + if key not in data: + data[key] = overrides[key] + plistlib.writePlist(data, target_path) + return target_path + + def _ExpandVariables(self, data, substitutions): + """Expands variables "$(variable)" in data. + + Args: + data: object, can be either string, list or dictionary + substitutions: dictionary, variable substitutions to perform + + Returns: + Copy of data where each references to "$(variable)" has been replaced + by the corresponding value found in substitutions, or left intact if + the key was not found. + """ + if isinstance(data, str): + for key, value in substitutions.iteritems(): + data = data.replace('$(%s)' % key, value) + return data + if isinstance(data, list): + return [self._ExpandVariables(v, substitutions) for v in data] + if isinstance(data, dict): + return dict((k, self._ExpandVariables(data[k], + substitutions)) for k in data) + return data + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/node_modules/utf-8-validate/build/validation.target.mk b/node_modules/utf-8-validate/build/validation.target.mk new file mode 100644 index 0000000..9d1b8df --- /dev/null +++ b/node_modules/utf-8-validate/build/validation.target.mk @@ -0,0 +1,165 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := validation +DEFS_Debug := \ + '-DNODE_GYP_MODULE_NAME=validation' \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-DBUILDING_NODE_EXTENSION' \ + '-DDEBUG' \ + '-D_DEBUG' + +# Flags passed to all source files. +CFLAGS_Debug := \ + -O0 \ + -gdwarf-2 \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Debug := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Debug := \ + -std=gnu++0x \ + -fno-rtti \ + -fno-exceptions \ + -fno-threadsafe-statics \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Debug := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Debug := + +INCS_Debug := \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/include/node \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/src \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/deps/uv/include \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/deps/v8/include \ + -I$(srcdir)/../nan + +DEFS_Release := \ + '-DNODE_GYP_MODULE_NAME=validation' \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-DBUILDING_NODE_EXTENSION' + +# Flags passed to all source files. +CFLAGS_Release := \ + -Os \ + -gdwarf-2 \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Release := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Release := \ + -std=gnu++0x \ + -fno-rtti \ + -fno-exceptions \ + -fno-threadsafe-statics \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Release := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Release := + +INCS_Release := \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/include/node \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/src \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/deps/uv/include \ + -I/Users/vincenthofmeister/.node-gyp/5.1.0/deps/v8/include \ + -I$(srcdir)/../nan + +OBJS := \ + $(obj).target/$(TARGET)/src/validation.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_Debug := \ + -undefined dynamic_lookup \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -L$(builddir) + +LIBTOOLFLAGS_Debug := \ + -undefined dynamic_lookup \ + -Wl,-search_paths_first + +LDFLAGS_Release := \ + -undefined dynamic_lookup \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -L$(builddir) + +LIBTOOLFLAGS_Release := \ + -undefined dynamic_lookup \ + -Wl,-search_paths_first + +LIBS := + +$(builddir)/validation.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(builddir)/validation.node: LIBS := $(LIBS) +$(builddir)/validation.node: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE)) +$(builddir)/validation.node: TOOLSET := $(TOOLSET) +$(builddir)/validation.node: $(OBJS) FORCE_DO_CMD + $(call do_cmd,solink_module) + +all_deps += $(builddir)/validation.node +# Add target alias +.PHONY: validation +validation: $(builddir)/validation.node + +# Short alias for building this executable. +.PHONY: validation.node +validation.node: $(builddir)/validation.node + +# Add executable to "all" target. +.PHONY: all +all: $(builddir)/validation.node + diff --git a/node_modules/utf-8-validate/fallback.js b/node_modules/utf-8-validate/fallback.js new file mode 100644 index 0000000..f929d77 --- /dev/null +++ b/node_modules/utf-8-validate/fallback.js @@ -0,0 +1,13 @@ +'use strict'; + +/*! + * UTF-8 validate: UTF-8 validation for WebSockets. + * Copyright(c) 2015 Einar Otto Stangvik + * MIT Licensed + */ + +module.exports.Validation = { + isValidUTF8: function(buffer) { + return true; + } +}; diff --git a/node_modules/utf-8-validate/index.js b/node_modules/utf-8-validate/index.js new file mode 100644 index 0000000..e7bfde8 --- /dev/null +++ b/node_modules/utf-8-validate/index.js @@ -0,0 +1,7 @@ +'use strict'; + +try { + module.exports = require('bindings')('validation'); +} catch (e) { + module.exports = require('./fallback'); +} diff --git a/node_modules/utf-8-validate/package.json b/node_modules/utf-8-validate/package.json new file mode 100644 index 0000000..5e1bb0f --- /dev/null +++ b/node_modules/utf-8-validate/package.json @@ -0,0 +1,89 @@ +{ + "_args": [ + [ + "utf-8-validate@1.2.x", + "/Applications/MAMP/htdocs/stream2/WebRTC-Example/node_modules/ws" + ] + ], + "_from": "utf-8-validate@>=1.2.0 <1.3.0", + "_id": "utf-8-validate@1.2.1", + "_inCache": true, + "_installable": true, + "_location": "/utf-8-validate", + "_nodeVersion": "0.12.3", + "_npmUser": { + "email": "npm@3rd-Eden.com", + "name": "3rdeden" + }, + "_npmVersion": "2.9.1", + "_phantomChildren": {}, + "_requested": { + "name": "utf-8-validate", + "raw": "utf-8-validate@1.2.x", + "rawSpec": "1.2.x", + "scope": null, + "spec": ">=1.2.0 <1.3.0", + "type": "range" + }, + "_requiredBy": [ + "/ws" + ], + "_resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-1.2.1.tgz", + "_shasum": "44cb7c6eead73d6b40448f71f745904357b9f72c", + "_shrinkwrap": null, + "_spec": "utf-8-validate@1.2.x", + "_where": "/Applications/MAMP/htdocs/stream2/WebRTC-Example/node_modules/ws", + "author": { + "email": "einaros@gmail.com", + "name": "Einar Otto Stangvik", + "url": "http://2x.io" + }, + "bugs": { + "url": "https://github.com/websockets/utf-8-validate/issues" + }, + "dependencies": { + "bindings": "1.2.x", + "nan": "^2.0.5" + }, + "description": "Validate UTF-8 for Web", + "devDependencies": {}, + "directories": {}, + "dist": { + "shasum": "44cb7c6eead73d6b40448f71f745904357b9f72c", + "tarball": "http://registry.npmjs.org/utf-8-validate/-/utf-8-validate-1.2.1.tgz" + }, + "gitHead": "8067ecff68899b9a1bb31d6906c80e1d5e88bcc7", + "gypfile": true, + "homepage": "https://github.com/websockets/utf-8-validate", + "keywords": [ + "utf-8-validate" + ], + "license": "MIT", + "main": "index.js", + "maintainers": [ + { + "name": "einaros", + "email": "einaros@gmail.com" + }, + { + "name": "3rdeden", + "email": "npm@3rd-Eden.com" + }, + { + "name": "v1", + "email": "info@3rd-Eden.com" + } + ], + "name": "utf-8-validate", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+https://github.com/websockets/utf-8-validate.git" + }, + "scripts": { + "install": "node-gyp rebuild", + "test": "echo \"Only testing builds, test have to be extraced from `ws`\" && exit 0" + }, + "version": "1.2.1" +} diff --git a/node_modules/utf-8-validate/src/validation.cc b/node_modules/utf-8-validate/src/validation.cc new file mode 100644 index 0000000..305ebaf --- /dev/null +++ b/node_modules/utf-8-validate/src/validation.cc @@ -0,0 +1,148 @@ +/*! + * UTF-8 validate: UTF-8 validation for WebSockets. + * Copyright(c) 2015 Einar Otto Stangvik + * MIT Licensed + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "nan.h" + +using namespace v8; +using namespace node; + +#define UNI_SUR_HIGH_START (uint32_t) 0xD800 +#define UNI_SUR_LOW_END (uint32_t) 0xDFFF +#define UNI_REPLACEMENT_CHAR (uint32_t) 0x0000FFFD +#define UNI_MAX_LEGAL_UTF32 (uint32_t) 0x0010FFFF + +static const uint8_t trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +static const uint32_t offsetsFromUTF8[6] = { + 0x00000000, 0x00003080, 0x000E2080, + 0x03C82080, 0xFA082080, 0x82082080 +}; + +static int isLegalUTF8(const uint8_t *source, const int length) +{ + uint8_t a; + const uint8_t *srcptr = source+length; + switch (length) { + default: return 0; + /* Everything else falls through when "true"... */ + /* RFC3629 makes 5 & 6 bytes UTF-8 illegal + case 6: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; + case 5: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; + case 2: if ((a = (*--srcptr)) > 0xBF) return 0; + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return 0; break; + case 0xED: if (a > 0x9F) return 0; break; + case 0xF0: if (a < 0x90) return 0; break; + case 0xF4: if (a > 0x8F) return 0; break; + default: if (a < 0x80) return 0; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return 0; + } + if (*source > 0xF4) return 0; + return 1; +} + +int is_valid_utf8 (size_t len, char *value) +{ + /* is the string valid UTF-8? */ + for (unsigned int i = 0; i < len; i++) { + uint32_t ch = 0; + uint8_t extrabytes = trailingBytesForUTF8[(uint8_t) value[i]]; + + if (extrabytes + i >= len) + return 0; + + if (isLegalUTF8 ((uint8_t *) (value + i), extrabytes + 1) == 0) return 0; + + switch (extrabytes) { + case 5 : ch += (uint8_t) value[i++]; ch <<= 6; + case 4 : ch += (uint8_t) value[i++]; ch <<= 6; + case 3 : ch += (uint8_t) value[i++]; ch <<= 6; + case 2 : ch += (uint8_t) value[i++]; ch <<= 6; + case 1 : ch += (uint8_t) value[i++]; ch <<= 6; + case 0 : ch += (uint8_t) value[i]; + } + + ch -= offsetsFromUTF8[extrabytes]; + + if (ch <= UNI_MAX_LEGAL_UTF32) { + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) + return 0; + } else { + return 0; + } + } + + return 1; +} + +class Validation : public ObjectWrap +{ +public: + + static void Initialize(v8::Handle target) + { + Nan::HandleScope scope; + Local t = Nan::New(New); + t->InstanceTemplate()->SetInternalFieldCount(1); + Nan::SetMethod(t, "isValidUTF8", Validation::IsValidUTF8); + Nan::Set(target, Nan::New("Validation").ToLocalChecked(), t->GetFunction()); + } + +protected: + + static NAN_METHOD(New) + { + Nan::HandleScope scope; + Validation* validation = new Validation(); + validation->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); + } + + static NAN_METHOD(IsValidUTF8) + { + Nan::HandleScope scope; + if (!Buffer::HasInstance(info[0])) { + return Nan::ThrowTypeError("First argument needs to be a buffer"); + } + Local buffer_obj = info[0]->ToObject(); + char *buffer_data = Buffer::Data(buffer_obj); + size_t buffer_length = Buffer::Length(buffer_obj); + info.GetReturnValue().Set(is_valid_utf8(buffer_length, buffer_data) == 1 ? Nan::True() : Nan::False()); + } +}; +#if !NODE_VERSION_AT_LEAST(0,10,0) +extern "C" +#endif +void init (Handle target) +{ + Nan::HandleScope scope; + Validation::Initialize(target); +} + +NODE_MODULE(validation, init) + diff --git a/node_modules/ws/.npmignore b/node_modules/ws/.npmignore new file mode 100644 index 0000000..1eba800 --- /dev/null +++ b/node_modules/ws/.npmignore @@ -0,0 +1,11 @@ +npm-debug.log +node_modules +.*.swp +.lock-* +build + +bench +doc +examples +test + diff --git a/node_modules/ws/.travis.yml b/node_modules/ws/.travis.yml new file mode 100644 index 0000000..ccb864f --- /dev/null +++ b/node_modules/ws/.travis.yml @@ -0,0 +1,29 @@ +language: node_js +sudo: false +npm_args: --ws:native +node_js: + - "4" + - "3" + - "2" + - "1" + - "0.12" + - "0.11" + - "0.10" + - "0.9" + - "0.8" +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-4.9 + - g++-4.9 +before_install: + - export CC="gcc-4.9" CXX="g++-4.9" + - "if [[ $(node --version) == v0.8.* ]]; then npm install -g npm@2.1.18; fi" +matrix: + fast_finish: true + allow_failures: + - node_js: "0.11" + - node_js: "0.9" + - node_js: "0.8" diff --git a/node_modules/ws/Makefile b/node_modules/ws/Makefile new file mode 100644 index 0000000..00f19fa --- /dev/null +++ b/node_modules/ws/Makefile @@ -0,0 +1,40 @@ +ALL_TESTS = $(shell find test/ -name '*.test.js') +ALL_INTEGRATION = $(shell find test/ -name '*.integration.js') + +all: + node-gyp configure build + +clean: + node-gyp clean + +run-tests: + @./node_modules/.bin/mocha \ + -t 5000 \ + -s 2400 \ + $(TESTFLAGS) \ + $(TESTS) + +run-integrationtests: + @./node_modules/.bin/mocha \ + -t 5000 \ + -s 6000 \ + $(TESTFLAGS) \ + $(TESTS) + +test: + @$(MAKE) NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_PATH=lib TESTS="$(ALL_TESTS)" run-tests + +integrationtest: + @$(MAKE) NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_PATH=lib TESTS="$(ALL_INTEGRATION)" run-integrationtests + +benchmark: + @node bench/sender.benchmark.js + @node bench/parser.benchmark.js + +autobahn: + @NODE_PATH=lib node test/autobahn.js + +autobahn-server: + @NODE_PATH=lib node test/autobahn-server.js + +.PHONY: test diff --git a/node_modules/ws/README.md b/node_modules/ws/README.md new file mode 100644 index 0000000..9647d08 --- /dev/null +++ b/node_modules/ws/README.md @@ -0,0 +1,225 @@ +# ws: a node.js websocket library + +[![Build Status](https://travis-ci.org/websockets/ws.svg?branch=master)](https://travis-ci.org/websockets/ws) + +`ws` is a simple to use WebSocket implementation, up-to-date against RFC-6455, +and [probably the fastest WebSocket library for node.js][archive]. + +Passes the quite extensive Autobahn test suite. See http://websockets.github.com/ws +for the full reports. + +## Protocol support + +* **Hixie draft 76** (Old and deprecated, but still in use by Safari and Opera. + Added to ws version 0.4.2, but server only. Can be disabled by setting the + `disableHixie` option to true.) +* **HyBi drafts 07-12** (Use the option `protocolVersion: 8`) +* **HyBi drafts 13-17** (Current default, alternatively option `protocolVersion: 13`) + +### Installing + +``` +npm install --save ws +``` + +### Sending and receiving text data + +```js +var WebSocket = require('ws'); +var ws = new WebSocket('ws://www.host.com/path'); + +ws.on('open', function open() { + ws.send('something'); +}); + +ws.on('message', function(data, flags) { + // flags.binary will be set if a binary data is received. + // flags.masked will be set if the data was masked. +}); +``` + +### Sending binary data + +```js +var WebSocket = require('ws'); +var ws = new WebSocket('ws://www.host.com/path'); + +ws.on('open', function open() { + var array = new Float32Array(5); + + for (var i = 0; i < array.length; ++i) { + array[i] = i / 2; + } + + ws.send(array, { binary: true, mask: true }); +}); +``` + +Setting `mask`, as done for the send options above, will cause the data to be +masked according to the WebSocket protocol. The same option applies for text +data. + +### Server example + +```js +var WebSocketServer = require('ws').Server + , wss = new WebSocketServer({ port: 8080 }); + +wss.on('connection', function connection(ws) { + ws.on('message', function incoming(message) { + console.log('received: %s', message); + }); + + ws.send('something'); +}); +``` + +### ExpressJS example + +```js +var server = require('http').createServer() + , url = require('url') + , WebSocketServer = require('ws').Server + , wss = new WebSocketServer({ server: server }) + , express = require('express') + , app = express() + , port = 4080; + +app.use(function (req, res) { + res.send({ msg: "hello" }); +}); + +wss.on('connection', function connection(ws) { + var location = url.parse(ws.upgradeReq.url, true); + // you might use location.query.access_token to authenticate or share sessions + // or ws.upgradeReq.headers.cookie (see http://stackoverflow.com/a/16395220/151312) + + ws.on('message', function incoming(message) { + console.log('received: %s', message); + }); + + ws.send('something'); +}); + +server.on('request', app); +server.listen(port, function () { console.log('Listening on ' + server.address().port) }); +``` + +### Server sending broadcast data + +```js +var WebSocketServer = require('ws').Server + , wss = new WebSocketServer({ port: 8080 }); + +wss.broadcast = function broadcast(data) { + wss.clients.forEach(function each(client) { + client.send(data); + }); +}; +``` + +### Error handling best practices + +```js +// If the WebSocket is closed before the following send is attempted +ws.send('something'); + +// Errors (both immediate and async write errors) can be detected in an optional +// callback. The callback is also the only way of being notified that data has +// actually been sent. +ws.send('something', function ack(error) { + // if error is not defined, the send has been completed, + // otherwise the error object will indicate what failed. +}); + +// Immediate errors can also be handled with try/catch-blocks, but **note** that +// since sends are inherently asynchronous, socket write failures will *not* be +// captured when this technique is used. +try { ws.send('something'); } +catch (e) { /* handle error */ } +``` + +### echo.websocket.org demo + +```js +var WebSocket = require('ws'); +var ws = new WebSocket('ws://echo.websocket.org/', { + protocolVersion: 8, + origin: 'http://websocket.org' +}); + +ws.on('open', function open() { + console.log('connected'); + ws.send(Date.now().toString(), {mask: true}); +}); + +ws.on('close', function close() { + console.log('disconnected'); +}); + +ws.on('message', function message(data, flags) { + console.log('Roundtrip time: ' + (Date.now() - parseInt(data)) + 'ms', flags); + + setTimeout(function timeout() { + ws.send(Date.now().toString(), {mask: true}); + }, 500); +}); +``` + +### Browserify users +When including ws via a browserify bundle, ws returns global.WebSocket which has slightly different API. +You should use the standard WebSockets API instead. + +https://developer.mozilla.org/en-US/docs/WebSockets/Writing_WebSocket_client_applications#Availability_of_WebSockets + + +### Other examples + +For a full example with a browser client communicating with a ws server, see the +examples folder. + +Note that the usage together with Express 3.0 is quite different from Express +2.x. The difference is expressed in the two different serverstats-examples. + +Otherwise, see the test cases. + +### Running the tests + +``` +make test +``` + +## API Docs + +See [`/doc/ws.md`](https://github.com/websockets/ws/blob/master/doc/ws.md) for Node.js-like docs for the ws classes. + +## Changelog + +We're using the GitHub [`releases`](https://github.com/websockets/ws/releases) for changelog entries. + +## License + +(The MIT License) + +Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.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. + +[archive]: http://web.archive.org/web/20130314230536/http://hobbycoding.posterous.com/the-fastest-websocket-module-for-nodejs diff --git a/node_modules/ws/index.js b/node_modules/ws/index.js new file mode 100644 index 0000000..a7e8644 --- /dev/null +++ b/node_modules/ws/index.js @@ -0,0 +1,49 @@ +'use strict'; + +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var WS = module.exports = require('./lib/WebSocket'); + +WS.Server = require('./lib/WebSocketServer'); +WS.Sender = require('./lib/Sender'); +WS.Receiver = require('./lib/Receiver'); + +/** + * Create a new WebSocket server. + * + * @param {Object} options Server options + * @param {Function} fn Optional connection listener. + * @returns {WS.Server} + * @api public + */ +WS.createServer = function createServer(options, fn) { + var server = new WS.Server(options); + + if (typeof fn === 'function') { + server.on('connection', fn); + } + + return server; +}; + +/** + * Create a new WebSocket connection. + * + * @param {String} address The URL/address we need to connect to. + * @param {Function} fn Open listener. + * @returns {WS} + * @api public + */ +WS.connect = WS.createConnection = function connect(address, fn) { + var client = new WS(address); + + if (typeof fn === 'function') { + client.on('open', fn); + } + + return client; +}; diff --git a/node_modules/ws/lib/BufferPool.js b/node_modules/ws/lib/BufferPool.js new file mode 100644 index 0000000..8ee5990 --- /dev/null +++ b/node_modules/ws/lib/BufferPool.js @@ -0,0 +1,63 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util'); + +function BufferPool(initialSize, growStrategy, shrinkStrategy) { + if (this instanceof BufferPool === false) { + throw new TypeError("Classes can't be function-called"); + } + + if (typeof initialSize === 'function') { + shrinkStrategy = growStrategy; + growStrategy = initialSize; + initialSize = 0; + } + else if (typeof initialSize === 'undefined') { + initialSize = 0; + } + this._growStrategy = (growStrategy || function(db, size) { + return db.used + size; + }).bind(null, this); + this._shrinkStrategy = (shrinkStrategy || function(db) { + return initialSize; + }).bind(null, this); + this._buffer = initialSize ? new Buffer(initialSize) : null; + this._offset = 0; + this._used = 0; + this._changeFactor = 0; + this.__defineGetter__('size', function(){ + return this._buffer == null ? 0 : this._buffer.length; + }); + this.__defineGetter__('used', function(){ + return this._used; + }); +} + +BufferPool.prototype.get = function(length) { + if (this._buffer == null || this._offset + length > this._buffer.length) { + var newBuf = new Buffer(this._growStrategy(length)); + this._buffer = newBuf; + this._offset = 0; + } + this._used += length; + var buf = this._buffer.slice(this._offset, this._offset + length); + this._offset += length; + return buf; +} + +BufferPool.prototype.reset = function(forceNewBuffer) { + var len = this._shrinkStrategy(); + if (len < this.size) this._changeFactor -= 1; + if (forceNewBuffer || this._changeFactor < -2) { + this._changeFactor = 0; + this._buffer = len ? new Buffer(len) : null; + } + this._offset = 0; + this._used = 0; +} + +module.exports = BufferPool; diff --git a/node_modules/ws/lib/BufferUtil.fallback.js b/node_modules/ws/lib/BufferUtil.fallback.js new file mode 100644 index 0000000..508542c --- /dev/null +++ b/node_modules/ws/lib/BufferUtil.fallback.js @@ -0,0 +1,47 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +module.exports.BufferUtil = { + merge: function(mergedBuffer, buffers) { + var offset = 0; + for (var i = 0, l = buffers.length; i < l; ++i) { + var buf = buffers[i]; + buf.copy(mergedBuffer, offset); + offset += buf.length; + } + }, + mask: function(source, mask, output, offset, length) { + var maskNum = mask.readUInt32LE(0, true); + var i = 0; + for (; i < length - 3; i += 4) { + var num = maskNum ^ source.readUInt32LE(i, true); + if (num < 0) num = 4294967296 + num; + output.writeUInt32LE(num, offset + i, true); + } + switch (length % 4) { + case 3: output[offset + i + 2] = source[i + 2] ^ mask[2]; + case 2: output[offset + i + 1] = source[i + 1] ^ mask[1]; + case 1: output[offset + i] = source[i] ^ mask[0]; + case 0:; + } + }, + unmask: function(data, mask) { + var maskNum = mask.readUInt32LE(0, true); + var length = data.length; + var i = 0; + for (; i < length - 3; i += 4) { + var num = maskNum ^ data.readUInt32LE(i, true); + if (num < 0) num = 4294967296 + num; + data.writeUInt32LE(num, i, true); + } + switch (length % 4) { + case 3: data[i + 2] = data[i + 2] ^ mask[2]; + case 2: data[i + 1] = data[i + 1] ^ mask[1]; + case 1: data[i] = data[i] ^ mask[0]; + case 0:; + } + } +} diff --git a/node_modules/ws/lib/BufferUtil.js b/node_modules/ws/lib/BufferUtil.js new file mode 100644 index 0000000..18c6998 --- /dev/null +++ b/node_modules/ws/lib/BufferUtil.js @@ -0,0 +1,13 @@ +'use strict'; + +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +try { + module.exports = require('bufferutil'); +} catch (e) { + module.exports = require('./BufferUtil.fallback'); +} diff --git a/node_modules/ws/lib/ErrorCodes.js b/node_modules/ws/lib/ErrorCodes.js new file mode 100644 index 0000000..55ebd52 --- /dev/null +++ b/node_modules/ws/lib/ErrorCodes.js @@ -0,0 +1,24 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +module.exports = { + isValidErrorCode: function(code) { + return (code >= 1000 && code <= 1011 && code != 1004 && code != 1005 && code != 1006) || + (code >= 3000 && code <= 4999); + }, + 1000: 'normal', + 1001: 'going away', + 1002: 'protocol error', + 1003: 'unsupported data', + 1004: 'reserved', + 1005: 'reserved for extensions', + 1006: 'reserved for extensions', + 1007: 'inconsistent or invalid data', + 1008: 'policy violation', + 1009: 'message too big', + 1010: 'extension handshake missing', + 1011: 'an unexpected condition prevented the request from being fulfilled', +}; \ No newline at end of file diff --git a/node_modules/ws/lib/Extensions.js b/node_modules/ws/lib/Extensions.js new file mode 100644 index 0000000..a465ace --- /dev/null +++ b/node_modules/ws/lib/Extensions.js @@ -0,0 +1,70 @@ + +var util = require('util'); + +/** + * Module exports. + */ + +exports.parse = parse; +exports.format = format; + +/** + * Parse extensions header value + */ + +function parse(value) { + value = value || ''; + + var extensions = {}; + + value.split(',').forEach(function(v) { + var params = v.split(';'); + var token = params.shift().trim(); + var paramsList = extensions[token] = extensions[token] || []; + var parsedParams = {}; + + params.forEach(function(param) { + var parts = param.trim().split('='); + var key = parts[0]; + var value = parts[1]; + if (typeof value === 'undefined') { + value = true; + } else { + // unquote value + if (value[0] === '"') { + value = value.slice(1); + } + if (value[value.length - 1] === '"') { + value = value.slice(0, value.length - 1); + } + } + (parsedParams[key] = parsedParams[key] || []).push(value); + }); + + paramsList.push(parsedParams); + }); + + return extensions; +} + +/** + * Format extensions header value + */ + +function format(value) { + return Object.keys(value).map(function(token) { + var paramsList = value[token]; + if (!util.isArray(paramsList)) { + paramsList = [paramsList]; + } + return paramsList.map(function(params) { + return [token].concat(Object.keys(params).map(function(k) { + var p = params[k]; + if (!util.isArray(p)) p = [p]; + return p.map(function(v) { + return v === true ? k : k + '=' + v; + }).join('; '); + })).join('; '); + }).join(', '); + }).join(', '); +} diff --git a/node_modules/ws/lib/PerMessageDeflate.js b/node_modules/ws/lib/PerMessageDeflate.js new file mode 100644 index 0000000..0060c5f --- /dev/null +++ b/node_modules/ws/lib/PerMessageDeflate.js @@ -0,0 +1,313 @@ + +var zlib = require('zlib'); + +var AVAILABLE_WINDOW_BITS = [8, 9, 10, 11, 12, 13, 14, 15]; +var DEFAULT_WINDOW_BITS = 15; +var DEFAULT_MEM_LEVEL = 8; + +PerMessageDeflate.extensionName = 'permessage-deflate'; + +/** + * Per-message Compression Extensions implementation + */ + +function PerMessageDeflate(options, isServer) { + if (this instanceof PerMessageDeflate === false) { + throw new TypeError("Classes can't be function-called"); + } + + this._options = options || {}; + this._isServer = !!isServer; + this._inflate = null; + this._deflate = null; + this.params = null; +} + +/** + * Create extension parameters offer + * + * @api public + */ + +PerMessageDeflate.prototype.offer = function() { + var params = {}; + if (this._options.serverNoContextTakeover) { + params.server_no_context_takeover = true; + } + if (this._options.clientNoContextTakeover) { + params.client_no_context_takeover = true; + } + if (this._options.serverMaxWindowBits) { + params.server_max_window_bits = this._options.serverMaxWindowBits; + } + if (this._options.clientMaxWindowBits) { + params.client_max_window_bits = this._options.clientMaxWindowBits; + } else if (this._options.clientMaxWindowBits == null) { + params.client_max_window_bits = true; + } + return params; +}; + +/** + * Accept extension offer + * + * @api public + */ + +PerMessageDeflate.prototype.accept = function(paramsList) { + paramsList = this.normalizeParams(paramsList); + + var params; + if (this._isServer) { + params = this.acceptAsServer(paramsList); + } else { + params = this.acceptAsClient(paramsList); + } + + this.params = params; + return params; +}; + +/** + * Releases all resources used by the extension + * + * @api public + */ + +PerMessageDeflate.prototype.cleanup = function() { + if (this._inflate) { + this._inflate.close(); + this._inflate = null; + } + if (this._deflate) { + this._deflate.close(); + this._deflate = null; + } +}; + +/** + * Accept extension offer from client + * + * @api private + */ + +PerMessageDeflate.prototype.acceptAsServer = function(paramsList) { + var accepted = {}; + var result = paramsList.some(function(params) { + accepted = {}; + if (this._options.serverNoContextTakeover === false && params.server_no_context_takeover) { + return; + } + if (this._options.serverMaxWindowBits === false && params.server_max_window_bits) { + return; + } + if (typeof this._options.serverMaxWindowBits === 'number' && + typeof params.server_max_window_bits === 'number' && + this._options.serverMaxWindowBits > params.server_max_window_bits) { + return; + } + if (typeof this._options.clientMaxWindowBits === 'number' && !params.client_max_window_bits) { + return; + } + + if (this._options.serverNoContextTakeover || params.server_no_context_takeover) { + accepted.server_no_context_takeover = true; + } + if (this._options.clientNoContextTakeover) { + accepted.client_no_context_takeover = true; + } + if (this._options.clientNoContextTakeover !== false && params.client_no_context_takeover) { + accepted.client_no_context_takeover = true; + } + if (typeof this._options.serverMaxWindowBits === 'number') { + accepted.server_max_window_bits = this._options.serverMaxWindowBits; + } else if (typeof params.server_max_window_bits === 'number') { + accepted.server_max_window_bits = params.server_max_window_bits; + } + if (typeof this._options.clientMaxWindowBits === 'number') { + accepted.client_max_window_bits = this._options.clientMaxWindowBits; + } else if (this._options.clientMaxWindowBits !== false && typeof params.client_max_window_bits === 'number') { + accepted.client_max_window_bits = params.client_max_window_bits; + } + return true; + }, this); + + if (!result) { + throw new Error('Doesn\'t support the offered configuration'); + } + + return accepted; +}; + +/** + * Accept extension response from server + * + * @api privaye + */ + +PerMessageDeflate.prototype.acceptAsClient = function(paramsList) { + var params = paramsList[0]; + if (this._options.clientNoContextTakeover != null) { + if (this._options.clientNoContextTakeover === false && params.client_no_context_takeover) { + throw new Error('Invalid value for "client_no_context_takeover"'); + } + } + if (this._options.clientMaxWindowBits != null) { + if (this._options.clientMaxWindowBits === false && params.client_max_window_bits) { + throw new Error('Invalid value for "client_max_window_bits"'); + } + if (typeof this._options.clientMaxWindowBits === 'number' && + (!params.client_max_window_bits || params.client_max_window_bits > this._options.clientMaxWindowBits)) { + throw new Error('Invalid value for "client_max_window_bits"'); + } + } + return params; +}; + +/** + * Normalize extensions parameters + * + * @api private + */ + +PerMessageDeflate.prototype.normalizeParams = function(paramsList) { + return paramsList.map(function(params) { + Object.keys(params).forEach(function(key) { + var value = params[key]; + if (value.length > 1) { + throw new Error('Multiple extension parameters for ' + key); + } + + value = value[0]; + + switch (key) { + case 'server_no_context_takeover': + case 'client_no_context_takeover': + if (value !== true) { + throw new Error('invalid extension parameter value for ' + key + ' (' + value + ')'); + } + params[key] = true; + break; + case 'server_max_window_bits': + case 'client_max_window_bits': + if (typeof value === 'string') { + value = parseInt(value, 10); + if (!~AVAILABLE_WINDOW_BITS.indexOf(value)) { + throw new Error('invalid extension parameter value for ' + key + ' (' + value + ')'); + } + } + if (!this._isServer && value === true) { + throw new Error('Missing extension parameter value for ' + key); + } + params[key] = value; + break; + default: + throw new Error('Not defined extension parameter (' + key + ')'); + } + }, this); + return params; + }, this); +}; + +/** + * Decompress message + * + * @api public + */ + +PerMessageDeflate.prototype.decompress = function (data, fin, callback) { + var endpoint = this._isServer ? 'client' : 'server'; + + if (!this._inflate) { + var maxWindowBits = this.params[endpoint + '_max_window_bits']; + this._inflate = zlib.createInflateRaw({ + windowBits: 'number' === typeof maxWindowBits ? maxWindowBits : DEFAULT_WINDOW_BITS + }); + } + + var self = this; + var buffers = []; + + this._inflate.on('error', onError).on('data', onData); + this._inflate.write(data); + if (fin) { + this._inflate.write(new Buffer([0x00, 0x00, 0xff, 0xff])); + } + this._inflate.flush(function() { + cleanup(); + callback(null, Buffer.concat(buffers)); + }); + + function onError(err) { + cleanup(); + callback(err); + } + + function onData(data) { + buffers.push(data); + } + + function cleanup() { + if (!self._inflate) return; + self._inflate.removeListener('error', onError); + self._inflate.removeListener('data', onData); + if (fin && self.params[endpoint + '_no_context_takeover']) { + self._inflate.close(); + self._inflate = null; + } + } +}; + +/** + * Compress message + * + * @api public + */ + +PerMessageDeflate.prototype.compress = function (data, fin, callback) { + var endpoint = this._isServer ? 'server' : 'client'; + + if (!this._deflate) { + var maxWindowBits = this.params[endpoint + '_max_window_bits']; + this._deflate = zlib.createDeflateRaw({ + flush: zlib.Z_SYNC_FLUSH, + windowBits: 'number' === typeof maxWindowBits ? maxWindowBits : DEFAULT_WINDOW_BITS, + memLevel: this._options.memLevel || DEFAULT_MEM_LEVEL + }); + } + + var self = this; + var buffers = []; + + this._deflate.on('error', onError).on('data', onData); + this._deflate.write(data); + this._deflate.flush(function() { + cleanup(); + var data = Buffer.concat(buffers); + if (fin) { + data = data.slice(0, data.length - 4); + } + callback(null, data); + }); + + function onError(err) { + cleanup(); + callback(err); + } + + function onData(data) { + buffers.push(data); + } + + function cleanup() { + if (!self._deflate) return; + self._deflate.removeListener('error', onError); + self._deflate.removeListener('data', onData); + if (fin && self.params[endpoint + '_no_context_takeover']) { + self._deflate.close(); + self._deflate = null; + } + } +}; + +module.exports = PerMessageDeflate; diff --git a/node_modules/ws/lib/Receiver.hixie.js b/node_modules/ws/lib/Receiver.hixie.js new file mode 100644 index 0000000..66bc561 --- /dev/null +++ b/node_modules/ws/lib/Receiver.hixie.js @@ -0,0 +1,184 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util'); + +/** + * State constants + */ + +var EMPTY = 0 + , BODY = 1; +var BINARYLENGTH = 2 + , BINARYBODY = 3; + +/** + * Hixie Receiver implementation + */ + +function Receiver () { + if (this instanceof Receiver === false) { + throw new TypeError("Classes can't be function-called"); + } + + this.state = EMPTY; + this.buffers = []; + this.messageEnd = -1; + this.spanLength = 0; + this.dead = false; + + this.onerror = function() {}; + this.ontext = function() {}; + this.onbinary = function() {}; + this.onclose = function() {}; + this.onping = function() {}; + this.onpong = function() {}; +} + +module.exports = Receiver; + +/** + * Add new data to the parser. + * + * @api public + */ + +Receiver.prototype.add = function(data) { + var self = this; + function doAdd() { + if (self.state === EMPTY) { + if (data.length == 2 && data[0] == 0xFF && data[1] == 0x00) { + self.reset(); + self.onclose(); + return; + } + if (data[0] === 0x80) { + self.messageEnd = 0; + self.state = BINARYLENGTH; + data = data.slice(1); + } else { + + if (data[0] !== 0x00) { + self.error('payload must start with 0x00 byte', true); + return; + } + data = data.slice(1); + self.state = BODY; + + } + } + if (self.state === BINARYLENGTH) { + var i = 0; + while ((i < data.length) && (data[i] & 0x80)) { + self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f); + ++i; + } + if (i < data.length) { + self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f); + self.state = BINARYBODY; + ++i; + } + if (i > 0) + data = data.slice(i); + } + if (self.state === BINARYBODY) { + var dataleft = self.messageEnd - self.spanLength; + if (data.length >= dataleft) { + // consume the whole buffer to finish the frame + self.buffers.push(data); + self.spanLength += dataleft; + self.messageEnd = dataleft; + return self.parse(); + } + // frame's not done even if we consume it all + self.buffers.push(data); + self.spanLength += data.length; + return; + } + self.buffers.push(data); + if ((self.messageEnd = bufferIndex(data, 0xFF)) != -1) { + self.spanLength += self.messageEnd; + return self.parse(); + } + else self.spanLength += data.length; + } + while(data) data = doAdd(); +}; + +/** + * Releases all resources used by the receiver. + * + * @api public + */ + +Receiver.prototype.cleanup = function() { + this.dead = true; + this.state = EMPTY; + this.buffers = []; +}; + +/** + * Process buffered data. + * + * @api public + */ + +Receiver.prototype.parse = function() { + var output = new Buffer(this.spanLength); + var outputIndex = 0; + for (var bi = 0, bl = this.buffers.length; bi < bl - 1; ++bi) { + var buffer = this.buffers[bi]; + buffer.copy(output, outputIndex); + outputIndex += buffer.length; + } + var lastBuffer = this.buffers[this.buffers.length - 1]; + if (this.messageEnd > 0) lastBuffer.copy(output, outputIndex, 0, this.messageEnd); + if (this.state !== BODY) --this.messageEnd; + var tail = null; + if (this.messageEnd < lastBuffer.length - 1) { + tail = lastBuffer.slice(this.messageEnd + 1); + } + this.reset(); + this.ontext(output.toString('utf8')); + return tail; +}; + +/** + * Handles an error + * + * @api private + */ + +Receiver.prototype.error = function (reason, terminate) { + this.reset(); + this.onerror(reason, terminate); + return this; +}; + +/** + * Reset parser state + * + * @api private + */ + +Receiver.prototype.reset = function (reason) { + if (this.dead) return; + this.state = EMPTY; + this.buffers = []; + this.messageEnd = -1; + this.spanLength = 0; +}; + +/** + * Internal api + */ + +function bufferIndex(buffer, byte) { + for (var i = 0, l = buffer.length; i < l; ++i) { + if (buffer[i] === byte) return i; + } + return -1; +} diff --git a/node_modules/ws/lib/Receiver.js b/node_modules/ws/lib/Receiver.js new file mode 100644 index 0000000..999af0a --- /dev/null +++ b/node_modules/ws/lib/Receiver.js @@ -0,0 +1,702 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util') + , Validation = require('./Validation').Validation + , ErrorCodes = require('./ErrorCodes') + , BufferPool = require('./BufferPool') + , bufferUtil = require('./BufferUtil').BufferUtil + , PerMessageDeflate = require('./PerMessageDeflate'); + +/** + * HyBi Receiver implementation + */ + +function Receiver (extensions) { + if (this instanceof Receiver === false) { + throw new TypeError("Classes can't be function-called"); + } + + // memory pool for fragmented messages + var fragmentedPoolPrevUsed = -1; + this.fragmentedBufferPool = new BufferPool(1024, function(db, length) { + return db.used + length; + }, function(db) { + return fragmentedPoolPrevUsed = fragmentedPoolPrevUsed >= 0 ? + (fragmentedPoolPrevUsed + db.used) / 2 : + db.used; + }); + + // memory pool for unfragmented messages + var unfragmentedPoolPrevUsed = -1; + this.unfragmentedBufferPool = new BufferPool(1024, function(db, length) { + return db.used + length; + }, function(db) { + return unfragmentedPoolPrevUsed = unfragmentedPoolPrevUsed >= 0 ? + (unfragmentedPoolPrevUsed + db.used) / 2 : + db.used; + }); + + this.extensions = extensions || {}; + this.state = { + activeFragmentedOperation: null, + lastFragment: false, + masked: false, + opcode: 0, + fragmentedOperation: false + }; + this.overflow = []; + this.headerBuffer = new Buffer(10); + this.expectOffset = 0; + this.expectBuffer = null; + this.expectHandler = null; + this.currentMessage = []; + this.messageHandlers = []; + this.expectHeader(2, this.processPacket); + this.dead = false; + this.processing = false; + + this.onerror = function() {}; + this.ontext = function() {}; + this.onbinary = function() {}; + this.onclose = function() {}; + this.onping = function() {}; + this.onpong = function() {}; +} + +module.exports = Receiver; + +/** + * Add new data to the parser. + * + * @api public + */ + +Receiver.prototype.add = function(data) { + var dataLength = data.length; + if (dataLength == 0) return; + if (this.expectBuffer == null) { + this.overflow.push(data); + return; + } + var toRead = Math.min(dataLength, this.expectBuffer.length - this.expectOffset); + fastCopy(toRead, data, this.expectBuffer, this.expectOffset); + this.expectOffset += toRead; + if (toRead < dataLength) { + this.overflow.push(data.slice(toRead)); + } + while (this.expectBuffer && this.expectOffset == this.expectBuffer.length) { + var bufferForHandler = this.expectBuffer; + this.expectBuffer = null; + this.expectOffset = 0; + this.expectHandler.call(this, bufferForHandler); + } +}; + +/** + * Releases all resources used by the receiver. + * + * @api public + */ + +Receiver.prototype.cleanup = function() { + this.dead = true; + this.overflow = null; + this.headerBuffer = null; + this.expectBuffer = null; + this.expectHandler = null; + this.unfragmentedBufferPool = null; + this.fragmentedBufferPool = null; + this.state = null; + this.currentMessage = null; + this.onerror = null; + this.ontext = null; + this.onbinary = null; + this.onclose = null; + this.onping = null; + this.onpong = null; +}; + +/** + * Waits for a certain amount of header bytes to be available, then fires a callback. + * + * @api private + */ + +Receiver.prototype.expectHeader = function(length, handler) { + if (length == 0) { + handler(null); + return; + } + this.expectBuffer = this.headerBuffer.slice(this.expectOffset, this.expectOffset + length); + this.expectHandler = handler; + var toRead = length; + while (toRead > 0 && this.overflow.length > 0) { + var fromOverflow = this.overflow.pop(); + if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead)); + var read = Math.min(fromOverflow.length, toRead); + fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset); + this.expectOffset += read; + toRead -= read; + } +}; + +/** + * Waits for a certain amount of data bytes to be available, then fires a callback. + * + * @api private + */ + +Receiver.prototype.expectData = function(length, handler) { + if (length == 0) { + handler(null); + return; + } + this.expectBuffer = this.allocateFromPool(length, this.state.fragmentedOperation); + this.expectHandler = handler; + var toRead = length; + while (toRead > 0 && this.overflow.length > 0) { + var fromOverflow = this.overflow.pop(); + if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead)); + var read = Math.min(fromOverflow.length, toRead); + fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset); + this.expectOffset += read; + toRead -= read; + } +}; + +/** + * Allocates memory from the buffer pool. + * + * @api private + */ + +Receiver.prototype.allocateFromPool = function(length, isFragmented) { + return (isFragmented ? this.fragmentedBufferPool : this.unfragmentedBufferPool).get(length); +}; + +/** + * Start processing a new packet. + * + * @api private + */ + +Receiver.prototype.processPacket = function (data) { + if (this.extensions[PerMessageDeflate.extensionName]) { + if ((data[0] & 0x30) != 0) { + this.error('reserved fields (2, 3) must be empty', 1002); + return; + } + } else { + if ((data[0] & 0x70) != 0) { + this.error('reserved fields must be empty', 1002); + return; + } + } + this.state.lastFragment = (data[0] & 0x80) == 0x80; + this.state.masked = (data[1] & 0x80) == 0x80; + var compressed = (data[0] & 0x40) == 0x40; + var opcode = data[0] & 0xf; + if (opcode === 0) { + if (compressed) { + this.error('continuation frame cannot have the Per-message Compressed bits', 1002); + return; + } + // continuation frame + this.state.fragmentedOperation = true; + this.state.opcode = this.state.activeFragmentedOperation; + if (!(this.state.opcode == 1 || this.state.opcode == 2)) { + this.error('continuation frame cannot follow current opcode', 1002); + return; + } + } + else { + if (opcode < 3 && this.state.activeFragmentedOperation != null) { + this.error('data frames after the initial data frame must have opcode 0', 1002); + return; + } + if (opcode >= 8 && compressed) { + this.error('control frames cannot have the Per-message Compressed bits', 1002); + return; + } + this.state.compressed = compressed; + this.state.opcode = opcode; + if (this.state.lastFragment === false) { + this.state.fragmentedOperation = true; + this.state.activeFragmentedOperation = opcode; + } + else this.state.fragmentedOperation = false; + } + var handler = opcodes[this.state.opcode]; + if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode, 1002); + else { + handler.start.call(this, data); + } +}; + +/** + * Endprocessing a packet. + * + * @api private + */ + +Receiver.prototype.endPacket = function() { + if (!this.state.fragmentedOperation) this.unfragmentedBufferPool.reset(true); + else if (this.state.lastFragment) this.fragmentedBufferPool.reset(true); + 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.expectHeader(2, this.processPacket); +}; + +/** + * Reset the parser state. + * + * @api private + */ + +Receiver.prototype.reset = function() { + if (this.dead) return; + this.state = { + activeFragmentedOperation: null, + lastFragment: false, + masked: false, + opcode: 0, + fragmentedOperation: false + }; + this.fragmentedBufferPool.reset(true); + this.unfragmentedBufferPool.reset(true); + this.expectOffset = 0; + this.expectBuffer = null; + this.expectHandler = null; + this.overflow = []; + this.currentMessage = []; + this.messageHandlers = []; +}; + +/** + * Unmask received data. + * + * @api private + */ + +Receiver.prototype.unmask = function (mask, buf, binary) { + if (mask != null && buf != null) bufferUtil.unmask(buf, mask); + if (binary) return buf; + return buf != null ? buf.toString('utf8') : ''; +}; + +/** + * Concatenates a list of buffers. + * + * @api private + */ + +Receiver.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); + bufferUtil.merge(mergedBuffer, buffers); + return mergedBuffer; +}; + +/** + * Handles an error + * + * @api private + */ + +Receiver.prototype.error = function (reason, protocolErrorCode) { + this.reset(); + this.onerror(reason, protocolErrorCode); + return this; +}; + +/** + * Execute message handler buffers + * + * @api private + */ + +Receiver.prototype.flush = function() { + if (this.processing || this.dead) return; + + var handler = this.messageHandlers.shift(); + if (!handler) return; + + this.processing = true; + var self = this; + + handler(function() { + self.processing = false; + self.flush(); + }); +}; + +/** + * Apply extensions to message + * + * @api private + */ + +Receiver.prototype.applyExtensions = function(messageBuffer, fin, compressed, callback) { + var self = this; + if (compressed) { + this.extensions[PerMessageDeflate.extensionName].decompress(messageBuffer, fin, function(err, buffer) { + if (self.dead) return; + if (err) { + callback(new Error('invalid compressed data')); + return; + } + callback(null, buffer); + }); + } else { + callback(null, messageBuffer); + } +}; + +/** + * Buffer utilities + */ + +function readUInt16BE(start) { + return (this[start]<<8) + + this[start+1]; +} + +function readUInt32BE(start) { + return (this[start]<<24) + + (this[start+1]<<16) + + (this[start+2]<<8) + + this[start+3]; +} + +function fastCopy(length, srcBuffer, dstBuffer, dstOffset) { + switch (length) { + default: srcBuffer.copy(dstBuffer, dstOffset, 0, length); break; + case 16: dstBuffer[dstOffset+15] = srcBuffer[15]; + case 15: dstBuffer[dstOffset+14] = srcBuffer[14]; + case 14: dstBuffer[dstOffset+13] = srcBuffer[13]; + case 13: dstBuffer[dstOffset+12] = srcBuffer[12]; + case 12: dstBuffer[dstOffset+11] = srcBuffer[11]; + case 11: dstBuffer[dstOffset+10] = srcBuffer[10]; + case 10: dstBuffer[dstOffset+9] = srcBuffer[9]; + case 9: dstBuffer[dstOffset+8] = srcBuffer[8]; + case 8: dstBuffer[dstOffset+7] = srcBuffer[7]; + case 7: dstBuffer[dstOffset+6] = srcBuffer[6]; + case 6: dstBuffer[dstOffset+5] = srcBuffer[5]; + case 5: dstBuffer[dstOffset+4] = srcBuffer[4]; + case 4: dstBuffer[dstOffset+3] = srcBuffer[3]; + case 3: dstBuffer[dstOffset+2] = srcBuffer[2]; + case 2: dstBuffer[dstOffset+1] = srcBuffer[1]; + case 1: dstBuffer[dstOffset] = srcBuffer[0]; + } +} + +function clone(obj) { + var cloned = {}; + for (var k in obj) { + if (obj.hasOwnProperty(k)) { + cloned[k] = obj[k]; + } + } + return cloned; +} + +/** + * Opcode handlers + */ + +var opcodes = { + // text + '1': { + start: function(data) { + var self = this; + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['1'].getData.call(self, firstLength); + } + else if (firstLength == 126) { + self.expectHeader(2, function(data) { + opcodes['1'].getData.call(self, readUInt16BE.call(data, 0)); + }); + } + else if (firstLength == 127) { + self.expectHeader(8, function(data) { + if (readUInt32BE.call(data, 0) != 0) { + self.error('packets with length spanning more than 32 bit is currently not supported', 1008); + return; + } + opcodes['1'].getData.call(self, readUInt32BE.call(data, 4)); + }); + } + }, + getData: function(length) { + var self = this; + if (self.state.masked) { + self.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['1'].finish.call(self, mask, data); + }); + }); + } + else { + self.expectData(length, function(data) { + opcodes['1'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + var self = this; + var packet = this.unmask(mask, data, true) || new Buffer(0); + var state = clone(this.state); + this.messageHandlers.push(function(callback) { + self.applyExtensions(packet, state.lastFragment, state.compressed, function(err, buffer) { + if (err) return self.error(err.message, 1007); + if (buffer != null) self.currentMessage.push(buffer); + + if (state.lastFragment) { + var messageBuffer = self.concatBuffers(self.currentMessage); + self.currentMessage = []; + if (!Validation.isValidUTF8(messageBuffer)) { + self.error('invalid utf8 sequence', 1007); + return; + } + self.ontext(messageBuffer.toString('utf8'), {masked: state.masked, buffer: messageBuffer}); + } + callback(); + }); + }); + this.flush(); + this.endPacket(); + } + }, + // binary + '2': { + start: function(data) { + var self = this; + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['2'].getData.call(self, firstLength); + } + else if (firstLength == 126) { + self.expectHeader(2, function(data) { + opcodes['2'].getData.call(self, readUInt16BE.call(data, 0)); + }); + } + else if (firstLength == 127) { + self.expectHeader(8, function(data) { + if (readUInt32BE.call(data, 0) != 0) { + self.error('packets with length spanning more than 32 bit is currently not supported', 1008); + return; + } + opcodes['2'].getData.call(self, readUInt32BE.call(data, 4, true)); + }); + } + }, + getData: function(length) { + var self = this; + if (self.state.masked) { + self.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['2'].finish.call(self, mask, data); + }); + }); + } + else { + self.expectData(length, function(data) { + opcodes['2'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + var self = this; + var packet = this.unmask(mask, data, true) || new Buffer(0); + var state = clone(this.state); + this.messageHandlers.push(function(callback) { + self.applyExtensions(packet, state.lastFragment, state.compressed, function(err, buffer) { + if (err) return self.error(err.message, 1007); + if (buffer != null) self.currentMessage.push(buffer); + if (state.lastFragment) { + var messageBuffer = self.concatBuffers(self.currentMessage); + self.currentMessage = []; + self.onbinary(messageBuffer, {masked: state.masked, buffer: messageBuffer}); + } + callback(); + }); + }); + this.flush(); + this.endPacket(); + } + }, + // close + '8': { + start: function(data) { + var self = this; + if (self.state.lastFragment == false) { + self.error('fragmented close is not supported', 1002); + return; + } + + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['8'].getData.call(self, firstLength); + } + else { + self.error('control frames cannot have more than 125 bytes of data', 1002); + } + }, + getData: function(length) { + var self = this; + if (self.state.masked) { + self.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['8'].finish.call(self, mask, data); + }); + }); + } + else { + self.expectData(length, function(data) { + opcodes['8'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + var self = this; + data = self.unmask(mask, data, true); + + var state = clone(this.state); + this.messageHandlers.push(function() { + if (data && data.length == 1) { + self.error('close packets with data must be at least two bytes long', 1002); + return; + } + var code = data && data.length > 1 ? readUInt16BE.call(data, 0) : 1000; + if (!ErrorCodes.isValidErrorCode(code)) { + self.error('invalid error code', 1002); + return; + } + var message = ''; + if (data && data.length > 2) { + var messageBuffer = data.slice(2); + if (!Validation.isValidUTF8(messageBuffer)) { + self.error('invalid utf8 sequence', 1007); + return; + } + message = messageBuffer.toString('utf8'); + } + self.onclose(code, message, {masked: state.masked}); + self.reset(); + }); + this.flush(); + }, + }, + // ping + '9': { + start: function(data) { + var self = this; + if (self.state.lastFragment == false) { + self.error('fragmented ping is not supported', 1002); + return; + } + + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['9'].getData.call(self, firstLength); + } + else { + self.error('control frames cannot have more than 125 bytes of data', 1002); + } + }, + getData: function(length) { + var self = this; + if (self.state.masked) { + self.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['9'].finish.call(self, mask, data); + }); + }); + } + else { + self.expectData(length, function(data) { + opcodes['9'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + var self = this; + data = this.unmask(mask, data, true); + var state = clone(this.state); + this.messageHandlers.push(function(callback) { + self.onping(data, {masked: state.masked, binary: true}); + callback(); + }); + this.flush(); + this.endPacket(); + } + }, + // pong + '10': { + start: function(data) { + var self = this; + if (self.state.lastFragment == false) { + self.error('fragmented pong is not supported', 1002); + return; + } + + // decode length + var firstLength = data[1] & 0x7f; + if (firstLength < 126) { + opcodes['10'].getData.call(self, firstLength); + } + else { + self.error('control frames cannot have more than 125 bytes of data', 1002); + } + }, + getData: function(length) { + var self = this; + if (this.state.masked) { + this.expectHeader(4, function(data) { + var mask = data; + self.expectData(length, function(data) { + opcodes['10'].finish.call(self, mask, data); + }); + }); + } + else { + this.expectData(length, function(data) { + opcodes['10'].finish.call(self, null, data); + }); + } + }, + finish: function(mask, data) { + var self = this; + data = self.unmask(mask, data, true); + var state = clone(this.state); + this.messageHandlers.push(function(callback) { + self.onpong(data, {masked: state.masked, binary: true}); + callback(); + }); + this.flush(); + this.endPacket(); + } + } +} diff --git a/node_modules/ws/lib/Sender.hixie.js b/node_modules/ws/lib/Sender.hixie.js new file mode 100644 index 0000000..b87d9dd --- /dev/null +++ b/node_modules/ws/lib/Sender.hixie.js @@ -0,0 +1,124 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var events = require('events') + , util = require('util') + , EventEmitter = events.EventEmitter; + +/** + * Hixie Sender implementation + */ + +function Sender(socket) { + if (this instanceof Sender === false) { + throw new TypeError("Classes can't be function-called"); + } + + events.EventEmitter.call(this); + + this.socket = socket; + this.continuationFrame = false; + this.isClosed = false; +} + +module.exports = Sender; + +/** + * Inherits from EventEmitter. + */ + +util.inherits(Sender, events.EventEmitter); + +/** + * Frames and writes data. + * + * @api public + */ + +Sender.prototype.send = function(data, options, cb) { + if (this.isClosed) return; + + var isString = typeof data == 'string' + , length = isString ? Buffer.byteLength(data) : data.length + , lengthbytes = (length > 127) ? 2 : 1 // assume less than 2**14 bytes + , writeStartMarker = this.continuationFrame == false + , writeEndMarker = !options || !(typeof options.fin != 'undefined' && !options.fin) + , buffer = new Buffer((writeStartMarker ? ((options && options.binary) ? (1 + lengthbytes) : 1) : 0) + length + ((writeEndMarker && !(options && options.binary)) ? 1 : 0)) + , offset = writeStartMarker ? 1 : 0; + + if (writeStartMarker) { + if (options && options.binary) { + buffer.write('\x80', 'binary'); + // assume length less than 2**14 bytes + if (lengthbytes > 1) + buffer.write(String.fromCharCode(128+length/128), offset++, 'binary'); + buffer.write(String.fromCharCode(length&0x7f), offset++, 'binary'); + } else + buffer.write('\x00', 'binary'); + } + + if (isString) buffer.write(data, offset, 'utf8'); + else data.copy(buffer, offset, 0); + + if (writeEndMarker) { + if (options && options.binary) { + // sending binary, not writing end marker + } else + buffer.write('\xff', offset + length, 'binary'); + this.continuationFrame = false; + } + else this.continuationFrame = true; + + try { + this.socket.write(buffer, 'binary', cb); + } catch (e) { + this.error(e.toString()); + } +}; + +/** + * Sends a close instruction to the remote party. + * + * @api public + */ + +Sender.prototype.close = function(code, data, mask, cb) { + if (this.isClosed) return; + this.isClosed = true; + try { + if (this.continuationFrame) this.socket.write(new Buffer([0xff], 'binary')); + this.socket.write(new Buffer([0xff, 0x00]), 'binary', cb); + } catch (e) { + this.error(e.toString()); + } +}; + +/** + * Sends a ping message to the remote party. Not available for hixie. + * + * @api public + */ + +Sender.prototype.ping = function(data, options) {}; + +/** + * Sends a pong message to the remote party. Not available for hixie. + * + * @api public + */ + +Sender.prototype.pong = function(data, options) {}; + +/** + * Handles an error + * + * @api private + */ + +Sender.prototype.error = function (reason) { + this.emit('error', reason); + return this; +}; diff --git a/node_modules/ws/lib/Sender.js b/node_modules/ws/lib/Sender.js new file mode 100644 index 0000000..2f8f7c4 --- /dev/null +++ b/node_modules/ws/lib/Sender.js @@ -0,0 +1,316 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var events = require('events') + , util = require('util') + , EventEmitter = events.EventEmitter + , ErrorCodes = require('./ErrorCodes') + , bufferUtil = require('./BufferUtil').BufferUtil + , PerMessageDeflate = require('./PerMessageDeflate'); + +/** + * HyBi Sender implementation + */ + +function Sender(socket, extensions) { + if (this instanceof Sender === false) { + throw new TypeError("Classes can't be function-called"); + } + + events.EventEmitter.call(this); + + this._socket = socket; + this.extensions = extensions || {}; + this.firstFragment = true; + this.compress = false; + this.messageHandlers = []; + this.processing = false; +} + +/** + * Inherits from EventEmitter. + */ + +util.inherits(Sender, events.EventEmitter); + +/** + * Sends a close instruction to the remote party. + * + * @api public + */ + +Sender.prototype.close = function(code, data, mask, cb) { + if (typeof code !== 'undefined') { + if (typeof code !== 'number' || + !ErrorCodes.isValidErrorCode(code)) throw new Error('first argument must be a valid error code number'); + } + code = code || 1000; + var dataBuffer = new Buffer(2 + (data ? Buffer.byteLength(data) : 0)); + writeUInt16BE.call(dataBuffer, code, 0); + if (dataBuffer.length > 2) dataBuffer.write(data, 2); + + var self = this; + this.messageHandlers.push(function(callback) { + self.frameAndSend(0x8, dataBuffer, true, mask); + callback(); + if (typeof cb == 'function') cb(); + }); + this.flush(); +}; + +/** + * Sends a ping message to the remote party. + * + * @api public + */ + +Sender.prototype.ping = function(data, options) { + var mask = options && options.mask; + var self = this; + this.messageHandlers.push(function(callback) { + self.frameAndSend(0x9, data || '', true, mask); + callback(); + }); + this.flush(); +}; + +/** + * Sends a pong message to the remote party. + * + * @api public + */ + +Sender.prototype.pong = function(data, options) { + var mask = options && options.mask; + var self = this; + this.messageHandlers.push(function(callback) { + self.frameAndSend(0xa, data || '', true, mask); + callback(); + }); + this.flush(); +}; + +/** + * Sends text or binary data to the remote party. + * + * @api public + */ + +Sender.prototype.send = function(data, options, cb) { + var finalFragment = options && options.fin === false ? false : true; + var mask = options && options.mask; + var compress = options && options.compress; + var opcode = options && options.binary ? 2 : 1; + if (this.firstFragment === false) { + opcode = 0; + compress = false; + } else { + this.firstFragment = false; + this.compress = compress; + } + if (finalFragment) this.firstFragment = true + + var compressFragment = this.compress; + + var self = this; + this.messageHandlers.push(function(callback) { + self.applyExtensions(data, finalFragment, compressFragment, function(err, data) { + if (err) { + if (typeof cb == 'function') cb(err); + else self.emit('error', err); + return; + } + self.frameAndSend(opcode, data, finalFragment, mask, compress, cb); + callback(); + }); + }); + this.flush(); +}; + +/** + * Frames and sends a piece of data according to the HyBi WebSocket protocol. + * + * @api private + */ + +Sender.prototype.frameAndSend = function(opcode, data, finalFragment, maskData, compressed, cb) { + var canModifyData = false; + + if (!data) { + try { + this._socket.write(new Buffer([opcode | (finalFragment ? 0x80 : 0), 0 | (maskData ? 0x80 : 0)].concat(maskData ? [0, 0, 0, 0] : [])), 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + return; + } + + if (!Buffer.isBuffer(data)) { + canModifyData = true; + if (data && (typeof data.byteLength !== 'undefined' || typeof data.buffer !== 'undefined')) { + data = getArrayBuffer(data); + } else { + data = new Buffer(data); + } + } + + var dataLength = data.length + , dataOffset = maskData ? 6 : 2 + , secondByte = dataLength; + + if (dataLength >= 65536) { + dataOffset += 8; + secondByte = 127; + } + else if (dataLength > 125) { + dataOffset += 2; + secondByte = 126; + } + + var mergeBuffers = dataLength < 32768 || (maskData && !canModifyData); + var totalLength = mergeBuffers ? dataLength + dataOffset : dataOffset; + var outputBuffer = new Buffer(totalLength); + outputBuffer[0] = finalFragment ? opcode | 0x80 : opcode; + if (compressed) outputBuffer[0] |= 0x40; + + switch (secondByte) { + case 126: + writeUInt16BE.call(outputBuffer, dataLength, 2); + break; + case 127: + writeUInt32BE.call(outputBuffer, 0, 2); + writeUInt32BE.call(outputBuffer, dataLength, 6); + } + + if (maskData) { + outputBuffer[1] = secondByte | 0x80; + var mask = this._randomMask || (this._randomMask = getRandomMask()); + outputBuffer[dataOffset - 4] = mask[0]; + outputBuffer[dataOffset - 3] = mask[1]; + outputBuffer[dataOffset - 2] = mask[2]; + outputBuffer[dataOffset - 1] = mask[3]; + if (mergeBuffers) { + bufferUtil.mask(data, mask, outputBuffer, dataOffset, dataLength); + try { + this._socket.write(outputBuffer, 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + } + else { + bufferUtil.mask(data, mask, data, 0, dataLength); + try { + this._socket.write(outputBuffer, 'binary'); + this._socket.write(data, 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + } + } + else { + outputBuffer[1] = secondByte; + if (mergeBuffers) { + data.copy(outputBuffer, dataOffset); + try { + this._socket.write(outputBuffer, 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + } + else { + try { + this._socket.write(outputBuffer, 'binary'); + this._socket.write(data, 'binary', cb); + } + catch (e) { + if (typeof cb == 'function') cb(e); + else this.emit('error', e); + } + } + } +}; + +/** + * Execute message handler buffers + * + * @api private + */ + +Sender.prototype.flush = function() { + if (this.processing) return; + + var handler = this.messageHandlers.shift(); + if (!handler) return; + + this.processing = true; + + var self = this; + + handler(function() { + self.processing = false; + self.flush(); + }); +}; + +/** + * Apply extensions to message + * + * @api private + */ + +Sender.prototype.applyExtensions = function(data, fin, compress, callback) { + if (compress && data) { + if ((data.buffer || data) instanceof ArrayBuffer) { + data = getArrayBuffer(data); + } + this.extensions[PerMessageDeflate.extensionName].compress(data, fin, callback); + } else { + callback(null, data); + } +}; + +module.exports = Sender; + +function writeUInt16BE(value, offset) { + this[offset] = (value & 0xff00)>>8; + this[offset+1] = value & 0xff; +} + +function writeUInt32BE(value, offset) { + this[offset] = (value & 0xff000000)>>24; + this[offset+1] = (value & 0xff0000)>>16; + this[offset+2] = (value & 0xff00)>>8; + this[offset+3] = value & 0xff; +} + +function getArrayBuffer(data) { + // data is either an ArrayBuffer or ArrayBufferView. + var array = new Uint8Array(data.buffer || data) + , l = data.byteLength || data.length + , o = data.byteOffset || 0 + , buffer = new Buffer(l); + for (var i = 0; i < l; ++i) { + buffer[i] = array[o+i]; + } + return buffer; +} + +function getRandomMask() { + return new Buffer([ + ~~(Math.random() * 255), + ~~(Math.random() * 255), + ~~(Math.random() * 255), + ~~(Math.random() * 255) + ]); +} diff --git a/node_modules/ws/lib/Validation.fallback.js b/node_modules/ws/lib/Validation.fallback.js new file mode 100644 index 0000000..2c7c4fd --- /dev/null +++ b/node_modules/ws/lib/Validation.fallback.js @@ -0,0 +1,12 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +module.exports.Validation = { + isValidUTF8: function(buffer) { + return true; + } +}; + diff --git a/node_modules/ws/lib/Validation.js b/node_modules/ws/lib/Validation.js new file mode 100644 index 0000000..0795fb7 --- /dev/null +++ b/node_modules/ws/lib/Validation.js @@ -0,0 +1,13 @@ +'use strict'; + +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +try { + module.exports = require('utf-8-validate'); +} catch (e) { + module.exports = require('./Validation.fallback'); +} diff --git a/node_modules/ws/lib/WebSocket.js b/node_modules/ws/lib/WebSocket.js new file mode 100644 index 0000000..27144c0 --- /dev/null +++ b/node_modules/ws/lib/WebSocket.js @@ -0,0 +1,964 @@ +'use strict'; + +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var url = require('url') + , util = require('util') + , http = require('http') + , https = require('https') + , crypto = require('crypto') + , stream = require('stream') + , Ultron = require('ultron') + , Options = require('options') + , Sender = require('./Sender') + , Receiver = require('./Receiver') + , SenderHixie = require('./Sender.hixie') + , ReceiverHixie = require('./Receiver.hixie') + , Extensions = require('./Extensions') + , PerMessageDeflate = require('./PerMessageDeflate') + , EventEmitter = require('events').EventEmitter; + +/** + * Constants + */ + +// Default protocol version + +var protocolVersion = 13; + +// Close timeout + +var closeTimeout = 30 * 1000; // Allow 30 seconds to terminate the connection cleanly + +/** + * WebSocket implementation + * + * @constructor + * @param {String} address Connection address. + * @param {String|Array} protocols WebSocket protocols. + * @param {Object} options Additional connection options. + * @api public + */ +function WebSocket(address, protocols, options) { + if (this instanceof WebSocket === false) { + return new WebSocket(address, protocols, options); + } + + EventEmitter.call(this); + + if (protocols && !Array.isArray(protocols) && 'object' === typeof protocols) { + // accept the "options" Object as the 2nd argument + options = protocols; + protocols = null; + } + + if ('string' === typeof protocols) { + protocols = [ protocols ]; + } + + if (!Array.isArray(protocols)) { + protocols = []; + } + + this._socket = null; + this._ultron = null; + this._closeReceived = false; + this.bytesReceived = 0; + this.readyState = null; + this.supports = {}; + this.extensions = {}; + + if (Array.isArray(address)) { + initAsServerClient.apply(this, address.concat(options)); + } else { + initAsClient.apply(this, [address, protocols, options]); + } +} + +/** + * Inherits from EventEmitter. + */ +util.inherits(WebSocket, EventEmitter); + +/** + * Ready States + */ +["CONNECTING", "OPEN", "CLOSING", "CLOSED"].forEach(function each(state, index) { + WebSocket.prototype[state] = WebSocket[state] = index; +}); + +/** + * Gracefully closes the connection, after sending a description message to the server + * + * @param {Object} data to be sent to the server + * @api public + */ +WebSocket.prototype.close = function close(code, data) { + if (this.readyState === WebSocket.CLOSED) return; + + if (this.readyState === WebSocket.CONNECTING) { + this.readyState = WebSocket.CLOSED; + return; + } + + if (this.readyState === WebSocket.CLOSING) { + if (this._closeReceived && this._isServer) { + this.terminate(); + } + return; + } + + var self = this; + try { + this.readyState = WebSocket.CLOSING; + this._closeCode = code; + this._closeMessage = data; + var mask = !this._isServer; + this._sender.close(code, data, mask, function(err) { + if (err) self.emit('error', err); + + if (self._closeReceived && self._isServer) { + self.terminate(); + } else { + // ensure that the connection is cleaned up even when no response of closing handshake. + clearTimeout(self._closeTimer); + self._closeTimer = setTimeout(cleanupWebsocketResources.bind(self, true), closeTimeout); + } + }); + } catch (e) { + this.emit('error', e); + } +}; + +/** + * Pause the client stream + * + * @api public + */ +WebSocket.prototype.pause = function pauser() { + if (this.readyState !== WebSocket.OPEN) throw new Error('not opened'); + + return this._socket.pause(); +}; + +/** + * Sends a ping + * + * @param {Object} data to be sent to the server + * @param {Object} Members - mask: boolean, binary: boolean + * @param {boolean} dontFailWhenClosed indicates whether or not to throw if the connection isnt open + * @api public + */ +WebSocket.prototype.ping = function ping(data, options, dontFailWhenClosed) { + if (this.readyState !== WebSocket.OPEN) { + if (dontFailWhenClosed === true) return; + throw new Error('not opened'); + } + + options = options || {}; + + if (typeof options.mask === 'undefined') options.mask = !this._isServer; + + this._sender.ping(data, options); +}; + +/** + * Sends a pong + * + * @param {Object} data to be sent to the server + * @param {Object} Members - mask: boolean, binary: boolean + * @param {boolean} dontFailWhenClosed indicates whether or not to throw if the connection isnt open + * @api public + */ +WebSocket.prototype.pong = function(data, options, dontFailWhenClosed) { + if (this.readyState !== WebSocket.OPEN) { + if (dontFailWhenClosed === true) return; + throw new Error('not opened'); + } + + options = options || {}; + + if (typeof options.mask === 'undefined') options.mask = !this._isServer; + + this._sender.pong(data, options); +}; + +/** + * Resume the client stream + * + * @api public + */ +WebSocket.prototype.resume = function resume() { + if (this.readyState !== WebSocket.OPEN) throw new Error('not opened'); + + return this._socket.resume(); +}; + +/** + * Sends a piece of data + * + * @param {Object} data to be sent to the server + * @param {Object} Members - mask: boolean, binary: boolean, compress: boolean + * @param {function} Optional callback which is executed after the send completes + * @api public + */ + +WebSocket.prototype.send = function send(data, options, cb) { + if (typeof options === 'function') { + cb = options; + options = {}; + } + + if (this.readyState !== WebSocket.OPEN) { + if (typeof cb === 'function') cb(new Error('not opened')); + else throw new Error('not opened'); + return; + } + + if (!data) data = ''; + if (this._queue) { + var self = this; + this._queue.push(function() { self.send(data, options, cb); }); + return; + } + + options = options || {}; + options.fin = true; + + if (typeof options.binary === 'undefined') { + options.binary = (data instanceof ArrayBuffer || data instanceof Buffer || + data instanceof Uint8Array || + data instanceof Uint16Array || + data instanceof Uint32Array || + data instanceof Int8Array || + data instanceof Int16Array || + data instanceof Int32Array || + data instanceof Float32Array || + data instanceof Float64Array); + } + + if (typeof options.mask === 'undefined') options.mask = !this._isServer; + if (typeof options.compress === 'undefined') options.compress = true; + if (!this.extensions[PerMessageDeflate.extensionName]) { + options.compress = false; + } + + var readable = typeof stream.Readable === 'function' + ? stream.Readable + : stream.Stream; + + if (data instanceof readable) { + startQueue(this); + var self = this; + + sendStream(this, data, options, function send(error) { + process.nextTick(function tock() { + executeQueueSends(self); + }); + + if (typeof cb === 'function') cb(error); + }); + } else { + this._sender.send(data, options, cb); + } +}; + +/** + * Streams data through calls to a user supplied function + * + * @param {Object} Members - mask: boolean, binary: boolean, compress: boolean + * @param {function} 'function (error, send)' which is executed on successive ticks of which send is 'function (data, final)'. + * @api public + */ +WebSocket.prototype.stream = function stream(options, cb) { + if (typeof options === 'function') { + cb = options; + options = {}; + } + + var self = this; + + if (typeof cb !== 'function') throw new Error('callback must be provided'); + + if (this.readyState !== WebSocket.OPEN) { + if (typeof cb === 'function') cb(new Error('not opened')); + else throw new Error('not opened'); + return; + } + + if (this._queue) { + this._queue.push(function () { self.stream(options, cb); }); + return; + } + + options = options || {}; + + if (typeof options.mask === 'undefined') options.mask = !this._isServer; + if (typeof options.compress === 'undefined') options.compress = true; + if (!this.extensions[PerMessageDeflate.extensionName]) { + options.compress = false; + } + + startQueue(this); + + function send(data, final) { + try { + if (self.readyState !== WebSocket.OPEN) throw new Error('not opened'); + options.fin = final === true; + self._sender.send(data, options); + if (!final) process.nextTick(cb.bind(null, null, send)); + else executeQueueSends(self); + } catch (e) { + if (typeof cb === 'function') cb(e); + else { + delete self._queue; + self.emit('error', e); + } + } + } + + process.nextTick(cb.bind(null, null, send)); +}; + +/** + * Immediately shuts down the connection + * + * @api public + */ +WebSocket.prototype.terminate = function terminate() { + if (this.readyState === WebSocket.CLOSED) return; + + if (this._socket) { + this.readyState = WebSocket.CLOSING; + + // End the connection + try { this._socket.end(); } + catch (e) { + // Socket error during end() call, so just destroy it right now + cleanupWebsocketResources.call(this, true); + return; + } + + // Add a timeout to ensure that the connection is completely + // cleaned up within 30 seconds, even if the clean close procedure + // fails for whatever reason + // First cleanup any pre-existing timeout from an earlier "terminate" call, + // if one exists. Otherwise terminate calls in quick succession will leak timeouts + // and hold the program open for `closeTimout` time. + if (this._closeTimer) { clearTimeout(this._closeTimer); } + this._closeTimer = setTimeout(cleanupWebsocketResources.bind(this, true), closeTimeout); + } else if (this.readyState === WebSocket.CONNECTING) { + cleanupWebsocketResources.call(this, true); + } +}; + +/** + * Expose bufferedAmount + * + * @api public + */ +Object.defineProperty(WebSocket.prototype, 'bufferedAmount', { + get: function get() { + var amount = 0; + if (this._socket) { + amount = this._socket.bufferSize || 0; + } + return amount; + } +}); + +/** + * Emulates the W3C Browser based WebSocket interface using function members. + * + * @see http://dev.w3.org/html5/websockets/#the-websocket-interface + * @api public + */ +['open', 'error', 'close', 'message'].forEach(function(method) { + Object.defineProperty(WebSocket.prototype, 'on' + method, { + /** + * Returns the current listener + * + * @returns {Mixed} the set function or undefined + * @api public + */ + get: function get() { + var listener = this.listeners(method)[0]; + return listener ? (listener._listener ? listener._listener : listener) : undefined; + }, + + /** + * Start listening for events + * + * @param {Function} listener the listener + * @returns {Mixed} the set function or undefined + * @api public + */ + set: function set(listener) { + this.removeAllListeners(method); + this.addEventListener(method, listener); + } + }); +}); + +/** + * Emulates the W3C Browser based WebSocket interface using addEventListener. + * + * @see https://developer.mozilla.org/en/DOM/element.addEventListener + * @see http://dev.w3.org/html5/websockets/#the-websocket-interface + * @api public + */ +WebSocket.prototype.addEventListener = function(method, listener) { + var target = this; + + function onMessage (data, flags) { + listener.call(target, new MessageEvent(data, !!flags.binary, target)); + } + + function onClose (code, message) { + listener.call(target, new CloseEvent(code, message, target)); + } + + function onError (event) { + event.type = 'error'; + event.target = target; + listener.call(target, event); + } + + function onOpen () { + listener.call(target, new OpenEvent(target)); + } + + if (typeof listener === 'function') { + if (method === 'message') { + // store a reference so we can return the original function from the + // addEventListener hook + onMessage._listener = listener; + this.on(method, onMessage); + } else if (method === 'close') { + // store a reference so we can return the original function from the + // addEventListener hook + onClose._listener = listener; + this.on(method, onClose); + } else if (method === 'error') { + // store a reference so we can return the original function from the + // addEventListener hook + onError._listener = listener; + this.on(method, onError); + } else if (method === 'open') { + // store a reference so we can return the original function from the + // addEventListener hook + onOpen._listener = listener; + this.on(method, onOpen); + } else { + this.on(method, listener); + } + } +}; + +module.exports = WebSocket; +module.exports.buildHostHeader = buildHostHeader + +/** + * W3C MessageEvent + * + * @see http://www.w3.org/TR/html5/comms.html + * @constructor + * @api private + */ +function MessageEvent(dataArg, isBinary, target) { + this.type = 'message'; + this.data = dataArg; + this.target = target; + this.binary = isBinary; // non-standard. +} + +/** + * W3C CloseEvent + * + * @see http://www.w3.org/TR/html5/comms.html + * @constructor + * @api private + */ +function CloseEvent(code, reason, target) { + this.type = 'close'; + this.wasClean = (typeof code === 'undefined' || code === 1000); + this.code = code; + this.reason = reason; + this.target = target; +} + +/** + * W3C OpenEvent + * + * @see http://www.w3.org/TR/html5/comms.html + * @constructor + * @api private + */ +function OpenEvent(target) { + this.type = 'open'; + this.target = target; +} + +// Append port number to Host header, only if specified in the url +// and non-default +function buildHostHeader(isSecure, hostname, port) { + var headerHost = hostname; + if (hostname) { + if ((isSecure && (port != 443)) || (!isSecure && (port != 80))){ + headerHost = headerHost + ':' + port; + } + } + return headerHost; +} + +/** + * Entirely private apis, + * which may or may not be bound to a sepcific WebSocket instance. + */ +function initAsServerClient(req, socket, upgradeHead, options) { + options = new Options({ + protocolVersion: protocolVersion, + protocol: null, + extensions: {} + }).merge(options); + + // expose state properties + this.protocol = options.value.protocol; + this.protocolVersion = options.value.protocolVersion; + this.extensions = options.value.extensions; + this.supports.binary = (this.protocolVersion !== 'hixie-76'); + this.upgradeReq = req; + this.readyState = WebSocket.CONNECTING; + this._isServer = true; + + // establish connection + if (options.value.protocolVersion === 'hixie-76') { + establishConnection.call(this, ReceiverHixie, SenderHixie, socket, upgradeHead); + } else { + establishConnection.call(this, Receiver, Sender, socket, upgradeHead); + } +} + +function initAsClient(address, protocols, options) { + options = new Options({ + origin: null, + protocolVersion: protocolVersion, + host: null, + headers: null, + protocol: protocols.join(','), + agent: null, + + // ssl-related options + pfx: null, + key: null, + passphrase: null, + cert: null, + ca: null, + ciphers: null, + rejectUnauthorized: null, + perMessageDeflate: true, + localAddress: null + }).merge(options); + + if (options.value.protocolVersion !== 8 && options.value.protocolVersion !== 13) { + throw new Error('unsupported protocol version'); + } + + // verify URL and establish http class + var serverUrl = url.parse(address); + var isUnixSocket = serverUrl.protocol === 'ws+unix:'; + if (!serverUrl.host && !isUnixSocket) throw new Error('invalid url'); + var isSecure = serverUrl.protocol === 'wss:' || serverUrl.protocol === 'https:'; + var httpObj = isSecure ? https : http; + var port = serverUrl.port || (isSecure ? 443 : 80); + var auth = serverUrl.auth; + + // prepare extensions + var extensionsOffer = {}; + var perMessageDeflate; + if (options.value.perMessageDeflate) { + perMessageDeflate = new PerMessageDeflate(typeof options.value.perMessageDeflate !== true ? options.value.perMessageDeflate : {}, false); + extensionsOffer[PerMessageDeflate.extensionName] = perMessageDeflate.offer(); + } + + // expose state properties + this._isServer = false; + this.url = address; + this.protocolVersion = options.value.protocolVersion; + this.supports.binary = (this.protocolVersion !== 'hixie-76'); + + // begin handshake + var key = new Buffer(options.value.protocolVersion + '-' + Date.now()).toString('base64'); + var shasum = crypto.createHash('sha1'); + shasum.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'); + var expectedServerKey = shasum.digest('base64'); + + var agent = options.value.agent; + + var headerHost = buildHostHeader(isSecure, serverUrl.hostname, port) + + var requestOptions = { + port: port, + host: serverUrl.hostname, + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Host': headerHost, + 'Sec-WebSocket-Version': options.value.protocolVersion, + 'Sec-WebSocket-Key': key + } + }; + + // If we have basic auth. + if (auth) { + requestOptions.headers.Authorization = 'Basic ' + new Buffer(auth).toString('base64'); + } + + if (options.value.protocol) { + requestOptions.headers['Sec-WebSocket-Protocol'] = options.value.protocol; + } + + if (options.value.host) { + requestOptions.headers.Host = options.value.host; + } + + if (options.value.headers) { + for (var header in options.value.headers) { + if (options.value.headers.hasOwnProperty(header)) { + requestOptions.headers[header] = options.value.headers[header]; + } + } + } + + if (Object.keys(extensionsOffer).length) { + requestOptions.headers['Sec-WebSocket-Extensions'] = Extensions.format(extensionsOffer); + } + + if (options.isDefinedAndNonNull('pfx') + || options.isDefinedAndNonNull('key') + || options.isDefinedAndNonNull('passphrase') + || options.isDefinedAndNonNull('cert') + || options.isDefinedAndNonNull('ca') + || options.isDefinedAndNonNull('ciphers') + || options.isDefinedAndNonNull('rejectUnauthorized')) { + + if (options.isDefinedAndNonNull('pfx')) requestOptions.pfx = options.value.pfx; + if (options.isDefinedAndNonNull('key')) requestOptions.key = options.value.key; + if (options.isDefinedAndNonNull('passphrase')) requestOptions.passphrase = options.value.passphrase; + if (options.isDefinedAndNonNull('cert')) requestOptions.cert = options.value.cert; + if (options.isDefinedAndNonNull('ca')) requestOptions.ca = options.value.ca; + if (options.isDefinedAndNonNull('ciphers')) requestOptions.ciphers = options.value.ciphers; + if (options.isDefinedAndNonNull('rejectUnauthorized')) requestOptions.rejectUnauthorized = options.value.rejectUnauthorized; + + if (!agent) { + // global agent ignores client side certificates + agent = new httpObj.Agent(requestOptions); + } + } + + requestOptions.path = serverUrl.path || '/'; + + if (agent) { + requestOptions.agent = agent; + } + + if (isUnixSocket) { + requestOptions.socketPath = serverUrl.pathname; + } + + if (options.value.localAddress) { + requestOptions.localAddress = options.value.localAddress; + } + + if (options.value.origin) { + if (options.value.protocolVersion < 13) requestOptions.headers['Sec-WebSocket-Origin'] = options.value.origin; + else requestOptions.headers.Origin = options.value.origin; + } + + var self = this; + var req = httpObj.request(requestOptions); + + req.on('error', function onerror(error) { + self.emit('error', error); + cleanupWebsocketResources.call(self, error); + }); + + req.once('response', function response(res) { + var error; + + if (!self.emit('unexpected-response', req, res)) { + error = new Error('unexpected server response (' + res.statusCode + ')'); + req.abort(); + self.emit('error', error); + } + + cleanupWebsocketResources.call(self, error); + }); + + req.once('upgrade', function upgrade(res, socket, upgradeHead) { + if (self.readyState === WebSocket.CLOSED) { + // client closed before server accepted connection + self.emit('close'); + self.removeAllListeners(); + socket.end(); + return; + } + + var serverKey = res.headers['sec-websocket-accept']; + if (typeof serverKey === 'undefined' || serverKey !== expectedServerKey) { + self.emit('error', 'invalid server key'); + self.removeAllListeners(); + socket.end(); + return; + } + + var serverProt = res.headers['sec-websocket-protocol']; + var protList = (options.value.protocol || "").split(/, */); + var protError = null; + + if (!options.value.protocol && serverProt) { + protError = 'server sent a subprotocol even though none requested'; + } else if (options.value.protocol && !serverProt) { + protError = 'server sent no subprotocol even though requested'; + } else if (serverProt && protList.indexOf(serverProt) === -1) { + protError = 'server responded with an invalid protocol'; + } + + if (protError) { + self.emit('error', protError); + self.removeAllListeners(); + socket.end(); + return; + } else if (serverProt) { + self.protocol = serverProt; + } + + var serverExtensions = Extensions.parse(res.headers['sec-websocket-extensions']); + if (perMessageDeflate && serverExtensions[PerMessageDeflate.extensionName]) { + try { + perMessageDeflate.accept(serverExtensions[PerMessageDeflate.extensionName]); + } catch (err) { + self.emit('error', 'invalid extension parameter'); + self.removeAllListeners(); + socket.end(); + return; + } + self.extensions[PerMessageDeflate.extensionName] = perMessageDeflate; + } + + establishConnection.call(self, Receiver, Sender, socket, upgradeHead); + + // perform cleanup on http resources + req.removeAllListeners(); + req = null; + agent = null; + }); + + req.end(); + this.readyState = WebSocket.CONNECTING; +} + +function establishConnection(ReceiverClass, SenderClass, socket, upgradeHead) { + var ultron = this._ultron = new Ultron(socket) + , called = false + , self = this; + + socket.setTimeout(0); + socket.setNoDelay(true); + + this._receiver = new ReceiverClass(this.extensions); + this._socket = socket; + + // socket cleanup handlers + ultron.on('end', cleanupWebsocketResources.bind(this)); + ultron.on('close', cleanupWebsocketResources.bind(this)); + ultron.on('error', cleanupWebsocketResources.bind(this)); + + // ensure that the upgradeHead is added to the receiver + function firstHandler(data) { + if (called || self.readyState === WebSocket.CLOSED) return; + + called = true; + socket.removeListener('data', firstHandler); + ultron.on('data', realHandler); + + if (upgradeHead && upgradeHead.length > 0) { + realHandler(upgradeHead); + upgradeHead = null; + } + + if (data) realHandler(data); + } + + // subsequent packets are pushed straight to the receiver + function realHandler(data) { + self.bytesReceived += data.length; + self._receiver.add(data); + } + + ultron.on('data', firstHandler); + + // if data was passed along with the http upgrade, + // this will schedule a push of that on to the receiver. + // this has to be done on next tick, since the caller + // hasn't had a chance to set event handlers on this client + // object yet. + process.nextTick(firstHandler); + + // receiver event handlers + self._receiver.ontext = function ontext(data, flags) { + flags = flags || {}; + + self.emit('message', data, flags); + }; + + self._receiver.onbinary = function onbinary(data, flags) { + flags = flags || {}; + + flags.binary = true; + self.emit('message', data, flags); + }; + + self._receiver.onping = function onping(data, flags) { + flags = flags || {}; + + self.pong(data, { + mask: !self._isServer, + binary: flags.binary === true + }, true); + + self.emit('ping', data, flags); + }; + + self._receiver.onpong = function onpong(data, flags) { + self.emit('pong', data, flags || {}); + }; + + self._receiver.onclose = function onclose(code, data, flags) { + flags = flags || {}; + + self._closeReceived = true; + self.close(code, data); + }; + + self._receiver.onerror = function onerror(reason, errorCode) { + // close the connection when the receiver reports a HyBi error code + self.close(typeof errorCode !== 'undefined' ? errorCode : 1002, ''); + self.emit('error', reason, errorCode); + }; + + // finalize the client + this._sender = new SenderClass(socket, this.extensions); + this._sender.on('error', function onerror(error) { + self.close(1002, ''); + self.emit('error', error); + }); + + this.readyState = WebSocket.OPEN; + this.emit('open'); +} + +function startQueue(instance) { + instance._queue = instance._queue || []; +} + +function executeQueueSends(instance) { + var queue = instance._queue; + if (typeof queue === 'undefined') return; + + delete instance._queue; + for (var i = 0, l = queue.length; i < l; ++i) { + queue[i](); + } +} + +function sendStream(instance, stream, options, cb) { + stream.on('data', function incoming(data) { + if (instance.readyState !== WebSocket.OPEN) { + if (typeof cb === 'function') cb(new Error('not opened')); + else { + delete instance._queue; + instance.emit('error', new Error('not opened')); + } + return; + } + + options.fin = false; + instance._sender.send(data, options); + }); + + stream.on('end', function end() { + if (instance.readyState !== WebSocket.OPEN) { + if (typeof cb === 'function') cb(new Error('not opened')); + else { + delete instance._queue; + instance.emit('error', new Error('not opened')); + } + return; + } + + options.fin = true; + instance._sender.send(null, options); + + if (typeof cb === 'function') cb(null); + }); +} + +function cleanupWebsocketResources(error) { + if (this.readyState === WebSocket.CLOSED) return; + + var emitClose = this.readyState !== WebSocket.CONNECTING; + this.readyState = WebSocket.CLOSED; + + clearTimeout(this._closeTimer); + this._closeTimer = null; + + if (emitClose) { + // If the connection was closed abnormally (with an error), + // then the close code must default to 1006. + if (error) { + this._closeCode = 1006; + } + this.emit('close', this._closeCode || 1000, this._closeMessage || ''); + } + + if (this._socket) { + if (this._ultron) this._ultron.destroy(); + this._socket.on('error', function onerror() { + try { this.destroy(); } + catch (e) {} + }); + + try { + if (!error) this._socket.end(); + else this._socket.destroy(); + } catch (e) { /* Ignore termination errors */ } + + this._socket = null; + this._ultron = null; + } + + if (this._sender) { + this._sender.removeAllListeners(); + this._sender = null; + } + + if (this._receiver) { + this._receiver.cleanup(); + this._receiver = null; + } + + if (this.extensions[PerMessageDeflate.extensionName]) { + this.extensions[PerMessageDeflate.extensionName].cleanup(); + } + + this.extensions = null; + + this.removeAllListeners(); + this.on('error', function onerror() {}); // catch all errors after this + delete this._queue; +} diff --git a/node_modules/ws/lib/WebSocketServer.js b/node_modules/ws/lib/WebSocketServer.js new file mode 100644 index 0000000..ba0e4c0 --- /dev/null +++ b/node_modules/ws/lib/WebSocketServer.js @@ -0,0 +1,513 @@ +/*! + * ws: a node.js websocket client + * Copyright(c) 2011 Einar Otto Stangvik + * MIT Licensed + */ + +var util = require('util') + , events = require('events') + , http = require('http') + , crypto = require('crypto') + , Options = require('options') + , WebSocket = require('./WebSocket') + , Extensions = require('./Extensions') + , PerMessageDeflate = require('./PerMessageDeflate') + , tls = require('tls') + , url = require('url'); + +/** + * WebSocket Server implementation + */ + +function WebSocketServer(options, callback) { + if (this instanceof WebSocketServer === false) { + return new WebSocketServer(options, callback); + } + + events.EventEmitter.call(this); + + options = new Options({ + host: '0.0.0.0', + port: null, + server: null, + verifyClient: null, + handleProtocols: null, + path: null, + noServer: false, + disableHixie: false, + clientTracking: true, + perMessageDeflate: true + }).merge(options); + + if (!options.isDefinedAndNonNull('port') && !options.isDefinedAndNonNull('server') && !options.value.noServer) { + throw new TypeError('`port` or a `server` must be provided'); + } + + var self = this; + + if (options.isDefinedAndNonNull('port')) { + this._server = http.createServer(function (req, res) { + var body = http.STATUS_CODES[426]; + res.writeHead(426, { + 'Content-Length': body.length, + 'Content-Type': 'text/plain' + }); + res.end(body); + }); + this._server.allowHalfOpen = false; + this._server.listen(options.value.port, options.value.host, callback); + this._closeServer = function() { if (self._server) self._server.close(); }; + } + else if (options.value.server) { + this._server = options.value.server; + if (options.value.path) { + // take note of the path, to avoid collisions when multiple websocket servers are + // listening on the same http server + if (this._server._webSocketPaths && options.value.server._webSocketPaths[options.value.path]) { + throw new Error('two instances of WebSocketServer cannot listen on the same http server path'); + } + if (typeof this._server._webSocketPaths !== 'object') { + this._server._webSocketPaths = {}; + } + this._server._webSocketPaths[options.value.path] = 1; + } + } + if (this._server) this._server.once('listening', function() { self.emit('listening'); }); + + if (typeof this._server != 'undefined') { + this._server.on('error', function(error) { + self.emit('error', error) + }); + this._server.on('upgrade', function(req, socket, upgradeHead) { + //copy upgradeHead to avoid retention of large slab buffers used in node core + var head = new Buffer(upgradeHead.length); + upgradeHead.copy(head); + + self.handleUpgrade(req, socket, head, function(client) { + self.emit('connection'+req.url, client); + self.emit('connection', client); + }); + }); + } + + this.options = options.value; + this.path = options.value.path; + this.clients = []; +} + +/** + * Inherits from EventEmitter. + */ + +util.inherits(WebSocketServer, events.EventEmitter); + +/** + * Immediately shuts down the connection. + * + * @api public + */ + +WebSocketServer.prototype.close = function(callback) { + // terminate all associated clients + var error = null; + try { + for (var i = 0, l = this.clients.length; i < l; ++i) { + this.clients[i].terminate(); + } + } + catch (e) { + error = e; + } + + // remove path descriptor, if any + if (this.path && this._server._webSocketPaths) { + delete this._server._webSocketPaths[this.path]; + if (Object.keys(this._server._webSocketPaths).length == 0) { + delete this._server._webSocketPaths; + } + } + + // close the http server if it was internally created + try { + if (typeof this._closeServer !== 'undefined') { + this._closeServer(); + } + } + finally { + delete this._server; + } + if(callback) + callback(error); + else if(error) + throw error; +} + +/** + * Handle a HTTP Upgrade request. + * + * @api public + */ + +WebSocketServer.prototype.handleUpgrade = function(req, socket, upgradeHead, cb) { + // check for wrong path + if (this.options.path) { + var u = url.parse(req.url); + if (u && u.pathname !== this.options.path) return; + } + + if (typeof req.headers.upgrade === 'undefined' || req.headers.upgrade.toLowerCase() !== 'websocket') { + abortConnection(socket, 400, 'Bad Request'); + return; + } + + if (req.headers['sec-websocket-key1']) handleHixieUpgrade.apply(this, arguments); + else handleHybiUpgrade.apply(this, arguments); +} + +module.exports = WebSocketServer; + +/** + * Entirely private apis, + * which may or may not be bound to a sepcific WebSocket instance. + */ + +function handleHybiUpgrade(req, socket, upgradeHead, cb) { + // handle premature socket errors + var errorHandler = function() { + try { socket.destroy(); } catch (e) {} + } + socket.on('error', errorHandler); + + // verify key presence + if (!req.headers['sec-websocket-key']) { + abortConnection(socket, 400, 'Bad Request'); + return; + } + + // verify version + var version = parseInt(req.headers['sec-websocket-version']); + if ([8, 13].indexOf(version) === -1) { + abortConnection(socket, 400, 'Bad Request'); + return; + } + + // verify protocol + var protocols = req.headers['sec-websocket-protocol']; + + // verify client + var origin = version < 13 ? + req.headers['sec-websocket-origin'] : + req.headers['origin']; + + // handle extensions offer + var extensionsOffer = Extensions.parse(req.headers['sec-websocket-extensions']); + + // handler to call when the connection sequence completes + var self = this; + var completeHybiUpgrade2 = function(protocol) { + + // calc key + var key = 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 + ]; + + if (typeof protocol != 'undefined') { + headers.push('Sec-WebSocket-Protocol: ' + protocol); + } + + var extensions = {}; + try { + extensions = acceptExtensions.call(self, extensionsOffer); + } catch (err) { + abortConnection(socket, 400, 'Bad Request'); + return; + } + + if (Object.keys(extensions).length) { + var serverExtensions = {}; + Object.keys(extensions).forEach(function(token) { + serverExtensions[token] = [extensions[token].params] + }); + headers.push('Sec-WebSocket-Extensions: ' + Extensions.format(serverExtensions)); + } + + // allows external modification/inspection of handshake headers + self.emit('headers', headers); + + socket.setTimeout(0); + socket.setNoDelay(true); + try { + socket.write(headers.concat('', '').join('\r\n')); + } + catch (e) { + // if the upgrade write fails, shut the connection down hard + try { socket.destroy(); } catch (e) {} + return; + } + + var client = new WebSocket([req, socket, upgradeHead], { + protocolVersion: version, + protocol: protocol, + extensions: extensions + }); + + if (self.options.clientTracking) { + self.clients.push(client); + client.on('close', function() { + var index = self.clients.indexOf(client); + if (index != -1) { + self.clients.splice(index, 1); + } + }); + } + + // signal upgrade complete + socket.removeListener('error', errorHandler); + cb(client); + } + + // optionally call external protocol selection handler before + // calling completeHybiUpgrade2 + var completeHybiUpgrade1 = function() { + // choose from the sub-protocols + if (typeof self.options.handleProtocols == 'function') { + var protList = (protocols || "").split(/, */); + var callbackCalled = false; + var res = self.options.handleProtocols(protList, function(result, protocol) { + callbackCalled = true; + if (!result) abortConnection(socket, 401, 'Unauthorized'); + else completeHybiUpgrade2(protocol); + }); + if (!callbackCalled) { + // the handleProtocols handler never called our callback + abortConnection(socket, 501, 'Could not process protocols'); + } + return; + } else { + if (typeof protocols !== 'undefined') { + completeHybiUpgrade2(protocols.split(/, */)[0]); + } + else { + completeHybiUpgrade2(); + } + } + } + + // optionally call external client verification handler + if (typeof this.options.verifyClient == 'function') { + var info = { + origin: origin, + secure: typeof req.connection.authorized !== 'undefined' || typeof req.connection.encrypted !== 'undefined', + req: req + }; + if (this.options.verifyClient.length == 2) { + this.options.verifyClient(info, function(result, code, name) { + if (typeof code === 'undefined') code = 401; + if (typeof name === 'undefined') name = http.STATUS_CODES[code]; + + if (!result) abortConnection(socket, code, name); + else completeHybiUpgrade1(); + }); + return; + } + else if (!this.options.verifyClient(info)) { + abortConnection(socket, 401, 'Unauthorized'); + return; + } + } + + completeHybiUpgrade1(); +} + +function handleHixieUpgrade(req, socket, upgradeHead, cb) { + // handle premature socket errors + var errorHandler = function() { + try { socket.destroy(); } catch (e) {} + } + socket.on('error', errorHandler); + + // bail if options prevent hixie + if (this.options.disableHixie) { + abortConnection(socket, 401, 'Hixie support disabled'); + return; + } + + // verify key presence + if (!req.headers['sec-websocket-key2']) { + abortConnection(socket, 400, 'Bad Request'); + return; + } + + var origin = req.headers['origin'] + , self = this; + + // setup handshake completion to run after client has been verified + var onClientVerified = function() { + var wshost; + if (!req.headers['x-forwarded-host']) + wshost = req.headers.host; + else + wshost = req.headers['x-forwarded-host']; + var location = ((req.headers['x-forwarded-proto'] === 'https' || socket.encrypted) ? 'wss' : 'ws') + '://' + wshost + req.url + , protocol = req.headers['sec-websocket-protocol']; + + // handshake completion code to run once nonce has been successfully retrieved + var completeHandshake = function(nonce, rest) { + // calculate key + var k1 = req.headers['sec-websocket-key1'] + , k2 = req.headers['sec-websocket-key2'] + , 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){ + abortConnection(socket, 400, 'Bad Request'); + return; + } + n /= spaces; + md5.update(String.fromCharCode( + n >> 24 & 0xFF, + n >> 16 & 0xFF, + n >> 8 & 0xFF, + n & 0xFF)); + }); + md5.update(nonce.toString('binary')); + + var headers = [ + 'HTTP/1.1 101 Switching Protocols' + , 'Upgrade: WebSocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Location: ' + location + ]; + if (typeof protocol != 'undefined') headers.push('Sec-WebSocket-Protocol: ' + protocol); + if (typeof origin != 'undefined') headers.push('Sec-WebSocket-Origin: ' + origin); + + socket.setTimeout(0); + socket.setNoDelay(true); + try { + // merge header and hash buffer + var headerBuffer = new Buffer(headers.concat('', '').join('\r\n')); + var hashBuffer = new Buffer(md5.digest('binary'), 'binary'); + var handshakeBuffer = new Buffer(headerBuffer.length + hashBuffer.length); + headerBuffer.copy(handshakeBuffer, 0); + hashBuffer.copy(handshakeBuffer, headerBuffer.length); + + // do a single write, which - upon success - causes a new client websocket to be setup + socket.write(handshakeBuffer, 'binary', function(err) { + if (err) return; // do not create client if an error happens + var client = new WebSocket([req, socket, rest], { + protocolVersion: 'hixie-76', + protocol: protocol + }); + if (self.options.clientTracking) { + self.clients.push(client); + client.on('close', function() { + var index = self.clients.indexOf(client); + if (index != -1) { + self.clients.splice(index, 1); + } + }); + } + + // signal upgrade complete + socket.removeListener('error', errorHandler); + cb(client); + }); + } + catch (e) { + try { socket.destroy(); } catch (e) {} + return; + } + } + + // retrieve nonce + var nonceLength = 8; + if (upgradeHead && upgradeHead.length >= nonceLength) { + var nonce = upgradeHead.slice(0, nonceLength); + var rest = upgradeHead.length > nonceLength ? upgradeHead.slice(nonceLength) : null; + completeHandshake.call(self, nonce, rest); + } + else { + // nonce not present in upgradeHead, so we must wait for enough data + // data to arrive before continuing + var nonce = new Buffer(nonceLength); + upgradeHead.copy(nonce, 0); + var received = upgradeHead.length; + var rest = null; + var handler = function (data) { + var toRead = Math.min(data.length, nonceLength - received); + if (toRead === 0) return; + data.copy(nonce, received, 0, toRead); + received += toRead; + if (received == nonceLength) { + socket.removeListener('data', handler); + if (toRead < data.length) rest = data.slice(toRead); + completeHandshake.call(self, nonce, rest); + } + } + socket.on('data', handler); + } + } + + // verify client + if (typeof this.options.verifyClient == 'function') { + var info = { + origin: origin, + secure: typeof req.connection.authorized !== 'undefined' || typeof req.connection.encrypted !== 'undefined', + req: req + }; + if (this.options.verifyClient.length == 2) { + var self = this; + this.options.verifyClient(info, function(result, code, name) { + if (typeof code === 'undefined') code = 401; + if (typeof name === 'undefined') name = http.STATUS_CODES[code]; + + if (!result) abortConnection(socket, code, name); + else onClientVerified.apply(self); + }); + return; + } + else if (!this.options.verifyClient(info)) { + abortConnection(socket, 401, 'Unauthorized'); + return; + } + } + + // no client verification required + onClientVerified(); +} + +function acceptExtensions(offer) { + var extensions = {}; + var options = this.options.perMessageDeflate; + if (options && offer[PerMessageDeflate.extensionName]) { + var perMessageDeflate = new PerMessageDeflate(options !== true ? options : {}, true); + perMessageDeflate.accept(offer[PerMessageDeflate.extensionName]); + extensions[PerMessageDeflate.extensionName] = perMessageDeflate; + } + return extensions; +} + +function abortConnection(socket, code, name) { + try { + var response = [ + 'HTTP/1.1 ' + code + ' ' + name, + 'Content-type: text/html' + ]; + socket.write(response.concat('', '').join('\r\n')); + } + catch (e) { /* ignore errors - we've aborted this connection */ } + finally { + // ensure that an early aborted connection is shut down completely + try { socket.destroy(); } catch (e) {} + } +} diff --git a/node_modules/ws/lib/browser.js b/node_modules/ws/lib/browser.js new file mode 100644 index 0000000..8d3a755 --- /dev/null +++ b/node_modules/ws/lib/browser.js @@ -0,0 +1,43 @@ + +/** + * Module dependencies. + */ + +var global = (function() { return this; })(); + +/** + * WebSocket constructor. + */ + +var WebSocket = global.WebSocket || global.MozWebSocket; + +/** + * Module exports. + */ + +module.exports = WebSocket ? ws : null; + +/** + * WebSocket constructor. + * + * The third `opts` options object gets ignored in web browsers, since it's + * non-standard, and throws a TypeError if passed to the constructor. + * See: https://github.com/einaros/ws/issues/227 + * + * @param {String} uri + * @param {Array} protocols (optional) + * @param {Object) opts (optional) + * @api public + */ + +function ws(uri, protocols, opts) { + var instance; + if (protocols) { + instance = new WebSocket(uri, protocols); + } else { + instance = new WebSocket(uri); + } + return instance; +} + +if (WebSocket) ws.prototype = WebSocket.prototype; diff --git a/node_modules/ws/package.json b/node_modules/ws/package.json new file mode 100644 index 0000000..3223367 --- /dev/null +++ b/node_modules/ws/package.json @@ -0,0 +1,111 @@ +{ + "_args": [ + [ + "ws", + "/Applications/MAMP/htdocs/stream2/WebRTC-Example" + ] + ], + "_from": "ws@*", + "_id": "ws@0.8.1", + "_inCache": true, + "_installable": true, + "_location": "/ws", + "_nodeVersion": "4.2.1", + "_npmUser": { + "email": "npm@3rd-Eden.com", + "name": "3rdeden" + }, + "_npmVersion": "2.14.7", + "_phantomChildren": {}, + "_requested": { + "name": "ws", + "raw": "ws", + "rawSpec": "", + "scope": null, + "spec": "*", + "type": "range" + }, + "_requiredBy": [ + "#USER" + ], + "_resolved": "https://registry.npmjs.org/ws/-/ws-0.8.1.tgz", + "_shasum": "6b65273b99193c5f067a4cf5809598f777e3b759", + "_shrinkwrap": null, + "_spec": "ws", + "_where": "/Applications/MAMP/htdocs/stream2/WebRTC-Example", + "author": { + "email": "einaros@gmail.com", + "name": "Einar Otto Stangvik", + "url": "http://2x.io" + }, + "browser": "./lib/browser.js", + "bugs": { + "url": "https://github.com/websockets/ws/issues" + }, + "component": { + "scripts": { + "ws/index.js": "./lib/browser.js" + } + }, + "dependencies": { + "bufferutil": "1.2.x", + "options": ">=0.0.5", + "ultron": "1.0.x", + "utf-8-validate": "1.2.x" + }, + "description": "simple to use, blazing fast and thoroughly tested websocket client, server and console for node.js, up-to-date against RFC-6455", + "devDependencies": { + "ansi": "0.3.x", + "benchmark": "0.3.x", + "expect.js": "0.3.x", + "mocha": "2.2.x", + "should": "4.3.x", + "tinycolor": "0.0.x" + }, + "directories": {}, + "dist": { + "shasum": "6b65273b99193c5f067a4cf5809598f777e3b759", + "tarball": "http://registry.npmjs.org/ws/-/ws-0.8.1.tgz" + }, + "gitHead": "74f567e0221a14071bb40eb1902e946524a11862", + "gypfile": true, + "homepage": "https://github.com/websockets/ws#readme", + "keywords": [ + "Hixie", + "HyBi", + "Push", + "RFC-6455", + "WebSocket", + "WebSockets", + "real-time" + ], + "license": "MIT", + "maintainers": [ + { + "name": "einaros", + "email": "einaros@gmail.com" + }, + { + "name": "v1", + "email": "info@3rd-Eden.com" + }, + { + "name": "3rdeden", + "email": "npm@3rd-Eden.com" + } + ], + "name": "ws", + "optionalDependencies": { + "bufferutil": "1.2.x", + "utf-8-validate": "1.2.x" + }, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git://github.com/websockets/ws.git" + }, + "scripts": { + "test": "make test" + }, + "version": "0.8.1" +}