aboutsummaryrefslogtreecommitdiffhomepage
path: root/node_modules/ws
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/ws')
-rw-r--r--node_modules/ws/LICENSE21
-rw-r--r--node_modules/ws/README.md260
-rw-r--r--node_modules/ws/index.js15
-rw-r--r--node_modules/ws/lib/BufferUtil.js71
-rw-r--r--node_modules/ws/lib/Constants.js10
-rw-r--r--node_modules/ws/lib/ErrorCodes.js28
-rw-r--r--node_modules/ws/lib/EventTarget.js155
-rw-r--r--node_modules/ws/lib/Extensions.js67
-rw-r--r--node_modules/ws/lib/PerMessageDeflate.js384
-rw-r--r--node_modules/ws/lib/Receiver.js555
-rw-r--r--node_modules/ws/lib/Sender.js403
-rw-r--r--node_modules/ws/lib/Validation.js17
-rw-r--r--node_modules/ws/lib/WebSocket.js712
-rw-r--r--node_modules/ws/lib/WebSocketServer.js336
-rw-r--r--node_modules/ws/node_modules/safe-buffer/.travis.yml7
-rw-r--r--node_modules/ws/node_modules/safe-buffer/LICENSE21
-rw-r--r--node_modules/ws/node_modules/safe-buffer/README.md581
-rw-r--r--node_modules/ws/node_modules/safe-buffer/browser.js1
-rw-r--r--node_modules/ws/node_modules/safe-buffer/index.js58
-rw-r--r--node_modules/ws/node_modules/safe-buffer/package.json103
-rw-r--r--node_modules/ws/node_modules/safe-buffer/test.js99
-rw-r--r--node_modules/ws/package.json127
22 files changed, 4031 insertions, 0 deletions
diff --git a/node_modules/ws/LICENSE b/node_modules/ws/LICENSE
new file mode 100644
index 0000000..a145cd1
--- /dev/null
+++ b/node_modules/ws/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+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.
diff --git a/node_modules/ws/README.md b/node_modules/ws/README.md
new file mode 100644
index 0000000..1ca0bdb
--- /dev/null
+++ b/node_modules/ws/README.md
@@ -0,0 +1,260 @@
+# ws: a Node.js WebSocket library
+
+[![Version npm](https://img.shields.io/npm/v/ws.svg)](https://www.npmjs.com/package/ws)
+[![Linux Build](https://img.shields.io/travis/websockets/ws/master.svg)](https://travis-ci.org/websockets/ws)
+[![Windows Build](https://ci.appveyor.com/api/projects/status/github/websockets/ws?branch=master&svg=true)](https://ci.appveyor.com/project/lpinca/ws)
+[![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg)](https://coveralls.io/r/websockets/ws?branch=master)
+
+`ws` is a simple to use, blazing fast, and thoroughly tested WebSocket client
+and server implementation.
+
+Passes the quite extensive Autobahn test suite. See http://websockets.github.io/ws/
+for the full reports.
+
+**Note**: This module does not work in the browser. The client in the docs is a
+reference to a back end with the role of a client in the WebSocket
+communication. Browser clients must use the native
+[`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) object.
+
+## Protocol support
+
+* **HyBi drafts 07-12** (Use the option `protocolVersion: 8`)
+* **HyBi drafts 13-17** (Current default, alternatively option `protocolVersion: 13`)
+
+## Installing
+
+```
+npm install --save ws
+```
+
+### Opt-in for performance and spec compliance
+
+There are 2 optional modules that can be installed along side with the `ws`
+module. These modules are binary addons which improve certain operations.
+Prebuilt binaries are available for the most popular platforms so you don't
+necessarily need to have a C++ compiler installed on your machine.
+
+- `npm install --save-optional bufferutil`: Allows to efficiently perform
+ operations such as masking and unmasking the data payload of the WebSocket
+ frames.
+- `npm install --save-optional utf-8-validate`: Allows to efficiently check
+ if a message contains valid UTF-8 as required by the spec.
+
+## 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.
+
+## WebSocket compression
+
+`ws` supports the [permessage-deflate extension][permessage-deflate] which
+enables the client and server to negotiate a compression algorithm and its
+parameters, and then selectively apply it to the data payloads of each
+WebSocket message.
+
+The extension is enabled by default but adds a significant overhead in terms of
+performance and memory comsumption. We suggest to use WebSocket compression
+only if it is really needed.
+
+To disable the extension you can set the `perMessageDeflate` option to `false`.
+On the server:
+
+```js
+const WebSocket = require('ws');
+
+const wss = new WebSocket.Server({
+ perMessageDeflate: false,
+ port: 8080
+});
+```
+
+On the client:
+
+```js
+const WebSocket = require('ws');
+
+const ws = new WebSocket('ws://www.host.com/path', {
+ perMessageDeflate: false
+});
+```
+
+## Usage examples
+
+### Sending and receiving text data
+
+```js
+const WebSocket = require('ws');
+
+const ws = new WebSocket('ws://www.host.com/path');
+
+ws.on('open', function open() {
+ ws.send('something');
+});
+
+ws.on('message', function incoming(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
+const WebSocket = require('ws');
+
+const ws = new WebSocket('ws://www.host.com/path');
+
+ws.on('open', function open() {
+ const array = new Float32Array(5);
+
+ for (var i = 0; i < array.length; ++i) {
+ array[i] = i / 2;
+ }
+
+ ws.send(array);
+});
+```
+
+### Server example
+
+```js
+const WebSocket = require('ws');
+
+const wss = new WebSocket.Server({ port: 8080 });
+
+wss.on('connection', function connection(ws) {
+ ws.on('message', function incoming(message) {
+ console.log('received: %s', message);
+ });
+
+ ws.send('something');
+});
+```
+
+### Broadcast example
+
+```js
+const WebSocket = require('ws');
+
+const wss = new WebSocket.Server({ port: 8080 });
+
+// Broadcast to all.
+wss.broadcast = function broadcast(data) {
+ wss.clients.forEach(function each(client) {
+ if (client.readyState === WebSocket.OPEN) {
+ client.send(data);
+ }
+ });
+};
+
+wss.on('connection', function connection(ws) {
+ ws.on('message', function incoming(data) {
+ // Broadcast to everyone else.
+ wss.clients.forEach(function each(client) {
+ if (client !== ws && client.readyState === WebSocket.OPEN) {
+ client.send(data);
+ }
+ });
+ });
+});
+```
+
+### ExpressJS example
+
+```js
+const express = require('express');
+const http = require('http');
+const url = require('url');
+const WebSocket = require('ws');
+
+const app = express();
+
+app.use(function (req, res) {
+ res.send({ msg: "hello" });
+});
+
+const server = http.createServer(app);
+const wss = new WebSocket.Server({ server });
+
+wss.on('connection', function connection(ws) {
+ const 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.listen(8080, function listening() {
+ console.log('Listening on %d', server.address().port);
+});
+```
+
+### echo.websocket.org demo
+
+```js
+const WebSocket = require('ws');
+
+const ws = new WebSocket('wss://echo.websocket.org/', {
+ origin: 'https://websocket.org'
+});
+
+ws.on('open', function open() {
+ console.log('connected');
+ ws.send(Date.now());
+});
+
+ws.on('close', function close() {
+ console.log('disconnected');
+});
+
+ws.on('message', function incoming(data, flags) {
+ console.log(`Roundtrip time: ${Date.now() - data} ms`, flags);
+
+ setTimeout(function timeout() {
+ ws.send(Date.now());
+ }, 500);
+});
+```
+
+### Other examples
+
+For a full example with a browser client communicating with a ws server, see the
+examples folder.
+
+Otherwise, see the test cases.
+
+## 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`, 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 */ }
+```
+
+## Changelog
+
+We're using the GitHub [`releases`](https://github.com/websockets/ws/releases)
+for changelog entries.
+
+## License
+
+[MIT](LICENSE)
+
+[permessage-deflate]: https://tools.ietf.org/html/rfc7692
diff --git a/node_modules/ws/index.js b/node_modules/ws/index.js
new file mode 100644
index 0000000..489e169
--- /dev/null
+++ b/node_modules/ws/index.js
@@ -0,0 +1,15 @@
+/*!
+ * ws: a node.js websocket client
+ * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+'use strict';
+
+const WebSocket = require('./lib/WebSocket');
+
+WebSocket.Server = require('./lib/WebSocketServer');
+WebSocket.Receiver = require('./lib/Receiver');
+WebSocket.Sender = require('./lib/Sender');
+
+module.exports = WebSocket;
diff --git a/node_modules/ws/lib/BufferUtil.js b/node_modules/ws/lib/BufferUtil.js
new file mode 100644
index 0000000..6a35e8f
--- /dev/null
+++ b/node_modules/ws/lib/BufferUtil.js
@@ -0,0 +1,71 @@
+/*!
+ * ws: a node.js websocket client
+ * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+'use strict';
+
+const safeBuffer = require('safe-buffer');
+
+const Buffer = safeBuffer.Buffer;
+
+/**
+ * Merges an array of buffers into a new buffer.
+ *
+ * @param {Buffer[]} list The array of buffers to concat
+ * @param {Number} totalLength The total length of buffers in the list
+ * @return {Buffer} The resulting buffer
+ * @public
+ */
+const concat = (list, totalLength) => {
+ const target = Buffer.allocUnsafe(totalLength);
+ var offset = 0;
+
+ for (var i = 0; i < list.length; i++) {
+ const buf = list[i];
+ buf.copy(target, offset);
+ offset += buf.length;
+ }
+
+ return target;
+};
+
+try {
+ const bufferUtil = require('bufferutil');
+
+ module.exports = Object.assign({ concat }, bufferUtil.BufferUtil || bufferUtil);
+} catch (e) /* istanbul ignore next */ {
+ /**
+ * Masks a buffer using the given mask.
+ *
+ * @param {Buffer} source The buffer to mask
+ * @param {Buffer} mask The mask to use
+ * @param {Buffer} output The buffer where to store the result
+ * @param {Number} offset The offset at which to start writing
+ * @param {Number} length The number of bytes to mask.
+ * @public
+ */
+ const mask = (source, mask, output, offset, length) => {
+ for (var i = 0; i < length; i++) {
+ output[offset + i] = source[i] ^ mask[i & 3];
+ }
+ };
+
+ /**
+ * Unmasks a buffer using the given mask.
+ *
+ * @param {Buffer} buffer The buffer to unmask
+ * @param {Buffer} mask The mask to use
+ * @public
+ */
+ const unmask = (buffer, mask) => {
+ // Required until https://github.com/nodejs/node/issues/9006 is resolved.
+ const length = buffer.length;
+ for (var i = 0; i < length; i++) {
+ buffer[i] ^= mask[i & 3];
+ }
+ };
+
+ module.exports = { concat, mask, unmask };
+}
diff --git a/node_modules/ws/lib/Constants.js b/node_modules/ws/lib/Constants.js
new file mode 100644
index 0000000..3904414
--- /dev/null
+++ b/node_modules/ws/lib/Constants.js
@@ -0,0 +1,10 @@
+'use strict';
+
+const safeBuffer = require('safe-buffer');
+
+const Buffer = safeBuffer.Buffer;
+
+exports.BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments'];
+exports.GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
+exports.EMPTY_BUFFER = Buffer.alloc(0);
+exports.NOOP = () => {};
diff --git a/node_modules/ws/lib/ErrorCodes.js b/node_modules/ws/lib/ErrorCodes.js
new file mode 100644
index 0000000..f515571
--- /dev/null
+++ b/node_modules/ws/lib/ErrorCodes.js
@@ -0,0 +1,28 @@
+/*!
+ * ws: a node.js websocket client
+ * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+'use strict';
+
+module.exports = {
+ isValidErrorCode: function (code) {
+ return (code >= 1000 && code <= 1013 && 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',
+ 1012: 'service restart',
+ 1013: 'try again later'
+};
diff --git a/node_modules/ws/lib/EventTarget.js b/node_modules/ws/lib/EventTarget.js
new file mode 100644
index 0000000..e30b1b3
--- /dev/null
+++ b/node_modules/ws/lib/EventTarget.js
@@ -0,0 +1,155 @@
+'use strict';
+
+/**
+ * Class representing an event.
+ *
+ * @private
+ */
+class Event {
+ /**
+ * Create a new `Event`.
+ *
+ * @param {String} type The name of the event
+ * @param {Object} target A reference to the target to which the event was dispatched
+ */
+ constructor (type, target) {
+ this.target = target;
+ this.type = type;
+ }
+}
+
+/**
+ * Class representing a message event.
+ *
+ * @extends Event
+ * @private
+ */
+class MessageEvent extends Event {
+ /**
+ * Create a new `MessageEvent`.
+ *
+ * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The received data
+ * @param {Boolean} isBinary Specifies if `data` is binary
+ * @param {WebSocket} target A reference to the target to which the event was dispatched
+ */
+ constructor (data, isBinary, target) {
+ super('message', target);
+
+ this.binary = isBinary; // non-standard.
+ this.data = data;
+ }
+}
+
+/**
+ * Class representing a close event.
+ *
+ * @extends Event
+ * @private
+ */
+class CloseEvent extends Event {
+ /**
+ * Create a new `CloseEvent`.
+ *
+ * @param {Number} code The status code explaining why the connection is being closed
+ * @param {String} reason A human-readable string explaining why the connection is closing
+ * @param {WebSocket} target A reference to the target to which the event was dispatched
+ */
+ constructor (code, reason, target) {
+ super('close', target);
+
+ this.wasClean = code === undefined || code === 1000;
+ this.reason = reason;
+ this.target = target;
+ this.type = 'close';
+ this.code = code;
+ }
+}
+
+/**
+ * Class representing an open event.
+ *
+ * @extends Event
+ * @private
+ */
+class OpenEvent extends Event {
+ /**
+ * Create a new `OpenEvent`.
+ *
+ * @param {WebSocket} target A reference to the target to which the event was dispatched
+ */
+ constructor (target) {
+ super('open', target);
+ }
+}
+
+/**
+ * This provides methods for emulating the `EventTarget` interface. It's not
+ * meant to be used directly.
+ *
+ * @mixin
+ */
+const EventTarget = {
+ /**
+ * Register an event listener.
+ *
+ * @param {String} method A string representing the event type to listen for
+ * @param {Function} listener The listener to add
+ * @public
+ */
+ addEventListener (method, listener) {
+ if (typeof listener !== 'function') return;
+
+ function onMessage (data, flags) {
+ listener.call(this, new MessageEvent(data, !!flags.binary, this));
+ }
+
+ function onClose (code, message) {
+ listener.call(this, new CloseEvent(code, message, this));
+ }
+
+ function onError (event) {
+ event.type = 'error';
+ event.target = this;
+ listener.call(this, event);
+ }
+
+ function onOpen () {
+ listener.call(this, new OpenEvent(this));
+ }
+
+ if (method === 'message') {
+ onMessage._listener = listener;
+ this.on(method, onMessage);
+ } else if (method === 'close') {
+ onClose._listener = listener;
+ this.on(method, onClose);
+ } else if (method === 'error') {
+ onError._listener = listener;
+ this.on(method, onError);
+ } else if (method === 'open') {
+ onOpen._listener = listener;
+ this.on(method, onOpen);
+ } else {
+ this.on(method, listener);
+ }
+ },
+
+ /**
+ * Remove an event listener.
+ *
+ * @param {String} method A string representing the event type to remove
+ * @param {Function} listener The listener to remove
+ * @public
+ */
+ removeEventListener (method, listener) {
+ const listeners = this.listeners(method);
+
+ for (var i = 0; i < listeners.length; i++) {
+ if (listeners[i] === listener || listeners[i]._listener === listener) {
+ this.removeListener(method, listeners[i]);
+ }
+ }
+ }
+};
+
+module.exports = EventTarget;
diff --git a/node_modules/ws/lib/Extensions.js b/node_modules/ws/lib/Extensions.js
new file mode 100644
index 0000000..a91910e
--- /dev/null
+++ b/node_modules/ws/lib/Extensions.js
@@ -0,0 +1,67 @@
+'use strict';
+
+/**
+ * Parse the `Sec-WebSocket-Extensions` header into an object.
+ *
+ * @param {String} value field value of the header
+ * @return {Object} The parsed object
+ * @public
+ */
+const parse = (value) => {
+ value = value || '';
+
+ const extensions = {};
+
+ value.split(',').forEach((v) => {
+ const params = v.split(';');
+ const token = params.shift().trim();
+ const paramsList = extensions[token] = extensions[token] || [];
+ const parsedParams = {};
+
+ params.forEach((param) => {
+ const parts = param.trim().split('=');
+ const key = parts[0];
+ var value = parts[1];
+
+ if (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;
+};
+
+/**
+ * Serialize a parsed `Sec-WebSocket-Extensions` header to a string.
+ *
+ * @param {Object} value The object to format
+ * @return {String} A string representing the given value
+ * @public
+ */
+const format = (value) => {
+ return Object.keys(value).map((token) => {
+ var paramsList = value[token];
+ if (!Array.isArray(paramsList)) paramsList = [paramsList];
+ return paramsList.map((params) => {
+ return [token].concat(Object.keys(params).map((k) => {
+ var p = params[k];
+ if (!Array.isArray(p)) p = [p];
+ return p.map((v) => v === true ? k : `${k}=${v}`).join('; ');
+ })).join('; ');
+ }).join(', ');
+ }).join(', ');
+};
+
+module.exports = { format, parse };
diff --git a/node_modules/ws/lib/PerMessageDeflate.js b/node_modules/ws/lib/PerMessageDeflate.js
new file mode 100644
index 0000000..c1a1d3c
--- /dev/null
+++ b/node_modules/ws/lib/PerMessageDeflate.js
@@ -0,0 +1,384 @@
+'use strict';
+
+const safeBuffer = require('safe-buffer');
+const zlib = require('zlib');
+
+const bufferUtil = require('./BufferUtil');
+
+const Buffer = safeBuffer.Buffer;
+
+const AVAILABLE_WINDOW_BITS = [8, 9, 10, 11, 12, 13, 14, 15];
+const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);
+const EMPTY_BLOCK = Buffer.from([0x00]);
+const DEFAULT_WINDOW_BITS = 15;
+const DEFAULT_MEM_LEVEL = 8;
+
+/**
+ * Per-message Deflate implementation.
+ */
+class PerMessageDeflate {
+ constructor (options, isServer, maxPayload) {
+ this._options = options || {};
+ this._isServer = !!isServer;
+ this._inflate = null;
+ this._deflate = null;
+ this.params = null;
+ this._maxPayload = maxPayload || 0;
+ this.threshold = this._options.threshold === undefined ? 1024 : this._options.threshold;
+ }
+
+ static get extensionName () {
+ return 'permessage-deflate';
+ }
+
+ /**
+ * Create extension parameters offer.
+ *
+ * @return {Object} Extension parameters
+ * @public
+ */
+ offer () {
+ const 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.
+ *
+ * @param {Array} paramsList Extension parameters
+ * @return {Object} Accepted configuration
+ * @public
+ */
+ accept (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.
+ *
+ * @public
+ */
+ cleanup () {
+ if (this._inflate) {
+ if (this._inflate.writeInProgress) {
+ this._inflate.pendingClose = true;
+ } else {
+ this._inflate.close();
+ this._inflate = null;
+ }
+ }
+ if (this._deflate) {
+ if (this._deflate.writeInProgress) {
+ this._deflate.pendingClose = true;
+ } else {
+ this._deflate.close();
+ this._deflate = null;
+ }
+ }
+ }
+
+ /**
+ * Accept extension offer from client.
+ *
+ * @param {Array} paramsList Extension parameters
+ * @return {Object} Accepted configuration
+ * @private
+ */
+ acceptAsServer (paramsList) {
+ const accepted = {};
+ const result = paramsList.some((params) => {
+ if ((
+ this._options.serverNoContextTakeover === false &&
+ params.server_no_context_takeover
+ ) || (
+ this._options.serverMaxWindowBits === false &&
+ params.server_max_window_bits
+ ) || (
+ typeof this._options.serverMaxWindowBits === 'number' &&
+ typeof params.server_max_window_bits === 'number' &&
+ this._options.serverMaxWindowBits > params.server_max_window_bits
+ ) || (
+ 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;
+ });
+
+ if (!result) throw new Error(`Doesn't support the offered configuration`);
+
+ return accepted;
+ }
+
+ /**
+ * Accept extension response from server.
+ *
+ * @param {Array} paramsList Extension parameters
+ * @return {Object} Accepted configuration
+ * @private
+ */
+ acceptAsClient (paramsList) {
+ const 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.
+ *
+ * @param {Array} paramsList Extension parameters
+ * @return {Array} Normalized extensions parameters
+ * @private
+ */
+ normalizeParams (paramsList) {
+ return paramsList.map((params) => {
+ Object.keys(params).forEach((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})`);
+ }
+ });
+ return params;
+ });
+ }
+
+ /**
+ * Decompress data.
+ *
+ * @param {Buffer} data Compressed data
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
+ * @param {Function} callback Callback
+ * @public
+ */
+ decompress (data, fin, callback) {
+ const endpoint = this._isServer ? 'client' : 'server';
+
+ if (!this._inflate) {
+ const maxWindowBits = this.params[`${endpoint}_max_window_bits`];
+ this._inflate = zlib.createInflateRaw({
+ windowBits: typeof maxWindowBits === 'number' ? maxWindowBits : DEFAULT_WINDOW_BITS
+ });
+ }
+ this._inflate.writeInProgress = true;
+
+ var totalLength = 0;
+ const buffers = [];
+ var err;
+
+ const onData = (data) => {
+ totalLength += data.length;
+ if (this._maxPayload < 1 || totalLength <= this._maxPayload) {
+ return buffers.push(data);
+ }
+
+ err = new Error('max payload size exceeded');
+ err.closeCode = 1009;
+ this._inflate.reset();
+ };
+
+ const onError = (err) => {
+ cleanup();
+ callback(err);
+ };
+
+ const cleanup = () => {
+ if (!this._inflate) return;
+
+ this._inflate.removeListener('error', onError);
+ this._inflate.removeListener('data', onData);
+ this._inflate.writeInProgress = false;
+
+ if (
+ (fin && this.params[`${endpoint}_no_context_takeover`]) ||
+ this._inflate.pendingClose
+ ) {
+ this._inflate.close();
+ this._inflate = null;
+ }
+ };
+
+ this._inflate.on('error', onError).on('data', onData);
+ this._inflate.write(data);
+ if (fin) this._inflate.write(TRAILER);
+
+ this._inflate.flush(() => {
+ cleanup();
+ if (err) callback(err);
+ else callback(null, bufferUtil.concat(buffers, totalLength));
+ });
+ }
+
+ /**
+ * Compress data.
+ *
+ * @param {Buffer} data Data to compress
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
+ * @param {Function} callback Callback
+ * @public
+ */
+ compress (data, fin, callback) {
+ if (!data || data.length === 0) {
+ process.nextTick(callback, null, EMPTY_BLOCK);
+ return;
+ }
+
+ const endpoint = this._isServer ? 'server' : 'client';
+
+ if (!this._deflate) {
+ const maxWindowBits = this.params[`${endpoint}_max_window_bits`];
+ this._deflate = zlib.createDeflateRaw({
+ flush: zlib.Z_SYNC_FLUSH,
+ windowBits: typeof maxWindowBits === 'number' ? maxWindowBits : DEFAULT_WINDOW_BITS,
+ memLevel: this._options.memLevel || DEFAULT_MEM_LEVEL
+ });
+ }
+ this._deflate.writeInProgress = true;
+
+ var totalLength = 0;
+ const buffers = [];
+
+ const onData = (data) => {
+ totalLength += data.length;
+ buffers.push(data);
+ };
+
+ const onError = (err) => {
+ cleanup();
+ callback(err);
+ };
+
+ const cleanup = () => {
+ if (!this._deflate) return;
+
+ this._deflate.removeListener('error', onError);
+ this._deflate.removeListener('data', onData);
+ this._deflate.writeInProgress = false;
+
+ if (
+ (fin && this.params[`${endpoint}_no_context_takeover`]) ||
+ this._deflate.pendingClose
+ ) {
+ this._deflate.close();
+ this._deflate = null;
+ }
+ };
+
+ this._deflate.on('error', onError).on('data', onData);
+ this._deflate.write(data);
+ this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {
+ cleanup();
+ var data = bufferUtil.concat(buffers, totalLength);
+ if (fin) data = data.slice(0, data.length - 4);
+ callback(null, data);
+ });
+ }
+}
+
+module.exports = PerMessageDeflate;
diff --git a/node_modules/ws/lib/Receiver.js b/node_modules/ws/lib/Receiver.js
new file mode 100644
index 0000000..6c1a10e
--- /dev/null
+++ b/node_modules/ws/lib/Receiver.js
@@ -0,0 +1,555 @@
+/*!
+ * ws: a node.js websocket client
+ * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+'use strict';
+
+const safeBuffer = require('safe-buffer');
+
+const PerMessageDeflate = require('./PerMessageDeflate');
+const isValidUTF8 = require('./Validation');
+const bufferUtil = require('./BufferUtil');
+const ErrorCodes = require('./ErrorCodes');
+const constants = require('./Constants');
+
+const Buffer = safeBuffer.Buffer;
+
+const GET_INFO = 0;
+const GET_PAYLOAD_LENGTH_16 = 1;
+const GET_PAYLOAD_LENGTH_64 = 2;
+const GET_MASK = 3;
+const GET_DATA = 4;
+const INFLATING = 5;
+
+/**
+ * HyBi Receiver implementation.
+ */
+class Receiver {
+ /**
+ * Creates a Receiver instance.
+ *
+ * @param {Object} extensions An object containing the negotiated extensions
+ * @param {Number} maxPayload The maximum allowed message length
+ * @param {String} binaryType The type for binary data
+ */
+ constructor (extensions, maxPayload, binaryType) {
+ this.binaryType = binaryType || constants.BINARY_TYPES[0];
+ this.extensions = extensions || {};
+ this.maxPayload = maxPayload | 0;
+
+ this.bufferedBytes = 0;
+ this.buffers = [];
+
+ this.compressed = false;
+ this.payloadLength = 0;
+ this.fragmented = 0;
+ this.masked = false;
+ this.fin = false;
+ this.mask = null;
+ this.opcode = 0;
+
+ this.totalPayloadLength = 0;
+ this.messageLength = 0;
+ this.fragments = [];
+
+ this.cleanupCallback = null;
+ this.hadError = false;
+ this.dead = false;
+ this.loop = false;
+
+ this.onmessage = null;
+ this.onclose = null;
+ this.onerror = null;
+ this.onping = null;
+ this.onpong = null;
+
+ this.state = GET_INFO;
+ }
+
+ /**
+ * Consumes bytes from the available buffered data.
+ *
+ * @param {Number} bytes The number of bytes to consume
+ * @return {Buffer} Consumed bytes
+ * @private
+ */
+ readBuffer (bytes) {
+ var offset = 0;
+ var dst;
+ var l;
+
+ this.bufferedBytes -= bytes;
+
+ if (bytes === this.buffers[0].length) return this.buffers.shift();
+
+ if (bytes < this.buffers[0].length) {
+ dst = this.buffers[0].slice(0, bytes);
+ this.buffers[0] = this.buffers[0].slice(bytes);
+ return dst;
+ }
+
+ dst = Buffer.allocUnsafe(bytes);
+
+ while (bytes > 0) {
+ l = this.buffers[0].length;
+
+ if (bytes >= l) {
+ this.buffers[0].copy(dst, offset);
+ offset += l;
+ this.buffers.shift();
+ } else {
+ this.buffers[0].copy(dst, offset, 0, bytes);
+ this.buffers[0] = this.buffers[0].slice(bytes);
+ }
+
+ bytes -= l;
+ }
+
+ return dst;
+ }
+
+ /**
+ * Checks if the number of buffered bytes is bigger or equal than `n` and
+ * calls `cleanup` if necessary.
+ *
+ * @param {Number} n The number of bytes to check against
+ * @return {Boolean} `true` if `bufferedBytes >= n`, else `false`
+ * @private
+ */
+ hasBufferedBytes (n) {
+ if (this.bufferedBytes >= n) return true;
+
+ this.loop = false;
+ if (this.dead) this.cleanup(this.cleanupCallback);
+ return false;
+ }
+
+ /**
+ * Adds new data to the parser.
+ *
+ * @public
+ */
+ add (data) {
+ if (this.dead) return;
+
+ this.bufferedBytes += data.length;
+ this.buffers.push(data);
+ this.startLoop();
+ }
+
+ /**
+ * Starts the parsing loop.
+ *
+ * @private
+ */
+ startLoop () {
+ this.loop = true;
+
+ while (this.loop) {
+ switch (this.state) {
+ case GET_INFO:
+ this.getInfo();
+ break;
+ case GET_PAYLOAD_LENGTH_16:
+ this.getPayloadLength16();
+ break;
+ case GET_PAYLOAD_LENGTH_64:
+ this.getPayloadLength64();
+ break;
+ case GET_MASK:
+ this.getMask();
+ break;
+ case GET_DATA:
+ this.getData();
+ break;
+ default: // `INFLATING`
+ this.loop = false;
+ }
+ }
+ }
+
+ /**
+ * Reads the first two bytes of a frame.
+ *
+ * @private
+ */
+ getInfo () {
+ if (!this.hasBufferedBytes(2)) return;
+
+ const buf = this.readBuffer(2);
+
+ if ((buf[0] & 0x30) !== 0x00) {
+ this.error(new Error('RSV2 and RSV3 must be clear'), 1002);
+ return;
+ }
+
+ const compressed = (buf[0] & 0x40) === 0x40;
+
+ if (compressed && !this.extensions[PerMessageDeflate.extensionName]) {
+ this.error(new Error('RSV1 must be clear'), 1002);
+ return;
+ }
+
+ this.fin = (buf[0] & 0x80) === 0x80;
+ this.opcode = buf[0] & 0x0f;
+ this.payloadLength = buf[1] & 0x7f;
+
+ if (this.opcode === 0x00) {
+ if (compressed) {
+ this.error(new Error('RSV1 must be clear'), 1002);
+ return;
+ }
+
+ if (!this.fragmented) {
+ this.error(new Error(`invalid opcode: ${this.opcode}`), 1002);
+ return;
+ } else {
+ this.opcode = this.fragmented;
+ }
+ } else if (this.opcode === 0x01 || this.opcode === 0x02) {
+ if (this.fragmented) {
+ this.error(new Error(`invalid opcode: ${this.opcode}`), 1002);
+ return;
+ }
+
+ this.compressed = compressed;
+ } else if (this.opcode > 0x07 && this.opcode < 0x0b) {
+ if (!this.fin) {
+ this.error(new Error('FIN must be set'), 1002);
+ return;
+ }
+
+ if (compressed) {
+ this.error(new Error('RSV1 must be clear'), 1002);
+ return;
+ }
+
+ if (this.payloadLength > 0x7d) {
+ this.error(new Error('invalid payload length'), 1002);
+ return;
+ }
+ } else {
+ this.error(new Error(`invalid opcode: ${this.opcode}`), 1002);
+ return;
+ }
+
+ if (!this.fin && !this.fragmented) this.fragmented = this.opcode;
+
+ this.masked = (buf[1] & 0x80) === 0x80;
+
+ if (this.payloadLength === 126) this.state = GET_PAYLOAD_LENGTH_16;
+ else if (this.payloadLength === 127) this.state = GET_PAYLOAD_LENGTH_64;
+ else this.haveLength();
+ }
+
+ /**
+ * Gets extended payload length (7+16).
+ *
+ * @private
+ */
+ getPayloadLength16 () {
+ if (!this.hasBufferedBytes(2)) return;
+
+ this.payloadLength = this.readBuffer(2).readUInt16BE(0, true);
+ this.haveLength();
+ }
+
+ /**
+ * Gets extended payload length (7+64).
+ *
+ * @private
+ */
+ getPayloadLength64 () {
+ if (!this.hasBufferedBytes(8)) return;
+
+ const buf = this.readBuffer(8);
+ const num = buf.readUInt32BE(0, true);
+
+ //
+ // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned
+ // if payload length is greater than this number.
+ //
+ if (num > Math.pow(2, 53 - 32) - 1) {
+ this.error(new Error('max payload size exceeded'), 1009);
+ return;
+ }
+
+ this.payloadLength = (num * Math.pow(2, 32)) + buf.readUInt32BE(4, true);
+ this.haveLength();
+ }
+
+ /**
+ * Payload length has been read.
+ *
+ * @private
+ */
+ haveLength () {
+ if (this.opcode < 0x08 && this.maxPayloadExceeded(this.payloadLength)) {
+ return;
+ }
+
+ if (this.masked) this.state = GET_MASK;
+ else this.state = GET_DATA;
+ }
+
+ /**
+ * Reads mask bytes.
+ *
+ * @private
+ */
+ getMask () {
+ if (!this.hasBufferedBytes(4)) return;
+
+ this.mask = this.readBuffer(4);
+ this.state = GET_DATA;
+ }
+
+ /**
+ * Reads data bytes.
+ *
+ * @private
+ */
+ getData () {
+ var data = constants.EMPTY_BUFFER;
+
+ if (this.payloadLength) {
+ if (!this.hasBufferedBytes(this.payloadLength)) return;
+
+ data = this.readBuffer(this.payloadLength);
+ if (this.masked) bufferUtil.unmask(data, this.mask);
+ }
+
+ if (this.opcode > 0x07) {
+ this.controlMessage(data);
+ } else if (this.compressed) {
+ this.state = INFLATING;
+ this.decompress(data);
+ } else if (this.pushFragment(data)) {
+ this.dataMessage();
+ }
+ }
+
+ /**
+ * Decompresses data.
+ *
+ * @param {Buffer} data Compressed data
+ * @private
+ */
+ decompress (data) {
+ const extension = this.extensions[PerMessageDeflate.extensionName];
+
+ extension.decompress(data, this.fin, (err, buf) => {
+ if (err) {
+ this.error(err, err.closeCode === 1009 ? 1009 : 1007);
+ return;
+ }
+
+ if (this.pushFragment(buf)) this.dataMessage();
+ this.startLoop();
+ });
+ }
+
+ /**
+ * Handles a data message.
+ *
+ * @private
+ */
+ dataMessage () {
+ if (this.fin) {
+ const messageLength = this.messageLength;
+ const fragments = this.fragments;
+
+ this.totalPayloadLength = 0;
+ this.messageLength = 0;
+ this.fragmented = 0;
+ this.fragments = [];
+
+ if (this.opcode === 2) {
+ var data;
+
+ if (this.binaryType === 'nodebuffer') {
+ data = toBuffer(fragments, messageLength);
+ } else if (this.binaryType === 'arraybuffer') {
+ data = toArrayBuffer(toBuffer(fragments, messageLength));
+ } else {
+ data = fragments;
+ }
+
+ this.onmessage(data, { masked: this.masked, binary: true });
+ } else {
+ const buf = toBuffer(fragments, messageLength);
+
+ if (!isValidUTF8(buf)) {
+ this.error(new Error('invalid utf8 sequence'), 1007);
+ return;
+ }
+
+ this.onmessage(buf.toString(), { masked: this.masked });
+ }
+ }
+
+ this.state = GET_INFO;
+ }
+
+ /**
+ * Handles a control message.
+ *
+ * @param {Buffer} data Data to handle
+ * @private
+ */
+ controlMessage (data) {
+ if (this.opcode === 0x08) {
+ if (data.length === 0) {
+ this.onclose(1000, '', { masked: this.masked });
+ this.loop = false;
+ this.cleanup(this.cleanupCallback);
+ } else if (data.length === 1) {
+ this.error(new Error('invalid payload length'), 1002);
+ } else {
+ const code = data.readUInt16BE(0, true);
+
+ if (!ErrorCodes.isValidErrorCode(code)) {
+ this.error(new Error(`invalid status code: ${code}`), 1002);
+ return;
+ }
+
+ const buf = data.slice(2);
+
+ if (!isValidUTF8(buf)) {
+ this.error(new Error('invalid utf8 sequence'), 1007);
+ return;
+ }
+
+ this.onclose(code, buf.toString(), { masked: this.masked });
+ this.loop = false;
+ this.cleanup(this.cleanupCallback);
+ }
+
+ return;
+ }
+
+ const flags = { masked: this.masked, binary: true };
+
+ if (this.opcode === 0x09) this.onping(data, flags);
+ else this.onpong(data, flags);
+
+ this.state = GET_INFO;
+ }
+
+ /**
+ * Handles an error.
+ *
+ * @param {Error} err The error
+ * @param {Number} code Close code
+ * @private
+ */
+ error (err, code) {
+ this.onerror(err, code);
+ this.hadError = true;
+ this.loop = false;
+ this.cleanup(this.cleanupCallback);
+ }
+
+ /**
+ * Checks payload size, disconnects socket when it exceeds `maxPayload`.
+ *
+ * @param {Number} length Payload length
+ * @private
+ */
+ maxPayloadExceeded (length) {
+ if (length === 0 || this.maxPayload < 1) return false;
+
+ const fullLength = this.totalPayloadLength + length;
+
+ if (fullLength <= this.maxPayload) {
+ this.totalPayloadLength = fullLength;
+ return false;
+ }
+
+ this.error(new Error('max payload size exceeded'), 1009);
+ return true;
+ }
+
+ /**
+ * Appends a fragment in the fragments array after checking that the sum of
+ * fragment lengths does not exceed `maxPayload`.
+ *
+ * @param {Buffer} fragment The fragment to add
+ * @return {Boolean} `true` if `maxPayload` is not exceeded, else `false`
+ * @private
+ */
+ pushFragment (fragment) {
+ if (fragment.length === 0) return true;
+
+ const totalLength = this.messageLength + fragment.length;
+
+ if (this.maxPayload < 1 || totalLength <= this.maxPayload) {
+ this.messageLength = totalLength;
+ this.fragments.push(fragment);
+ return true;
+ }
+
+ this.error(new Error('max payload size exceeded'), 1009);
+ return false;
+ }
+
+ /**
+ * Releases resources used by the receiver.
+ *
+ * @param {Function} cb Callback
+ * @public
+ */
+ cleanup (cb) {
+ this.dead = true;
+
+ if (!this.hadError && (this.loop || this.state === INFLATING)) {
+ this.cleanupCallback = cb;
+ } else {
+ this.extensions = null;
+ this.fragments = null;
+ this.buffers = null;
+ this.mask = null;
+
+ this.cleanupCallback = null;
+ this.onmessage = null;
+ this.onclose = null;
+ this.onerror = null;
+ this.onping = null;
+ this.onpong = null;
+
+ if (cb) cb();
+ }
+ }
+}
+
+module.exports = Receiver;
+
+/**
+ * Makes a buffer from a list of fragments.
+ *
+ * @param {Buffer[]} fragments The list of fragments composing the message
+ * @param {Number} messageLength The length of the message
+ * @return {Buffer}
+ * @private
+ */
+function toBuffer (fragments, messageLength) {
+ if (fragments.length === 1) return fragments[0];
+ if (fragments.length > 1) return bufferUtil.concat(fragments, messageLength);
+ return constants.EMPTY_BUFFER;
+}
+
+/**
+ * Converts a buffer to an `ArrayBuffer`.
+ *
+ * @param {Buffer} The buffer to convert
+ * @return {ArrayBuffer} Converted buffer
+ */
+function toArrayBuffer (buf) {
+ if (buf.byteOffset === 0 && buf.byteLength === buf.buffer.byteLength) {
+ return buf.buffer;
+ }
+
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
+}
diff --git a/node_modules/ws/lib/Sender.js b/node_modules/ws/lib/Sender.js
new file mode 100644
index 0000000..79e68a5
--- /dev/null
+++ b/node_modules/ws/lib/Sender.js
@@ -0,0 +1,403 @@
+/*!
+ * ws: a node.js websocket client
+ * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+'use strict';
+
+const safeBuffer = require('safe-buffer');
+const crypto = require('crypto');
+
+const PerMessageDeflate = require('./PerMessageDeflate');
+const bufferUtil = require('./BufferUtil');
+const ErrorCodes = require('./ErrorCodes');
+
+const Buffer = safeBuffer.Buffer;
+
+/**
+ * HyBi Sender implementation.
+ */
+class Sender {
+ /**
+ * Creates a Sender instance.
+ *
+ * @param {net.Socket} socket The connection socket
+ * @param {Object} extensions An object containing the negotiated extensions
+ */
+ constructor (socket, extensions) {
+ this.perMessageDeflate = (extensions || {})[PerMessageDeflate.extensionName];
+ this._socket = socket;
+
+ this.firstFragment = true;
+ this.compress = false;
+
+ this.bufferedBytes = 0;
+ this.deflating = false;
+ this.queue = [];
+
+ this.onerror = null;
+ }
+
+ /**
+ * Frames a piece of data according to the HyBi WebSocket protocol.
+ *
+ * @param {Buffer} data The data to frame
+ * @param {Object} options Options object
+ * @param {Number} options.opcode The opcode
+ * @param {Boolean} options.readOnly Specifies whether `data` can be modified
+ * @param {Boolean} options.fin Specifies whether or not to set the FIN bit
+ * @param {Boolean} options.mask Specifies whether or not to mask `data`
+ * @param {Boolean} options.rsv1 Specifies whether or not to set the RSV1 bit
+ * @return {Buffer[]} The framed data as a list of `Buffer` instances
+ * @public
+ */
+ static frame (data, options) {
+ const merge = data.length < 1024 || (options.mask && options.readOnly);
+ var offset = options.mask ? 6 : 2;
+ var payloadLength = data.length;
+
+ if (data.length >= 65536) {
+ offset += 8;
+ payloadLength = 127;
+ } else if (data.length > 125) {
+ offset += 2;
+ payloadLength = 126;
+ }
+
+ const target = Buffer.allocUnsafe(merge ? data.length + offset : offset);
+
+ target[0] = options.fin ? options.opcode | 0x80 : options.opcode;
+ if (options.rsv1) target[0] |= 0x40;
+
+ if (payloadLength === 126) {
+ target.writeUInt16BE(data.length, 2, true);
+ } else if (payloadLength === 127) {
+ target.writeUInt32BE(0, 2, true);
+ target.writeUInt32BE(data.length, 6, true);
+ }
+
+ if (!options.mask) {
+ target[1] = payloadLength;
+ if (merge) {
+ data.copy(target, offset);
+ return [target];
+ }
+
+ return [target, data];
+ }
+
+ const mask = crypto.randomBytes(4);
+
+ target[1] = payloadLength | 0x80;
+ target[offset - 4] = mask[0];
+ target[offset - 3] = mask[1];
+ target[offset - 2] = mask[2];
+ target[offset - 1] = mask[3];
+
+ if (merge) {
+ bufferUtil.mask(data, mask, target, offset, data.length);
+ return [target];
+ }
+
+ bufferUtil.mask(data, mask, data, 0, data.length);
+ return [target, data];
+ }
+
+ /**
+ * Sends a close message to the other peer.
+ *
+ * @param {(Number|undefined)} code The status code component of the body
+ * @param {String} data The message component of the body
+ * @param {Boolean} mask Specifies whether or not to mask the message
+ * @param {Function} cb Callback
+ * @public
+ */
+ close (code, data, mask, cb) {
+ if (code !== undefined && (typeof code !== 'number' || !ErrorCodes.isValidErrorCode(code))) {
+ throw new Error('first argument must be a valid error code number');
+ }
+
+ const buf = Buffer.allocUnsafe(2 + (data ? Buffer.byteLength(data) : 0));
+
+ buf.writeUInt16BE(code || 1000, 0, true);
+ if (buf.length > 2) buf.write(data, 2);
+
+ if (this.deflating) {
+ this.enqueue([this.doClose, buf, mask, cb]);
+ } else {
+ this.doClose(buf, mask, cb);
+ }
+ }
+
+ /**
+ * Frames and sends a close message.
+ *
+ * @param {Buffer} data The message to send
+ * @param {Boolean} mask Specifies whether or not to mask `data`
+ * @param {Function} cb Callback
+ * @private
+ */
+ doClose (data, mask, cb) {
+ this.sendFrame(Sender.frame(data, {
+ fin: true,
+ rsv1: false,
+ opcode: 0x08,
+ mask,
+ readOnly: false
+ }), cb);
+ }
+
+ /**
+ * Sends a ping message to the other peer.
+ *
+ * @param {*} data The message to send
+ * @param {Boolean} mask Specifies whether or not to mask `data`
+ * @public
+ */
+ ping (data, mask) {
+ var readOnly = true;
+
+ if (!Buffer.isBuffer(data)) {
+ if (data instanceof ArrayBuffer) {
+ data = Buffer.from(data);
+ } else if (ArrayBuffer.isView(data)) {
+ data = viewToBuffer(data);
+ } else {
+ data = Buffer.from(data);
+ readOnly = false;
+ }
+ }
+
+ if (this.deflating) {
+ this.enqueue([this.doPing, data, mask, readOnly]);
+ } else {
+ this.doPing(data, mask, readOnly);
+ }
+ }
+
+ /**
+ * Frames and sends a ping message.
+ *
+ * @param {*} data The message to send
+ * @param {Boolean} mask Specifies whether or not to mask `data`
+ * @param {Boolean} readOnly Specifies whether `data` can be modified
+ * @private
+ */
+ doPing (data, mask, readOnly) {
+ this.sendFrame(Sender.frame(data, {
+ fin: true,
+ rsv1: false,
+ opcode: 0x09,
+ mask,
+ readOnly
+ }));
+ }
+
+ /**
+ * Sends a pong message to the other peer.
+ *
+ * @param {*} data The message to send
+ * @param {Boolean} mask Specifies whether or not to mask `data`
+ * @public
+ */
+ pong (data, mask) {
+ var readOnly = true;
+
+ if (!Buffer.isBuffer(data)) {
+ if (data instanceof ArrayBuffer) {
+ data = Buffer.from(data);
+ } else if (ArrayBuffer.isView(data)) {
+ data = viewToBuffer(data);
+ } else {
+ data = Buffer.from(data);
+ readOnly = false;
+ }
+ }
+
+ if (this.deflating) {
+ this.enqueue([this.doPong, data, mask, readOnly]);
+ } else {
+ this.doPong(data, mask, readOnly);
+ }
+ }
+
+ /**
+ * Frames and sends a pong message.
+ *
+ * @param {*} data The message to send
+ * @param {Boolean} mask Specifies whether or not to mask `data`
+ * @param {Boolean} readOnly Specifies whether `data` can be modified
+ * @private
+ */
+ doPong (data, mask, readOnly) {
+ this.sendFrame(Sender.frame(data, {
+ fin: true,
+ rsv1: false,
+ opcode: 0x0a,
+ mask,
+ readOnly
+ }));
+ }
+
+ /**
+ * Sends a data message to the other peer.
+ *
+ * @param {*} data The message to send
+ * @param {Object} options Options object
+ * @param {Boolean} options.compress Specifies whether or not to compress `data`
+ * @param {Boolean} options.binary Specifies whether `data` is binary or text
+ * @param {Boolean} options.fin Specifies whether the fragment is the last one
+ * @param {Boolean} options.mask Specifies whether or not to mask `data`
+ * @param {Function} cb Callback
+ * @public
+ */
+ send (data, options, cb) {
+ var opcode = options.binary ? 2 : 1;
+ var rsv1 = options.compress;
+ var readOnly = true;
+
+ if (!Buffer.isBuffer(data)) {
+ if (data instanceof ArrayBuffer) {
+ data = Buffer.from(data);
+ } else if (ArrayBuffer.isView(data)) {
+ data = viewToBuffer(data);
+ } else {
+ data = Buffer.from(data);
+ readOnly = false;
+ }
+ }
+
+ if (this.firstFragment) {
+ this.firstFragment = false;
+ if (rsv1 && this.perMessageDeflate) {
+ rsv1 = data.length >= this.perMessageDeflate.threshold;
+ }
+ this.compress = rsv1;
+ } else {
+ rsv1 = false;
+ opcode = 0;
+ }
+
+ if (options.fin) this.firstFragment = true;
+
+ if (this.perMessageDeflate) {
+ const opts = {
+ fin: options.fin,
+ rsv1,
+ opcode,
+ mask: options.mask,
+ readOnly
+ };
+
+ if (this.deflating) {
+ this.enqueue([this.dispatch, data, this.compress, opts, cb]);
+ } else {
+ this.dispatch(data, this.compress, opts, cb);
+ }
+ } else {
+ this.sendFrame(Sender.frame(data, {
+ fin: options.fin,
+ rsv1: false,
+ opcode,
+ mask: options.mask,
+ readOnly
+ }), cb);
+ }
+ }
+
+ /**
+ * Dispatches a data message.
+ *
+ * @param {Buffer} data The message to send
+ * @param {Boolean} compress Specifies whether or not to compress `data`
+ * @param {Object} options Options object
+ * @param {Number} options.opcode The opcode
+ * @param {Boolean} options.readOnly Specifies whether `data` can be modified
+ * @param {Boolean} options.fin Specifies whether or not to set the FIN bit
+ * @param {Boolean} options.mask Specifies whether or not to mask `data`
+ * @param {Boolean} options.rsv1 Specifies whether or not to set the RSV1 bit
+ * @param {Function} cb Callback
+ * @private
+ */
+ dispatch (data, compress, options, cb) {
+ if (!compress) {
+ this.sendFrame(Sender.frame(data, options), cb);
+ return;
+ }
+
+ this.deflating = true;
+ this.perMessageDeflate.compress(data, options.fin, (err, buf) => {
+ if (err) {
+ if (cb) cb(err);
+ else this.onerror(err);
+ return;
+ }
+
+ options.readOnly = false;
+ this.sendFrame(Sender.frame(buf, options), cb);
+ this.deflating = false;
+ this.dequeue();
+ });
+ }
+
+ /**
+ * Executes queued send operations.
+ *
+ * @private
+ */
+ dequeue () {
+ while (!this.deflating && this.queue.length) {
+ const params = this.queue.shift();
+
+ this.bufferedBytes -= params[1].length;
+ params[0].apply(this, params.slice(1));
+ }
+ }
+
+ /**
+ * Enqueues a send operation.
+ *
+ * @param {Array} params Send operation parameters.
+ * @private
+ */
+ enqueue (params) {
+ this.bufferedBytes += params[1].length;
+ this.queue.push(params);
+ }
+
+ /**
+ * Sends a frame.
+ *
+ * @param {Buffer[]} list The frame to send
+ * @param {Function} cb Callback
+ * @private
+ */
+ sendFrame (list, cb) {
+ if (list.length === 2) {
+ this._socket.write(list[0]);
+ this._socket.write(list[1], cb);
+ } else {
+ this._socket.write(list[0], cb);
+ }
+ }
+}
+
+module.exports = Sender;
+
+/**
+ * Converts an `ArrayBuffer` view into a buffer.
+ *
+ * @param {(DataView|TypedArray)} view The view to convert
+ * @return {Buffer} Converted view
+ * @private
+ */
+function viewToBuffer (view) {
+ const buf = Buffer.from(view.buffer);
+
+ if (view.byteLength !== view.buffer.byteLength) {
+ return buf.slice(view.byteOffset, view.byteOffset + view.byteLength);
+ }
+
+ return buf;
+}
diff --git a/node_modules/ws/lib/Validation.js b/node_modules/ws/lib/Validation.js
new file mode 100644
index 0000000..fcb170f
--- /dev/null
+++ b/node_modules/ws/lib/Validation.js
@@ -0,0 +1,17 @@
+/*!
+ * ws: a node.js websocket client
+ * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+'use strict';
+
+try {
+ const isValidUTF8 = require('utf-8-validate');
+
+ module.exports = typeof isValidUTF8 === 'object'
+ ? isValidUTF8.Validation.isValidUTF8 // utf-8-validate@<3.0.0
+ : isValidUTF8;
+} catch (e) /* istanbul ignore next */ {
+ module.exports = () => true;
+}
diff --git a/node_modules/ws/lib/WebSocket.js b/node_modules/ws/lib/WebSocket.js
new file mode 100644
index 0000000..41868d8
--- /dev/null
+++ b/node_modules/ws/lib/WebSocket.js
@@ -0,0 +1,712 @@
+/*!
+ * ws: a node.js websocket client
+ * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+'use strict';
+
+const EventEmitter = require('events');
+const crypto = require('crypto');
+const Ultron = require('ultron');
+const https = require('https');
+const http = require('http');
+const url = require('url');
+
+const PerMessageDeflate = require('./PerMessageDeflate');
+const EventTarget = require('./EventTarget');
+const Extensions = require('./Extensions');
+const constants = require('./Constants');
+const Receiver = require('./Receiver');
+const Sender = require('./Sender');
+
+const protocolVersions = [8, 13];
+const closeTimeout = 30 * 1000; // Allow 30 seconds to terminate the connection cleanly.
+
+/**
+ * Class representing a WebSocket.
+ *
+ * @extends EventEmitter
+ */
+class WebSocket extends EventEmitter {
+ /**
+ * Create a new `WebSocket`.
+ *
+ * @param {String} address The URL to which to connect
+ * @param {(String|String[])} protocols The subprotocols
+ * @param {Object} options Connection options
+ */
+ constructor (address, protocols, options) {
+ super();
+
+ if (!protocols) {
+ protocols = [];
+ } else if (typeof protocols === 'string') {
+ protocols = [protocols];
+ } else if (!Array.isArray(protocols)) {
+ options = protocols;
+ protocols = [];
+ }
+
+ this.readyState = WebSocket.CONNECTING;
+ this.bytesReceived = 0;
+ this.extensions = {};
+ this.protocol = '';
+
+ this._binaryType = constants.BINARY_TYPES[0];
+ this._finalize = this.finalize.bind(this);
+ this._finalizeCalled = false;
+ this._closeMessage = null;
+ this._closeTimer = null;
+ this._closeCode = null;
+ this._receiver = null;
+ this._sender = null;
+ this._socket = null;
+ this._ultron = null;
+
+ if (Array.isArray(address)) {
+ initAsServerClient.call(this, address[0], address[1], address[2], options);
+ } else {
+ initAsClient.call(this, address, protocols, options);
+ }
+ }
+
+ get CONNECTING () { return WebSocket.CONNECTING; }
+ get CLOSING () { return WebSocket.CLOSING; }
+ get CLOSED () { return WebSocket.CLOSED; }
+ get OPEN () { return WebSocket.OPEN; }
+
+ /**
+ * @type {Number}
+ */
+ get bufferedAmount () {
+ var amount = 0;
+
+ if (this._socket) {
+ amount = this._socket.bufferSize + this._sender.bufferedBytes;
+ }
+ return amount;
+ }
+
+ /**
+ * This deviates from the WHATWG interface since ws doesn't support the required
+ * default "blob" type (instead we define a custom "nodebuffer" type).
+ *
+ * @type {String}
+ */
+ get binaryType () {
+ return this._binaryType;
+ }
+
+ set binaryType (type) {
+ if (constants.BINARY_TYPES.indexOf(type) < 0) return;
+
+ this._binaryType = type;
+
+ //
+ // Allow to change `binaryType` on the fly.
+ //
+ if (this._receiver) this._receiver.binaryType = type;
+ }
+
+ /**
+ * Set up the socket and the internal resources.
+ *
+ * @param {net.Socket} socket The network socket between the server and client
+ * @param {Buffer} head The first packet of the upgraded stream
+ * @private
+ */
+ setSocket (socket, head) {
+ socket.setTimeout(0);
+ socket.setNoDelay();
+
+ this._receiver = new Receiver(this.extensions, this.maxPayload, this.binaryType);
+ this._sender = new Sender(socket, this.extensions);
+ this._ultron = new Ultron(socket);
+ this._socket = socket;
+
+ // socket cleanup handlers
+ this._ultron.on('close', this._finalize);
+ this._ultron.on('error', this._finalize);
+ this._ultron.on('end', this._finalize);
+
+ // ensure that the head is added to the receiver
+ if (head && head.length > 0) {
+ socket.unshift(head);
+ head = null;
+ }
+
+ // subsequent packets are pushed to the receiver
+ this._ultron.on('data', (data) => {
+ this.bytesReceived += data.length;
+ this._receiver.add(data);
+ });
+
+ // receiver event handlers
+ this._receiver.onmessage = (data, flags) => this.emit('message', data, flags);
+ this._receiver.onping = (data, flags) => {
+ this.pong(data, !this._isServer, true);
+ this.emit('ping', data, flags);
+ };
+ this._receiver.onpong = (data, flags) => this.emit('pong', data, flags);
+ this._receiver.onclose = (code, reason) => {
+ this._closeMessage = reason;
+ this._closeCode = code;
+ this.close(code, reason);
+ };
+ this._receiver.onerror = (error, code) => {
+ // close the connection when the receiver reports a HyBi error code
+ this.close(code, '');
+ this.emit('error', error);
+ };
+
+ // sender event handlers
+ this._sender.onerror = (error) => {
+ this.close(1002, '');
+ this.emit('error', error);
+ };
+
+ this.readyState = WebSocket.OPEN;
+ this.emit('open');
+ }
+
+ /**
+ * Clean up and release internal resources.
+ *
+ * @param {(Boolean|Error)} Indicates whether or not an error occurred
+ * @private
+ */
+ finalize (error) {
+ if (this._finalizeCalled) return;
+
+ this.readyState = WebSocket.CLOSING;
+ this._finalizeCalled = true;
+
+ clearTimeout(this._closeTimer);
+ this._closeTimer = null;
+
+ //
+ // If the connection was closed abnormally (with an error), or if the close
+ // control frame was malformed or not received then the close code must be
+ // 1006.
+ //
+ if (error) this._closeCode = 1006;
+
+ if (this._socket) {
+ this._ultron.destroy();
+ this._socket.on('error', function onerror () {
+ this.destroy();
+ });
+
+ if (!error) this._socket.end();
+ else this._socket.destroy();
+
+ this._socket = null;
+ this._ultron = null;
+ }
+
+ if (this._sender) {
+ this._sender = this._sender.onerror = null;
+ }
+
+ if (this._receiver) {
+ this._receiver.cleanup(() => this.emitClose());
+ this._receiver = null;
+ } else {
+ this.emitClose();
+ }
+ }
+
+ /**
+ * Emit the `close` event.
+ *
+ * @private
+ */
+ emitClose () {
+ this.readyState = WebSocket.CLOSED;
+ this.emit('close', this._closeCode || 1006, this._closeMessage || '');
+
+ if (this.extensions[PerMessageDeflate.extensionName]) {
+ this.extensions[PerMessageDeflate.extensionName].cleanup();
+ }
+
+ this.extensions = null;
+
+ this.removeAllListeners();
+ this.on('error', constants.NOOP); // Catch all errors after this.
+ }
+
+ /**
+ * Pause the socket stream.
+ *
+ * @public
+ */
+ pause () {
+ if (this.readyState !== WebSocket.OPEN) throw new Error('not opened');
+
+ this._socket.pause();
+ }
+
+ /**
+ * Resume the socket stream
+ *
+ * @public
+ */
+ resume () {
+ if (this.readyState !== WebSocket.OPEN) throw new Error('not opened');
+
+ this._socket.resume();
+ }
+
+ /**
+ * Start a closing handshake.
+ *
+ * @param {Number} code Status code explaining why the connection is closing
+ * @param {String} data A string explaining why the connection is closing
+ * @public
+ */
+ close (code, data) {
+ if (this.readyState === WebSocket.CLOSED) return;
+ if (this.readyState === WebSocket.CONNECTING) {
+ if (this._req && !this._req.aborted) {
+ this._req.abort();
+ this.emit('error', new Error('closed before the connection is established'));
+ this.finalize(true);
+ }
+ return;
+ }
+
+ if (this.readyState === WebSocket.CLOSING) {
+ if (this._closeCode && this._socket) this._socket.end();
+ return;
+ }
+
+ this.readyState = WebSocket.CLOSING;
+ this._sender.close(code, data, !this._isServer, (err) => {
+ if (err) this.emit('error', err);
+
+ if (this._socket) {
+ if (this._closeCode) this._socket.end();
+ //
+ // Ensure that the connection is cleaned up even when the closing
+ // handshake fails.
+ //
+ clearTimeout(this._closeTimer);
+ this._closeTimer = setTimeout(this._finalize, closeTimeout, true);
+ }
+ });
+ }
+
+ /**
+ * Send a ping message.
+ *
+ * @param {*} data The message to send
+ * @param {Boolean} mask Indicates whether or not to mask `data`
+ * @param {Boolean} failSilently Indicates whether or not to throw if `readyState` isn't `OPEN`
+ * @public
+ */
+ ping (data, mask, failSilently) {
+ if (this.readyState !== WebSocket.OPEN) {
+ if (failSilently) return;
+ throw new Error('not opened');
+ }
+
+ if (typeof data === 'number') data = data.toString();
+ if (mask === undefined) mask = !this._isServer;
+ this._sender.ping(data || constants.EMPTY_BUFFER, mask);
+ }
+
+ /**
+ * Send a pong message.
+ *
+ * @param {*} data The message to send
+ * @param {Boolean} mask Indicates whether or not to mask `data`
+ * @param {Boolean} failSilently Indicates whether or not to throw if `readyState` isn't `OPEN`
+ * @public
+ */
+ pong (data, mask, failSilently) {
+ if (this.readyState !== WebSocket.OPEN) {
+ if (failSilently) return;
+ throw new Error('not opened');
+ }
+
+ if (typeof data === 'number') data = data.toString();
+ if (mask === undefined) mask = !this._isServer;
+ this._sender.pong(data || constants.EMPTY_BUFFER, mask);
+ }
+
+ /**
+ * Send a data message.
+ *
+ * @param {*} data The message to send
+ * @param {Object} options Options object
+ * @param {Boolean} options.compress Specifies whether or not to compress `data`
+ * @param {Boolean} options.binary Specifies whether `data` is binary or text
+ * @param {Boolean} options.fin Specifies whether the fragment is the last one
+ * @param {Boolean} options.mask Specifies whether or not to mask `data`
+ * @param {Function} cb Callback which is executed when data is written out
+ * @public
+ */
+ send (data, options, cb) {
+ if (typeof options === 'function') {
+ cb = options;
+ options = {};
+ }
+
+ if (this.readyState !== WebSocket.OPEN) {
+ if (cb) cb(new Error('not opened'));
+ else throw new Error('not opened');
+ return;
+ }
+
+ if (typeof data === 'number') data = data.toString();
+
+ const opts = Object.assign({
+ binary: typeof data !== 'string',
+ mask: !this._isServer,
+ compress: true,
+ fin: true
+ }, options);
+
+ if (!this.extensions[PerMessageDeflate.extensionName]) {
+ opts.compress = false;
+ }
+
+ this._sender.send(data || constants.EMPTY_BUFFER, opts, cb);
+ }
+
+ /**
+ * Forcibly close the connection.
+ *
+ * @public
+ */
+ terminate () {
+ if (this.readyState === WebSocket.CLOSED) return;
+ if (this.readyState === WebSocket.CONNECTING) {
+ if (this._req && !this._req.aborted) {
+ this._req.abort();
+ this.emit('error', new Error('closed before the connection is established'));
+ this.finalize(true);
+ }
+ return;
+ }
+
+ this.finalize(true);
+ }
+}
+
+WebSocket.CONNECTING = 0;
+WebSocket.OPEN = 1;
+WebSocket.CLOSING = 2;
+WebSocket.CLOSED = 3;
+
+//
+// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.
+// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface
+//
+['open', 'error', 'close', 'message'].forEach((method) => {
+ Object.defineProperty(WebSocket.prototype, `on${method}`, {
+ /**
+ * Return the listener of the event.
+ *
+ * @return {(Function|undefined)} The event listener or `undefined`
+ * @public
+ */
+ get () {
+ const listeners = this.listeners(method);
+ for (var i = 0; i < listeners.length; i++) {
+ if (listeners[i]._listener) return listeners[i]._listener;
+ }
+ },
+ /**
+ * Add a listener for the event.
+ *
+ * @param {Function} listener The listener to add
+ * @public
+ */
+ set (listener) {
+ const listeners = this.listeners(method);
+ for (var i = 0; i < listeners.length; i++) {
+ //
+ // Remove only the listeners added via `addEventListener`.
+ //
+ if (listeners[i]._listener) this.removeListener(method, listeners[i]);
+ }
+ this.addEventListener(method, listener);
+ }
+ });
+});
+
+WebSocket.prototype.addEventListener = EventTarget.addEventListener;
+WebSocket.prototype.removeEventListener = EventTarget.removeEventListener;
+
+module.exports = WebSocket;
+
+/**
+ * Initialize a WebSocket server client.
+ *
+ * @param {http.IncomingMessage} req The request object
+ * @param {net.Socket} socket The network socket between the server and client
+ * @param {Buffer} head The first packet of the upgraded stream
+ * @param {Object} options WebSocket attributes
+ * @param {Number} options.protocolVersion The WebSocket protocol version
+ * @param {Object} options.extensions The negotiated extensions
+ * @param {Number} options.maxPayload The maximum allowed message size
+ * @param {String} options.protocol The chosen subprotocol
+ * @private
+ */
+function initAsServerClient (req, socket, head, options) {
+ this.protocolVersion = options.protocolVersion;
+ this.extensions = options.extensions;
+ this.maxPayload = options.maxPayload;
+ this.protocol = options.protocol;
+
+ this.upgradeReq = req;
+ this._isServer = true;
+
+ this.setSocket(socket, head);
+}
+
+/**
+ * Initialize a WebSocket client.
+ *
+ * @param {String} address The URL to which to connect
+ * @param {String[]} protocols The list of subprotocols
+ * @param {Object} options Connection options
+ * @param {String} options.protocol Value of the `Sec-WebSocket-Protocol` header
+ * @param {(Boolean|Object)} options.perMessageDeflate Enable/disable permessage-deflate
+ * @param {String} options.localAddress Local interface to bind for network connections
+ * @param {Number} options.protocolVersion Value of the `Sec-WebSocket-Version` header
+ * @param {Object} options.headers An object containing request headers
+ * @param {String} options.origin Value of the `Origin` or `Sec-WebSocket-Origin` header
+ * @param {http.Agent} options.agent Use the specified Agent
+ * @param {String} options.host Value of the `Host` header
+ * @param {Number} options.family IP address family to use during hostname lookup (4 or 6).
+ * @param {Function} options.checkServerIdentity A function to validate the server hostname
+ * @param {Boolean} options.rejectUnauthorized Verify or not the server certificate
+ * @param {String} options.passphrase The passphrase for the private key or pfx
+ * @param {String} options.ciphers The ciphers to use or exclude
+ * @param {(String|String[]|Buffer|Buffer[])} options.cert The certificate key
+ * @param {(String|String[]|Buffer|Buffer[])} options.key The private key
+ * @param {(String|Buffer)} options.pfx The private key, certificate, and CA certs
+ * @param {(String|String[]|Buffer|Buffer[])} options.ca Trusted certificates
+ * @private
+ */
+function initAsClient (address, protocols, options) {
+ options = Object.assign({
+ protocolVersion: protocolVersions[1],
+ protocol: protocols.join(','),
+ perMessageDeflate: true,
+ localAddress: null,
+ headers: null,
+ family: null,
+ origin: null,
+ agent: null,
+ host: null,
+
+ //
+ // SSL options.
+ //
+ checkServerIdentity: null,
+ rejectUnauthorized: null,
+ passphrase: null,
+ ciphers: null,
+ cert: null,
+ key: null,
+ pfx: null,
+ ca: null
+ }, options);
+
+ if (protocolVersions.indexOf(options.protocolVersion) === -1) {
+ throw new Error(
+ `unsupported protocol version: ${options.protocolVersion} ` +
+ `(supported versions: ${protocolVersions.join(', ')})`
+ );
+ }
+
+ this.protocolVersion = options.protocolVersion;
+ this._isServer = false;
+ this.url = address;
+
+ const serverUrl = url.parse(address);
+ const isUnixSocket = serverUrl.protocol === 'ws+unix:';
+
+ if (!serverUrl.host && (!isUnixSocket || !serverUrl.path)) {
+ throw new Error('invalid url');
+ }
+
+ const isSecure = serverUrl.protocol === 'wss:' || serverUrl.protocol === 'https:';
+ const key = crypto.randomBytes(16).toString('base64');
+ const httpObj = isSecure ? https : http;
+
+ //
+ // Prepare extensions.
+ //
+ const extensionsOffer = {};
+ var perMessageDeflate;
+
+ if (options.perMessageDeflate) {
+ perMessageDeflate = new PerMessageDeflate(
+ options.perMessageDeflate !== true ? options.perMessageDeflate : {},
+ false
+ );
+ extensionsOffer[PerMessageDeflate.extensionName] = perMessageDeflate.offer();
+ }
+
+ const requestOptions = {
+ port: serverUrl.port || (isSecure ? 443 : 80),
+ host: serverUrl.hostname,
+ path: '/',
+ headers: {
+ 'Sec-WebSocket-Version': options.protocolVersion,
+ 'Sec-WebSocket-Key': key,
+ 'Connection': 'Upgrade',
+ 'Upgrade': 'websocket'
+ }
+ };
+
+ if (options.headers) Object.assign(requestOptions.headers, options.headers);
+ if (Object.keys(extensionsOffer).length) {
+ requestOptions.headers['Sec-WebSocket-Extensions'] = Extensions.format(extensionsOffer);
+ }
+ if (options.protocol) {
+ requestOptions.headers['Sec-WebSocket-Protocol'] = options.protocol;
+ }
+ if (options.origin) {
+ if (options.protocolVersion < 13) {
+ requestOptions.headers['Sec-WebSocket-Origin'] = options.origin;
+ } else {
+ requestOptions.headers.Origin = options.origin;
+ }
+ }
+ if (options.host) requestOptions.headers.Host = options.host;
+ if (serverUrl.auth) requestOptions.auth = serverUrl.auth;
+
+ if (options.localAddress) requestOptions.localAddress = options.localAddress;
+ if (options.family) requestOptions.family = options.family;
+
+ if (isUnixSocket) {
+ const parts = serverUrl.path.split(':');
+
+ requestOptions.socketPath = parts[0];
+ requestOptions.path = parts[1];
+ } else if (serverUrl.path) {
+ //
+ // Make sure that path starts with `/`.
+ //
+ if (serverUrl.path.charAt(0) !== '/') {
+ requestOptions.path = `/${serverUrl.path}`;
+ } else {
+ requestOptions.path = serverUrl.path;
+ }
+ }
+
+ var agent = options.agent;
+
+ //
+ // A custom agent is required for these options.
+ //
+ if (
+ options.rejectUnauthorized != null ||
+ options.checkServerIdentity ||
+ options.passphrase ||
+ options.ciphers ||
+ options.cert ||
+ options.key ||
+ options.pfx ||
+ options.ca
+ ) {
+ if (options.passphrase) requestOptions.passphrase = options.passphrase;
+ if (options.ciphers) requestOptions.ciphers = options.ciphers;
+ if (options.cert) requestOptions.cert = options.cert;
+ if (options.key) requestOptions.key = options.key;
+ if (options.pfx) requestOptions.pfx = options.pfx;
+ if (options.ca) requestOptions.ca = options.ca;
+ if (options.checkServerIdentity) {
+ requestOptions.checkServerIdentity = options.checkServerIdentity;
+ }
+ if (options.rejectUnauthorized != null) {
+ requestOptions.rejectUnauthorized = options.rejectUnauthorized;
+ }
+
+ if (!agent) agent = new httpObj.Agent(requestOptions);
+ }
+
+ if (agent) requestOptions.agent = agent;
+
+ this._req = httpObj.get(requestOptions);
+
+ this._req.on('error', (error) => {
+ if (this._req.aborted) return;
+
+ this._req = null;
+ this.emit('error', error);
+ this.finalize(true);
+ });
+
+ this._req.on('response', (res) => {
+ if (!this.emit('unexpected-response', this._req, res)) {
+ this._req.abort();
+ this.emit('error', new Error(`unexpected server response (${res.statusCode})`));
+ this.finalize(true);
+ }
+ });
+
+ this._req.on('upgrade', (res, socket, head) => {
+ this.emit('headers', res.headers, res);
+
+ //
+ // The user may have closed the connection from a listener of the `headers`
+ // event.
+ //
+ if (this.readyState !== WebSocket.CONNECTING) return;
+
+ this._req = null;
+
+ const digest = crypto.createHash('sha1')
+ .update(key + constants.GUID, 'binary')
+ .digest('base64');
+
+ if (res.headers['sec-websocket-accept'] !== digest) {
+ socket.destroy();
+ this.emit('error', new Error('invalid server key'));
+ return this.finalize(true);
+ }
+
+ const serverProt = res.headers['sec-websocket-protocol'];
+ const protList = (options.protocol || '').split(/, */);
+ var protError;
+
+ if (!options.protocol && serverProt) {
+ protError = 'server sent a subprotocol even though none requested';
+ } else if (options.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) {
+ socket.destroy();
+ this.emit('error', new Error(protError));
+ return this.finalize(true);
+ }
+
+ if (serverProt) this.protocol = serverProt;
+
+ const serverExtensions = Extensions.parse(res.headers['sec-websocket-extensions']);
+
+ if (perMessageDeflate && serverExtensions[PerMessageDeflate.extensionName]) {
+ try {
+ perMessageDeflate.accept(serverExtensions[PerMessageDeflate.extensionName]);
+ } catch (err) {
+ socket.destroy();
+ this.emit('error', new Error('invalid extension parameter'));
+ return this.finalize(true);
+ }
+
+ this.extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
+ }
+
+ this.setSocket(socket, head);
+ });
+}
diff --git a/node_modules/ws/lib/WebSocketServer.js b/node_modules/ws/lib/WebSocketServer.js
new file mode 100644
index 0000000..bd3ef24
--- /dev/null
+++ b/node_modules/ws/lib/WebSocketServer.js
@@ -0,0 +1,336 @@
+/*!
+ * ws: a node.js websocket client
+ * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+'use strict';
+
+const safeBuffer = require('safe-buffer');
+const EventEmitter = require('events');
+const crypto = require('crypto');
+const Ultron = require('ultron');
+const http = require('http');
+const url = require('url');
+
+const PerMessageDeflate = require('./PerMessageDeflate');
+const Extensions = require('./Extensions');
+const constants = require('./Constants');
+const WebSocket = require('./WebSocket');
+
+const Buffer = safeBuffer.Buffer;
+
+/**
+ * Class representing a WebSocket server.
+ *
+ * @extends EventEmitter
+ */
+class WebSocketServer extends EventEmitter {
+ /**
+ * Create a `WebSocketServer` instance.
+ *
+ * @param {Object} options Configuration options
+ * @param {String} options.host The hostname where to bind the server
+ * @param {Number} options.port The port where to bind the server
+ * @param {http.Server} options.server A pre-created HTTP/S server to use
+ * @param {Function} options.verifyClient An hook to reject connections
+ * @param {Function} options.handleProtocols An hook to handle protocols
+ * @param {String} options.path Accept only connections matching this path
+ * @param {Boolean} options.noServer Enable no server mode
+ * @param {Boolean} options.clientTracking Specifies whether or not to track clients
+ * @param {(Boolean|Object)} options.perMessageDeflate Enable/disable permessage-deflate
+ * @param {Number} options.maxPayload The maximum allowed message size
+ * @param {Function} callback A listener for the `listening` event
+ */
+ constructor (options, callback) {
+ super();
+
+ options = Object.assign({
+ maxPayload: 100 * 1024 * 1024,
+ perMessageDeflate: true,
+ handleProtocols: null,
+ clientTracking: true,
+ verifyClient: null,
+ noServer: false,
+ backlog: null, // use default (511 as implemented in net.js)
+ server: null,
+ host: null,
+ path: null,
+ port: null
+ }, options);
+
+ if (options.port == null && !options.server && !options.noServer) {
+ throw new TypeError('missing or invalid options');
+ }
+
+ if (options.port != null) {
+ this._server = http.createServer((req, res) => {
+ const 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.port, options.host, options.backlog, callback);
+ } else if (options.server) {
+ this._server = options.server;
+ }
+
+ if (this._server) {
+ this._ultron = new Ultron(this._server);
+ this._ultron.on('listening', () => this.emit('listening'));
+ this._ultron.on('error', (err) => this.emit('error', err));
+ this._ultron.on('upgrade', (req, socket, head) => {
+ this.handleUpgrade(req, socket, head, (client) => {
+ this.emit(`connection${req.url}`, client);
+ this.emit('connection', client);
+ });
+ });
+ }
+
+ if (options.clientTracking) this.clients = new Set();
+ this.options = options;
+ this.path = options.path;
+ }
+
+ /**
+ * Close the server.
+ *
+ * @param {Function} cb Callback
+ * @public
+ */
+ close (cb) {
+ //
+ // Terminate all associated clients.
+ //
+ if (this.clients) {
+ for (const client of this.clients) client.terminate();
+ }
+
+ const server = this._server;
+
+ if (server) {
+ this._ultron.destroy();
+ this._ultron = this._server = null;
+
+ //
+ // Close the http server if it was internally created.
+ //
+ if (this.options.port != null) return server.close(cb);
+ }
+
+ if (cb) cb();
+ }
+
+ /**
+ * See if a given request should be handled by this server instance.
+ *
+ * @param {http.IncomingMessage} req Request object to inspect
+ * @return {Boolean} `true` if the request is valid, else `false`
+ * @public
+ */
+ shouldHandle (req) {
+ if (this.options.path && url.parse(req.url).pathname !== this.options.path) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle a HTTP Upgrade request.
+ *
+ * @param {http.IncomingMessage} req The request object
+ * @param {net.Socket} socket The network socket between the server and client
+ * @param {Buffer} head The first packet of the upgraded stream
+ * @param {Function} cb Callback
+ * @public
+ */
+ handleUpgrade (req, socket, head, cb) {
+ socket.on('error', socketError);
+
+ const version = +req.headers['sec-websocket-version'];
+
+ if (
+ req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket' ||
+ !req.headers['sec-websocket-key'] || (version !== 8 && version !== 13) ||
+ !this.shouldHandle(req)
+ ) {
+ return abortConnection(socket, 400);
+ }
+
+ var protocol = (req.headers['sec-websocket-protocol'] || '').split(/, */);
+
+ //
+ // Optionally call external protocol selection handler.
+ //
+ if (this.options.handleProtocols) {
+ protocol = this.options.handleProtocols(protocol, req);
+ if (protocol === false) return abortConnection(socket, 401);
+ } else {
+ protocol = protocol[0];
+ }
+
+ //
+ // Optionally call external client verification handler.
+ //
+ if (this.options.verifyClient) {
+ const info = {
+ origin: req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],
+ secure: !!(req.connection.authorized || req.connection.encrypted),
+ req
+ };
+
+ if (this.options.verifyClient.length === 2) {
+ this.options.verifyClient(info, (verified, code, message) => {
+ if (!verified) return abortConnection(socket, code || 401, message);
+
+ this.completeUpgrade(protocol, version, req, socket, head, cb);
+ });
+ return;
+ } else if (!this.options.verifyClient(info)) {
+ return abortConnection(socket, 401);
+ }
+ }
+
+ this.completeUpgrade(protocol, version, req, socket, head, cb);
+ }
+
+ /**
+ * Upgrade the connection to WebSocket.
+ *
+ * @param {String} protocol The chosen subprotocol
+ * @param {Number} version The WebSocket protocol version
+ * @param {http.IncomingMessage} req The request object
+ * @param {net.Socket} socket The network socket between the server and client
+ * @param {Buffer} head The first packet of the upgraded stream
+ * @param {Function} cb Callback
+ * @private
+ */
+ completeUpgrade (protocol, version, req, socket, head, cb) {
+ //
+ // Destroy the socket if the client has already sent a FIN packet.
+ //
+ if (!socket.readable || !socket.writable) return socket.destroy();
+
+ const key = crypto.createHash('sha1')
+ .update(req.headers['sec-websocket-key'] + constants.GUID, 'binary')
+ .digest('base64');
+
+ const headers = [
+ 'HTTP/1.1 101 Switching Protocols',
+ 'Upgrade: websocket',
+ 'Connection: Upgrade',
+ `Sec-WebSocket-Accept: ${key}`
+ ];
+
+ if (protocol) headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
+
+ const offer = Extensions.parse(req.headers['sec-websocket-extensions']);
+ var extensions;
+
+ try {
+ extensions = acceptExtensions(this.options, offer);
+ } catch (err) {
+ return abortConnection(socket, 400);
+ }
+
+ const props = Object.keys(extensions);
+
+ if (props.length) {
+ const serverExtensions = props.reduce((obj, key) => {
+ obj[key] = [extensions[key].params];
+ return obj;
+ }, {});
+
+ headers.push(`Sec-WebSocket-Extensions: ${Extensions.format(serverExtensions)}`);
+ }
+
+ //
+ // Allow external modification/inspection of handshake headers.
+ //
+ this.emit('headers', headers, req);
+
+ socket.write(headers.concat('', '').join('\r\n'));
+
+ const client = new WebSocket([req, socket, head], null, {
+ maxPayload: this.options.maxPayload,
+ protocolVersion: version,
+ extensions,
+ protocol
+ });
+
+ if (this.clients) {
+ this.clients.add(client);
+ client.on('close', () => this.clients.delete(client));
+ }
+
+ socket.removeListener('error', socketError);
+ cb(client);
+ }
+}
+
+module.exports = WebSocketServer;
+
+/**
+ * Handle premature socket errors.
+ *
+ * @private
+ */
+function socketError () {
+ this.destroy();
+}
+
+/**
+ * Accept WebSocket extensions.
+ *
+ * @param {Object} options The `WebSocketServer` configuration options
+ * @param {Object} offer The parsed value of the `sec-websocket-extensions` header
+ * @return {Object} Accepted extensions
+ * @private
+ */
+function acceptExtensions (options, offer) {
+ const pmd = options.perMessageDeflate;
+ const extensions = {};
+
+ if (pmd && offer[PerMessageDeflate.extensionName]) {
+ const perMessageDeflate = new PerMessageDeflate(
+ pmd !== true ? pmd : {},
+ true,
+ options.maxPayload
+ );
+
+ perMessageDeflate.accept(offer[PerMessageDeflate.extensionName]);
+ extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
+ }
+
+ return extensions;
+}
+
+/**
+ * Close the connection when preconditions are not fulfilled.
+ *
+ * @param {net.Socket} socket The socket of the upgrade request
+ * @param {Number} code The HTTP response status code
+ * @param {String} [message] The HTTP response body
+ * @private
+ */
+function abortConnection (socket, code, message) {
+ if (socket.writable) {
+ message = message || http.STATUS_CODES[code];
+ socket.write(
+ `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
+ 'Connection: close\r\n' +
+ 'Content-type: text/html\r\n' +
+ `Content-Length: ${Buffer.byteLength(message)}\r\n` +
+ '\r\n' +
+ message
+ );
+ }
+
+ socket.removeListener('error', socketError);
+ socket.destroy();
+}
diff --git a/node_modules/ws/node_modules/safe-buffer/.travis.yml b/node_modules/ws/node_modules/safe-buffer/.travis.yml
new file mode 100644
index 0000000..7b20f28
--- /dev/null
+++ b/node_modules/ws/node_modules/safe-buffer/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+ - 'node'
+ - '5'
+ - '4'
+ - '0.12'
+ - '0.10'
diff --git a/node_modules/ws/node_modules/safe-buffer/LICENSE b/node_modules/ws/node_modules/safe-buffer/LICENSE
new file mode 100644
index 0000000..0c068ce
--- /dev/null
+++ b/node_modules/ws/node_modules/safe-buffer/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Feross Aboukhadijeh
+
+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/ws/node_modules/safe-buffer/README.md b/node_modules/ws/node_modules/safe-buffer/README.md
new file mode 100644
index 0000000..96eb387
--- /dev/null
+++ b/node_modules/ws/node_modules/safe-buffer/README.md
@@ -0,0 +1,581 @@
+# safe-buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][npm-url]
+
+#### Safer Node.js Buffer API
+
+**Use the new Node.js v6 Buffer APIs (`Buffer.from`, `Buffer.alloc`,
+`Buffer.allocUnsafe`, `Buffer.allocUnsafeSlow`) in Node.js v0.10, v0.12, v4.x, and v5.x.**
+
+**Uses the built-in implementations when available.**
+
+[travis-image]: https://img.shields.io/travis/feross/safe-buffer.svg
+[travis-url]: https://travis-ci.org/feross/safe-buffer
+[npm-image]: https://img.shields.io/npm/v/safe-buffer.svg
+[npm-url]: https://npmjs.org/package/safe-buffer
+[downloads-image]: https://img.shields.io/npm/dm/safe-buffer.svg
+
+## install
+
+```
+npm install safe-buffer
+```
+
+## usage
+
+The goal of this package is to provide a safe replacement for the node.js `Buffer`.
+
+It's a drop-in replacement for `Buffer`. You can use it by adding one `require` line to
+the top of your node.js modules:
+
+```js
+var Buffer = require('safe-buffer').Buffer
+
+// Existing buffer code will continue to work without issues:
+
+new Buffer('hey', 'utf8')
+new Buffer([1, 2, 3], 'utf8')
+new Buffer(obj)
+new Buffer(16) // create an uninitialized buffer (potentially unsafe)
+
+// But you can use these new explicit APIs to make clear what you want:
+
+Buffer.from('hey', 'utf8') // convert from many types to a Buffer
+Buffer.alloc(16) // create a zero-filled buffer (safe)
+Buffer.allocUnsafe(16) // create an uninitialized buffer (potentially unsafe)
+```
+
+## api
+
+### Class Method: Buffer.from(array)
+<!-- YAML
+added: v3.0.0
+-->
+
+* `array` {Array}
+
+Allocates a new `Buffer` using an `array` of octets.
+
+```js
+const buf = Buffer.from([0x62,0x75,0x66,0x66,0x65,0x72]);
+ // creates a new Buffer containing ASCII bytes
+ // ['b','u','f','f','e','r']
+```
+
+A `TypeError` will be thrown if `array` is not an `Array`.
+
+### Class Method: Buffer.from(arrayBuffer[, byteOffset[, length]])
+<!-- YAML
+added: v5.10.0
+-->
+
+* `arrayBuffer` {ArrayBuffer} The `.buffer` property of a `TypedArray` or
+ a `new ArrayBuffer()`
+* `byteOffset` {Number} Default: `0`
+* `length` {Number} Default: `arrayBuffer.length - byteOffset`
+
+When passed a reference to the `.buffer` property of a `TypedArray` instance,
+the newly created `Buffer` will share the same allocated memory as the
+TypedArray.
+
+```js
+const arr = new Uint16Array(2);
+arr[0] = 5000;
+arr[1] = 4000;
+
+const buf = Buffer.from(arr.buffer); // shares the memory with arr;
+
+console.log(buf);
+ // Prints: <Buffer 88 13 a0 0f>
+
+// changing the TypedArray changes the Buffer also
+arr[1] = 6000;
+
+console.log(buf);
+ // Prints: <Buffer 88 13 70 17>
+```
+
+The optional `byteOffset` and `length` arguments specify a memory range within
+the `arrayBuffer` that will be shared by the `Buffer`.
+
+```js
+const ab = new ArrayBuffer(10);
+const buf = Buffer.from(ab, 0, 2);
+console.log(buf.length);
+ // Prints: 2
+```
+
+A `TypeError` will be thrown if `arrayBuffer` is not an `ArrayBuffer`.
+
+### Class Method: Buffer.from(buffer)
+<!-- YAML
+added: v3.0.0
+-->
+
+* `buffer` {Buffer}
+
+Copies the passed `buffer` data onto a new `Buffer` instance.
+
+```js
+const buf1 = Buffer.from('buffer');
+const buf2 = Buffer.from(buf1);
+
+buf1[0] = 0x61;
+console.log(buf1.toString());
+ // 'auffer'
+console.log(buf2.toString());
+ // 'buffer' (copy is not changed)
+```
+
+A `TypeError` will be thrown if `buffer` is not a `Buffer`.
+
+### Class Method: Buffer.from(str[, encoding])
+<!-- YAML
+added: v5.10.0
+-->
+
+* `str` {String} String to encode.
+* `encoding` {String} Encoding to use, Default: `'utf8'`
+
+Creates a new `Buffer` containing the given JavaScript string `str`. If
+provided, the `encoding` parameter identifies the character encoding.
+If not provided, `encoding` defaults to `'utf8'`.
+
+```js
+const buf1 = Buffer.from('this is a tést');
+console.log(buf1.toString());
+ // prints: this is a tést
+console.log(buf1.toString('ascii'));
+ // prints: this is a tC)st
+
+const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex');
+console.log(buf2.toString());
+ // prints: this is a tést
+```
+
+A `TypeError` will be thrown if `str` is not a string.
+
+### Class Method: Buffer.alloc(size[, fill[, encoding]])
+<!-- YAML
+added: v5.10.0
+-->
+
+* `size` {Number}
+* `fill` {Value} Default: `undefined`
+* `encoding` {String} Default: `utf8`
+
+Allocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the
+`Buffer` will be *zero-filled*.
+
+```js
+const buf = Buffer.alloc(5);
+console.log(buf);
+ // <Buffer 00 00 00 00 00>
+```
+
+The `size` must be less than or equal to the value of
+`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is
+`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will
+be created if a `size` less than or equal to 0 is specified.
+
+If `fill` is specified, the allocated `Buffer` will be initialized by calling
+`buf.fill(fill)`. See [`buf.fill()`][] for more information.
+
+```js
+const buf = Buffer.alloc(5, 'a');
+console.log(buf);
+ // <Buffer 61 61 61 61 61>
+```
+
+If both `fill` and `encoding` are specified, the allocated `Buffer` will be
+initialized by calling `buf.fill(fill, encoding)`. For example:
+
+```js
+const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');
+console.log(buf);
+ // <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
+```
+
+Calling `Buffer.alloc(size)` can be significantly slower than the alternative
+`Buffer.allocUnsafe(size)` but ensures that the newly created `Buffer` instance
+contents will *never contain sensitive data*.
+
+A `TypeError` will be thrown if `size` is not a number.
+
+### Class Method: Buffer.allocUnsafe(size)
+<!-- YAML
+added: v5.10.0
+-->
+
+* `size` {Number}
+
+Allocates a new *non-zero-filled* `Buffer` of `size` bytes. The `size` must
+be less than or equal to the value of `require('buffer').kMaxLength` (on 64-bit
+architectures, `kMaxLength` is `(2^31)-1`). Otherwise, a [`RangeError`][] is
+thrown. A zero-length Buffer will be created if a `size` less than or equal to
+0 is specified.
+
+The underlying memory for `Buffer` instances created in this way is *not
+initialized*. The contents of the newly created `Buffer` are unknown and
+*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such
+`Buffer` instances to zeroes.
+
+```js
+const buf = Buffer.allocUnsafe(5);
+console.log(buf);
+ // <Buffer 78 e0 82 02 01>
+ // (octets will be different, every time)
+buf.fill(0);
+console.log(buf);
+ // <Buffer 00 00 00 00 00>
+```
+
+A `TypeError` will be thrown if `size` is not a number.
+
+Note that the `Buffer` module pre-allocates an internal `Buffer` instance of
+size `Buffer.poolSize` that is used as a pool for the fast allocation of new
+`Buffer` instances created using `Buffer.allocUnsafe(size)` (and the deprecated
+`new Buffer(size)` constructor) only when `size` is less than or equal to
+`Buffer.poolSize >> 1` (floor of `Buffer.poolSize` divided by two). The default
+value of `Buffer.poolSize` is `8192` but can be modified.
+
+Use of this pre-allocated internal memory pool is a key difference between
+calling `Buffer.alloc(size, fill)` vs. `Buffer.allocUnsafe(size).fill(fill)`.
+Specifically, `Buffer.alloc(size, fill)` will *never* use the internal Buffer
+pool, while `Buffer.allocUnsafe(size).fill(fill)` *will* use the internal
+Buffer pool if `size` is less than or equal to half `Buffer.poolSize`. The
+difference is subtle but can be important when an application requires the
+additional performance that `Buffer.allocUnsafe(size)` provides.
+
+### Class Method: Buffer.allocUnsafeSlow(size)
+<!-- YAML
+added: v5.10.0
+-->
+
+* `size` {Number}
+
+Allocates a new *non-zero-filled* and non-pooled `Buffer` of `size` bytes. The
+`size` must be less than or equal to the value of
+`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is
+`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will
+be created if a `size` less than or equal to 0 is specified.
+
+The underlying memory for `Buffer` instances created in this way is *not
+initialized*. The contents of the newly created `Buffer` are unknown and
+*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such
+`Buffer` instances to zeroes.
+
+When using `Buffer.allocUnsafe()` to allocate new `Buffer` instances,
+allocations under 4KB are, by default, sliced from a single pre-allocated
+`Buffer`. This allows applications to avoid the garbage collection overhead of
+creating many individually allocated Buffers. This approach improves both
+performance and memory usage by eliminating the need to track and cleanup as
+many `Persistent` objects.
+
+However, in the case where a developer may need to retain a small chunk of
+memory from a pool for an indeterminate amount of time, it may be appropriate
+to create an un-pooled Buffer instance using `Buffer.allocUnsafeSlow()` then
+copy out the relevant bits.
+
+```js
+// need to keep around a few small chunks of memory
+const store = [];
+
+socket.on('readable', () => {
+ const data = socket.read();
+ // allocate for retained data
+ const sb = Buffer.allocUnsafeSlow(10);
+ // copy the data into the new allocation
+ data.copy(sb, 0, 0, 10);
+ store.push(sb);
+});
+```
+
+Use of `Buffer.allocUnsafeSlow()` should be used only as a last resort *after*
+a developer has observed undue memory retention in their applications.
+
+A `TypeError` will be thrown if `size` is not a number.
+
+### All the Rest
+
+The rest of the `Buffer` API is exactly the same as in node.js.
+[See the docs](https://nodejs.org/api/buffer.html).
+
+
+## Related links
+
+- [Node.js issue: Buffer(number) is unsafe](https://github.com/nodejs/node/issues/4660)
+- [Node.js Enhancement Proposal: Buffer.from/Buffer.alloc/Buffer.zalloc/Buffer() soft-deprecate](https://github.com/nodejs/node-eps/pull/4)
+
+## Why is `Buffer` unsafe?
+
+Today, the node.js `Buffer` constructor is overloaded to handle many different argument
+types like `String`, `Array`, `Object`, `TypedArrayView` (`Uint8Array`, etc.),
+`ArrayBuffer`, and also `Number`.
+
+The API is optimized for convenience: you can throw any type at it, and it will try to do
+what you want.
+
+Because the Buffer constructor is so powerful, you often see code like this:
+
+```js
+// Convert UTF-8 strings to hex
+function toHex (str) {
+ return new Buffer(str).toString('hex')
+}
+```
+
+***But what happens if `toHex` is called with a `Number` argument?***
+
+### Remote Memory Disclosure
+
+If an attacker can make your program call the `Buffer` constructor with a `Number`
+argument, then they can make it allocate uninitialized memory from the node.js process.
+This could potentially disclose TLS private keys, user data, or database passwords.
+
+When the `Buffer` constructor is passed a `Number` argument, it returns an
+**UNINITIALIZED** block of memory of the specified `size`. When you create a `Buffer` like
+this, you **MUST** overwrite the contents before returning it to the user.
+
+From the [node.js docs](https://nodejs.org/api/buffer.html#buffer_new_buffer_size):
+
+> `new Buffer(size)`
+>
+> - `size` Number
+>
+> The underlying memory for `Buffer` instances created in this way is not initialized.
+> **The contents of a newly created `Buffer` are unknown and could contain sensitive
+> data.** Use `buf.fill(0)` to initialize a Buffer to zeroes.
+
+(Emphasis our own.)
+
+Whenever the programmer intended to create an uninitialized `Buffer` you often see code
+like this:
+
+```js
+var buf = new Buffer(16)
+
+// Immediately overwrite the uninitialized buffer with data from another buffer
+for (var i = 0; i < buf.length; i++) {
+ buf[i] = otherBuf[i]
+}
+```
+
+
+### Would this ever be a problem in real code?
+
+Yes. It's surprisingly common to forget to check the type of your variables in a
+dynamically-typed language like JavaScript.
+
+Usually the consequences of assuming the wrong type is that your program crashes with an
+uncaught exception. But the failure mode for forgetting to check the type of arguments to
+the `Buffer` constructor is more catastrophic.
+
+Here's an example of a vulnerable service that takes a JSON payload and converts it to
+hex:
+
+```js
+// Take a JSON payload {str: "some string"} and convert it to hex
+var server = http.createServer(function (req, res) {
+ var data = ''
+ req.setEncoding('utf8')
+ req.on('data', function (chunk) {
+ data += chunk
+ })
+ req.on('end', function () {
+ var body = JSON.parse(data)
+ res.end(new Buffer(body.str).toString('hex'))
+ })
+})
+
+server.listen(8080)
+```
+
+In this example, an http client just has to send:
+
+```json
+{
+ "str": 1000
+}
+```
+
+and it will get back 1,000 bytes of uninitialized memory from the server.
+
+This is a very serious bug. It's similar in severity to the
+[the Heartbleed bug](http://heartbleed.com/) that allowed disclosure of OpenSSL process
+memory by remote attackers.
+
+
+### Which real-world packages were vulnerable?
+
+#### [`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht)
+
+[Mathias Buus](https://github.com/mafintosh) and I
+([Feross Aboukhadijeh](http://feross.org/)) found this issue in one of our own packages,
+[`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht). The bug would allow
+anyone on the internet to send a series of messages to a user of `bittorrent-dht` and get
+them to reveal 20 bytes at a time of uninitialized memory from the node.js process.
+
+Here's
+[the commit](https://github.com/feross/bittorrent-dht/commit/6c7da04025d5633699800a99ec3fbadf70ad35b8)
+that fixed it. We released a new fixed version, created a
+[Node Security Project disclosure](https://nodesecurity.io/advisories/68), and deprecated all
+vulnerable versions on npm so users will get a warning to upgrade to a newer version.
+
+#### [`ws`](https://www.npmjs.com/package/ws)
+
+That got us wondering if there were other vulnerable packages. Sure enough, within a short
+period of time, we found the same issue in [`ws`](https://www.npmjs.com/package/ws), the
+most popular WebSocket implementation in node.js.
+
+If certain APIs were called with `Number` parameters instead of `String` or `Buffer` as
+expected, then uninitialized server memory would be disclosed to the remote peer.
+
+These were the vulnerable methods:
+
+```js
+socket.send(number)
+socket.ping(number)
+socket.pong(number)
+```
+
+Here's a vulnerable socket server with some echo functionality:
+
+```js
+server.on('connection', function (socket) {
+ socket.on('message', function (message) {
+ message = JSON.parse(message)
+ if (message.type === 'echo') {
+ socket.send(message.data) // send back the user's message
+ }
+ })
+})
+```
+
+`socket.send(number)` called on the server, will disclose server memory.
+
+Here's [the release](https://github.com/websockets/ws/releases/tag/1.0.1) where the issue
+was fixed, with a more detailed explanation. Props to
+[Arnout Kazemier](https://github.com/3rd-Eden) for the quick fix. Here's the
+[Node Security Project disclosure](https://nodesecurity.io/advisories/67).
+
+
+### What's the solution?
+
+It's important that node.js offers a fast way to get memory otherwise performance-critical
+applications would needlessly get a lot slower.
+
+But we need a better way to *signal our intent* as programmers. **When we want
+uninitialized memory, we should request it explicitly.**
+
+Sensitive functionality should not be packed into a developer-friendly API that loosely
+accepts many different types. This type of API encourages the lazy practice of passing
+variables in without checking the type very carefully.
+
+#### A new API: `Buffer.allocUnsafe(number)`
+
+The functionality of creating buffers with uninitialized memory should be part of another
+API. We propose `Buffer.allocUnsafe(number)`. This way, it's not part of an API that
+frequently gets user input of all sorts of different types passed into it.
+
+```js
+var buf = Buffer.allocUnsafe(16) // careful, uninitialized memory!
+
+// Immediately overwrite the uninitialized buffer with data from another buffer
+for (var i = 0; i < buf.length; i++) {
+ buf[i] = otherBuf[i]
+}
+```
+
+
+### How do we fix node.js core?
+
+We sent [a PR to node.js core](https://github.com/nodejs/node/pull/4514) (merged as
+`semver-major`) which defends against one case:
+
+```js
+var str = 16
+new Buffer(str, 'utf8')
+```
+
+In this situation, it's implied that the programmer intended the first argument to be a
+string, since they passed an encoding as a second argument. Today, node.js will allocate
+uninitialized memory in the case of `new Buffer(number, encoding)`, which is probably not
+what the programmer intended.
+
+But this is only a partial solution, since if the programmer does `new Buffer(variable)`
+(without an `encoding` parameter) there's no way to know what they intended. If `variable`
+is sometimes a number, then uninitialized memory will sometimes be returned.
+
+### What's the real long-term fix?
+
+We could deprecate and remove `new Buffer(number)` and use `Buffer.allocUnsafe(number)` when
+we need uninitialized memory. But that would break 1000s of packages.
+
+~~We believe the best solution is to:~~
+
+~~1. Change `new Buffer(number)` to return safe, zeroed-out memory~~
+
+~~2. Create a new API for creating uninitialized Buffers. We propose: `Buffer.allocUnsafe(number)`~~
+
+#### Update
+
+We now support adding three new APIs:
+
+- `Buffer.from(value)` - convert from any type to a buffer
+- `Buffer.alloc(size)` - create a zero-filled buffer
+- `Buffer.allocUnsafe(size)` - create an uninitialized buffer with given size
+
+This solves the core problem that affected `ws` and `bittorrent-dht` which is
+`Buffer(variable)` getting tricked into taking a number argument.
+
+This way, existing code continues working and the impact on the npm ecosystem will be
+minimal. Over time, npm maintainers can migrate performance-critical code to use
+`Buffer.allocUnsafe(number)` instead of `new Buffer(number)`.
+
+
+### Conclusion
+
+We think there's a serious design issue with the `Buffer` API as it exists today. It
+promotes insecure software by putting high-risk functionality into a convenient API
+with friendly "developer ergonomics".
+
+This wasn't merely a theoretical exercise because we found the issue in some of the
+most popular npm packages.
+
+Fortunately, there's an easy fix that can be applied today. Use `safe-buffer` in place of
+`buffer`.
+
+```js
+var Buffer = require('safe-buffer').Buffer
+```
+
+Eventually, we hope that node.js core can switch to this new, safer behavior. We believe
+the impact on the ecosystem would be minimal since it's not a breaking change.
+Well-maintained, popular packages would be updated to use `Buffer.alloc` quickly, while
+older, insecure packages would magically become safe from this attack vector.
+
+
+## links
+
+- [Node.js PR: buffer: throw if both length and enc are passed](https://github.com/nodejs/node/pull/4514)
+- [Node Security Project disclosure for `ws`](https://nodesecurity.io/advisories/67)
+- [Node Security Project disclosure for`bittorrent-dht`](https://nodesecurity.io/advisories/68)
+
+
+## credit
+
+The original issues in `bittorrent-dht`
+([disclosure](https://nodesecurity.io/advisories/68)) and
+`ws` ([disclosure](https://nodesecurity.io/advisories/67)) were discovered by
+[Mathias Buus](https://github.com/mafintosh) and
+[Feross Aboukhadijeh](http://feross.org/).
+
+Thanks to [Adam Baldwin](https://github.com/evilpacket) for helping disclose these issues
+and for his work running the [Node Security Project](https://nodesecurity.io/).
+
+Thanks to [John Hiesey](https://github.com/jhiesey) for proofreading this README and
+auditing the code.
+
+
+## license
+
+MIT. Copyright (C) [Feross Aboukhadijeh](http://feross.org)
diff --git a/node_modules/ws/node_modules/safe-buffer/browser.js b/node_modules/ws/node_modules/safe-buffer/browser.js
new file mode 100644
index 0000000..0bd1202
--- /dev/null
+++ b/node_modules/ws/node_modules/safe-buffer/browser.js
@@ -0,0 +1 @@
+module.exports = require('buffer')
diff --git a/node_modules/ws/node_modules/safe-buffer/index.js b/node_modules/ws/node_modules/safe-buffer/index.js
new file mode 100644
index 0000000..74a7358
--- /dev/null
+++ b/node_modules/ws/node_modules/safe-buffer/index.js
@@ -0,0 +1,58 @@
+var buffer = require('buffer')
+
+if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {
+ module.exports = buffer
+} else {
+ // Copy properties from require('buffer')
+ Object.keys(buffer).forEach(function (prop) {
+ exports[prop] = buffer[prop]
+ })
+ exports.Buffer = SafeBuffer
+}
+
+function SafeBuffer (arg, encodingOrOffset, length) {
+ return Buffer(arg, encodingOrOffset, length)
+}
+
+// Copy static methods from Buffer
+Object.keys(Buffer).forEach(function (prop) {
+ SafeBuffer[prop] = Buffer[prop]
+})
+
+SafeBuffer.from = function (arg, encodingOrOffset, length) {
+ if (typeof arg === 'number') {
+ throw new TypeError('Argument must not be a number')
+ }
+ return Buffer(arg, encodingOrOffset, length)
+}
+
+SafeBuffer.alloc = function (size, fill, encoding) {
+ if (typeof size !== 'number') {
+ throw new TypeError('Argument must be a number')
+ }
+ var buf = Buffer(size)
+ if (fill !== undefined) {
+ if (typeof encoding === 'string') {
+ buf.fill(fill, encoding)
+ } else {
+ buf.fill(fill)
+ }
+ } else {
+ buf.fill(0)
+ }
+ return buf
+}
+
+SafeBuffer.allocUnsafe = function (size) {
+ if (typeof size !== 'number') {
+ throw new TypeError('Argument must be a number')
+ }
+ return Buffer(size)
+}
+
+SafeBuffer.allocUnsafeSlow = function (size) {
+ if (typeof size !== 'number') {
+ throw new TypeError('Argument must be a number')
+ }
+ return buffer.SlowBuffer(size)
+}
diff --git a/node_modules/ws/node_modules/safe-buffer/package.json b/node_modules/ws/node_modules/safe-buffer/package.json
new file mode 100644
index 0000000..fcb6641
--- /dev/null
+++ b/node_modules/ws/node_modules/safe-buffer/package.json
@@ -0,0 +1,103 @@
+{
+ "_args": [
+ [
+ {
+ "raw": "safe-buffer@~5.0.1",
+ "scope": null,
+ "escapedName": "safe-buffer",
+ "name": "safe-buffer",
+ "rawSpec": "~5.0.1",
+ "spec": ">=5.0.1 <5.1.0",
+ "type": "range"
+ },
+ "/mnt/e/Yaroslav/Documents/Webs/nodejs/checkers/node_modules/ws"
+ ]
+ ],
+ "_from": "safe-buffer@>=5.0.1 <5.1.0",
+ "_id": "safe-buffer@5.0.1",
+ "_inCache": true,
+ "_location": "/ws/safe-buffer",
+ "_nodeVersion": "4.4.5",
+ "_npmOperationalInternal": {
+ "host": "packages-12-west.internal.npmjs.com",
+ "tmp": "tmp/safe-buffer-5.0.1.tgz_1464588482081_0.8112505874596536"
+ },
+ "_npmUser": {
+ "name": "feross",
+ "email": "feross@feross.org"
+ },
+ "_npmVersion": "2.15.5",
+ "_phantomChildren": {},
+ "_requested": {
+ "raw": "safe-buffer@~5.0.1",
+ "scope": null,
+ "escapedName": "safe-buffer",
+ "name": "safe-buffer",
+ "rawSpec": "~5.0.1",
+ "spec": ">=5.0.1 <5.1.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/ws"
+ ],
+ "_resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+ "_shasum": "d263ca54696cd8a306b5ca6551e92de57918fbe7",
+ "_shrinkwrap": null,
+ "_spec": "safe-buffer@~5.0.1",
+ "_where": "/mnt/e/Yaroslav/Documents/Webs/nodejs/checkers/node_modules/ws",
+ "author": {
+ "name": "Feross Aboukhadijeh",
+ "email": "feross@feross.org",
+ "url": "http://feross.org"
+ },
+ "browser": "./browser.js",
+ "bugs": {
+ "url": "https://github.com/feross/safe-buffer/issues"
+ },
+ "dependencies": {},
+ "description": "Safer Node.js Buffer API",
+ "devDependencies": {
+ "standard": "^7.0.0",
+ "tape": "^4.0.0",
+ "zuul": "^3.0.0"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "d263ca54696cd8a306b5ca6551e92de57918fbe7",
+ "tarball": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz"
+ },
+ "gitHead": "1e371a367da962afae2bebc527b50271c739d28c",
+ "homepage": "https://github.com/feross/safe-buffer",
+ "keywords": [
+ "buffer",
+ "buffer allocate",
+ "node security",
+ "safe",
+ "safe-buffer",
+ "security",
+ "uninitialized"
+ ],
+ "license": "MIT",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "feross",
+ "email": "feross@feross.org"
+ },
+ {
+ "name": "mafintosh",
+ "email": "mathiasbuus@gmail.com"
+ }
+ ],
+ "name": "safe-buffer",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/feross/safe-buffer.git"
+ },
+ "scripts": {
+ "test": "standard && tape test.js"
+ },
+ "version": "5.0.1"
+}
diff --git a/node_modules/ws/node_modules/safe-buffer/test.js b/node_modules/ws/node_modules/safe-buffer/test.js
new file mode 100644
index 0000000..7da8ad7
--- /dev/null
+++ b/node_modules/ws/node_modules/safe-buffer/test.js
@@ -0,0 +1,99 @@
+var test = require('tape')
+var SafeBuffer = require('./').Buffer
+
+test('new SafeBuffer(value) works just like Buffer', function (t) {
+ t.deepEqual(new SafeBuffer('hey'), new Buffer('hey'))
+ t.deepEqual(new SafeBuffer('hey', 'utf8'), new Buffer('hey', 'utf8'))
+ t.deepEqual(new SafeBuffer('686579', 'hex'), new Buffer('686579', 'hex'))
+ t.deepEqual(new SafeBuffer([1, 2, 3]), new Buffer([1, 2, 3]))
+ t.deepEqual(new SafeBuffer(new Uint8Array([1, 2, 3])), new Buffer(new Uint8Array([1, 2, 3])))
+
+ t.equal(typeof SafeBuffer.isBuffer, 'function')
+ t.equal(SafeBuffer.isBuffer(new SafeBuffer('hey')), true)
+ t.equal(Buffer.isBuffer(new SafeBuffer('hey')), true)
+ t.notOk(SafeBuffer.isBuffer({}))
+
+ t.end()
+})
+
+test('SafeBuffer.from(value) converts to a Buffer', function (t) {
+ t.deepEqual(SafeBuffer.from('hey'), new Buffer('hey'))
+ t.deepEqual(SafeBuffer.from('hey', 'utf8'), new Buffer('hey', 'utf8'))
+ t.deepEqual(SafeBuffer.from('686579', 'hex'), new Buffer('686579', 'hex'))
+ t.deepEqual(SafeBuffer.from([1, 2, 3]), new Buffer([1, 2, 3]))
+ t.deepEqual(SafeBuffer.from(new Uint8Array([1, 2, 3])), new Buffer(new Uint8Array([1, 2, 3])))
+
+ t.end()
+})
+
+test('SafeBuffer.alloc(number) returns zeroed-out memory', function (t) {
+ for (var i = 0; i < 10; i++) {
+ var expected1 = new Buffer(1000)
+ expected1.fill(0)
+ t.deepEqual(SafeBuffer.alloc(1000), expected1)
+
+ var expected2 = new Buffer(1000 * 1000)
+ expected2.fill(0)
+ t.deepEqual(SafeBuffer.alloc(1000 * 1000), expected2)
+ }
+ t.end()
+})
+
+test('SafeBuffer.allocUnsafe(number)', function (t) {
+ var buf = SafeBuffer.allocUnsafe(100) // unitialized memory
+ t.equal(buf.length, 100)
+ t.equal(SafeBuffer.isBuffer(buf), true)
+ t.equal(Buffer.isBuffer(buf), true)
+ t.end()
+})
+
+test('SafeBuffer.from() throws with number types', function (t) {
+ t.plan(5)
+ t.throws(function () {
+ SafeBuffer.from(0)
+ })
+ t.throws(function () {
+ SafeBuffer.from(-1)
+ })
+ t.throws(function () {
+ SafeBuffer.from(NaN)
+ })
+ t.throws(function () {
+ SafeBuffer.from(Infinity)
+ })
+ t.throws(function () {
+ SafeBuffer.from(99)
+ })
+})
+
+test('SafeBuffer.allocUnsafe() throws with non-number types', function (t) {
+ t.plan(4)
+ t.throws(function () {
+ SafeBuffer.allocUnsafe('hey')
+ })
+ t.throws(function () {
+ SafeBuffer.allocUnsafe('hey', 'utf8')
+ })
+ t.throws(function () {
+ SafeBuffer.allocUnsafe([1, 2, 3])
+ })
+ t.throws(function () {
+ SafeBuffer.allocUnsafe({})
+ })
+})
+
+test('SafeBuffer.alloc() throws with non-number types', function (t) {
+ t.plan(4)
+ t.throws(function () {
+ SafeBuffer.alloc('hey')
+ })
+ t.throws(function () {
+ SafeBuffer.alloc('hey', 'utf8')
+ })
+ t.throws(function () {
+ SafeBuffer.alloc([1, 2, 3])
+ })
+ t.throws(function () {
+ SafeBuffer.alloc({})
+ })
+})
diff --git a/node_modules/ws/package.json b/node_modules/ws/package.json
new file mode 100644
index 0000000..d007539
--- /dev/null
+++ b/node_modules/ws/package.json
@@ -0,0 +1,127 @@
+{
+ "_args": [
+ [
+ {
+ "raw": "ws@~2.3.1",
+ "scope": null,
+ "escapedName": "ws",
+ "name": "ws",
+ "rawSpec": "~2.3.1",
+ "spec": ">=2.3.1 <2.4.0",
+ "type": "range"
+ },
+ "/mnt/e/Yaroslav/Documents/Webs/nodejs/checkers/node_modules/engine.io"
+ ]
+ ],
+ "_from": "ws@>=2.3.1 <2.4.0",
+ "_id": "ws@2.3.1",
+ "_inCache": true,
+ "_location": "/ws",
+ "_nodeVersion": "7.9.0",
+ "_npmOperationalInternal": {
+ "host": "packages-12-west.internal.npmjs.com",
+ "tmp": "tmp/ws-2.3.1.tgz_1492711201097_0.04034068179316819"
+ },
+ "_npmUser": {
+ "name": "lpinca",
+ "email": "luigipinca@gmail.com"
+ },
+ "_npmVersion": "4.2.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "raw": "ws@~2.3.1",
+ "scope": null,
+ "escapedName": "ws",
+ "name": "ws",
+ "rawSpec": "~2.3.1",
+ "spec": ">=2.3.1 <2.4.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/engine.io",
+ "/engine.io-client"
+ ],
+ "_resolved": "https://registry.npmjs.org/ws/-/ws-2.3.1.tgz",
+ "_shasum": "6b94b3e447cb6a363f785eaf94af6359e8e81c80",
+ "_shrinkwrap": null,
+ "_spec": "ws@~2.3.1",
+ "_where": "/mnt/e/Yaroslav/Documents/Webs/nodejs/checkers/node_modules/engine.io",
+ "author": {
+ "name": "Einar Otto Stangvik",
+ "email": "einaros@gmail.com",
+ "url": "http://2x.io"
+ },
+ "bugs": {
+ "url": "https://github.com/websockets/ws/issues"
+ },
+ "dependencies": {
+ "safe-buffer": "~5.0.1",
+ "ultron": "~1.1.0"
+ },
+ "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
+ "devDependencies": {
+ "benchmark": "~2.1.2",
+ "bufferutil": "~3.0.0",
+ "eslint": "~3.19.0",
+ "eslint-config-standard": "~10.2.0",
+ "eslint-plugin-import": "~2.2.0",
+ "eslint-plugin-node": "~4.2.0",
+ "eslint-plugin-promise": "~3.5.0",
+ "eslint-plugin-standard": "~3.0.0",
+ "mocha": "~3.2.0",
+ "nyc": "~10.2.0",
+ "utf-8-validate": "~3.0.0"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "6b94b3e447cb6a363f785eaf94af6359e8e81c80",
+ "tarball": "https://registry.npmjs.org/ws/-/ws-2.3.1.tgz"
+ },
+ "files": [
+ "index.js",
+ "lib"
+ ],
+ "gitHead": "732aaf06b76700f104eeff2740e1896be4e88199",
+ "homepage": "https://github.com/websockets/ws",
+ "keywords": [
+ "HyBi",
+ "Push",
+ "RFC-6455",
+ "WebSocket",
+ "WebSockets",
+ "real-time"
+ ],
+ "license": "MIT",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "3rdeden",
+ "email": "npm@3rd-Eden.com"
+ },
+ {
+ "name": "einaros",
+ "email": "einaros@gmail.com"
+ },
+ {
+ "name": "lpinca",
+ "email": "luigipinca@gmail.com"
+ },
+ {
+ "name": "v1",
+ "email": "npm@3rd-Eden.com"
+ }
+ ],
+ "name": "ws",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/websockets/ws.git"
+ },
+ "scripts": {
+ "integration": "eslint . && mocha test/*.integration.js",
+ "lint": "eslint .",
+ "test": "eslint . && nyc --reporter=html --reporter=text mocha test/*.test.js"
+ },
+ "version": "2.3.1"
+}